Wednesday, January 25, 2006

Taming iTunes with Python

Thanks to the gazillions of iPods sold, iTunes is arguably the world's most popular organizer for music, among other things. That's just fine, as iTunes has a fairly intuitive and polished interface, and handles most organizing tasks with ease. But sometimes iTunes behaves like a toddler throwing a tantrum that makes you want to pull all your hair out.

Case in point. I have a bunch of mp3 files I ripped from audiobook CDs I borrowed from the library (this is fair use, right, RIAA?). To facilitate listening to audiobooks, the newer versions of iTunes added two options for each track, "Remember playback position" and "Skip when shuffling", which allow the track to be bookmarkable, and not interrupt your music play when you shuffle.

The problem is these options can only be changed track by track. When you select multiple tracks and right-click to get the options panel, these two checkboxes are not in there. So if you have 500 audiobook tracks to change, you need to click your mouse 1,500 times (two for the checkboxes and one for the "next" button).

That was exactly what I did the first time around, and I swore I'd never do it again. But somehow after I changed some settings in iTunes and upgraded to a newer version, many, but not all, of the audiobook tracks lost those options. They became unchecked.

So here is the pulling hair out part. I'd rather be bald than click through those tracks again. A quick googling led me to some AppleScripts, but unfortunately I am on Windows so they are not much use to me. Further digging turned up Apple's iTunes COM for Windows SDK. Now I am not really a Windows COM guy, but this looked simple enough.

My first attempt was to use javascript to automate the mouse clicking. That didn't go very far as for some weird reason you have to downcast an IITTrack interface to IITFileOrCDTrack in order to access the bookmarkable and no shuffle options. I couldn't figure out how to type cast in javascript.

For the next step I could have used C++ or C# to access the COM interfaces, but that seems so heavy-handed for something simple like this. More googling showed, aha, of course, python is the perfect language for this. I've been trying to learn python and been reading the excellent online book Dive into Python, so this is the perfect chance to practice.

After looking at a few examples and some false starts, I finally got this to do what I wanted. Without further ado, I give you the python script to automate those 1,500 mouse clicks:
import win32com.client

def main():

iTunes = win32com.client.gencache.EnsureDispatch("iTunes.Application")
tracks = iTunes.SelectedTracks
track_count = tracks.Count

for track_index in range(1, track_count+1):
track = win32com.client.CastTo(tracks.Item(track_index), 'IITFileOrCDTrack')
track.RememberBookmark = True
track.ExcludeFromShuffle = True

if __name__ == '__main__':
main()