iTunes info in NerdTool on Lion

I’ve written about this so many times in the past, I’m not sure I can link to every iteration. The idea is to show—on the Desktop via NerdTool—the name, the artist, the rating, the album, and the album artwork of the iTunes track currently playing. Like this:

iTunes info via NerdTool

The album artwork part broke under Lion and the Lion-compatible version of NerdTool, so I had to do a little code surgery. Rather than taking you through the convoluted history of this code, I’m going to try to present everything you need in one post.

The text info

The text is generated through a Python script called itunes-playing, which I keep, along with most of the scripts I write, in my ~/bin/ folder. It uses the third-party appscript library, which gives Python the AppleScript-like ability to control other Mac applications. So before you try to use itunes-playing, you’ll have to install appscript. Since appscript needs to be compiled, you’ll first have to install Xcode, which is a free—albeit lengthy— download from the Mac App Store. Be aware that installing what the MAS calls Xcode doesn’t actually install Xcode itself; it installs an Xcode installer that you’ll then have to run. I screwed this up a couple of weeks ago.

Forgot that installing Xcode 4 from the Mac App Store only installs the installer. Now installing from the installer that I installed from…

2:51 PM Thu Oct 13, 2011

In summary:

  1. Install the Xcode installer from the Mac App Store.
  2. Run the Xcode installer.
  3. Install the appscript Python library.

There are lots of ways to do this third step. If you’re not a big Python user, my suggestion is to do this from the Terminal:

sudo easy_install appscript

and type your administrator password when prompted for it.

You may be wondering whether all this preliminary bullshit is worth it. I can’t answer for you, but for me installing Xcode and appscript are things I’d be doing anyway so there’s no extra burden.

OK, onto itunes-playing itself. It’s a short script that pulls the information about the current track from iTunes and formats it.

 1  #!/usr/bin/env python
 2  
 3  from appscript import *
 4  
 5  template = '"%s" by %s (%d)\n from %s'
 6  info = ''
 7  
 8  iTunesCount = app('System Events').processes[its.name == 'iTunes'].count()
 9  if iTunesCount > 0:
10    iTunes = app('iTunes')
11    if iTunes.player_state.get() == k.playing:
12      track = iTunes.current_track.get()
13      who = track.artist.get()
14      what = track.name.get()
15      onwhat = track.album.get()
16      stars = track.rating.get()/20
17      info = template % (what, who, stars, onwhat)
18  print info

Lines 8-9 check to see if iTunes is running. Line 11 check to see if it’s playing. If both of those are true, it pulls the information out of iTunes and prints it, otherwise it prints an empty string.

I have NerdTool set to run this command via

python ~/bin/itunes-playing

every 10 seconds and display it, right justified in 14-point white Lucida Grande Bold, down near the lower right corner of my screen.

The album artwork

The next script is an embarrassingly convoluted and deeply nested AppleScript. It started out as a fairly simple AppleScript, but it grew in complexity as I added provisions to handle situations that I didn’t consider originally. I probably should rewrite it entirely in Python and appscript, but I don’t feel up to it yet. And for all its Rube Goldbergian intricacies, it does work.

It’s called itunes-art, and it’s also kept in ~/bin/. Its purpose is to get the album artwork for the playing track and write it, in PNG format, to a particular file. NerdTool, in turn, looks for that file to display on the Desktop. If iTunes isn’t playing, or if there’s no artwork for the track, a transparent PNG image is written to that file instead.

Here’s the code.

 1  -- Paths and stuff
 2  set JPEGFromiTunes to ((path to home folder) as text) & ¬
 3    "Pictures:iTunes Artwork:From iTunes:albumArt.jpg" as alias
 4  set PNGFromiTunes to ((path to home folder) as text) & ¬
 5    "Pictures:iTunes Artwork:From iTunes:albumArt.png" as alias
 6  set TIFFFromiTunes to ((path to home folder) as text) & ¬
 7    "Pictures:iTunes Artwork:From iTunes:albumArt.tiff" as alias
 8  set iTunesArtwork to ((path to home folder) as text) & ¬
 9    "Pictures:iTunes Artwork:From iTunes:albumArt.png"
