Interesting hacking around in python, OSX, and the iTunes Library

Tuesday, January 1st, 2008

While working on a project for a friend, Amber accidentally deleted a playlist of music. “Uh oh”, she said, “it looks like you can't undo that!”. A bit of googling showed that to be the case.

Thankfully, though it's a bit out of date, we've been good(ish) about keeping backups. I thought “I bet I can get the playlist info out of the iTunes library file in the backup!” Sure enough, I mounted the drive, took a look, and there the data was. It wasn't that useful though.

 <key>Name</key><string>The Special Playlist</string>
                        <key>Playlist ID</key><integer>14915</integer>
                        <key>Playlist Persistent ID</key><string>F668E7C09FF9F9AC</string>
                        <key>All Items</key><true/>
                        <key>Playlist Items</key>
                        <array>
                                <dict>
                                        <key>Track ID</key><integer>3533</integer>
                                </dict>
                                <dict>
                                        <key>Track ID</key><integer>3532</integer>
                                </dict>
                                <dict>
                                        <key>Track ID</key><integer>3527</integer>
                                </dict>

So normally I break out the perl here, and it looked like there was some CPAN modules to get it done, but the iTunes XML parser library looks like it wasn't packaged right and I couldn't install it via CPAN, blah blah blah. I've been trying to break out the python more often, so searched for 'python itunes xml library parse' and found this gem from 2005:

Airport Express Hates Me

In which the author uses a neat trick (the Python/Objective C bindings) to parse the iTunes library. After a bit of a bumpy start, I ended up with the following code:

#!/usr/bin/python
from Foundation import *
dbFile = "itunes_from_backup.xml"
db = NSDictionary.dictionaryWithContentsOfFile_(dbFile)
printtrack = {}

for playlist in db[u'Playlists'].itervalues():
        if playlist[u'Name'] == u"The Special Playlist":
                for track in playlist[u'Playlist Items'].itervalues():
                        printtrack[track[u'Track ID']] = 1

for track in db[u'Tracks'].itervalues():
        try:
                if printtrack[track[u'Track ID']]:
                        print "%s: %s, %s" % (track[u'Artist'], track[u'Album'], track[u'Name'])
        except:
                pass

Which yeilds a nice list like:
Andrew Bird: Armchair Apocrypha, Scythian Empires
Andrew Bird: Armchair Apocrypha, Self-Torture
Andrew Bird: Armchair Apocrypha, Simple X
Andrew Bird: Armchair Apocrypha, Spare-Ohs
Andrew Bird: Armchair Apocrypha, The Supine
Andrew Bird: Armchair Apocrypha, Yawny at the Apocalypse
Arcade Fire: Funeral, Crown Of Love
Arcade Fire: Funeral, Haiti
Arcade Fire: Funeral, In The Backseat
Arcade Fire: Funeral, Neighborhood 1 – Tunnels
Arcade Fire: Funeral, Neighborhood 2 – Laika

I think there is a way to look up track information from track ID's directly, but I couldn't suss it, hence the double loop with the dictionary for bookkeeping. (Yes, my python looks very perlish, I'm sure.) In any case, the Python Objective C bindings look pretty cool and I plan to explore those further.

Scary times with my mac (and a fix!)

Wednesday, December 26th, 2007

My macbook just scared the crap out of me.

Since I couldn't sleep until I fixed, I figured I'd blog it. (It's finishing up fixing itself now.)

Symptom:

Running Leopard, all normal updates. On 12/25/2007 I get a popup window with some macbook upgrades, a quicktime patch, and another innocuous looking update. However, after authorizing it to reboot the computer, I get the message “Reboot failed because application 'Software Update' failed to quit.” This, I think, is a bad sign. I quit every other application and tried running software update again. Same thing happens. I then try and shut down. It won't. Power button's not even working to bring up the “shutdown” menu. Only thing I can do is hold down the power button and power it back up.

Here's the thing — on next boot, I'm looking at the OS X Setup Assistant. Yeah. As if I'd just installed Leopard. Great.

Fix:

Thankfully, the fix was easy, after I got my heart rate back down from 210 BPM. I searched in the KB a bit and found: Setup Assistant Appears after Every Restart

And that worked. Start it in safe mode, (hold shift right after power-on 'Bong!') when it gets to the login screen don't login, but hit back arrow, then restart, and viola — upgrades continued like they should have, and on next reboot I was normal.

All's well that ends well, but this DID make me want to get my backups back in shape one way or another; no more waiting around for SuperDuper to get Leopard-ready. (Even though his latest update suggests I could be good to go within a week… it's rsync time, at least.)

Edit: Turns out the rsync was is easy. Just listen to jwz.

Awesome perl module for sending mail

Friday, November 2nd, 2007

I found a perl module today which made me disproportionately happy; thus, I decided to share.

MIME::Lite

Check out, specifically, the example of sending email “with images attached”.

I'm now able to quickly blast myself summary emails including exciting things like visual maps of the data, etc. I'm sure the evil amongst us would appreciate this tool for other reasons, but we'll ignore the evil for now.