Syncing iTunes… Again (Or, Building a Better Mousetrap)

Introduction

In my previous article “Syncing iTunes” I illustrated a way to transfer iTunes playlists from one music library to another using some XML glue. Here, we’ll take a look at a different way of synchronizing playlists. Rather than forcing you to generate the XML that describes your playlists and then go through the steps to download it (or, on the other end of things, find an XML file and then import it into your copy of iTunes), we’ll make use of Apple’s Mail application to take care of the delivery and receipt of the playlist. And to keep things interesting—and keep ourselves sane—we’ll use YAML instead of XML to describe the payload (if you’re unfamiliar with YAML, don't fret—I'll get to that in due time).

A Quick Note

The premise of this solution—using email as a method of getting your data from one place to another—is by no means a revolutionary idea; two examples of web applications off the top of my head that include this feature are:

  1. emailing photos to your Flickr account,
  2. and emailing adding notes/images/to–do items to your Backpack pages.

However, this article shows how easy it can be to set up something similar to process email on your Mac to save yourself some time, rather than sending your data to an application hosted elsewhere. Let’s take a look at what we’ll need to get the job done.

The Building Blocks

The project requires the following building blocks:

Note: The solution discussed in this article only works on the latest version of OS X, Tiger. However, it is a relatively painless process to tweak various bits of code (mainly the AppleScript front–end) so that it can also be used on Panther. However, this step will be left to the readers as an exercise; feel free to post your work in the comments section at the end of this article (there are still people out there using Panther, right?).

The first three items in the list above—Mail, iTunes, and AppleScript—will be familiar to anyone who uses OS X on a regular basis, so there’s not much point in giving them attention right now. However, the last two pieces—Ruby, and YAML— are a little more obscure. These topics may be old hat to some readers, but let’s take a quick look at each of them in turn.

Regarding Ruby

Those readers who hang around in web development circles—or even just pay attention to the buzz going around in the blogosphere—will surely have heard of the buzz around Ruby on Rails, a framework that allows the rapid design and construction of web applications using Ruby. Rails is just a framework that’s built on top of Ruby, in much the same way that Cocoa is OS X’s desktop application framework built on top of Objective–C.

In a nutshell, Ruby is an object–oriented scripting language that mashes the best parts of Perl and Python together, leaves out their warts, and adds several original concepts for good measure.

Regarding YAML (YAML Ain’t Markup Language)

According to its homepage, YAML is a…

straightforward machine parsable data serialization format designed for human readability and interaction with scripting languages.

Which sounds great, but what does that mean in English, exactly? Essentially, YAML is a simple way to store programming language constructs in a plain–text format that is easy to create and parse by programs, and is just as easy to edit by hand through a regular text editor. While it is often compared to XML, YAML should be thought of a method for encoding datatypes (such as arrays, hashes, lists, structs, classes, and scalars) rather than documents (such as books, hypertext pages, and vector images), although some overlap certainly exists between the two domains.

For the most part, YAML constructs look surprisingly intuitive, despite their technical nature and strict rules governing their composition. As a simple example (and one that contains all YAML structures that will be necessary for this article), the following YAML document describes the contents of two hypothetical playlists in my iTunes library:

---
quickies:
 - The Corb Lund Band : (Gonna) Shine Up My Boots
 - Swamp Baby : Hawaii
 - Buck 65 : Kennedy Killed the Hat
 - Chad VanGaalen : Clinically Dead
 - Sam Roberts : On The Run
 - Chixdiggit! : Koo Stark
 - Tegan And Sara : Walking With A Ghost
 - Danko Jones : Wait A Minute
 - Sloan : Deeper Than Beauty
 - Tigre Benvie : Decade Of Sunsets
 - Hayden : Carried Away
 - Franz Ferdinand : You're The Reason I'm Leaving
 - Cake : Commissioning A Symphony In C
 - Death From Above 1979 : Blood On Our Hands
 - City Field : Pretenders
 - Bran Van 3000 : Problems

"jamz:slow":
 - Rufus Wainwright : Hallelujah
 - Feist : Secret Heart
 - Crash Vegas : Please Don't Ask
 - Hawksley Workman : Old Bloody Orange
 - King Cobb Steelie : Drowning
 - Cowboy Junkies : To Love Is To Bury
 - Joel Plaskett Emergency : You Came Along
...

Explaining YAML

The preceeding document is an example of what we’ll be sending back and forth in our email messages. You’ll notice that it looks surprisingly similar to how you might describe the playlists if you were to create a plain–text email to send to a friend. This transparency is, in fact, one of YAML’s greatest strengths: creating documents manually is as easy as writing a program to take care of it (it just might take a little longer to do). That being said, let’s take a closer look at exactly what’s going on in the above snippet:

That’s all the YAML you’ll need to know to get by in this article; the YAML site has the reference documentation and there exist several resources that make learning YAML a piece of cake.

Regarding a couple minor design decisions…

The Situation

So now that we’ve met the actors in our play, it’s time to get into some plot development. Grab a copy of all the code from here and play along.

Chapter 1

The first step is to create a rule in Mail that will invoke an AppleScript which will then pass off the heavy–lifting (ie: transforming the YAML contents into AppleScript code that will then be executed to create our playlists) to the Ruby script. The following snippet of code will get the job done:

