Getting iTunes Genius into MPD

I just wrote my first ever AppleScript to solve a problem I’ve had for some time. As I’ve mentioned several times before, I use the MPD music player on my HTPC to play music through my amplifier while controlling playback using my laptop or mobile phone. This works like a charm and I’ve been really satisfied with this setup — until I fell in love with iTunes’ Genius function.

I use iTunes on my MacBook and mainly at work, either listening through my headphones or streaming music to the office speakers using our AirPort Extreme. As my library is rather diverse, I like to use Genius to get an ad hoc playlist of similar songs to avoid the “shuffle all, press next until a good song comes along” selection method. Needless to say, Genius has worked fabulously. However, when I come home and start playing music through MPD, I’m back to the shuffle all hell since I can’t be bothered creating playlists manually.

So this got me thinking: Is there any way I can use iTunes Genius together with MPD? The answer is yes, and the tool I used is AppleScript.

It’s not a complicated script, but it took me some hours to get it together since I’ve never written any AppleScripts before. The idea is to get the current playlist from iTunes (e.g. the currently playing Genius playlist) and look up and add each song to MPD. This of course requires that MPD has access to the same songs as iTunes by some means. In my case, I use a simple bash script to rsync my iTunes library on my MacBook to the HTPC’s MPD library:

rsync -tr --del --progress --perms --chmod=Da+rx,Fa+r /Users/bostrom/Music/iTunes/iTunes Music fredde@10.0.0.4:/media/lacie2/music

I run this script manually every time there’s been any changes to my iTunes library. This way MPD always has the exact same library as iTunes, and thus there should be no problem to replicate any iTunes playlist to MPD.

The script itself, at the time of writing, looks like this:

set mpdHost to "localhost"
set mpdPort to "6600"
set mpcCommand to "mpc -h " & mpdHost & " -p " & mpdPort & " "

tell application "iTunes"
 set allTracks to every file track in current playlist
 do shell script mpcCommand & "clear"

 repeat with i from 1 to (length of allTracks)
  -- grab song
  set song to item i of allTracks

  -- construct search song command for mpc
  set searchCommand to mpcCommand & "search artist "" & (artist of song) & "" title "" & (name of song) & """
  if album of song is not "" then
   set searchCommand to searchCommand & " album "" & (album of song) & """
  end if

  -- execute command and grab the filename
  set filename to do shell script searchCommand

  -- add song if we got a filename
  if filename is not "" then
   do shell script mpcCommand & "add "" & filename & """
  end if
 end repeat
end tell

The script can be run from anywhere, but a convenient location is the iTunes script folder in ~/Library/Scripts/Applications/iTunes. This way, the script shows up in the scripts menu when iTunes is focused.

scriptsmenu

You can find the most recent version of this script in my SVN repository and on the Projects page.

Advertisements

3 Comments

Filed under AppleScript, Geek speak, Linux, Mac

3 responses to “Getting iTunes Genius into MPD

  1. Excellent job!

    Well, I would like a iTunes-mpd-proxy/bridge. I mean, so I can use my MPD client of choice to control iTunes. Does anyone know about anything like that?

    The basics of MPD-protocol cannot be very hard to implement. And interfacing with iTunes seems simple with AppleScript.

    Next thing is to build a Spotify-mpd-bridge 😉

  2. Justi

    Thanks for posting this script, very handy!

    I found that it crashed on filenames that have shell special characters on them.

    Here’s a fixed version of main lopp which has a modified function I copied from another script somewhere else (encodeText):

    tell application "iTunes"
    	set allTracks to every file track in current playlist
    
    	do shell script mpcCommand & "clear"
    	--display dialog "Adding " & (length of allTracks) & " tracks to MPD..."
    	repeat with i from 1 to (length of allTracks)
    		-- grab song
    		set song to item i of allTracks
    
    		set safeTrack to my encodeText(name of song)
    		set safeArtist to my encodeText(artist of song)
    		set safeAlbum to my encodeText(album of song)
    
    		-- construct search song command for mpc
    		set searchCommand to mpcCommand & "search title "" & (my truncateString(safeTrack, 30)) & """
    		if artist of song is not "" then
    			set searchCommand to searchCommand & " artist "" & (my truncateString(safeArtist, 30)) & """
    		end if
    		if album of song is not "" then
    			set searchCommand to searchCommand & " album "" & (my truncateString(safeAlbum, 30)) & """
    		end if
    		-- display dialog "Searching with command: " & searchCommand
    		log "Search command: " & searchCommand
    
    		-- execute command and grab the filename
    		set filename to do shell script searchCommand
    		log filename
    
    		-- add song if we got a filename
    		if filename is not "" then
    			log "Adding file " & filename
    			try
    				do shell script mpcCommand & "add "" & (my encodeText(filename)) & """
    			on error errmsg number errnr
    			end try
    			-- start playing after we've added the first song
    			if i is equal to 1 then do shell script mpcCommand & "play"
    		end if
    	end repeat
    end tell
    
    -- encodeText: takes care of shell escapes
    on encodeText(theText)
    	--set the listOfUnacceptableCharacters to " &$'/"\()`;"
    	set the listOfUnacceptableCharacters to "$'"\"
    	set the encodedText to ""
    	set the characterList to {}
    	repeat with thisChar in theText
    		set thisChar to the contents of thisChar
    		if thisChar is not in the listOfUnacceptableCharacters then
    			set the end of the characterList to thisChar
    		else
    			set the end of the characterList to ("\" & thisChar)
    		end if
    	end repeat
    	return (the characterList) as string
    end encodeText
    
  3. Justi

    Sorry that version still isn’t quite right. Remove the quote from the listOfUnacceptableCharacters, do the truncation before the encoding, and select the first line of the filename in case of more than one match (I appended “| head -1” onto the search command because I couldn’t figure out the Applescript). With those changes I get 100/100 on long lists.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s