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.

python:
 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.