PDA

View Full Version : iTunes playlist script



IPGuy
2007-05-26, 08:33
I manage my music & playlists on my laptop, but have a shadow music storage on a NAS at home and run slimserver from a home server (been both windows box and linux box from time to time) pointed to the NAS. With this setup, the built in iTunes playlist usage in slimserver doesn't help (as my local iTunes Library.xml file is on my laptop).

I tried a few iTunes playlist export utilities, but none fixed the fact that the path (and if I was using the linux box for slimserver, forward slash vs. backslash in the paths) is different between my iTunes Library.xml and where slimserver expects to see files on the NAS. This left me doing a series of editpad search and replaces every time. Which not surprisingly meant I didn't update the slimserver playlists very often.

Recently, I wrote a PowerShell (formerly know as Monad) script that will parse the iTunes Library.xml, make the necessary path conversions, output extended m3u playlists to my NAS playlist directory, and force a slimserver rescan.

In the case anybody else out there would find something like this helpful here is the script. Just fill in the right paths, etc. in the Variable Setup section and it should work fine. FWIW, it takes about 55 seconds to complete the conversion of my 6000 song, 100 playlist iTunes Library on my Core 2 Duo laptop. Its been 10 years since I wrote any code so excuse any inefficiencies that may offend a pro.

--------Powershell Script---------------------------

################################################## ########################
# Key Variable Setup
################################################## ########################

$itunesxml = "C:\XXXX\XXXXXX\Music\iTunes\iTunes Music Library.xml"
$plloc = "X:\PLAYLISTFOLDER\"
$oldpath = "file://localhost/X:/"
$newpath = "\\SERVER\Music\"
$olddirsep = "/"
$newdirsep = "\"
$blocklist = "Library", "Movies", "Music", "Party Shuffle", "Podcasts", "Purchased", "TV Shows"
$rescan = "http://XXX.XXX.XXX.XXX:9000/status.html?p0=rescan;cauth=XXXXXXXXXXXXXXXXXXXX"

################################################## ########################
# Export Playlists & Rescan Slimserver Library
################################################## ########################

$playlisttrigger = $false
$newstr="#EXTM3U"
$starttime=$(get-date)
echo "" "Parsing Library . . . " ""
gc $itunesxml | % {
if (-not $playlisttrigger) {
Switch -regex ($_) {
'(<key>Track ID<.key><integer>)([0-9]*)(<.integer>)' {
$idtemp=$matches[2]
$nametemp = "NAMEERROR"
$timetemp = [int] -1
$loctemp = "LOCATIONERROR"
}
'(<key>Name<.key><string>)(.*)(<.string>)' {$nametemp=$matches[2]}
'(<key>Total Time<.key><integer>)([0-9]*)(<.integer>)' {$timetemp=[int]($matches[2]/1000)}
'(<key>Location<.key><string>)(.*)(<.string>)' {
$loctemp=$matches[2]
$tracktable += @{"$idtemp" = @{ "name" = $nametemp; "playtime" = $timetemp; "location" = $loctemp}}
}
'<key>Playlists<.key>' {
$playlisttrigger=$true
del "$plloc*.m3u"
echo "Writing Playlists . . . " ""
}
}
}
else {
Switch -regex ($_) {
'(<key>Name<.key><string>)(.*)(<.string>)' {
$skippl=$false
foreach ($bltemp in $blocklist) {
$bltemp = "^$bltemp"
if ($matches[2] -match $bltemp) {
$skippl=$true
break
}
}
if (-not $skippl) {
if ($emt) {del temp.tmp}
if (test-path temp.tmp) {Move-Item temp.tmp $newm3u}
$newm3u=$plloc+$matches[2]+".m3u"
Add-Content temp.tmp $newstr
$emt=$true
}
}
'(<key>Track ID<.key><integer>)([0-9]*)(<.integer>)' {
if (-not $skippl) {
$id=$matches[2]
$newline="EXTINF:" + $tracktable[$id].playtime + ", " + $tracktable[$id].name
Add-Content temp.tmp $newline
$newline=$tracktable[$matches[2]].location
$newline=$newline -replace $oldpath, $newpath
$newline=$newline -replace $olddirsep, $newdirsep
$newline=$newline -replace "%20", " "
Add-Content temp.tmp $newline
$emt=$false
}
}
}
}
}
if ($emt) {del temp.tmp}
if (test-path temp.tmp) {Move-Item temp.tmp $newm3u}
echo "Initiating Rescan of Slimserver . . . " ""
$wc=New-Object net.webclient
$page=$wc.DownloadString($rescan)
$runtime=(New-TimeSpan $starttime $(get-date)).TotalMilliseconds/1000
echo "Completed" "" "Script Run Time: $runtime seconds" "" "Press any key to exit"
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

--------------End-----------------------------------

PS. Not sure why this Forum collapsed the indenting in the script, as I know this makes it harder to read I am also posting a txt file that should retain the formating.

artv
2007-12-12, 22:05
This posting was very helpful to the same problem, but I decided to use Python to solve the issue. This was fairly easy and the xml parsing appear very fast with cElementTree.

import time
import datetime
import os
import string
import xml.etree.cElementTree as ET
import urllib

