I am fed up with using GUIs to sync my ipod with my music database, so I hacked the attached script together this evening. It uses the python bindings of libgpod.
Originally, I thought of using rsync for the file update part of this, but the issue is rsync doesn’t allow you to reformat the destination filenames, and there are restrictions on filename length/character set in the ipod’s iTunesDb/filing system.
I found various other implementations of this around the web, but they all seemed to be attachments to blogs which had gone missing. So I’ve included this one as part of the post.
Any mp3s in the content database and not on the ipod (or which have changed since they were added to the ipod) will be added.
Any mp3s on the ipod which are not in the content database will be removed.
#!/usr/bin/python import os import gpod import sys
Parse args
if len(sys.argv) != 3:
print >>sys.stderr, “Syntax: ipodsync
Open/create the itunesdb
try: db = gpod.Database(mountpoint) except: gpod.itdb_init_ipod(mountpoint, None, “IPOD”, None) db = gpod.Database(mountpoint)
Get details of all the tracks within the itunesdb
invalid_tracks = [] ipod_tracks = {} ipod_files = {} for track in db:
Get userdata
userdata = track[‘userdata’]
if userdata == None:
invalid_tracks.append(track)
continue
if ‘filename_utf8’ not in userdata:
invalid_tracks.append(track)
continue
if ‘sha1_hash’ not in userdata:
invalid_tracks.append(track)
continue
original_filename = userdata[‘filename_utf8’]
hash = userdata[‘sha1_hash’]
ipod_filename = track.ipod_filename()
if its a dupe, mark it invalid
if original_filename in ipod_tracks: print >>sys.stderr, “Content file %s duplicated” % original_filename invalid_tracks.append(track) continue
if it doesn’t exist in the content store, mark it invalid
if not os.path.exists(content + ”/” + original_filename): print >>sys.stderr, “Content file %s vanished” % original_filename invalid_tracks.append(track) continue
if it doesn’t exist on the ipod, mark it invalid
if not os.path.exists(ipod_filename): print >>sys.stderr, “IPod file %s vanished” % ipod_filename invalid_tracks.append(track) continue
if the hash doesn’t match, mark it invalid
new_hash = gpod.gtkpod.sha1_hash(content + ”/” + original_filename) if new_hash != hash: print >>sys.stderr, “Content file %s changed” % original_filename invalid_tracks.append(track) continue
Keep note of it
ipod_tracks = track; ipod_files = track;
remove any invalid ones from the database
for track in invalid_tracks: db.remove(track)
Now, go through the files in content, checking if they should be added
os.chdir(content) for root, dirs, files in os.walk(”.”): for content_filename in files: full_filename = root + ”/” + content_filename
# Ignore bad extensions
if full\_filename.lower().endswith(('jpg', 'nfo', 'htaccess', 'bmp', 'txt', 'sfv')):
continue
# Ignore tracks we already have
if full\_filename in ipod\_tracks:
continue
# Add it!
try:
track = db.new\_Track(filename=full\_filename)
except:
print >>sys.stderr, "Failed to add: %s" % full\_filename
Now, go through the files on the ipod, checking if they’re defunct
for root, dirs, files in os.walk(mountpoint + “/iPod_Control/Music”): for content_filename in files: full_filename = root + ”/” + content_filename
# Ignore tracks we already have
if full\_filename.lower() in ipod\_files:
continue
print >>sys.stderr, "IPod file %s defunct" % full\_filename
os.unlink(full\_filename)
def print_progress(database, track, i, total): print >>sys.stderr, “Copying to iPod %04d/%d: %s” % (i,total,track)
Finally, sync the db etc
try: db.copy_delayed_files(callback=print_progress) except Exception,ex: print >>sys.stderr, ex db.close()
Leave a comment
Comments are moderated, so yours won't appear immediately. Your email is never published.