Make .M3U master playlist - output as relative path names

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
thr333
Posts: 16
Joined: 24 Aug 2009 10:24

Make .M3U master playlist - output as relative path names

#1 Post by thr333 » 24 Aug 2009 12:10

Hi guys.

Let's say we have a target directory structure like this:

C:\My Music\parent folder\01 - parent folder.mp3
C:\My Music\parent folder\02 - parent folder.mp3
C:\My Music\parent folder\03 - parent folder.mp3
C:\My Music\parent folder\child folder 1\01 - child folder 1.mp3
C:\My Music\parent folder\child folder 1\02 - child folder 1.mp3
C:\My Music\parent folder\child folder 1\03 - child folder 1.mp3
C:\My Music\parent folder\child folder 2\01 - child folder 2.mp3
C:\My Music\parent folder\child folder 2\02 - child folder 2.mp3
C:\My Music\parent folder\child folder 2\03 - child folder 2.mp3


So...
If I just run Command Prompt from the 'parent folder' and type:
    dir /s /b *.mp3 > listall.txt

I get an output text file with absolute path exactly as you see above.

But this is not what I want.
I want a master playlist file dumped at "parent folder" which lists all, including subdirectories,
AND ALSO
output the text with relative path names (having "parent folder" as root)
AND ALSO
auto-name the playlist file as [the name of the parent folder].m3u

So we end up with this (example):

parent folder.m3u
--------------------------------------------------------------
parent folder\01 - parent folder.mp3
parent folder\02 - parent folder.mp3
parent folder\03 - parent folder.mp3
parent folder\child folder 1\01 - child folder 1.mp3
parent folder\child folder 1\02 - child folder 1.mp3
parent folder\child folder 1\03 - child folder 1.mp3
parent folder\child folder 2\01 - child folder 2.mp3
parent folder\child folder 2\02 - child folder 2.mp3
parent folder\child folder 2\03 - child folder 2.mp3
--------------------------------------------------------------



This code here recurses all subdir,
and dumps separate playlist.m3u files in each subdir (Bad, not what I want)
    for /R %%A in (*.mp3) do @echo %%~nxA >> "%%~dpAplaylist.m3u"


This code will create a master playlist (Good +++)
and recurses all subdir
and renames it to [the name of the parent folder].m3u:
    CD %1
    Dir /o:n /s /b *.mp3 > TempPlaylist.m3u
    Set foldervar=%CD%
    Set foldervar=%foldervar:*\=%
    Set foldervar=%foldervar:*\=%
    Set foldervar=%foldervar:*\=%
    Set foldervar=%foldervar:*\=%
    Set foldervar=%foldervar:*\=%
    Ren TempPlaylist.m3u "%foldervar%.m3u"


Close, but no cigar...
I'm still left with absolute path names in the playlist

There is a simple solution to this... but
I guess I'm not savvy enough to see it.
Cheers.
Last edited by thr333 on 26 Aug 2009 08:01, edited 4 times in total.

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#2 Post by avery_larry » 25 Aug 2009 09:02

Specific to the relative path code:

Code: Select all

@echo off
for /f "tokens=*" %%a in ('cd') do set "parent=%%~a\"
for /f "tokens=*" %%a in ('dir /s /b *.mp3') do (
   set "file=%%~a"
   call echo %%file:%parent%=%%>listall.txt
)

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#3 Post by thr333 » 25 Aug 2009 18:28

Spot on avery_larry your code works !!
Thankyou ++++
I needed to change line 5 to append (>>)
rather than overwrite (>) the text file.

I made the code echo the results line-by-line in the console
and added pauses between each line so I could visualize the runtime.
Yes sir, she kept outputting and outputting and outputting
every line with relative path names.
Great Stuff.

As you can see, I'm a DOS n00b.

It would be nice for my learning
if you could explain to me what each line is doing.
What are the brackets doing from lines 3 to 6 and why are you indenting
lines 4 and 5.

Ummm, one last thing...
So to make your batch also rename listall.txt to [the name of the parent folder].m3u
I add this code to the end of yours:
    set foldervar=%CD%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    ren listall.txt "%foldervar%.m3u"

