patternpythonMinor
iTunes playlist copier
Viewed 0 times
copierplaylistitunes
Problem
When you own an Android device and want your iTunes playlist to be copied over onto it, what do you do?
What if your playlist hits something in the region of 20GB+ ? Well, I am sure I could've paid for a tool, to do this for me and keep things in sync, but I wanted to challenge myself into writing something in Python to resolve it.
I tried dragging and dropping the files on the playlist onto the phone via Android Device Manager and often found it would just hang. This is what I ended up with:
I have found a bug in it when copying over bands or songs with UTF-8 names in it e.g. Fantômas. Because the UTF-8 elements are encoded in the Playlist XML the names do not match the directory so I need to fix that. Have kept a copy on Gist, so if you want a copy go grab/comment/whatever. I'm new to Py
What if your playlist hits something in the region of 20GB+ ? Well, I am sure I could've paid for a tool, to do this for me and keep things in sync, but I wanted to challenge myself into writing something in Python to resolve it.
I tried dragging and dropping the files on the playlist onto the phone via Android Device Manager and often found it would just hang. This is what I ended up with:
from xml.etree.ElementTree import ElementTree
import os
from shutil import copyfile
import urllib
srcfile = "/path/to/playlist.xml"
dst = '/path/to/destination';
overwrite = 0
tree = ElementTree()
tree.parse(srcfile)
songs = tree.findall('/dict/dict/dict/string')
# Run through all the found elements
for song in songs:
# Is this element a file?
if song.text[0:7] == "file://":
# Grab everything after file://
myfile = urllib.unquote(song.text[7:])
# Grab the filename without the path
basefile = os.path.basename(myfile)
# Grab the last dirname
dirname = myfile.split('/')[-2]
# If the dir does not exist on the destination, create it
if not os.path.exists(dst+dirname):
os.mkdir(dst+dirname)
# Create the final filename
dstFile = dst + dirname + '/' + basefile
# If the file exists and we have chosen to not overwrite it, dont copy the file
if os.path.exists(dstFile) and not overwrite:
print "Skipping " + myfile
else:
copyfile(myfile, dst + dirname + '/' + basefile)
print "Copying " + myfile
print "Finished...."I have found a bug in it when copying over bands or songs with UTF-8 names in it e.g. Fantômas. Because the UTF-8 elements are encoded in the Playlist XML the names do not match the directory so I need to fix that. Have kept a copy on Gist, so if you want a copy go grab/comment/whatever. I'm new to Py
Solution
overwrite would be better as True or False.Since each file is treated independently, you should define a function to make the independence obvious.
To split and join path components, use
os.path.split() and os.path.join() instead of doing your own string analysis. The interface is slightly nicer, and it also ensures that there won't be missing or extra / separators.If you reorder the conditionals, you could reduce the number of
os.path.exists() tests in the don't-overwrite case, where the destination file already exists.'Copying filename' before copying the file, so that if the copying fails, you'll see which file it failed on. Print "Finished." instead of "Finished....", because ellipses imply that the job is incomplete.import os
from shutil import copyfile
import urllib
from xml.etree.ElementTree import ElementTree
def copy_song(url, dest, overwrite=False):
if not url.startswith('file://'):
return
orig_path = urllib.unquote(url[len('file://'):])
orig_dirname, basename = os.path.split(orig_path)
dest_dirname = os.path.join(dest, orig_dirname)
dest_path = os.path.join(dest_dirname, basename)
if not overwrite and os.path.exists(dest_path):
print 'Skipping ' + orig_path
else:
if not os.path.exists(dest_dirname):
os.mkdir(dest_dirname)
print 'Copying ' + orig_path
copyfile(orig_path, dest_path)
playlist = "/path/to/playlist.xml"
dest = '/path/to/destination';
playlist_xml = ElementTree.parse(playlist)
for song in playlist_xml.findall('/dict/dict/dict/string'):
copy_song(song.text, dest)
print 'Finished.'Code Snippets
import os
from shutil import copyfile
import urllib
from xml.etree.ElementTree import ElementTree
def copy_song(url, dest, overwrite=False):
if not url.startswith('file://'):
return
orig_path = urllib.unquote(url[len('file://'):])
orig_dirname, basename = os.path.split(orig_path)
dest_dirname = os.path.join(dest, orig_dirname)
dest_path = os.path.join(dest_dirname, basename)
if not overwrite and os.path.exists(dest_path):
print 'Skipping ' + orig_path
else:
if not os.path.exists(dest_dirname):
os.mkdir(dest_dirname)
print 'Copying ' + orig_path
copyfile(orig_path, dest_path)
playlist = "/path/to/playlist.xml"
dest = '/path/to/destination';
playlist_xml = ElementTree.parse(playlist)
for song in playlist_xml.findall('/dict/dict/dict/string'):
copy_song(song.text, dest)
print 'Finished.'Context
StackExchange Code Review Q#94445, answer score: 6
Revisions (0)
No revisions yet.