Automatically update iTunes Library when Music Folder Changes?

I found a folder action script that will update itunes library when something is added to the music folder, but it doesn’t work for sub folders of the music folder, as folder actions aren’t recursive – is there a way to automatically attach this folder action to every subfolder of my music folder? How? I’m desperately looking for a way to keep several itunes libraries up to date with their shared music folder.

Here’s the folder action script:

on adding folder items to my_folder after receiving the_files
	repeat with i from 1 to number of items in the_files
		tell application "iTunes"
			launch
			try
				set this_file to (item i of the_files)
				
				add this_file
				
				(*
				-- if you have iTunes set to 
				--"Copy files to iTunes Music folder when adding to library"
				-- then you might want to delete the original file...
				-- if so, remove comments from this block and 
				-- use the UNIX commands below to delete the file
				
				set the file_path to the quoted form of the POSIX path of this_file
				do shell script ("rm -f " & file_path)
				
				*)
			end try
		end tell
	end repeat
end adding folder items to

How much experience do you have writing an AppleScript? It’s fairly straightforward, if you’re comfortable with scripting. For starters, I point you to the main scripts folder /Library/Scripts (or “Macintosh HD:Library:Scripts:” if you are more comfortable with Finder-style paths-substitute the name of your own hard drive if yours isn’t named “Macintosh HD”).

In that folder you’ll find folders of scripts that show up on the script menu (if you have it installed). In the “Folder Actions” folder you’ll find the script “Attach Script to Folder” (which may have .scpt on the end of the file name). If you open this script (double-click it) it will open in Script Editor. Then you can read through the following code:

property ChooseScriptPrompt : "Select a compiled script file containing folder actions"
property ChooseFolderPrompt : "Select a folder to attach actions"
property ErrorMsg : " is not a compiled script. (Ignored)."

on open DroppedItems
	choose folder with prompt ChooseFolderPrompt
	set TargetFolder to the result
	repeat with EachItem in DroppedItems
		set ItemInfo to info for EachItem
		if not folder of ItemInfo then
			set FileTypeOfItem to file type of ItemInfo
			set FileExtensionOfItem to name extension of ItemInfo
			if FileTypeOfItem is "osas" or FileExtensionOfItem is "scpt" then
				tell application "System Events" to ¬
					attach action to TargetFolder using EachItem
			else
				set ItemName to name of ItemInfo
				display dialog ItemName & ErrorMsg with icon caution
			end if
		end if
	end repeat
end open

on run
	my ChooseFileFromFAScriptFolder()
	open the result
end run


to ChooseFileFromFAScriptFolder()
	try
		set LibraryScripts to list folder (path to Folder Action scripts folder from local domain) without invisibles
	on error
		set LibraryScripts to {}
	end try
	try
		set UserScripts to list folder (path to Folder Action scripts folder from user domain) without invisibles
	on error
		set UserScripts to {}
	end try
	if (count LibraryScripts) + (count UserScripts) > 0 then
		set ChosenScript to choose from list LibraryScripts & UserScripts with prompt ChooseScriptPrompt
		if ChosenScript is in LibraryScripts then
			return {alias ((path to Folder Action scripts folder from local domain as Unicode text) & ChosenScript)}
		else if ChosenScript is in UserScripts then
			return {alias ((path to Folder Action scripts folder from user domain as Unicode text) & ChosenScript)}
		end if
	end if
	return {}
end ChooseFileFromFAScriptFolder

The section that begins on open DroppedItems is where you want to look. This script is the reverse of what you need, in that it accepts dropped scripts and then asks you to choose a folder to attach them to. You want one that allows you to choose a folder and then digs down each level attaching the same script to all of them.

This should be enough to get you started. If you need help, post back here and we’ll get you through the rough parts! :slight_smile:

If it’s not too much trouble, I would LOVE to be walked through how to do this - I’m brand new to applescript, just learning how to do minor modifications to pre-existing scripts. Is it possible to have a script that will automatically attach another script to every sub-folder, and any new sub-folders of my music folder as they are added?

Organik,

I haven’t had a chance to get to your post the last few days, I apologize. I’m looking at the “add music to iTunes” issue you bring up and I’m wondering about something…when you add a file to iTunes, it will automatically move it to the correct folder. I’m wondering if you NEED to attach this folder action to every folder in your iTunes directory. In other words, when you add an MP3 file (just as an example), if you have iTunes set up to “copy added files to your iTunes music folder” (in preferences, I think that’s the default setting), then iTunes will read the ID tags in the MP3 and figure out what artist and album are in the tags and move it to the appropriate place.

If those tags are wrong or don’t exist, then iTunes will dump it in the “various artists” folder. So I’m wondering if, rather than tagging every folder, just tagging the iTunes folder with a script that will add the file to iTunes and let iTunes figure out where it wants to put it will work for you?

Let me know. In the meantime, I’m working on that version of a script that I’ll post back later with a walkthrough for you.

Organik,

OK, let’s look at the simpler case I talked about previously, that of creating a folder action that will add tracks to iTunes when files are dropped onto a Finder folder.

First, let’s go from simpler to harder. We need the standard “on adding items” handler. It’s run when items (files or folders) are added to a Finder folder window. Here’s the basic handler:

on adding folder items to this_folder after receiving added_items
	addTunes(added_items)
end adding folder items to

Part of what you get with an adding folder items handler is a list of items. Here we’ll call it added_items (we could have called it scoobydoo if we wanted to, AppleScript doesn’t care what we call it, just that it’s there).

