Script to duplicate Apple Lossless iTunes library as MP3 files

Discussion in 'macOS' started by nick_harambee, Sep 26, 2010.

  1. nick_harambee macrumors regular

    Joined:
    May 20, 2005
    #1
    Hi,

    I have written the applescript below to duplicate my Apple Lossless iTunes library as a MP3 Library. I wanted the script to be able to do the following things:

    1. For all Apple Lossless tracks in iTunes Library (at the moment the script is just set to work with a selection for testing purposes) check if track already exists in MP3 folder with more recent modification date and:
    a If yes, do nothing
    b If same track with earlier modification date convert and replace track (so that tag changes are transferred)
    c If track doesn't exist convert track.

    2. If there are any MP3 files in the target folder that aren't in the source folder (i.e. the iTunes Music Folder), delete these files. This is for the scenario when I delete files from my iTunes Library that I no longer want, and I want the equivalent MP3 file to be deleted as well. So once the script has finished running there should be an exact match between the Apple Lossless library and the MP3 folder.

    The script below does everything I want it to do with the following caveats:

    1. I am not sure how to go about deleting the MP3 files as in part 2. I guess it would have to be an additional section of script which compares each file by name in the folder/subfolder in the iTunes Music Library with the equivalent folders in the target music folder, deleting any files found in the target music folder that don't exist in the iTunes Music folders, but I'm not sure if this is the best/only method, and how I would go about scripting this.

    2. Because I need to specify the conversion twice (once if no file exists in target folder and once if it does but with an older modification date) I am wondering about using a subroutine method here. I tried doing so, but no conversions happened even though some should have happened. I wonder if this is because the relevant variables aren't picked up properly by the script when it's a subroutine. I can leave things as they are, just thought it would be good to make the script neater.

    Code:
    tell application "iTunes"
    	activate
    	
    	set sel to selection
    	set encoderBackup to name of current encoder
    	set this_folder to "Macintosh HD:Users:nick:Desktop:music:" as text
    	set current encoder to encoder "MP3 Encoder"
    	
    	
    	repeat with this_track in sel
    		set trackComposer to this_track's composer
    		set trackAlbum to this_track's album
    		set trackName to this_track's name
    		tell application "Finder"
    			
    			set path1 to "Macintosh HD:Users:nick:Desktop:music:" & trackComposer as text
    			
    			if folder path1 exists then
    				{}
    			else
    				make new folder at this_folder with properties {name:trackComposer}
    			end if
    			
    			set path2 to this_folder & trackComposer & ":" & trackAlbum as text
    			
    			if folder path2 exists then
    				{}
    			else
    				make new folder at path1 with properties {name:trackAlbum}
    			end if
    			
    			if exists file (path2 & ":" & trackName & ".mp3") then
    				set file2 to (path2 & ":" & trackName & ".mp3") as alias
    				set modDate to modification date of file2
    				set modDate2 to this_track's modification date
    				if modDate is greater than modDate2 then
    					{}
    				else
    					tell application "iTunes"
    						try -- skip on failure
    							set new_track to item 1 of (convert this_track)
    							set loc to new_track's location
    							set dbid to new_track's database ID
    							delete artworks of new_track
    							
    							-- move the file to new location
    							do shell script "mv " & (quoted form of POSIX path of loc) & " " & (quoted form of POSIX path of path2 as string)
    							
    							-- delete the track
    							delete new_track
    						end try
    					end tell
    					
    				end if
    			else
    				tell application "iTunes"
    					try -- skip on failure
    						set new_track to item 1 of (convert this_track)
    						set loc to new_track's location
    						set dbid to new_track's database ID
    						delete artworks of new_track
    						
    						-- move the file to new location
    						do shell script "mv " & (quoted form of POSIX path of loc) & " " & (quoted form of POSIX path of path2 as string)
    						
    						-- delete the track
    						delete new_track
    					end try
    				end tell
    				
    			end if
    		end tell
    		
    	end repeat
    	
    	set current encoder to encoder encoderBackup
    	display dialog "done"
    end tell
    Can anyone help with either points?

    Thanks

    Nick
     
  2. calderone macrumors 68040

    calderone

    Joined:
    Aug 28, 2009
    Location:
    Seattle
    #2
    If you are using variables in functions, that are declared outside the function, you need to define them as global for example:

    Code:
    global myFirstGlobal
    set myFirstGlobal to "2"
    In terms of how to script the stuff you want, you have to determine the best method to get those things done.
     
  3. nick_harambee thread starter macrumors regular

    Joined:
    May 20, 2005
    #3
    Thanks. I have tried to integrate the global variables as you suggest, but I can't have got it right, because the script is not converting any files when it should be doing so:

    Here's the amended script:

    Code:
    tell application "iTunes"
    	activate
    	
    	set sel to selection
    	set encoderBackup to name of current encoder
    	set this_folder to "Macintosh HD:Users:nick:Desktop:music:" as text
    	set current encoder to encoder "MP3 Encoder"
    	
    	global this_track
    	repeat with this_track in sel
    		set trackComposer to this_track's composer
    		set trackAlbum to this_track's album
    		set trackName to this_track's name
    		tell application "Finder"
    			
    			set path1 to "Macintosh HD:Users:nick:Desktop:music:" & trackComposer as text
    			
    			if folder path1 exists then
    				{}
    			else
    				make new folder at this_folder with properties {name:trackComposer}
    			end if
    			
    			global path2
    			set path2 to this_folder & trackComposer & ":" & trackAlbum as text
    			
    			if folder path2 exists then
    				{}
    			else
    				make new folder at path1 with properties {name:trackAlbum}
    			end if
    			
    			if exists file (path2 & ":" & trackName & ".mp3") then
    				set file2 to (path2 & ":" & trackName & ".mp3") as alias
    				set modDate to modification date of file2
    				set modDate2 to this_track's modification date
    				if modDate is greater than modDate2 then
    					{}
    				else
    					my convertTrack
    				end if
    			else
    				my convertTrack
    			end if
    		end tell
    		
    	end repeat
    	
    	set current encoder to encoder encoderBackup
    	display dialog "done"
    end tell
    
    on convertTrack()
    	tell application "iTunes"
    		try -- skip on failure
    			global path2
    			global this_track
    			set new_track to item 1 of (convert this_track)
    			set loc to new_track's location
    			set dbid to new_track's database ID
    			delete artworks of new_track
    			
    			-- move the file to new location
    			do shell script "mv " & (quoted form of POSIX path of loc) & " " & (quoted form of POSIX path of path2 as string)
    			
    			-- delete the track
    			delete new_track
    		end try
    	end tell
    end convertTrack
    I worked out there are two variables which are not declared within the function, path2 and this_track, so I added a line to define them as global above the line where they are declared, and also in the handler (not sure if this second step is necessary). I then simply used 'my convertTrack' in the script. But as I said, it's not working as it stands.

    Regarding point 1 in my original post, I presume that the best method would be to work folder by folder comparing folders and subfolders of the main destination folder 'music' with their equivalent folders and subfolders in the iTunes music library, removing any file (checked by filename) in the destination folder that is not found in the source folder. But I am not sure how to go about this.

    Nick
     
  4. nick_harambee thread starter macrumors regular

    Joined:
    May 20, 2005
    #4
    Just to say that I have worked out the second issue, so that I can use a handler to specify the conversion and call it in the script when necessary. I am not sure where to start though with the first issue, i.e. how to delete any MP3 files in the destination folders/subfolders, that don't exist as m4a files in the source (iTunes) folders/subfolders (presumably this would have to be by generating a list of files of in each folder and comparing file names, but I am not sure how to go about this - would I do it folder by folder, or just generate one long list of all the files in the folders/subfolders?). Here's the revised script:

    Code:
    tell application "iTunes"
    	activate
    	
    	set sel to selection
    	set encoderBackup to name of current encoder
    	set this_folder to "Macintosh HD:Users:nick:Desktop:music:" as text
    	set current encoder to encoder "MP3 Encoder"
    	
    	repeat with this_track in sel
    		set trackComposer to this_track's composer
    		set trackAlbum to this_track's album
    		set trackName to this_track's name
    		tell application "Finder"
    			
    			set path1 to "Macintosh HD:Users:nick:Desktop:music:" & trackComposer as text
    			
    			if not (folder path1 exists) then
    				make new folder at this_folder with properties {name:trackComposer}
    			end if
    			
    			local path2
    			set path2 to this_folder & trackComposer & ":" & trackAlbum as text
    			
    			if not (folder path2 exists) then
    				make new folder at path1 with properties {name:trackAlbum}
    			end if
    			
    			if exists file (path2 & ":" & trackName & ".mp3") then
    				set file2 to (path2 & ":" & trackName & ".mp3") as alias
    				set modDate to modification date of file2
    				set modDate2 to this_track's modification date
    				if not (modDate is greater than modDate2) then
    					my convertTrack(this_track, path2)
    				end if
    			else
    				my convertTrack(this_track, path2)
    			end if
    		end tell
    		
    	end repeat
    	
    	set current encoder to encoder encoderBackup
    	display dialog "done"
    end tell
    
    on convertTrack(this_track, path2)
    	tell application "iTunes"
    		try -- skip on failure
    			set new_track to item 1 of (convert this_track)
    			set loc to new_track's location
    			set dbid to new_track's database ID
    			delete artworks of new_track
    			-- move the file to new location
    			do shell script "mv " & (quoted form of POSIX path of loc) & " " & (quoted form of POSIX path of path2 as string)
    			
    			-- delete the track
    			delete new_track
    		end try
    	end tell
    end convertTrack
     
  5. nick_harambee thread starter macrumors regular

    Joined:
    May 20, 2005
    #5
    Thanks.

    I now have a script that does everything I want, including deleting superfluous tracks from the destination folder, except where there are characters in the track name in iTunes that aren't supported in filenames in Finder (i.e. ? / :). This means that all tracks which contain these characters in the name are re-converted every time I run the script.

    Is there a way I wonder of adapting the script so that when it is checking to see if the track already exists in the destination folder, it replaces these characters in the track name with an _ (which is what happens in Finder) for the purposes of the comparison?

    Nick

    Code:
    tell application "iTunes"
    	activate
    	
    	set sel to every track of playlist "1 music library"
    	set encoderBackup to name of current encoder
    	set this_folder to "Macintosh HD:Users:nick:Desktop:music:" as text
    	set current encoder to encoder "MP3 Encoder"
    	
    	repeat with this_track in sel
    		set trackComposer to this_track's composer
    		set trackAlbum to this_track's album
    		set trackName to this_track's name
    		tell application "Finder"
    			
    			set path1 to "Macintosh HD:Users:nick:Desktop:music:" & trackComposer as text
    			
    			if not (folder path1 exists) then
    				make new folder at this_folder with properties {name:trackComposer}
    			end if
    			
    			local path2
    			set path2 to this_folder & trackComposer & ":" & trackAlbum as text
    			
    			if not (folder path2 exists) then
    				make new folder at path1 with properties {name:trackAlbum}
    			end if
    			
    			if exists file (path2 & ":" & trackName & ".mp3") then
    				set file2 to (path2 & ":" & trackName & ".mp3") as alias
    				set modDate to modification date of file2
    				set modDate2 to this_track's modification date
    				if not (modDate is greater than modDate2) then
    					my convertTrack(this_track, path2)
    				end if
    			else
    				my convertTrack(this_track, path2)
    			end if
    		end tell
    		
    	end repeat
    	
    	set current encoder to encoder encoderBackup
    	display dialog "done"
    end tell
    
    on convertTrack(this_track, path2)
    	tell application "iTunes"
    		try -- skip on failure
    			set new_track to item 1 of (convert this_track)
    			set loc to new_track's location
    			-- move the file to new location
    			do shell script "mv " & (quoted form of POSIX path of loc) & " " & (quoted form of POSIX path of path2 as string)
    			
    			-- delete the track
    			delete new_track
    		end try
    	end tell
    end convertTrack
     

Share This Page