Friday, February 15, 2013

PowerShell: Clean & Manage Music Files

Disclaimer: USE THIS AT YOUR OWN RISK! This script is made for Windows 7!  There will be file renaming and moving so TEST, TEST, TEST.  You can test this script by copying one folder of music into an empty folder then run the script in that folder.  It will only process the files in that folder.  If all goes well, all files will move into a new folder structure named Music on your desktop.

To run this or any other PowerShell script, you'll have to read up on the Get-Executionpolicy and Set-Executionpolicy as PowerShell disables scripts by default.

My previous article explained how to clean the extra "stuff" added to music file names.  This article further cleans those file names, gets rid of the troublesome [brackets], then uses the Genre, Artist, and Album information to create a new folder structure on your desktop.  You can then move it to wherever you store your music.


Here is an example of some files my friend wanted help managing:

Notice the brackets, curly brackets, and other special characters in the file names and properties.


This is the same folder of music files after running the script:
I performed a search for all files to display the name changes.  Notice the subfolder structure that each file is located in.  The left side is the Genre structure created based on the file information.

Three more notes before going through the script:  

  1. The script automatically ignores subfolders.  I strongly recommend you perform this move one folder at a time so you can ensure it worked properly.
  2. The script will process any type of file.  You'll have to create an -exclude in the top $filename variable if you want it to ignore JPG's, AVI's, and etc.
  3. Do not save this script to the folder you are processing. It will be moved into the Music folder and could cause problems.
## Start of Script

#We call the Shell Object

$shell = new-object -com shell.application

#Organized Music Folder Location
#You can change the location. The Music Root Folder defaults to your desktop

$MusicFolder = ($home + '\desktop\music')

#remove brackets from filenames per PowerShells bug with brackets

gci .\* |?{(!($_.psiscontainer))}|foreach{move -literalpath $_ ($_.name -replace ('\[|]','~'))}

#Set directory and file variables.  Add -exclude to the Get-Item if you want 
#to ignore other filetypes
#For instance: (get-item .\* -exclude *.avi,*.jpg)

$dirname = (get-item .\).fullname
$filename = (get-item .\*)|?{(!($_.psiscontainer))}|foreach-object{$_.name}

