Controlling iTunes with Ruby

In working on Ruby Scripting Leopard, I’ve been helped by searching for AppleScript examples, such as those at Doug’s AppleScripts for iTunes. To pay it forward, I offer an example to some future searcher after the jump. Since WordPress (or something) is turning quotes into “smart” quotes, follow this link if you want plain text.

This should work on stock Leopard.

I run it via launchd, the replacement for cron(1). Lingon is a convenient way to create a launchd configuration file.

#!/usr/bin/env ruby

# Run to create a playlist named "today’s tunes". The playlist is 
# populated with tracks selected because the first character of their
# names begins with a randomly selected letter or digit. For example, 
# my list today begins like this:
#  Galang
#  Gamma Ray
#  Gary Stomp
#  Gear

require osx/cocoa
include OSX
OSX.require_framework ScriptingBridge

PLAYLIST_NAME = "today’s tunes"

def main
  todays_tunes = make_empty_playlist
  tracks = tracks_beginning_with(some_random_character, all_songs)
  tracks.each do | track |
    track.duplicateTo(todays_tunes)
  end
end

def make_empty_playlist
  ensure_no_playlist(PLAYLIST_NAME)
  p = ITunesPlaylist.alloc.initWithProperties({’name => PLAYLIST_NAME})
  # TODO: why does following fail?
  # LIBRARY.userPlaylists.addObject(p)
  LIBRARY.userPlaylists.insertObject_atIndex(p,0)
  p.shuffle = true
  p
end

def tracks_beginning_with(letter, tracks)
  tracks.find_all do | track |
    name = if starts_with_qualifier?(track.name)
             phrase_tail(track.name)
           else
             track.name
           end
    /^#{letter}/i =~ name
  end
end

def ensure_no_playlist(name)
  p = LIBRARY.playlists.objectWithName(name)
  p.delete if p.exists == 1
end

def all_songs
  LIBRARY.playlists.objectWithName(’Library‘).tracks
end

def some_random_character
  possibilities = (’a‘..’z‘).to_a + (’0‘..’9‘).to_a
  possibilities[rand(possibilities.length)]
end

# Works with either a NSCFString or a string.
# TODO: Change tests to indicate that?
def starts_with_qualifier?(name)
  name =~ /^thes/i || name =~ /^ans/i || name =~ /^as/i
end

def phrase_tail(name)
  name.gsub(/^w+s+/, ‘)
end

def bapp(bundle_name)
  SBApplication.applicationWithBundleIdentifier(bundle_name)
end

ITUNES = bapp(’com.apple.iTunes‘)
LIBRARY = ITUNES.sources.objectWithName(’Library‘)

if $0 == __FILE__
  main
end

Leave a Reply