10  set DefaultArtwork to ((path to home folder) as text) & ¬
11    "Pictures:iTunes Artwork:Default:albumArt.png"
12  set displayArtwork to ((path to home folder) as text) & ¬
13    "Pictures:iTunes Artwork:albumArt.png"
14  
15  -- Unix versions of the above path strings
16  set unixITunesArtwork to the quoted form of POSIX path of iTunesArtwork
17  set unixDefaultArtwork to the quoted form of POSIX path of DefaultArtwork
18  set unixDisplayArtwork to the quoted form of POSIX path of displayArtwork
19  
20  set whichArt to "blank"
21  tell application "System Events"
22    if exists process "iTunes" then -- iTunes is running
23      tell application "iTunes"
24        if player state is playing then -- iTunes is playing
25          set aLibrary to name of current playlist -- Name of Current Playlist
26          set aTrack to current track
27          set aTrackArtwork to null
28          if (count of artwork of aTrack) ≥ 1 then -- there's an album cover
29            set aTrackArtwork to raw data of artwork 1 of aTrack
30            if (format of artwork 1 of aTrack) contains "JPEG" then
31              set fileRef to ¬
32                (open for access JPEGFromiTunes with write permission)
33            else
34              if (format of artwork 1 of aTrack) contains "TIFF" then
35                set fileRef to ¬
36                  (open for access TIFFFromiTunes with write permission)
37              else
38                set fileRef to ¬
39                  (open for access PNGFromiTunes with write permission)
40              end if
41            end if
42            write aTrackArtwork to fileRef starting at 0
43            close access fileRef
44            
45            if (format of artwork 1 of aTrack) contains "JPEG" then
46              tell application "Image Events"
47                set theImage to open JPEGFromiTunes
48                save theImage as PNG in unixITunesArtwork
49              end tell
50            else
51              if (format of artwork 1 of aTrack) contains "TIFF" then
52                tell application "Image Events"
53                  set theImage to open JPEGFromiTunes
54                  save theImage as PNG in unixITunesArtwork
55                end tell
56              end if
57            end if
58            set whichArt to "iTunes"
59          end if
60        end if
61      end tell
62    end if
63  end tell
64  
65  if whichArt is "iTunes" then
66    do shell script "ditto -rsrc " & unixITunesArtwork & space & unixDisplayArtwork
67  else
68    do shell script "ditto -rsrc " & unixDefaultArtwork & space & unixDisplayArtwork
69  end if

Yuck.

Lines 1-18 define the names and locations of a bunch of files that the script writes and/or reads. They’re all kept in the ~/Pictures/iTunes Artwork/ folder, the contents of which looks like this:

iTunes Artwork folder contents

The albumArt.png at the top is the one NerdTool looks for. The albumArt.png in the Default folder is the transparent PNG we use when iTunes isn’t playing or the track has no artwork. The albumArt.* files in the From iTunes folder are what the script gets from iTunes.

Lines 21-24 make sure iTunes is running and a track is playing. Lines 28-41 get the artwork for the currently playing track, determine its format (JPEG, TIFF, or PNG), and open a file in the From iTunes folder for writing. Lines 42-43 write the data—whatever its format—out to the file and close it.

If the artwork is in JPEG or TIFF format, we have to convert it to PNG, which is what Lines 45-57 do. NerdTool can display JPEGs and TIFFs just fine, but because we’re going to tell it to look for a particular file, we have to choose a format—I chose PNG.

Finally, Lines 65-68 copy the appropriate file—either Default/albumArt.png or From iTunes/albumArt.png—to the top level of iTunes Artwork where NerdTool can find it.

I have NerdTool configured to run the script

osascript ~/bin/itunes-art.scpt

every 10 seconds, and to look at

file://localhost/Users/drdrang/Pictures/iTunes%20Artwork/albumArt.png

for the image to display. It’s set to scale the image proportionally and center it in a 150×150 square just above the text.

NerdTool image configuration

Summary

To review, there are three NerdTool entries:

  1. A Command entry for the Python script that displays the text.
  2. A Command entry for the AppleScript that pulls out the album art and copies it to the right place.
  3. A URL entry that displays the copied album art on the Desktop.

To run the Python script, you’ll need the appscript library, which means you’ll need Xcode. This is why I can’t simply package this stuff up and give you a ready-to-run, self-installing bundle of code.

What about GeekTool?

All of these scripts have run at one time or another under GeekTool, and I see no reason to believe they wouldn’t do so now. I prefer NerdTool because GeekTool seems like a bit of a memory hog, but your experience may be different.