foreach($file in $filename){

#original filename holder, then split it to capture the extension and name only.

$fileholder = $file
$ext = ('.' + ($file.split('.')[-1]))
$noext = $file.trimend($ext)

#get Title (item number 21) property from the file

$shellfolder = $shell.namespace($dirname).parsename($file)
$title = $shell.namespace($dirname).getdetailsof($shellfolder,21)

#PowerShell filename bug for brackets. 
#If there's a bracket in the title, $title will equal nul

if ($title -like "*``[*" -or $title -like "*``]*"){$title = $nul}

#if the title isn't empty, replace the filename with it

if ($title -gt 0){$file = ($title + $ext)}

#clean extraneous characters from the filename
#BTW, let me know if you have a better way to filter files
#for now, I borrowed this filter technique:

$file2 = $file -replace ('^[0-100]','')
$file3 = $file2 -replace ('.mp33','.mp3')
$file4 = $file3 -replace (' - ','-')
$file5 = $file4 -replace ('   ',' ')
$file6 = $file5 -replace ('  ',' ')
$file7 = $file6 -replace ('\(','')
$file8 = $file7 -replace (':','')
$file9 = $file8 -replace ('\)','')
$file10 = $file9 -replace ('\/','')
$file11 = $file10 -replace ('\>','')
$file12 = $file11 -replace ('\<','')

#Split the filename at the hyphen and only keep the last portion
#since that's normally the song name

$file13 = $file12.split('-')[-1]

$finalfilename = $file13

#rename the file after all the modifications

ren -erroraction silentlycontinue -path ($dirname + '\' + $fileholder) -newname $finalfilename

$shellfolder = $shell.namespace($dirname).parsename($finalfilename)

#Filtering for Artist - Items 13 and 217

$contribartist = $shell.namespace($dirname).getdetailsof($shellfolder,13)
$albumartist = $shell.namespace($dirname).getdetailsof($shellfolder,217)

#filtering the Album Name - Item 14

$album = $shell.namespace($dirname).getdetailsof($shellfolder,14)
$album1 = $album -replace ('^[0-100]','')
$album2 = $album1 -replace ('.mp33','.mp3')
$album3 = $album2 -replace (' - ','-')
$album4 = $album3 -replace ('   ',' ')
$album5 = $album4 -replace ('  ',' ')
$album6 = $album5 -replace ('\(','')
$album7 = $album6 -replace (':','')
$album8 = $album7 -replace ('\)','')
$album9 = $album8 -replace ('\/','')
$album10 = $album9 -replace ('\>','')
$album11 = $album10 -replace ('\<','')

$finalalbumname = $album11

#filtering the genre name - Item 16

$genre = $shell.namespace($dirname).getdetailsof($shellfolder,16)
$genre1 = $genre -replace ('^[0-100]','')
$genre2 = $genre1 -replace ('.mp33','.mp3')
$genre3 = $genre2 -replace (' - ','-')
$genre4 = $genre3 -replace ('   ',' ')
$genre5 = $genre4 -replace ('  ',' ')
$genre6 = $genre5 -replace ('\(','')
$genre7 = $genre6 -replace (':','')
$genre8 = $genre7 -replace ('\)','')
$genre9 = $genre8 -replace ('\/','')
$genre10 = $genre9 -replace ('\>','')
$genre11 = $genre10 -replace ('\<','')

$finalgenrename = $genre11

#Deciding between Album and Contributing artist then cleaning the name

$artist = if ($contribartist -gt 0){$contribartist}else{$albumartist}
$artist1 = $artist -replace ('^[0-100]','')
$artist2 = $artist1 -replace ('.mp33','.mp3')
$artist3 = $artist2 -replace (' - ','-')
$artist4 = $artist3 -replace ('   ',' ')
$artist5 = $artist4 -replace ('  ',' ')
$artist6 = $artist5 -replace ('\(','')
$artist7 = $artist6 -replace (':','')
$artist8 = $artist7 -replace ('\)','')
$artist9 = $artist8 -replace ('\/','')
$artist10 = $artist9 -replace ('\>','')
$artist11 = $artist10 -replace ('\<','')

$finalartistname = $artist11

$filetrim = $finalfilename.trimend($ext)
$filedupeinsert = ($filetrim + 'DUPE')
$filedupe = ($filedupeinsert + $ext)


#move file based on its Genre, Artist, and Album

#Replacing Brackets for tildes

if ($finalgenrename -like "*``[*" -or $finalgenrename -like "*``]*"){$finalgenrename -replace ('\[|]','~')}
if ($finalalbumname -like "*``[*" -or $finalalbumname -like "*``]*"){$finalalbumname -replace ('\[|]','~')}
if ($finalartistname -like "*``[*" -or $finalartistname -like "*``]*"){$finalartistname -replace ('\[|]','~')}

#moving songs to folders

#If there's no Genre entry, a default is used
#For the sake of endless genre possibilities, I used this filter to group
#the various types.  Manipulate as you see fit:

if ($finalgenrename -like "*Rock*"){$finalgenrename = "Rock"}
if ($finalgenrename -like "*Alt*"){$finalgenrename = "Alternative"}
if ($finalgenrename -like "*Metal*"){$finalgenrename = "Metal"}
if ($finalgenrename -like "*Pop*"){$finalgenrename = "Pop"}
if ($finalgenrename -like "*Rap*"){$finalgenrename = "Rap"}
if ($finalgenrename -like "*Hip*"){$finalgenrename = "Hip-Hop"}
if ($finalgenrename -like "*R&B*"){$finalgenrename = "R&B"}

if (!($finalgenrename -gt 0)){$finalgenrename = "Genre"}

#If there's no Album entry, a default is used

if (!($finalalbumname -gt 0)){$finalalbumname = "Album"}

#Creating the desktop\music folder structure
#and moving files to their new folders

if (!(dir $MusicFolder\$finalgenrename -erroraction silentlycontinue)){md $MusicFolder\$finalgenrename -force}
if (!(dir $MusicFolder\$finalgenrename\$finalartistname -erroraction silentlycontinue)){md $MusicFolder\$finalgenrename\$finalartistname -force}
if (!(dir $MusicFolder\$finalgenrename\$finalartistname\$finalalbumname -erroraction silentlycontinue)){md $MusicFolder\$finalgenrename\$finalartistname\$finalalbumname -force}
if (dir $MusicFolder\$finalgenrename\$finalartistname\$finalalbumname\$finalfilename -erroraction silentlycontinue){move -erroraction silentlycontinue ($dirname + '\' + $finalfilename) -destination $MusicFolder\$finalgenrename\$finalartistname\$finalalbumname\$filedupe}else{move -erroraction silentlycontinue ($dirname + '\' + $finalfilename) $MusicFolder\$finalgenrename\$finalartistname\$finalalbumname\$finalfilename -force}
}

## End of Script

Click Here to view the list of Windows 7 file properties you can access via shell.application.


8 comments:

The Automator said...

Hi, nice work. One thing, If I don't save the script in my music folder, how do I call the script. Does it take parameters? An example of how to call the script would help us slow learners.

George said...

1. Open Notepad
2. Copy the Script
3. Paste the script in Notepad
4. Save the script as CleanMusic.PS1 (or w/e filename you want) filetype
5. Save it in a folder such as c:\powershell
6. Open PowerShell
7. Go to your music folder via the PowerShell window (cd \MyMusic - for example)(ENSURE you copy some test files into an empty folder and test this first before performing on live music files)
8. Type c:\powershell\CleanMusic.ps1 . This will process the files in the c:\mymusic folder (if you have set your execution policy so it can run scripts)
9. Open the new Music desktop folder to check your results. Once confirmed, cd to the next music folder and c:\powershell\cleanmusic.ps1 again.

Anonymous said...

Great Work George!!
I had been meaning to do this for a while...Perhaps I can build up on your solution here.

Regards
~Dexter~

George said...

@dexterdhami - Exactly. I get asked to help manage peoples music files and the task always seemed daunting. Now that I'm learning PowerShell, finally have an easy scripting language powerful enough to manage the task. It'd be awesome if you can find some ways to clean and share your improved script. One thing I'd like to do is be able to change the properties rather than just read them. Thanks for the kind words.

John said...

While I loves me some PowerShell, there's just too many awesomely powerful apps out there that do all this and more, and much more easily. It's definitely an interesting programming exercise, but to truly manage your MP3s (both tags and locations), I've gotta recommend Mp3tag. It's awesome (and free)!

George said...

You're right John, there are GUI solutions that'll do more. This was a fun PS exercise. I enjoy the challenge and thought I'd share my solution with others. Thanks for the link too, I've been looking for a good app with an API to look up the meta tags and update my files. I'll try it out.

George said...

My follow-up article answers how to access and update your music files from the PowerShell 3.0 command line:
Invoke-RestMethod is a potential automated command-line answer to GUI apps that John mentions. PS3's some fun stuff.

Joy kumar saha SEO expert said...
This comment has been removed by the author.