Sort music files and go to the target folder

This command does the following (inspired by this question):

  • Moves all .mp3 files from the current directory into your My Music folder, using the music tags to find/create the correct directory under Albums\Genre\Artist\Title.

  • Makes the current file display go up one level to the parent.

  • Makes the window's other file display open (if not already) and go to the place that the music files were moved to. (If they ended up in multiple places, e.g. because they were not all part of the same album, then it'll pick just one of them.)

  • Deletes the original starting directory, if it is now empty.

You probably won't want to do exactly that, but the command may help you do similar things by example.

Here is the command in XML format. See How to add buttons from this forum to your toolbars for instructions on pasting it as a button on your toolbar.

<?xml version="1.0"?>
<button backcol="none" display="both" textcol="none">
    <label>Sort Music</label>
    <icon1>#script</icon1>
    <function type="batch">
        <instruction>@noexpandenv</instruction>
        <instruction>@runmode hide</instruction>
        <instruction />
        <instruction>@set OriginalSource={sourcepath$|noterm}</instruction>
        <instruction />
        <instruction>Rename FILEINFO FROM &quot;*.mp3&quot; TO &quot;{alias|mymusic}\Albums\{mp3genre}\{mp3artist}\{mp3album}\{mp3track|#2} {mp3title}.{ext}&quot;</instruction>
        <instruction />
        <instruction>Go PATH &quot;..&quot; DUALPATH &quot;%RENAME_TARGET%&quot;</instruction>
        <instruction />
        <instruction>rmdir {$OriginalSource}</instruction>
        <instruction />
        <instruction />
        <instruction>@script vbscript</instruction>
        <instruction>Option Explicit</instruction>
        <instruction />
        <instruction>Dim fs</instruction>
        <instruction>Set fs = CreateObject(&quot;Scripting.FileSystemObject&quot;)</instruction>
        <instruction />
        <instruction>Dim Shell</instruction>
        <instruction>Set Shell = CreateObject(&quot;WScript.Shell&quot;)</instruction>
        <instruction />
        <instruction>Dim EnvVars</instruction>
        <instruction>Set EnvVars = Shell.Environment(&quot;PROCESS&quot;)</instruction>
        <instruction />
        <instruction>Function Rename_GetNewName(strFileName, strFilePath, fIsFolder, strOldName, ByRef strNewName)</instruction>
        <instruction />
        <instruction>	&apos; Fix any double \ chars resulting from empty tags (e.g. no genre).</instruction>
        <instruction>	&apos; If we don&apos;t do this, things can get confused about the destination path.</instruction>
        <instruction />
        <instruction>	strNewName = Replace(strNewName, &quot;\\&quot;, &quot;\&quot;)</instruction>
        <instruction />
        <instruction>	&apos; Set the %RENAME_TARGET% environment variable to the folder we&apos;re moving the file to.</instruction>
        <instruction>	&apos; This can be used in the main command above to go to the folder.</instruction>
        <instruction>	&apos; Note that we use &quot;@noexpandenv&quot; at the top of the command; if we didn&apos;t then %RENAME_TARGET%</instruction>
        <instruction>	&apos; would be expanded *before* this script had run, which obviously would not work.</instruction>
        <instruction />
        <instruction>	EnvVars(&quot;RENAME_TARGET&quot;) = fs.GetParentFolderName(strNewName)</instruction>
        <instruction />
        <instruction>End Function</instruction>
    </function>
</button>

Here is the main body of the command, so you can more easily look at it without leaving this post:

@noexpandenv
@runmode hide

@set OriginalSource={sourcepath$|noterm}

Rename FILEINFO FROM "*.mp3" TO "{alias|mymusic}\Albums\{mp3genre}\{mp3artist}\{mp3album}\{mp3track|#2} {mp3title}.{ext}"

Go PATH ".." DUALPATH "%RENAME_TARGET%"

rmdir {$OriginalSource}


@script vbscript
Option Explicit

Dim fs
Set fs = CreateObject("Scripting.FileSystemObject")

Dim Shell
Set Shell = CreateObject("WScript.Shell")

Dim EnvVars
Set EnvVars = Shell.Environment("PROCESS")

Function Rename_GetNewName(strFileName, strFilePath, fIsFolder, strOldName, ByRef strNewName)

	' Fix any double \ chars resulting from empty tags (e.g. no genre).
	' If we don't do this, things can get confused about the destination path.

	strNewName = Replace(strNewName, "\\", "\")

	' Set the %RENAME_TARGET% environment variable to the folder we're moving the file to.
	' This can be used in the main command above to go to the folder.
	' Note that we use "@noexpandenv" at the top of the command; if we didn't then %RENAME_TARGET%
	' would be expanded *before* this script had run, which obviously would not work.

	EnvVars("RENAME_TARGET") = fs.GetParentFolderName(strNewName)

End Function

Points of interest

  • Sorting the MP3 files by tags is all done on the Rename line and doesn't involve the VBScript part at all (except that the VBScript part cleans things up a bit in case any tags are missing). Using things like {mp3title} is covered in several more simple rename examples so I won't go into that here. Just note that, for each file, the result of the Rename command is fed into the VBScript as the strNewName argument, and the script can then (if it wants to) modify the new name further and/or perform other actions.

  • It's also worth noting that this command ignores the file selection. It will work on *.mp3 within the current folder, whether or not those files are selected first. To make it work only on the selected files, use PATTERN instead of FROM on the Rename line.

  • The VBScript part will create an environment variable called RENAME_TARGET and set it to the path that each file is moved to. (Since the script is run for each file, the environment variable will be overwritten for each file, leaving just the last file's path at the end. The assumption is that all the files will be part of the same album and all end up in the same place. You could make a different script which opened each target folder in a new tab instead.)

  • The RENAME_TARGET environment variable is used outside of the VBScript to tell the Go command where to send the other file display.

  • @noexpandenv appears at the top of the button to ensure that %RENAME_TARGET% is expanded when the Go command runs instead of when the button first starts. If @noexpandenv was not used then %RENAME_TARGET% would be expanded before the VBScript part had run and set it up.

  • When creating the EnvVars object, the PROCESS type is specified. That means that the environment variable we set will be visible to Opus but will not be visible to any other programs and will not be saved across reboots.

  • Since the RENAME_TARGET environment variable is global to the Opus process, you should never run this script at the same time as itself (or any other which uses the same variable name). If you did then the two scripts would see and/or change each other's RENAME_TARGET variable with unpredictable results.

  • The MS-DOS rmdir command is used to delete the original directory instead of Opus's own Delete command. This is so that the directory is only deleted if it is empty. (The directory might not be empty if it had some non-MP3 files within it and blindly deleting it would mean those files were lost at the click of a button.) This use of the rmdir command is also why the function type is set to MS-DOS Batch Function and the @runmode hide line near the top ensures that a Command Prompt window does not flash on the screen when the command runs.

Whoopee. I have been looking for something like this for months.

I was getting there slowly, very slowly, but this has lots of neat pointers to work from.

Now I can fiddle around with this and perhaps learn something.

Just one thing, is the link to "How to add buttons from this forum to your toolbars" relevant here? Isn't that about xml coded buttons? Or am I, as is quite likely, missing something. The code won't paste here as is. Had to make a button and go from there.

When I did that, I then get a button with xml code that I can then copy.

Oops, my mistake. Thanks for spotting that!

I've updated the post so it has both the XML version (for pasting to toolbars) and the text version (for easier reading on the web).

Hi leo, thanks for this wonderful solution.
When testing the Button I got a little Problem with the rmdir {$OriginalSource} command not deleting the empty folder .
So I tried my old version: Delete FILE . QUIET filled in before the "Go PATH" section.
This is working fine for me.
I also deleted the now unused @set OriginalSource={sourcepath$|noterm} variable.

Did you paste the command into a normal button type? rmdir won't work unless it's an MS-DOS type button.

If you do use the Delete command I would still use the set/originalsource stuff in case the current dir changes and "." isn't what you expect it to be.

@leo: No that wasn't the Problem.
I just discovered why my folder wasn't deleted: There was a hidden "coverart.jpg" in it.

My old Button moved everything in the Folder to the new Location.

I would prefer to have this behaviour because with your version I'll have to move e.g. Coverart-files manually.

I fixed the buttons using *.wma instead of *.mp3 (something I changed when testing it and forgot to change back).

If you want to move the whole current directory, add this to the end of the VBScript, just before the End Function line:

	strNewName = ""

That will make it so the Rename line doesn't actually rename or move the files at all, but still sets the RENAME_TARGET env-var.

Now you should be able to use %RENAME_TARGET% as the destination in a Copy MOVE command, similar to how your original button worked.

This works for me now:

Copy MOVE * TO "%RENAME_TARGET%"
Go PATH ".." DUALPATH "%RENAME_TARGET%"
rmdir {$OriginalSource}

But surely it's a dangerous Button this way. No Problem to use it by mistake on Folders containing no MP3-files because you'll get an error message. Otherwise it will move erything to my Music directory...

I tried the above before reading your last post. This way it worked, but does a second Move-action. With your additionally strNewName = "" it's perfekt now. Thanks again and again!

If you click that button in a folder without any music files then it'll move the current folder's contents to whatever the previous music destination was, if you had used the button since starting Opus. Else it would use an empty destination, which I don't think will do anything (not sure, actually).

You could make it a bit safer by adding this right after the Set EnvVars = Shell.Environment("PROCESS") line:

EnvVars("RENAME_TARGET") = "zzzzz:\"

That sets the default destination to zzzzz:\ which is an impossible path and will result in an error message instead of anything happening. The destination will be left that way if the rename script doesn't get to run for any files.

@leo:
I was too quick to say it's perfekt with strNewName = "":

It should rename the files and create the folder-structure based on tags. Just the "Move to %RENAME_TARGET%" Part should be skipped.

Just for Fun I added a Line calling my favourite music player to play all files in "%RENAME_TARGET%" right behind the rmdir {$OriginalSource} command.
Worked on the first try.
Here's the simple Code (using Aimp2):

"C:\Program Files\AIMP2\AIMP2.exe" %* "%RENAME_TARGET%"

Ah, true. Well, you can always do both, so the Rename command takes care of the MP3 files and then a Copy MOVE command moves any additional files which are still leftover.

BTW, I edited your post above to put quotes around the AIMP2.exe path. Makes it work if something creates a folder called "C:\Program" (which happens every so often).

WOW NICE WORK ... I know you said no questions but what happens if there are no tags ? I did not see it .. I will try it with a file that has no tags.. I asked it here so its under the same place just in case someone wants to know... update I just tried on a file with no tags . all i got was a file named 13.mp3 ... so a bit scary can it be updated to take no actions on files with no tags

The whole thing could be done in a better way now, with the improved scripting functionality added to Opus over the last 7 years.

Not something I have time to do right now but I can offer some pointers if anyone else wants to.

well i only came across it because looking for info on rename presets for music

i will post in questions did not know it was 7 years old

would love for this to be updated

can we have a nice new version of this please ? or is this something better already i have not asked about for sometime even if it could be updated not to move files / folders with blank tags thanks again

Original script seems to have gotten broken at one point as it no longer works properly in 12
This is a great script. Sad it's no longer supported

Leo, If you still haven't found the time I'd be willing to look at some pointers.

If I didn't thank you 7+ years ago, I'll thank you now. That script was indispensable!

Thanks

What goes wrong?

It doesn't seem to be picking up the track info on the files. I have checked and the files are tagged with ID3v2.3 tag format. I tried retagging so they also have ID#v1 as well
It doesn't seem to create the folder based on the artist and album name.
It creates a single file with no name on the first file and then the second file generates a renaming error: "Cannot create a file when that file already exists"

Also, I notepad text is generated and opened when the process completes: dop201912132119220083.bat

echo off
chcp 1252 > nul
D:
cd "\Downloads"
rmdir D:\Downloads\Gong_-_The_Universe_Also_Collapses_(2019)

Thanks