Is there a better way to code this function
or do I really need to add all those lines ?

I'm pretty sure the answer has something to do with the FOR command.

--thr333

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#4 Post by avery_larry » 26 Aug 2009 09:24

thr333 wrote:Spot on avery_larry your code works !!
Thankyou ++++
I needed to change line 5 to append (>>)
rather than overwrite (>) the text file.
Good catch.
I made the code echo the results line-by-line in the console
and added pauses between each line so I could visualize the runtime.
Yes sir, she kept outputting and outputting and outputting
every line with relative path names.
Great Stuff.

As you can see, I'm a DOS n00b.

It would be nice for my learning
if you could explain to me what each line is doing.


Code: Select all

for /f "tokens=*" %%a in ('cd') do set "parent=%%~a"

fairly standard for expression to use the ouput of a command to set a variable. In this case, the command is 'cd' and the output of the command is stored in the variable "parent", with a backslash appended. This variable is used later. Note now that I recognize I could have just used %cd%\ instead.

Code: Select all

for /f "tokens=*" %%a in ('dir /s /b *.mp3') do ( 
   set "file=%%~a"
   call echo %%file:%parent%=%%>>listall.txt
)

This is one for loop. Once again, we're using the output of a command to run the for loop against. The "tokens=*" portion simply accomodates long file names. The 'dir /s /b *.mp3' portion you should already understand. The rest of the for loop is done on each filename returned by the dir command, one at a time.

Code: Select all

set "file=%%~a"
This just sets a variable to use in the next line of code. I can't do the substitutions and double expansion with the %%a variable. Wrapping the variable name, equal sign, and variable value inside double quotes does 2 things:
1) It helps the set command deal with some special characters.
2) It helps to make sure you don't accidentally add any spaces to the variable.

Code: Select all

call echo %%file:%parent%=%%>>listall.txt

This is where the magic happens. At the basic level, we're using a simple substring substitution to eliminate the parent directories. If your current directory was c:\tmp then we're trying to do this:

echo %file:c:\tmp\=% Which substitutes nothing (blank or nul) for c:\tmp\

The rest of it I'm not going to explain very well, because it's quite complicated. The %parent% is the variable that contains the parent directory, which we want to blank out of the lines, effectively we are stripping "c:\my music\parent folder" out of the dir's ouput. That's what this portion does:

:%parent%=

Using the "call" function allows us to evaluate the variable string twice. The first evaluation will expand any normal looking variables (single % surround) and it will evaluate any double percents as single percents. Something like this:

Code: Select all

call echo %%file:%parent%=%%>>listall.txt    becomes:
    echo  %file:c:\parentfolder\=%>>listall.txt

And THEN the echo command is run, which echos the %file% variable (which we just set to %%~a) and replaces "c:\parentfolder" with nul.
What are the brackets doing from lines 3 to 6 . . .

The parentheses will group the commands together, so that everything in the parentheses is done to each line of the for loop.
. . . and why are you indenting
lines 4 and 5.
Just because it's easier to read and keep track of the parentheses -- the groupings.
Ummm, one last thing...
So to make your batch also rename listall.txt to [the name of the parent folder].m3u
I add this code to the end of yours:
    set foldervar=%CD%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    set foldervar=%foldervar:*\=%
    ren listall.txt "%foldervar%.m3u"
Is there a better way to code this function
or do I really need to add all those lines ?

I'm pretty sure the answer has something to do with the FOR command.

--thr333
Well, you could do something similar to the above and strip out the parent folder from the current folder something like this:

**untested**

Code: Select all

set "folder=%cd%"
cd ..
call ren "%folder%\templaylist.m3u" "%%folder:%cd%\=%%"


Or you can use a for loop like this:

Code: Select all

CD %1
Dir /o:n /s /b *.mp3 > TempPlaylist.m3u
Set "foldervar=%CD%"
for /l %%a in (1,1,10) do call set "foldervar=%%foldervar:*\=%%"
Ren TempPlaylist.m3u "%foldervar%.m3u"
Nice use, by the way, of a wildcard substring replace. I'd forgotten that you can do that.

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#5 Post by thr333 » 26 Aug 2009 15:41

