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.
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:
- iTunesControl.scpt AppleScript to control things.
- com.wh1t3s.iTunesControl.plist Lauch Agent to invoke AppleScript above as needed
- _iTunes_.app Automator application to trigger remote shutdown
- iTunesOnServer.app Automator application to trigger remote iTunes restart
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
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.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.wh1t3s.iTunesControl</string> <key>ProgramArguments</key> <array> <string>osascript</string> <string>/Users/myUserName/Dropbox/iTunesControl.scpt</string> </array> <key>QueueDirectories</key> <array/> <key>WatchPaths</key> <array> <string>/Users/myUserName/Dropbox/iTunesSync/</string> </array> </dict> </plist>
An even simpler Automator application; a script to create the server run iTunes trigger file.
Making it All Work
To bring it all together:
- Install the Dropbox client on all machines.
- Save iTunesControl.scpt to ~/Dropbox/ (or wherever your Dropbox folder is located, I put mine in my home directory.)
- Save com.wh1t3s.iTunesControl.plist to ~/Library/LaunchAgents on all machines.
- Copy _iTunes_.app to all machines.
- 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.