################################################## ########################
# Variable Setup
################################################## ########################

itunesxml = "C:\Documents and Settings\calvinh\My Documents\My Music\iTunes\iTunes Music Library.xml"
#itunesxml = "C:\\test\\iTunes Music Library.xml"
startM3U ="#CURTRACK 0\r\n#EXTM3U\r\n"
startName = "#EXINF:-1,"
plloc = "M:\\iTunes\\Playlist\\" #Windows mapped path
oldpath = "file://localhost/M:/iTunes/iTunesMusic/" #iTunes mapped path
newpath = "/ext/Qmultimedia/iTunes/iTunesMusic/" #NAS music location
blocklist = "Library","Audiobooks", "Movies", "Music", "Party Shuffle", "Podcasts", "Purchased", "TV Shows"
rescan = "http://192.168.1.99:9000/status.html?p0=rescan;cauth=c6249a38db11db959094f8 56e91d2f66"

print "Current System Variables"
print
print "Local iTunes xml file =",itunesxml
print "Mapped Playlist location =",plloc
print "Local iTunes path =",oldpath
print "New NAS path =",newpath
print "Current Blocked Playlist =",blocklist
print rescan
print
################################################## ########################
# Export Playlists & Rescan Slimserver Library
################################################## ########################

starttime = datetime.datetime.now()
print "Script Started @ ", starttime
print "" "Parsing Local iTunes Library . . . " ""
print

# Parsing iTunes xml
root = ET.parse(itunesxml).getroot()

#get non-blocked Playlists and Tracks in array
def getPlaylist():
for playlist in root[0].find('array').findall('dict'):
l = list(playlist)
plInfo = dict(zip([t.text for t in l[::2]], [t.text for t in l[1::2]]))
plName = plInfo.get('Name',0)
plID = plInfo.get('Playlist ID',0)
#check for blocked Playlist and empty directories
if plName not in blocklist and playlist.find('array') is not None:
plx = playlist.find('array').findall('dict')
print plName + " ID =" + plID
trackID = []
if playlist.find('array') is not '':
for tr in playlist.find('array').findall('dict'):
l = list(tr)
tracks = dict(zip([t.text for t in l[::2]], [t.text for t in l[1::2]]))
trackID.append(tracks.get('Track ID',0))
setTrackInfo(plName,trackID)

#write track information to m3u file
def setTrackInfo(fileName,trackID):
trf = file(plloc+fileName+'.m3u','w')
trf.write(startM3U)
for trackList in root[0].find('dict').findall('dict'):
l = list(trackList)
trackInfo = dict(zip([t.text for t in l[::2]], [t.text for t in l[1::2]]))
track = trackInfo.get('Track ID',0)
trackLoc = trackInfo.get('Location',0)
trackName = trackInfo.get('Name',0)
if track in trackID:
trackLoc = string.replace(trackLoc,oldpath,newpath)
trackLoc = string.replace(trackLoc,'%20',' ')
trf.write('#EXTINF:-1,'+trackName+'\r\n')
trf.write(trackLoc+'\r\n')
trf.close()
#Get iTune playlist and write tracks to E3U file
getPlaylist()
#Send rescan to Slimserver
urllib.urlopen(rescan).read()

################################################## ############################
# End of Playlist script
endtime = datetime.datetime.now()
print
print "Script Complete @ ", endtime
print "Execution Time = ",endtime - starttime
print
################################################## ############################

See attached playlist.txt for proper python formatting

bgriffis
2012-04-23, 10:24
This thread is pretty old but it came up pretty high in my Google search results so I thought I'd add a little more info...

I have been running Logitech Media Server for many years from Windows. Recently I moved all my music to a Synology NAS and was having trouble getting the Media Server to "see" my content on the box. So I installed Logitech Media Server on the Synology NAS itself (supported right out of the box with just a few clicks!). Everything was working great except for the fact that all my playlists were being held captive by iTunes in Windows.

My solution was to download iTunes Export from here:

http://www.ericdaugherty.com/dev/itunesexport/

I grabbed the command line version so I could write a batch file to invoke it easily. Here's the contents of my command file:

"C:\Program Files (x86)\Java\jre6\bin\java" -jar itunesexport.jar -outputDir=\\diskstation\Media\Music\iTunes\Playlis ts -musicPath=/volume1/Media/Music/iTunes/Music -musicPathOld=C:\Media\Music\iTunes\Music -fileTypes=ALL -separator=MAC -includePlaylist="Brad 4 Star Sorted,Brad 5 Star Sorted,Kids 4 Star"

In the above command line the musicPathOld is where iTunes "sees" all my files from Windows, i.e. I created a softlink at C:\Media that points to \\diskstation\Media. The musicPath is the path that gets inserted into the m3u files, which is where Logitech Media Server "sees" the music locally on the NAS. I only wanted to create a few playlists as indicated by the includePlaylist. If you get rid of that part it generates all the playlists. I also have my iTunes library xml in the default location so didn't need to specify anything there.

Anyway, I hope this helps someone else having a similar issue. Now if I want to re-create the m3u files I simply run the batch file and then rescan playlists.