Thanks for taking the time to write ALL of that !!

The last code example.
Yeah, it works flawlessly, adding only this part to your previous code:
    Set "foldervar=%CD%"
    for /l %%a in (1,1,10) do call set "foldervar=%%foldervar:*\=%%"
    Ren listall.txt "%foldervar%.m3u"

What are the set of numbers in parenthesis (1,1,10) refering to again ?

The second last code example.
    set "folder=%cd%"
    cd ..
    call ren "%folder%\listall.txt" "%%folder:%cd%\=%%"

When appended to your previous code doesn't work,
even though It's much simpler looking.
Aren't we supposed to be adding .m3u file extension
somewhere in here: "%%folder:%cd%\=%%"

DccD
Posts: 23
Joined: 26 Aug 2009 19:34

#6 Post by DccD » 26 Aug 2009 20:51

This is a very nice piece of batch code... congrats avery_larry !
I did not know about the double evaluation with the call function. This will save me from headache. :wink:

To answer thr333:
What are the set of numbers in parenthesis (1,1,10) refering to again ?

The for loop runs trough a sequence of numbers from 1 to 10 with a step of 1. So in this case the loop will be applied 10 times to remove anything before a backslash (including the backslash). Am I wrong avery_larry ?

Aren't we supposed to be adding .m3u file extension
somewhere in here: "%%folder:%cd%\=%%"

That's correct:

Code: Select all

set "folder=%cd%"
cd ..
call ren "%folder%\listall.txt" "%%folder:%cd%\=%%.m3u"


I put my personal touch to optimize the code so it looks like this :

Code: Select all

@ECHO OFF
SET "currentfolder=%cd%"
CD ..
SET "upperfolder=%cd%"
CALL SET folder=%%currentfolder:%upperfolder%\=%%
CD %folder%
TITLE Generating Playlist for "%folder%"
ECHO.
ECHO Start time: %time:~0,-3%
ECHO Please wait...
FOR /F "tokens=*" %%A in ('dir /s /b *.mp3') DO (
SET "file=%%~A"
CALL ECHO %%file:%currentfolder%\=%% >>"# %folder%.m3u"
)
ECHO End time: %time:~0,-3%
ECHO 
PAUSE
Last edited by DccD on 26 Aug 2009 21:34, edited 1 time in total.

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#7 Post by thr333 » 26 Aug 2009 21:33

Well done DccD +++++
Thanks a lot for your contribution.
Your added details are cool.
I like a bit of interaction with scripts like this one.

And another thankyou to avery_larry.
Thanks for EVERYTHING +++++++

If anyone wants to copy and paste this and share it...
Make sure you give credits to these guys and this forum





                   makeplaylist.bat

                   [Build 3 - September 02, 2009]
                    - fixed illegal/special characters issue, see post by DccD further down
                    - fixed bug when running batch from root of a drive, see post by DccD further down

@ECHO OFF
:: -----------------------------------------------------------------------------
:: ---makeplaylist.bat
:: ---September 02, 2009 - build 3
:: ---.M3U MASTER PLAYLIST GENERATOR -- by avery_larry and DccD
:: ---developed at this forum thread:
:: ---http://www.dostips.com/forum/viewtopic.php?t=629
:: -----------------------------------------------------------------------------

ECHO.
SET currentfolder="%cd%"
CD ..
SET upperfolder="%cd%"
IF %upperfolder:~-2,-1%==\ SET upperfolder=%upperfolder:\=%
CALL SET folder=%%currentfolder:%upperfolder:"=%\=%%
CD %folder%
TITLE Generating Master Playlist for %folder%
ECHO.
ECHO ---------------------------------------------------------------------------
ECHO -- .M3U MASTER PLAYLIST GENERATOR -- by avery_larry and DccD --
ECHO.
ECHO makes master playlist file at "parent folder" (includes all subdirectories)
ECHO and outputs the text with relative path names ("parent folder" is root)
ECHO and auto-names the playlist file as "[the name of the parent folder].m3u"
ECHO.
ECHO ---------------------------------------------------------------------------
ECHO.
ECHO Start time: %time:~0,-3%
ECHO Please wait...
FOR /F "tokens=*" %%A IN ('dir /o:n /s /b *.mp3 *.flac *.m4a *.wav *.ape') DO CALL :loop "%%~A"
GOTO end