tell application "Mail"
  
  -- find all messages that are mytunes-related 
  set mymessages to every message in mailbox MY_MAILBOX
    of account MY_ACCOUNT whose subject starts with MY_SUBJECT
  
  repeat with m in mymessages

    set myid to (id of m) as string
    set mymessage to PATH_TO_EMAIL_MESSAGES & myid & ".emlx"

    set cmd to "/usr/bin/ruby " & PATH_TO_MYTUNES_YAML & " " &
      mymessage & " | osascript"

    try
      set r to do shell script cmd
    on error e
      display dialog (e as string)
    end try

    delete m

  end repeat

end tell

The tokens whose names are ALL_IN_CAPITAL_LETTERS are configuration variables that are specific to your account. Essentially, the above snippet invokes a Ruby script (located at PATH_TO_MYTUNES_YAML ) whose sole argument is the path to the email message saved in your mailbox whose subject starts with the value of MY_SUBJECT. For example, if I receive a message whose subject is “mytunes:ugly ducklings”, the AppleScript invoked by our rule will invoke a shell command resembling the following (apart from the line break):

/usr/bin/ruby ~/Utilities/bin/yamltunesmail.rb
~/Library/Mail/POP-dave@fivevoltlogic.com@smtp.fivevoltlogic.com
/INBOX.mbox/Messages/245.emlx

… where 245.emlx is the file saved on the hard disk that contains the email message whose subject is “mytunes:ugly ducklings”. So the AppleScript has done it’s job; it’s now up to the Ruby script to read in the contents of that message and create a playlist out of it.

Chapter 2: Enter Ruby, Stage Left

The bulk of the work is done by the script mytunesmail.rb (available here), which, in turn, is reliant upon a few other classes/packages:

(YAML support is built–in to Ruby as of v1.8.0; if for some reason you need to install it, you can grab a copy from here.)

Installing the Dependencies

Ruby Gems (the equivalent to Perl’s CPAN) make installing libraries a snap; copy & paste the following command in a Terminal window to install RubyMail on your machine:

sudo gem install rmail

YAMLTunes and Applescript can be downloaded here, and here respectively.

Aside: One of Mail’s Many Quirks

Apple’s Mail application has used the standard mbox format for storing your email messages since its launch in OS X. However, with the release of v2.0 in Tiger, Mail’s messages have an extra chunk of data appended to them, which typically looks something like the following:

--Apple-Mail-4--999511826--

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC
  "-//Apple Computer//DTD PLIST 1.0//EN"
  "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>date-sent</key>
  <real>1121189091</real>
  <key>flags</key>
  <integer>570623105</integer>
  <key>original-mailbox</key>
  <string>pop://dave%40fivevoltlogic.com@host.com/</string>
  <key>remote-id</key>
  <string>1121189115.27313.pop</string>
  <key>sender</key>
  <string>dave miller <dave@fivevoltlogic.com></string>
  <key>subject</key>
  <string>mytunes</string>
  <key>to</key>
  <string>dave miller <dave@fivevoltlogic.com></string>
</dict>
</plist>

While the purpose of this blob is unclear (it’s most likely used in Mail’s internal message indexing and/or Spotlight support), what is clear is that trying to parse a emlx file with a library that groks the reglar mbox format will result in having the above included in the body of the email message. So for those of you that have looked at mytunesmail.rb and are wondering what all the extra regular expressions are for, now you know.

Taking it for a Test Drive

Once all the scripts are installed and your rule in Mail is properly configured, having your friends, family, and coworkers create playlists on your computer is as easy as having them send you an email. Or, if they’re too lazy to type, send them an AppleScript (Make YAML For Playlist) to create YAML files on their desktop which can then be easily copied & pasted into a new message:

YAMLTunes Documents on the Desktop

Image #1: A series of YAMLTunes files whose contents can be sent via email to automatically create your playlist in another iTunes music library.

Or, if you wanna skip a few steps in the flow, use the other script included in the zip file (Email YAML For Playlist) to automatically create a new Mail message with the YAML already included in the body:

TODO

Image #1: TODO

Wrapping Up

Not everything about this solution is peachy, as some potential security problems may be encountered (namely, the fact that anyone with your email address is now able to tinker with your music library). Before you know it, you could end up with all sorts of playlists full of your Kenny G and John Tesh tracks that are tucked away in the crevices of your library. As a preventative measure, I strongly suggest tightening the reins on the criteria required to have the AppleScript automatically invoked by the rule in Mail. Perhaps the easiest and most effective method of doing this is to create a group in your Address Book, and add a filter to the rule requiring that the message sender be a member of this group, as shown below:

Setting up a Rule in Mail

Image #2: Setting up a rule in Mail to invoke an AppleScript when a message containing YAMLTunes is received.

Alternatively, you could stop the AppleScript from being invoked automatically and run it manually instead. The choice is yours.

Other Applications

The idea presented in this article could be extended very easily to send other information between two computers; sending calendar events or an address book entry could also be transferred in a similar way (of course, you could always just attach a vCard or iCalendar file to the message). However, these two domains also have standard file formats that are almost universally transferable. That being said, there are plenty of other situations where a similar workflow could be used.