Categories
Programming

Automating Shared iTunes Library Access

I’ve been sharing my iTunes library in-house with multiple Macs reading from the same library on a shared drive for about three months now.

Most of the time iTunes is running on a MacMini server in the office and access to the single library containing all our content is done through the iTunes Home Sharing. This work great (most of the time) when all we are doing is playing music or videos. Things get more difficult when I want to add some content to the library from the MacBook.

The major issue I keep running into is iTunes’ lock of the library file and the need to shut down the server instance of iTunes. This requires a trip to the office or a remote login to the server. Not a huge bother, but more work than it ought to be, IMHO.

I figured there had to be a way to simpify things and after several hours of research, help from the TheMacTipper, Daring Fireball, and a lot of trial-and-error, I’ve crafted a solution which runs with only a click or two with the help of my DropBox account.

Folder Actions Fail

Since I was using a shared folder for my iTunes library I started off thinking that the solution would entail the use of some AppleScript and Folder Actions. I was half right. The AppleScript is required, but the Folder Actions weren’t up to snuff.

I put together a Folder Actions script which would shut down iTunes when triggered to do so. I figured an easy trigger would the existence of a file with a specific name, say “iTunesQuit”. Simple enough. And it worked. Sort of.

First there was the issue of folder actions not being reliable. So I decided to research using LaunchD instead.

Second, it turns out that the afp: protocol which defines the shared mount has an indeterminate lag when syncing writes to the disk. This lag was longer than I was willing to wait within a scripted action. When I need access to my iTunes library, I’d like it to happen quickly, not in twenty or thirty seconds.

Dropbox to the Rescue

Since writing a file to a shared drive was too slow I started to look at the other ways I share data between computers and I was immediately drawn to DropBox. The key feature in this solution is the “Enable LAN Sync” option which Dropbox uses to reduce network traffic to its servers.

It turns out that Dropbox is pretty quick on the draw with this LAN sync and I could script a wait of mere seconds–more than fast enough for what I wanted to accomplish.

Dropbox had the added benefit of making the solution presented below portable as well. The AppleScript to control things could be saved in a Dropbox folder and referenced from any machine configure to sync with Dropbox.

The Solution in Four Parts

Since I was automating the shutdown of the iTunes instance on the office server I thought I could do the reverse and automate the startup of iTunes on the server once I was done accessing the library from the MacBook. My need to get the server in the office running iTunes again is not as urgent so I use a little longer delay in coordinating this action.

So my ultimate solution is comprised of four parts:

  1. iTunesControl.scpt AppleScript to control things.
  2. com.wh1t3s.iTunesControl.plist Lauch Agent to invoke AppleScript above as needed
  3. _iTunes_.app Automator application to trigger remote shutdown
  4. iTunesOnServer.app Automator application to trigger remote iTunes restart

iTunesControl.scpt

I want to preface my code here with the caveat that this is the first AppleScript I’ve ever written. There may be simpler, more elegant, or simply more correct ways to do the things I am doing, but I stopped my development at what worked for me. (Please kindly leave suggestions for improvement in the comments below, preferably sans judgement.)

This is the script which is tied to the LaunchD launch agent created to watch the Dropbox folder (/Users/myUserName/Dropbox/iTunesSync) I am using to trigger my iTunes actions: existence of “iTunesQuit” will shut down iTunes on any machine configured with the launch agent, existence of “iTunesRun” will activate iTunes on the named server, while also shutting down other iTunes instances by creating “iTunesQuit”.

Please remember to change myUserName and MacMiniServer items below with comparable items suitable to your implementation.

--
-- saved as /Users/myUserName/Dropbox/iTunesControl.scpt
--
property quitFile : POSIX file "/Users/myUserName/Dropbox/iTunesSync/iTunesQuit"
property runFile : POSIX file "/Users/myUserName/Dropbox/iTunesSync/iTunesRun"

on run
  try
    set isRunning to appIsRunning("iTunes")

    tell application "Finder"
      if exists quitFile then
        if isRunning then
          tell application "iTunes" to quit
        end if

        -- delay to allow Dropbox to complete
        delay 5

        -- check existence again in case another Mac already deleted it
        if exists quitFile then
          move quitFile to trash
        end if

      else if exists runFile then
        if "MacMiniServer" is equal to computer name of (system info) then
          -- delete runFile
          move runFile to trash

          -- trigger remote iTunes shutdown
          do shell script "touch /Users/myUserName/Dropbox/iTunesSync/iTunesQuit"

          -- delay while any other instances of iTunes are shutdown
          delay 15

          -- start iTunes on server
          tell application "iTunes" to activate
        end if
      end if
    end tell
  end try
end run

on appIsRunning(app_name)
  tell application "System Events"
    set app_list to every application process whose name is equal to app_name
    if the (count of app_list) > 0 then
      return true
    else
      return false
    end if
  end tell
end appIsRunning

com.wh1t3s.iTunesControl.plist

I actually created this launch agent with Lingon since this was my first attempt at launch agents. I will save you the new and improved cost of the app in the new Apple Mac App Store of $4.99 and post the resulting plist file in its entirety. This file was saved as /Users/myUserName/LIbrary/LaunchAgents/com.wh1t3s.iTunesControl.plist.





    Label
    com.wh1t3s.iTunesControl
    ProgramArguments
    
        osascript
        /Users/myUserName/Dropbox/iTunesControl.scpt
    
    QueueDirectories
    
    WatchPaths
    
        /Users/myUserName/Dropbox/iTunesSync/
    


_iTunes_.app

This is a very simple Automator application; a shell script to create the iTunes shut down trigger file, wait a few seconds, then start iTunes.

iTunesOnServer.app

An even simpler Automator application; a script to create the server run iTunes trigger file.

Making it All Work

To bring it all together:

  1. Install the Dropbox client on all machines.
  2. Save iTunesControl.scpt to ~/Dropbox/ (or wherever your Dropbox folder is located, I put mine in my home directory.)
  3. Save com.wh1t3s.iTunesControl.plist to ~/Library/LaunchAgents on all machines.
  4. Copy _iTunes_.app to all machines.
  5. Copy iTunesOnServer.app to all machines but the server.

To start iTunes on the server, start the app iTunesOnServer on any machine. To shutdown the server instance and run iTunes on another machine, start the _iTunes_ app on that machine. Shared instances point to the same iTunes library on the shared disk.

This solution is working for me for a few days now, YMMV.