:loop
SET file="%~1"
CALL SET file2="%%file:*%currentfolder:"=%\=%%"
SET file2=%file2:~0,-1%
setlocal enabledelayedexpansion
>>"# %folder:"=%.m3u" ECHO !file2:"=!
GOTO :EOF

:end
ECHO End time: %time:~0,-3%
ECHO 
PAUSE

Last edited by thr333 on 01 Sep 2009 16:46, edited 8 times in total.

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#8 Post by thr333 » 27 Aug 2009 03:28

MORE: Make this a Windows Shell Extension
_______________________________________________

Right Click on any folder and create a listing (with relative paths)
of everything including subdirectories !!
This is really useful for people who play with portable applications.
In the example batch code above we are indexing all music files,
but you could customize other batch files for other file types...
I like the idea !!

A registry (.REG) file to add this to your right-click context menu
!! and don't forget to edit the .REG file to point to where you place the .BAT file !!
(in the example below it is at the Windows directory).




                  makeplaylist.reg

Windows Registry Editor Version 5.00

; --- makeplaylist.reg ---
; --- adds 'makeplaylist.bat' to right-click context menu ---


[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\makeplaylist]
@="&Make Playlist (M3U)"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Directory\shell\makeplaylist\command]
@="cmd /C C:\\WINDOWS\\makeplaylist.bat \"%L\""

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\makeplaylist]
@="&Make playlist (M3U)"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Folder\shell\makeplaylist\command]
@="cmd /C C:\\WINDOWS\\makeplaylist.bat \"%L\""



Now, there is only one little problem to solve...
The .M3U playlist file is created OUTSIDE the ("parent") folder you clicked on,
and also (unfortunately) indexes the next higher directory above the "parent"
I want the playlist made INSIDE the "parent folder",
and NOT to index the next higher directory.

I guess the batch script needs a little tweaking.
Anybody got a solution?

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#9 Post by avery_larry » 27 Aug 2009 12:07

th33 -- What DccD said.

DccD -- the call function for the double expansion of variables can also be accomplished using delayedexpansion like this:

Code: Select all

@echo off
setlocal enabledelayedexpansion

. . .

echo !file:%parent%=!>>listall.txt

. . .

ren "%folder%\templaylist.m3u" "!folder:%cd%\=!.m3u"

. . .


for /l %%a in (1,1,10) do call set "foldervar=!foldervar:*\=!"


I use delayedexpansion most of the time. In this case I couldn't remember if substring replacement worked with the various special characters properly so I just did the "call . . ." trick to expand the variable twice.

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#10 Post by thr333 » 28 Aug 2009 07:14

Hey avery_larry (and DccD),

The Batch file doesn't quite work (in all instances) !!

I dumped the batch at root of the following folders (and double clicked on it):

D:\_DESK\!uTorrent\Steppenwolf - (1970) Born to be Wild [Vinyl Mono45 192..44-16]-pbthal

and

D:\_DESK\!uTorrent\the B-52's - (1979) the B-52's [Vinyl 192..44-16]-pbthal


And nothing happened !!

Any Ideas ?

avery_larry
Expert
Posts: 391
Joined: 19 Mar 2009 08:47
Location: Iowa

#11 Post by avery_larry » 28 Aug 2009 10:01

A) Don't run it by double clicking on it. Open a command prompt and start in the correct directory when running the file.

2) I tend to doubt strongly that you'll be successful with a directory that includes ! -- and who knows about ()[] . . .

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#12 Post by thr333 » 28 Aug 2009 22:22

Thanks for that info avery_larry.
I had a suspicion it was what you mentioned.

