Writing code into the night

Every now and then I get into a code writing frenzy. Not that I’m much a programmer, but I enjoy the process (generally) and the satisfaction after a successful jaunt.

Last night (Tuesday), after a management meeting, I got back to the office, with the intent of catching up on email and heading out, when a question from a coworker got me investigating an issue.

I was able to get a basic (though not complete) answer out in a relatively short period of time, but finding the complete answer left me writing code into the late evening (and by “late evening” I mean 10pm. Yes, at work).

The problem was about the ability to receive drags from iTunes playlists and songs. I first looked at what iTunes was putting onto the OS X pasteboard by downloading and running PasteboardPeeker (from Apple’s Reference Libary).

The results of dragging an item from iTunes to PasteboardPeeker looked like this:

PasteboardRef: 3391984   ItemCount: 1
    Index: 1   item ID: 1
       'phfs' ______ 14      hook  rWm1

       'rWm1' P_____ 70      H   04 Burnin .m4p

       'Hpfl' ___n__ 70      H   04 Burnin .m4p

       'itun' P__n__ 1754 

I had no clue what each of the items meant. (Remember, I’m not really a programmer, and I don’t know much about Carbon.) I spent about an hour (re-) writing code to handle the dragged items (I started with CocoaDragAndDrop, another sample code from Apple’s Reference Library), with many false starts, trying to figure out how to interpret ‘phfs’, and so on.

I ended up modifying CocoaDragAndDrop to output the raw drag and drop information (looking back, I should have probably done this from the start, but I was learning as I went along). I added the following code:

NSPasteboard *pboard;
pboard = [sender draggingPasteboard];
NSLog(@"Types: %@", [pboard types]);

This returned

Types: (
"CorePasteboardFlavorType 0x70686673",
"Apple files promise pasteboard type",
"CorePasteboardFlavorType 0x72576D31",
"CorePasteboardFlavorType 0x4A524653",
"CorePasteboardFlavorType 0x4870666C",
"CorePasteboardFlavorType 0x44736964",
"CorePasteboardFlavorType 0x4F69646C",
"CorePasteboardFlavorType 0x6974756E"

Hm. A few Google searches later, I found propertyListForType, and, after some trial and error, figured out that CorePasteboardFlavorType 0x6974756E gave me a dictionary I could easily parse out:

 "Application Version" = "6.0.3";
 Features = 1;


 Tracks = {
  333 = {
   Album = "Wicked (Original Broadway Cast Recording)";
   Artist = "Idina Menzel & Kristen Chenoweth";
   Location = "file://localhost/Volumes/[...]
   Name = "Defying Gravity";
   "Store URL" = "itms://itunes.com/album?p=4426862&s=143441&i=4426835";
   "Track ID" = 333;
   "Track Type" = File;

Excellent! With just a few lines of code, I could pull out any information I wanted about the dragged items. For example, I could grab the song name and artist easily enough:

NSPasteboard *pboard;   
pboard = [sender draggingPasteboard];

NSDictionary *iTunesData;
iTunesData = [pboard propertyListForType:
  @"CorePasteboardFlavorType 0x6974756E"];

NSDictionary *tracks;
tracks = [iTunesData objectForKey:@"Tracks"];

NSEnumerator *trackEnum = [tracks objectEnumerator];
id value;
while ((value = [trackEnum nextObject]))
  NSLog(@"Song: %@, Artist: %@", 
     [value valueForKey:@"Name"], 
     [value valueForKey:@"Artist"]);

This results in:

Song: Defying Gravity, Artist: Idina Menzel & Kristen Chenoweth

It was fun (and frustrating!) digging through Apple’s documentation, Google results and so on to piece together stuff I’d never dealt with before, and extremely satisfying to get a working application that lets me parse out any dropped iTunes item.