Part 4: Copy shared tracks here

  • Copy selected tracks in the shared libraries to your iTunes library.

I want to be able to select some tracks in a shared library1 and add them to my iTunes library (their files will be scp'd to my iTunes Music folder and added from there). Additionally, I want a mechanism that will manage my login information for the various user's whose shared libraries are displayed in my iTunes; that is, the script should automatically supply the correct username and IP address for the particular remote user account whose shared tracks I have selected. And if it can't, then it should ask for this information and store it. (Of course, each of the remote accounts has traded public keys with my user account on the local machine.) We already have most of the routines to acomplish this.

At the start of the script we will need the selected tracks and the name of the shared library they appear in:

tell application "iTunes"
	set sel to selection
	if sel is {} then
		display dialog "No tracks selected." buttons {"Cancel"} default button 1 with icon 0
		set t1 to item 1 of sel
		if (get class of t1 is shared track) then
			set sharedLibName to (get name of container of container of t1)
			display dialog "No shared tracks selected." buttons {"Cancel"} default button 1 with icon 0
		end if
	end if
end tell

Use the first item in the selection of tracks to test the selection as shared tracks and to get the name of the shared library. Be sure to include both the sel and sharedLibName variables in the global declarations, too. They will be required by upcoming handlers.

This is the point in the script I'd be setting the remUserName and remHostIPAddr variables by hard-coding the requisite username and IP address. But this script is going to be smarter than that. We will create a preferences file (a.k.a. a ".plist" file) that the script can use to store the username and IP address for each individual shared library. We will need routines that can read the .plist file and write to it, and to do those things we need to use the defaults utility.

For the moment, pretend we have already devised the routines to read and write with defaults. Here is the essential get_login_info() handler that calls them:

to get_login_info()
		set {remUserName, remHostIPAddr} to my read_defaults(sharedLibName)
	on error m number n
		if n is in {1, -1728} then
			-- .plist doesn't exist OR key/value pair doesn't exist in the .plist
			-- get username for sharedLibName
			set remUserName to text returned of (display dialog ¬
				"Enter the username associated with the shared library \"" & ¬
				sharedLibName & "\":" default answer "")
			-- get ip address for sharedLibName
			set remHostIPAddr to text returned of (display dialog ¬
				"Enter the IP address associated with the shared library \"" & ¬
				sharedLibName & "\":" default answer "")
			-- there is NO error checking!
			my write_defaults(sharedLibName, {remUserName, remHostIPAddr})
			-- some other error; abort
			log m
			log n
			error number -128 -- cancel
		end if
	end try
	set remAddr to (remUserName & "@" & remHostIPAddr) as text
end get_login_info

One way or another, this handler will set the remUserName, remHostIPAddr and remAddr variables; these should be declared global.

First, an attempt is made to set the remUserName and remHostIPAddr variables by retrieving the value for the key named sharedLibName from the read_defaults() handler. If this command triggers an error because either the ".plist" file doesn't exist (error number 1) or there is no such key named sharedLibName (error number -1728) then ask the user to input the strings for remUserName and remHostIPAddr. Store them in the preference ".plist" file with the write_defaults() handler. If there is any other type of error--and I don't anticipate any other type--then abort the script at this point.

If the error wasn't triggered then the variables have been set as expected.

In either case, the remAddr variable is set.

Now, in a nutshell, the two defaults commands we will be using look like this:

defaults write domain key value defaults read domain key

... where domain is the name of the .plist file (which will be created in ~/Library/Preferences/), key is the name of a preference in the file and value is the data associated with that key.

For our purposes, the domain will be "com.dougscripts.copyshared" (the ".plist" extension is understood), the key will be the name of the shared library, and the value will be a list (an array, technically) comprised of the username and associated IP address.

Here are the defaults handlers; defaultsDomain should be declared a property at the beginning of the script with the string value "com.dougscripts.copyshared"2:

on write_defaults(k, l)
	do shell script "defaults write " & defaultsDomain & space & ¬
		quoted form of k & " -array " & (("'") & my list_to_text(l, "' '") & ("'"))
end write_defaults

on read_defaults(k)
	return paragraphs of (do shell script (("defaults read " & defaultsDomain & space & ¬
		quoted form of k) & space & "| grep ' '|sed -e 's/ //g' -e's/\"//g' -e's/\\,//g'"))
end read_defaults

The write_defaults() handler is fairly straight forward; the -array flag specifies that the value for the key whose name is passed as k will be a list of items; the list_to_text() prepares the two variables (passed as a list in l) as an array with the correct quoting. It would look like this (note how single quotes would be escaped using quoted form of):

defaults write com.dougscripts.copyshared 'Clean User'\\''s Library' -array 'cleanuser' ''

The read_defaults() handler returns something like this:

"( cleanuser, \"\" )"

...and the piped grep and sed search/replace commands remove the spaces, double-quotes, and commas so that only the data we need is extracted.

Call the get_login_info() handler right after the selection is obtained from iTunes. The full listing will appear later.

Coupla important things

There is no error checking. Do not include spaces in either the username or IP address; there shouldn't be any spaces in them anyway. To delete any entry, you will have to delete the "com.dougscripts.copyshared.plist" file from ~/Library/Preferences/ (unless--not for nothin'-- you'd care to write your own delete option). If the IP address of a machine changes you may have to do this.


Get More Information:

See the man pages for:
grep; everybody ought to know a little about regular expressions.

Here's a Linux-oriented rundown on sed, as good as any other.

Apple's Technical Note TN2065 should be read by anyone who uses do shell script, with especial regard to string quoting and escaping.


1When I say "shared library", I am referring to the libraries which appear in iTunes in the "SHARED" section and not a iTunes Music folder that is somehow file-shared.

2The naming convention used for the ".plist" file is more or less the same used for the launchd agent file, so feel free to customize it here.

Site contents © 2001 - 2021 (that's right: 2001) Doug Adams and weblished by Doug Adams. Contact support AT dougscripts DOT com. About.
All rights reserved. Privacy.
AppleScript, iTunes, iPod, iPad, and iPhone are registered trademarks of Apple Inc. This site has no direct affiliation with Apple, Inc.
The one who says "it cannot be done" should not interrupt the one doing it.