So I played around with the folder/file names and discovered:
    --------------------------------------------
    Ampersand     &
    Excalamation      !
    and Round Brackets/Parenthesis      ( )

    ARE NOT ACCEPTABLE . BATCH WILL FAIL .
    --------------------------------------------
    Square/Box Brackets      [ ]
    and Dash      -
    and Underscore      _

    ARE OK . BATCH SUCCESSFUL .

DccD
Posts: 23
Joined: 26 Aug 2009 19:34

#13 Post by DccD » 30 Aug 2009 17:47

This should fix the special characters issue:

Code: Select all

@ECHO OFF
SET currentfolder="%cd%"
CD ..
SET upperfolder="%cd%"
CALL SET folder=%%currentfolder:%upperfolder:"=%\=%%
CD %folder%
TITLE Generating Playlist for %folder%
ECHO.
ECHO Start time: %time:~0,-3%
ECHO Please wait...
FOR /F "tokens=*" %%A in ('dir /s /b *.mp3') DO CALL :loop "%%~A"
GOTO end

:loop
SET file="%~1"
CALL SET file2="%%file:*%currentfolder:"=%\=%%"
setlocal enabledelayedexpansion
>>"# %folder:"=%.m3u" ECHO !file2:"=!
GOTO :EOF

:end
ECHO End time: %time:~0,-3%
ECHO 
PAUSE

thr333
Posts: 16
Joined: 24 Aug 2009 10:24

#14 Post by thr333 » 31 Aug 2009 13:06

DccD ... Great DOS Coding !!

~~~~ WORKS LIKE A CHARM ~~~~

I tried my best to "test/fool" your code by running command line from this test "parent directory"
(which also had "illegal character name" child folders):

    C:\USERS\Administrator\Desktop\!make batch file playlist\& parent folder !!

and here is the output text (totally correct !!):

    # & parent folder .m3u
    ------------------------------------------------------
    01 - parent folder.flac
    01 - parent folder.mp3
    02 - parent folder.flac
    02 - parent folder.mp3
    03 - parent folder.flac
    03 - parent folder.mp3
    (1964) ! exclamation !\(CD) 1\01. ! exclamation ! 1.flac
    (1964) ! exclamation !\(CD) 2\02. ! exclamation ! 2.flac
    (2007) child folder & 1\01 - child folder & 1.flac
    (2007) child folder & 1\01 - child folder & 1.mp3
    (2007) child folder & 1\02 - child folder (& 1).flac
    (2007) child folder & 1\02 - child folder (& 1).mp3
    (2009) child folder 2 !!\01 - child folder 2 !!.flac
    (2009) child folder 2 !!\01 - child folder 2 !!.mp3
    (2009) child folder 2 !!\02 - child folder (2 !!) .mp3
    (2009) child folder 2 !!\02 - child folder (2 !!).flac
    -------------------------------------------------------


EXCELLENT WORK.

Only one small problem/error...
Notice the "parent folder" name and the output playlist name.
Missing last two exclamation marks...

DccD
Posts: 23
Joined: 26 Aug 2009 19:34

#15 Post by DccD » 01 Sep 2009 15:38

hmmm... I'm still working on this... special characters are tough !

In the mean time here is the new code fixing a bug when started from the root of a drive:

Code: Select all

@ECHO OFF
SET currentfolder="%cd%"
CD ..
SET upperfolder="%cd%"
IF %upperfolder:~-2,-1%==\ SET upperfolder=%upperfolder:\=%
CALL SET folder=%%currentfolder:%upperfolder:"=%\=%%
CD %folder%
TITLE Generating Playlist for %folder%
ECHO.
ECHO Start time: %time:~0,-3%
ECHO Please wait...
FOR /F "tokens=*" %%A IN ('dir /s /b *.mp3') DO CALL :loop "%%~A"
GOTO end

:loop
SET file="%~1"
CALL SET file2="%%file:*%currentfolder:"=%\=%%"
SET file2=%file2:~0,-1%
setlocal enabledelayedexpansion
>>"# %folder:"=%.m3u" ECHO !file2:"=!
GOTO :EOF

:end
ECHO End time: %time:~0,-3%
ECHO 
PAUSE

Post Reply