The basic mechanics of the script are finished and it will probably run fine...about 90% of the time. We need to add some details.
Is the remote user logged in and is iTunes active? It should be in order to add files to it.
The rsync routines will work even if "cleanuser" is not logged in. However, the osascript routine--the routine that actually adds the files to the remote iTunes--cannot work if "cleanuser" is not logged in and iTunes isn't running. Since that's pretty much the essence of the workflow, it wouldn't make much sense to go to all the trouble to run it and have it error because the remote user isn't logged in. Plus, we don't want rsync to copy any files if they're not going to be added to iTunes--they would be "stranded" in the iTunes Music folder.
Below is a handler that will check if the remote user is logged in and then attempt to launch iTunes. If either task cannot be performed, the handler returns false; otherwise, if successful, the handler returns true. Add this handler to the script:
on are_you_logged_in() set whoCom to quoted form of ("who -q | grep \"" & remUserName & "\"") try set rez to (do shell script ("ssh " & remAddr & space & whoCom)) set osaCom to quoted form of ("osascript -e 'tell application\"iTunes\" to launch'") do shell script ("ssh " & remAddr & space & osaCom) return true on error return false end try end are_you_logged_in
This handler ssh's the unix command who with the "q" option to the remote machine that returns the names of the users logged in. If this list contains the remUserName then it proceeds to try and launch iTunes. If iTunes can be launched , all's well and the handler returns true (if iTunes is already running then launch has no effect, but it will not error); if it cannot then the script will error, returning false.
Call it early in the script, right after the requisite variables are set:
-- == allocate globals global remUserName, remHostIPAddr, remAddr -- == init variables set remUserName to "cleanuser" -- use your remote username set remHostIPAddr to "192.168.1.206" -- use your remote IP address set remAddr to (remUserName & "@" & remHostIPAddr) as text if my are_you_logged_in() is false then return
Make sure that you have declared remUserName, remHost, and destAddr as globals at the top of the script.
Get iTunes Music folder paths
Rather than hard-code the source and destination path variables (locMusicLibrary and remMusicLibrary, respectively), you can use the routines below to get the location of the iTunes Music folder for each source and destination iTunes user. Then, the only variables that would need to be hard-coded in the script are remUserName and remHost. (Perhaps a mod to make would have no hard-coded variables in the script, but read from an external editable preferences file of some sort.)
The location of your iTunes Music folder is listed in your current iTunes library's "iTunes Music Library.xml" file, and the location of that file is listed in "com.apple.iApps.plist". Here's a subroutine to get the current user's current iTunes Music folder location:1
to get_music_folder() set o to (do shell script "defaults read com.apple.iApps iTunesRecentDatabasePaths") as text set xm to text ((offset of "\"" in o) + 1) through ((offset of ".xml" in o) + 3) of o set xml to (my replace_chars(xm, " ", "\\ ")) as text -- based on unix script by Dave Taylor return (do shell script "head -n 14 " & xml & ¬ "| grep '>Music Folder<' | cut -d/ -f4- | sed 's/localhost//g' | \\cut -d\\< -f1 | sed 's/%20/ /g'") end get_music_folder
To get the remote user's iTunes Music library location, we'll ssh a variation of this.
to get_remote_music_folder() set dCom to quoted form of ("defaults read com.apple.iApps iTunesRecentDatabasePaths") set o to (do shell script ("ssh " & remAddr & space & dCom)) set xm to text ((offset of "\"" in o) + 1) through ((offset of ".xml" in o) + 3) of o set xml to (my replace_chars(xm, " ", "\\ ")) as text -- again, based on unix script by Dave Taylor set hCom to quoted form of ("head -n 14 " & xml & ¬ "| grep '>Music Folder<' | cut -d/ -f4- | sed 's/localhost//g' | \\cut -d\\< -f1 | sed 's/%20/ /g'") return (do shell script ("ssh " & remAddr & space & hCom)) end get_remote_music_folder
Escape single quotes
The file path data returned from the first rsync routine may contain single quotes (apostrophes) and these have to be escaped before the perl and osascript routines. (Each of these commands is within single quotes so real single quotes inside them need to be escaped. In fact, for the osascript, the escapes have to be escaped!) Add this handler:
...and call it just as the first rsync command is run, like so:
set rezList to my text_to_list(my fix_single_quotes(do shell script theCommand), ASCII character 13)
...and later in the repeat loop:
repeat with fileToAdd in filesToAdd set fileToAdd to my fix_single_quotes(fileToAdd) -- and so on...
Optional: Exclude special folders
I've used rsync's "--exclude" option to prevent pesky ".DS_Store" files from being copied. But I can include as many "--exclude" patterns as I want. To prevent podcast, movie, and TV show files from being considered by rsync I'm going to create this excludeThese variable at the top of the script and then use it in each of my rsync codes:
-- place at top of script with other variables set excludeThese to "--exclude 'Movies/' --exclude 'Podcasts/' --exclude 'TV Shows/'" -- first rsync (dry run): set theCommand to ("rsync -nEvauz --ignore-existing --exclude '.DS_Store'" & space & ¬ excludeThese & space & ¬ locMusicLibraryQuoted & space & ¬ remAddr & ":" & remMusicLibraryEscapedQuoted) -- second rsync (for real): set theCommand to ("rsync -Evauz --ignore-existing --exclude '.DS_Store'" & space & ¬ excludeThese & space & ¬ locMusicLibraryQuoted & space & ¬ remAddr & ":" & remMusicLibraryEscapedQuoted)
rsync will ignore the paths I've listed in excludeThese. You could also filter Artist folders, say to make sure your wife never gets any of your "Eagles of Death Metal" tracks, which, surprisingly, she really doesn't care for.
Optional: Update a text log using info from rsync's "--stats" option
One of rsync's many cool options is "--stats". It will report how many files were copied, size, and so on. You can then capture this info and dump it to a text log. For added measure, I've included the start and stop time of the script and a tally of how many files were added. Here's a terse run-through:
First, include the "--stats" option in the second rsync routine and make sure to set a variable to the result of the do shell script that runs it:
-- == rsync for real set theCommand to ("rsync -Evauz --stats --ignore-existing --exclude '.DS_Store'" & space & ¬ excludeThese & space & ¬ locMusicLibraryQuoted & space & ¬ remAddr & ":" & remMusicLibraryEscapedQuoted)
Add the following handler with the other handlers to get the current date and time and set a start_time variable to its result when the script begins:
Then, initialize a variable as a counter, here trackAddedCounter, and increment it on each loop of the routine adding the files:
-- == add files to iTunes set trackAddedCounter to 0 repeat with fileToAdd in filesToAdd set fileToAdd to my fix_single_quotes(fileToAdd) try with timeout of (3 * days) seconds set osaCom to quoted form of ¬ ("osascript -e 'tell application\"iTunes\" to add POSIX file \"" & fileToAdd & "\"'") do shell script ("ssh " & remAddr & space & osaCom) set trackAddedCounter to (trackAddedCounter + 1) end timeout on error m number n log m log n end try end repeat
After that routine has run, prepare the output:
set logResults to ("Started: " & start_time & return & ¬ "Finished: " & my get_now() & return & ¬ rez & return & return & ¬ "Files added to iTunes: " & trackAddedCounter & return & ¬ "== == == == == == == == == == == ==" & return)
This would produce something like this in the logResults variable:
Started: 05/28/09 14:24:54 Finished: 05/28/09 14:27:08 Number of files: 66 Number of files transferred: 7 Total file size: 414440850 bytes Total transferred file size: 69328934 bytes Literal data: 69328934 bytes Matched data: 0 bytes File list size: 2331 File list generation time: 0.003 seconds File list transfer time: 0.000 seconds Total bytes sent: 68692715 Total bytes received: 216 sent 68692715 bytes received 216 bytes 570065.82 bytes/sec total size is 414440850 speedup is 6.03 Files added to iTunes: 7 == == == == == == == == == == == ==
Append it to a text file; I'll leave it to you to put that together.
The Other Way 'Round
This "push" workflow could be written the other way around, as a "pull" workflow, such that the local machine periodically checks the remote machine for new new files and copies them over to add to the local iTunes. That's the next project.
Get More Information:
Here's a Linux-oriented rundown on sed, as good as any other.