Now the addTunes handler doesn’t exist (yet) so let’s write that. We need to tell iTunes we want to talk to it, then tell it what to do. During that, we need to take the added_items list and individually add each one, so we need a repeat loop. The handler looks like this:

on addTunes(added_tunes)
	tell application "iTunes"
		activate
		if not (exists user playlist "AutoAdd") then ¬
			make new user playlist with properties {name:"AutoAdd"}
		set theCount to 0
		repeat with myItem in added_tunes
			set theTrack to add myItem as alias to user playlist "AutoAdd"
			copy theCount + 1 to theCount
		end repeat
		display dialog "Added " & theCount & " tracks to iTunes"
	end tell
end addTunes

Keep in mind, that while the “adding folder items” handler is something AppleScript understands, the addTunes handler is OUR creation, so we could call it Snoopy if we wanted to. Notice, though, that when we passed added_items we accepted it in our handler with a different name (just to prove that handler parameters are local to the parameter, just making a point). So when we get the list in addTunes, the added_items list is renamed to added_tunes.

First we get iTunes attention with the “tell application iTunes” line and tell it to launch if it isn’t already running with “activate”.

Then we check to see if there is a playlist called “AutoAdd” (could be SpongeBob, if we wanted). I thought it would be nice to have a playlist that keeps track of items we’ve added with the folder action. If the folder doesn’t exist, we make one.

Then we set a counter because we want to keep track of how many items get added. We’ll use it later, you’ll see.

Then we repeat through the items in added_tunes and add each one. The reason we say “set theTrack to add myItem” instead of just “add myItem” is that the add command in iTunes expects to return to you a reference to the added track, just to prove it did it. We’re not going to use the variable theTrack in anything, it’s kind of a throw-away.

During the repeat and after the add, we update the counter.

Then at the end, we display a message to the user telling them how many tracks were added. This serves two purposes: 1) it lets the user know we’re done adding, which is nice if you add a lot of tracks because it may take a minute or two and 2) it gives them an idea of how many files were added.

OK, so far we have a nice folder action. But what if we think “Gee, it’d be nice if I could use the same script to add files or folders of files without having to open the scripted folder.” For that reason, I added an “on run” handler.

Most AppleScripts have an implied “on run” handler–the whole script is assumed to be in an “on run” handler! But in a folder action script, we have to be specific, so we say:

on run
	display dialog ¬
		"Add a single file or a whole folder?" buttons {"File", "Folder", "Cancel"} default button 1 with icon "alert"
	copy button returned of the result to myBtn
	if myBtn is "File" then
		set myList to (choose file with prompt ¬
			"Select an audio file" without invisibles) as list
		addTunes(myList)
	else if myBtn is "Folder" then
		tell application "Finder"
			set myList to every file of (choose folder with prompt ¬
				"Select a folder of audio files") whose name extension is in {"mp3", "aiff", "wav", "m4a"}
		end tell
		addTunes(myList)
	end if
end run

Here we ask the user if he wants to add a single file or a folder of them, and let him navigate to the file/folder, then we add the file or folder of files to iTunes using the same addTunes handler we created earlier!

Note: The part that reads whose name extension is in {“mp3”, “aiff”, “wav”, “m4a”} specifies what kind of audio files to add. If you have other types, just add their file extensions to the list.

Hope this helps. Just take the 3 handlers and put them in a script, then save it to either “/Library/Scripts/Folder Action Scripts” or put it into your own Library folder’s Scripts folder in a folder named “Folder Action Scripts” (create it if it doesn’t exist). Then use the Script Menu and select the “Folder Actions” submenu and then “Attach Script to Folder”. It will ask you to select a script (hopefully this one will be listed!) and a folder.

Then you’re Done!

Whoa! Thanks for the help - this is great. I’m learning about applescript, and it’s cool!

Here’s the problem I’m having, and why I need the folder action to be added to every sub folder. I have several computers that each have their own iTunes library, and they share the same networked music folder. When one computer adds a song, or album, to it’s iTunes, the music gets copied into the music folder under the artist name, album name, song title…so a folder action script on the music folder will not detect files that have been added to a subfolder, only when a NEW artist is added (thus modifying the music folder). I want each computer to retain individual libraries (playlists, etc), but have the iTunes library updated whenever anything is added to the music folder (via another instance of iTunes on another computer), or in the case of an already existing artist, any sub folder of the music folder.

Do you get what I’m looking for? I don’t want to sound too needy, you’ve already helped so much… but a solution to this problem would not only benefit me, but a great number of users (probably thousands) with this same situation.

OK, so each user has their own iTunes library (the file in the iTunes folder that keeps track of what tracks you know about and your playlists) but each one has had his iTunes pointed at a shared folder of music?

You’re right, in that this is more common than people think. I’ve done it myself when I was sharing a computer with a roommate and needed to conserve hard drive space. Didn’t see any point in both of us having our own copies of the same file, duplicating disk space usage.

The folder action I gave you will update iTunes when an item is added, but given what you’ve told me, I’m not sure it’s a folder action you need. Because other users can add a file (or folder) to the shared folder, even a triggered folder action script won’t update iTunes for OTHER users, just the current user.

Hmmmm…I’ll need to think on this one…

Whatever the solution is for updating each library, it could be run on each individual computer - but yeah, a folder action might not be the way to go, folder actions seems to be using quite a bit of cpu on my machine as well…