October 25, 2011 at 6:06 PM by Dr. Drang
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:
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…
- Install the Xcode installer from the Mac App Store.
- Run the Xcode installer.
- 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
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
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:
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
From iTunes/albumArt.png—to the top level of
iTunes Artwork where NerdTool can find it.
I have NerdTool configured to run the script
every 10 seconds, and to look at
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.
To review, there are three NerdTool entries:
- A Command entry for the Python script that displays the text.
- A Command entry for the AppleScript that pulls out the album art and copies it to the right place.
- 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.