Applescript to read mp3 metatags and sort file into folder

For the below I was wanting that if either theGenre,theArtist,theTempo or theKey contain a null, then to prompt saying which file it is and then NOT move the file and continue with the next file.


   #SOME MP3 TAGS ARE NOT PROPERLY FILLED OUT- THIS BELOW PART DOESNT WORK AS SCRIPT PROCEEDS??????. # problem solved below
   if (count theGenre) ≤ (count "(null)") and theGenre contains "null" then set theGenre to "(no Genre)" # ADDED
   if (count theArtist) ≤ (count "(null)") and theArtist contains "null" then set theArtist to "(no Artist)" # ADDED
   if (count theTempo) ≤ (count "(null)") and theTempo contains "null" then set theTempo to "(no Tempo)" # ADDED
   if (count theKey) ≤ (count "(null)") and theKey contains "null" then set theKey to "(no Key)" # ADDED

So it’s effectively a non-problem. I suspect the OP doesn’t have many French MP3s anyway, correctly coded or otherwise.

Since there’s been no feedback about that, and since the OP appears to have ignored the two scripts I posted, I don’t think there’s much else I can contribute to this thread. I’ve replaced the mainBusiness() handler in the ASObjC script with the working version of Shane’s and I’ve updated the “vanilla” script to handle null results in the same way.

Go to messages #53 & 54

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) dimanche 16 avril 2017 18:10:33

NS¿¿¿¿¿¿StringEncoding should do it. :wink:

use AppleScript version "2.4" # requires at least Yosemite
use scripting additions
use framework "Foundation"

# Decode the string extracted by ASObjC from the metadatas.

my decodeText("David Guetta, Giorgio Tuinfort, Frédéric Riesterer, Taio Cruz, Nick Van De Wall, Rico Love, Raymond Usher & Aviici")
-- my decodeText("David Guetta, Giorgio Tuinfort, Frédéric Riesterer, Taio Cruz, Nick Van De Wall, Rico Love, Raymond Usher & Aviici")

on decodeText(theText)
	set |⌘| to current application
	
	set theText to |⌘|'s class "NSString"'s stringWithString:(theText)
	-- If the string contains at least two consecutive 8+bit characters, assume it's a mangled result.
	if ((theText's rangeOfString:("[\\u0080-\\U0010ffff]{2}") options:(|⌘|'s NSRegularExpressionSearch))'s |length|() > 0) then
		set dataObj to (theText's dataUsingEncoding:(|⌘|'s NSISOLatin1StringEncoding))
		set theText to (|⌘|'s class "NSString"'s alloc()'s initWithData:(dataObj) encoding:(|⌘|'s NSUTF8StringEncoding))
	end if
	
	return theText -- as text
end decodeText

Thanks Nigel
I would have certainly not build that.

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) dimanche 16 avril 2017 19:52:52

Hi Yvan.

I’ve just shortened it considerably!

Although they’ll still get bitten if they’re fans of Beyoncé…

But the version for use with mdls is slightly longer:

use AppleScript version "2.4" # requires at least Yosemite
use scripting additions
use framework "Foundation"

# Decode the string extracted by mdls from the metadata.

my decodeText("Le garA\\U0303\\U00a7on est arrivA\\U0303\\U00a9.")
my decodeText("Le gar\\U00e7on est arrive\\U0301.")

on decodeText(theText)
	set |⌘| to current application
	
	set theText to |⌘|'s class "NSString"'s stringWithString:(theText)
	-- Set up and use a regex to find Unicode substitute expressions of the garbled kind (misderived from UTF-8 sequences).
	set aHandyRegex to |⌘|'s class "NSRegularExpression"'s regularExpressionWithPattern:("([[:alpha:]]\\\\U[[:hex:]]{4})(\\\\U[[:hex:]]{4})") options:(0) |error|:(missing value)
	set regexMatches to aHandyRegex's matchesInString:(theText) options:(0) range:({0, theText's |length|()})
	set matchCount to (count regexMatches)
	-- If none are found, look for Unicode substitute expressions of the correct kind instead.
	set containsGarbledBlips to (matchCount > 0)
	if (not containsGarbledBlips) then
		set aHandyRegex to |⌘|'s class "NSRegularExpression"'s regularExpressionWithPattern:("(\\\\U[[:hex:]]{4})") options:(0) |error|:(missing value)
		set regexMatches to aHandyRegex's matchesInString:(theText) options:(0) range:({0, theText's |length|()})
		set matchCount to (count regexMatches)
	end if
	-- If either kind is found, reconstitute the original characters and substitute them for the matched expressions.
	if (matchCount > 0) then
		set theText to theText's mutableCopy()
		repeat with i from (count regexMatches) to 1 by -1 -- Reverse loop because theText's length will change.
			-- With each match, get the text matching the first first capture group in the regex.
			set thisMatch to item i of regexMatches
			set subrange1 to (thisMatch's rangeAtIndex:(1))
			set component1 to (theText's substringWithRange:(subrange1))
			-- Convert it to data using 7-bit ASCII encoding.
			set dataObj to (component1's dataUsingEncoding:(|⌘|'s NSASCIIStringEncoding))
			-- Convert it back to a character using "non-lossy ASCII" encoding.
			set reconstitutedCharacter to (|⌘|'s class "NSString"'s alloc()'s initWithData:(dataObj) encoding:(|⌘|'s NSNonLossyASCIIStringEncoding))
			-- If dealing with misderived expressions, perform a further twiddle.
			if (containsGarbledBlips) then
				-- Get the text matching the other capture group in the regex.
				set subrange2 to (thisMatch's rangeAtIndex:(2))
				set component2 to (theText's substringWithRange:(subrange2))
				-- Convert that to data using 7-bit ASCII encoding.
				set dataObj to (component2's dataUsingEncoding:(|⌘|'s NSASCIIStringEncoding))
				-- Convert it back to a character using "non-lossy ASCII" encoding.
				set component2 to (|⌘|'s class "NSString"'s alloc()'s initWithData:(dataObj) encoding:(|⌘|'s NSNonLossyASCIIStringEncoding))
				-- Convert the first character back to data, now with ISO Latin-1 encoding.
				set dataObj to (reconstitutedCharacter's dataUsingEncoding:(|⌘|'s NSISOLatin1StringEncoding))'s mutableCopy()
				-- Convert the second character to data too and append it to the data from the first.
				tell dataObj to appendData:(component2's dataUsingEncoding:(|⌘|'s NSISOLatin1StringEncoding))
				-- Convert the combination back to a single character using UTF-8 encoding.
				set reconstitutedCharacter to (|⌘|'s class "NSString"'s alloc()'s initWithData:(dataObj) encoding:(|⌘|'s NSUTF8StringEncoding))
			end if
			-- Replace the whole of the matched expression in the text with the character derived from it.
			tell theText to replaceCharactersInRange:(thisMatch's range()) withString:(reconstitutedCharacter)
		end repeat
	end if
	
	return theText -- as text
end decodeText

Ah yes. Or of Blue Öyster Cult. Mmm. That ages me …

In case there’s anyone still hanging in here, I maintain that making these “corrections” is wrong. If the file says “François”, even if the correct name is “François”, the code should return what the file (and iTunes) says, in this case “François”.

I tend to agree, although maybe it should be that the main code should return what the file says and a “correction” after-process can be bolted on if people like Yvan so wish.

I wrote the correction handlers mainly out of interest and for the challenge. They only handle the situations I currently know about and assume that intended eight-bit-or-more characters aren’t adjacent to each other in the text.

I apologizes but in the case of the example which I gave,“David Guetta, Giorgio Tuinfort, Frédéric Riesterer, Taio Cruz, Nick Van De Wall, Rico Love, Raymond Usher & Aviici”,
iTunes displays only the first author “David Guetta”
I’m curious and wish to get readable strings.

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) lundi 17 avril 2017 12:45:42

Nothing to apologize for – it took long enough for the penny to drop here. It could well be that “official” metadata format is ambiguous anyhow.

Any ideas on how to stop the script from moving files that have null in any of the below fields. I can get it to prompt but it continues to move the file.

This is the last part I need to work. :smiley:


#SOME MP3 TAGS ARE NOT PROPERLY FILLED OUT- THIS BELOW PART DOESNT WORK AS SCRIPT PROCEEDS??????. # problem solved below
	if (count theGenre) ≤ (count "(null)") and theGenre contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Genre)"
	if (count theArtist) ≤ (count "(null)") and theArtist contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Artist)"
	if (count theTempo) ≤ (count "(null)") and theTempo contains "null" then display dialog "Error: " & (theFile as text) & " has a blank field - Please Fix (no Tempo)"
	if (count theKey) ≤ (count "(null)") and theKey contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Key)" 


Go to messages #53 &54

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) mardi 18 avril 2017 15:36:18

the above script doesn’t work. I selected the mp3, it only creates the genre and artist folder path but doesn’t move the actual file.

Is there any chance you could modify the below?. So that it doesn’t move the file if the genre,artist,key and tempo are equal to null.

FYI the mp3/aiff I use come from beatport so all the BPM,Key etc are filled out when you buy them. However sometimes I might select a folder that may not contain Beatport mp3s within, hence why I don’t want to move them.



use AppleScript version "2.4" # requires at least Yosemite
use scripting additions
use framework "Foundation"

on listFolder:POSIXPath # handler using ASObjC
	set fileManager to current application's NSFileManager's defaultManager()
	set aURL to current application's |NSURL|'s fileURLWithPath:POSIXPath
	set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theEnumerator to fileManager's enumeratorAtURL:aURL includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value)
	set theFiles to theEnumerator's allObjects()
	set theFiles to theFiles's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"(lastPathComponent ENDSWITH '.mp3') OR (lastPathComponent ENDSWITH '.aiff')")
	return theFiles as list # if we work upon files
	--return (theFiles's valueForKey:"path") as list # if we work upon POSIX paths
end listFolder:


-- Creates a new folder. There is no error if the folder already exists, and it will also create intermediate folders if required
on createFolder:POSIXPath
	set |⌘| to current application
	set theFolderURL to |⌘|'s |NSURL|'s fileURLWithPath:POSIXPath
	set theFileManager to |⌘|'s NSFileManager's defaultManager()
	set {theResult, theError} to theFileManager's createDirectoryAtURL:theFolderURL withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
	if not (theResult as boolean) then error (theError's |localizedDescription|() as text)
end createFolder:

set theFolder to choose folder with prompt "Please select a folder containing MP3/AIFF files" # ADDED

set theFiles to its listFolder:(POSIX path of theFolder) # ADDED

repeat with aFile in theFiles
	my treatThisFile(aFile)
end repeat

on treatThisFile(theFile)
	set posixFilePath to the quoted form of (POSIX path of theFile)
	
	set genreTag to (do shell script "mdls " & posixFilePath & " -name kMDItemMusicalGenre")
	set artistTag to (do shell script "mdls " & posixFilePath & " -name kMDItemAuthors")
	set tempoTag to (do shell script "mdls " & posixFilePath & " -name kMDItemTempo")
	set keyTag to (do shell script "mdls " & posixFilePath & " -name kMDItemKeySignature")
	set titleTag to (do shell script "mdls " & posixFilePath & " -name kMDItemTitle")
	
	set theGenre to text ((offset of "= " in genreTag) + 3) through -2 of genreTag
	set theArtist to text ((offset of "= " in artistTag) + 9) through -4 of artistTag
	set theTempo to text ((offset of "= " in tempoTag) + 2) through -1 of tempoTag
	set theKey to text ((offset of "= " in keyTag) + 3) through -2 of keyTag
	set theTitle to text ((offset of "= " in titleTag) + 3) through -2 of titleTag
	
	#SOME MP3 TAGS ARE NOT PROPERLY FILLED OUT- THIS BELOW PART DOESNT WORK AS SCRIPT PROCEEDS??????. # problem solved below
	if (count theGenre) ≤ (count "(null)") and theGenre contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Genre)"
	if (count theArtist) ≤ (count "(null)") and theArtist contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Artist)"
	if (count theTempo) ≤ (count "(null)") and theTempo contains "null" then display dialog "Error: " & (theFile as text) & " has a blank field - Please Fix (no Tempo)"
	if (count theKey) ≤ (count "(null)") and theKey contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Key)" 
	
	# For some files, theTitle is returned as "null" or "(null)" so it may generate duplicates # Edited
	# I choose to use the original name deprieved of the extension
	
	if (count theTitle) ≤ (count "(null)") and theTitle contains "null" then # EDITED
		tell application "System Events" # ADDED
			set theTitle to text 1 thru -5 of (get name of file (theFile as text))
		end tell
	end if
	
	set renamedTitle to ("{" & theTempo & "-" & theKey & "}  " & theTitle)
	
	set DestFolder to ("/Volumes/Production/test/" & theGenre & "/" & theArtist)
	--set DestFolder to ("/Volumes/Macintosh HD/Users/Important/Test/" & theGenre & "/" & theArtist)
	
	my createFolder:DestFolder
	
	set DestFolder to POSIX file DestFolder
	
	set theFile to (theFile as text) as alias # ADDED. Finder refuse to get extension or rename the object returned by the ASObjC handler
	tell application "Finder"
		set theExtension to name extension of theFile
		set name of theFile to renamedTitle & "." & theExtension #AS MAYBE AIFF OR MP3
		try
			move theFile to DestFolder
		on error errMsg
			display dialog renamedTitle & errMsg # IF ALREADY EXISTS WILL PROMPT
		end try
		
	end tell
	
end treatThisFile



Go to messages #53 &54

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) mercredi 19 avril 2017 10:20:41

I got this below error with the long script.


error "You don't have permission to save the file "Derek Howell" in the folder "Progressive House"." number -2700 from «script» to item

Can you please amend the below script (the first one) to not move null mp3s.


use AppleScript version "2.4" # requires at least Yosemite
use scripting additions
use framework "Foundation"

on listFolder:POSIXPath # handler using ASObjC
	set fileManager to current application's NSFileManager's defaultManager()
	set aURL to current application's |NSURL|'s fileURLWithPath:POSIXPath
	set theOptions to (current application's NSDirectoryEnumerationSkipsPackageDescendants as integer) + (current application's NSDirectoryEnumerationSkipsHiddenFiles as integer)
	set theEnumerator to fileManager's enumeratorAtURL:aURL includingPropertiesForKeys:{} options:theOptions errorHandler:(missing value)
	set theFiles to theEnumerator's allObjects()
	set theFiles to theFiles's filteredArrayUsingPredicate:(current application's NSPredicate's predicateWithFormat:"(lastPathComponent ENDSWITH '.mp3') OR (lastPathComponent ENDSWITH '.aiff')")
	return theFiles as list # if we work upon files
	--return (theFiles's valueForKey:"path") as list # if we work upon POSIX paths
end listFolder:


-- Creates a new folder. There is no error if the folder already exists, and it will also create intermediate folders if required
on createFolder:POSIXPath
	set |⌘| to current application
	set theFolderURL to |⌘|'s |NSURL|'s fileURLWithPath:POSIXPath
	set theFileManager to |⌘|'s NSFileManager's defaultManager()
	set {theResult, theError} to theFileManager's createDirectoryAtURL:theFolderURL withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
	if not (theResult as boolean) then error (theError's |localizedDescription|() as text)
end createFolder:

set theFolder to choose folder with prompt "Please select a folder containing MP3/AIFF files" # ADDED

set theFiles to its listFolder:(POSIX path of theFolder) # ADDED

repeat with aFile in theFiles
	my treatThisFile(aFile)
end repeat

on treatThisFile(theFile)
	set posixFilePath to the quoted form of (POSIX path of theFile)
	
	set genreTag to (do shell script "mdls " & posixFilePath & " -name kMDItemMusicalGenre")
	set artistTag to (do shell script "mdls " & posixFilePath & " -name kMDItemAuthors")
	set tempoTag to (do shell script "mdls " & posixFilePath & " -name kMDItemTempo")
	set keyTag to (do shell script "mdls " & posixFilePath & " -name kMDItemKeySignature")
	set titleTag to (do shell script "mdls " & posixFilePath & " -name kMDItemTitle")
	
	set theGenre to text ((offset of "= " in genreTag) + 3) through -2 of genreTag
	set theArtist to text ((offset of "= " in artistTag) + 9) through -4 of artistTag
	set theTempo to text ((offset of "= " in tempoTag) + 2) through -1 of tempoTag
	set theKey to text ((offset of "= " in keyTag) + 3) through -2 of keyTag
	set theTitle to text ((offset of "= " in titleTag) + 3) through -2 of titleTag
	
	#SOME MP3 TAGS ARE NOT PROPERLY FILLED OUT- THIS BELOW PART DOESNT WORK AS SCRIPT PROCEEDS??????. # problem solved below
	if (count theGenre) ≤ (count "(null)") and theGenre contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Genre)"
	if (count theArtist) ≤ (count "(null)") and theArtist contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Artist)"
	if (count theTempo) ≤ (count "(null)") and theTempo contains "null" then display dialog "Error: " & (theFile as text) & " has a blank field - Please Fix (no Tempo)"
	if (count theKey) ≤ (count "(null)") and theKey contains "null" then display dialog "Error: " & theTitle & " has a blank field - Please Fix (no Key)" 
	
	# For some files, theTitle is returned as "null" or "(null)" so it may generate duplicates # Edited
	# I choose to use the original name deprieved of the extension
	
	if (count theTitle) ≤ (count "(null)") and theTitle contains "null" then # EDITED
		tell application "System Events" # ADDED
			set theTitle to text 1 thru -5 of (get name of file (theFile as text))
		end tell
	end if
	
	set renamedTitle to ("{" & theTempo & "-" & theKey & "}  " & theTitle)
	
	set DestFolder to ("/Volumes/Production/test/" & theGenre & "/" & theArtist)
	--set DestFolder to ("/Volumes/Macintosh HD/Users/Important/Test/" & theGenre & "/" & theArtist)
	
	my createFolder:DestFolder
	
	set DestFolder to POSIX file DestFolder
	
	set theFile to (theFile as text) as alias # ADDED. Finder refuse to get extension or rename the object returned by the ASObjC handler
	tell application "Finder"
		set theExtension to name extension of theFile
		set name of theFile to renamedTitle & "." & theExtension #AS MAYBE AIFF OR MP3
		try
			move theFile to DestFolder
		on error errMsg
			display dialog renamedTitle & errMsg # IF ALREADY EXISTS WILL PROMPT
		end try
		
	end tell
	
end treatThisFile

Go to messages #53 &54

Yvan KOENIG running Sierra 10.12.4 in French (VALLAURIS, France) mercredi 19 avril 2017 16:24:34

how do you get the long script to handle folders?


error "Can't get alias \"Untitled:_Production Drive backup 13/3/17:iTunes Media Folder:\"." number -1728 from alias "Untitled:_Production Drive backup 13/3/17:iTunes Media Folder:"


(*
rename & move mp3 ASObjC - 2

Written for http://macscripter.net/viewtopic.php?id=45629

by Nigel GARVEY, Shane STANLEY & Yvan KOENIG

2017/04/15

Tested under 10.12.4 public version
# Edited on 2017/04/18 : report the list of files which weren't moved
# Edited on 2017/04/19 : at Nigel GARVEY's request, removed some instructions


CAUTION. THE SCRIPT IS SUPPOSED TO RENAME AND MOVE SOME FILES.
IF YOU ARE NOT SURE OF WHAT IT DOES, EDIT THE PROPERTY NAMED testIt SETTING IT THE VALUE : true
*)



use AppleScript version "2.4" # requires at least Yosemite
use scripting additions
use framework "Foundation"

property copyString : " #" -- added to file names for copies; edit to suit your language

property destinationRootPath : "/Volumes/Production/test/" # I assume that it's the one you need


property testIt : false
#################### true = log some metadatas and DON'T MOVE the files
#################### false = don't log these metadatas and MOVE the files

on run -- For when testing.
	set theFiles to choose folder with prompt "Please select folder"
	mainBusiness(theFiles)
end run

on adding folder items to thisFolder after receiving addedItems -- For when run as a folder action.
	mainBusiness(addedItems)
end adding folder items to

on mainBusiness(theFiles)
	-- Get the root path in a convenient form for use with ASObjC.
	local destinationRootPath, |⌘|
	
	# Instructions useful to get a script running flawlessly on my machine!
	set run4YK to (path to home folder as text) starts with "SSD 500"
	if run4YK then
		set my destinationRootPath to "/Volumes/Production/test3"
		set my testIt to true
	end if
	
	set |⌘| to current application
	set newArray to |⌘|'s NSMutableArray's arrayWithArray:{}
	set destinationRootPath to |⌘|'s class "NSString"'s stringWithString:(my destinationRootPath)
	repeat with thisFile in theFiles
		set thePath to POSIX path of thisFile
		set thePath to (|⌘|'s NSString's stringWithString:thePath)
		set theExtension to thePath's pathExtension()
		set theName to thePath's lastPathComponent()
		set theContainer to thePath's stringByDeletingLastPathComponent()
		set thePred to |⌘|'s NSPredicate's predicateWithFormat_("kMDItemFSName == %@", theName)
		-- build and start query
		set theQuery to |⌘|'s NSMetadataQuery's new()
		(theQuery's setPredicate:thePred)
		(theQuery's setSearchScopes:{theContainer})
		theQuery's startQuery()
		-- loop until it's stopped gathering
		repeat while theQuery's isGathering() as boolean
			delay 0.1
		end repeat
		-- stop and get the first NSMetadataItem (there can only be one in this case)
		theQuery's stopQuery()
		set metaItem to (theQuery's resultAtIndex:0)
		
		-- get the required attribute values, or default alternatives where the attributes weren't found.
		-- Firstly the artist ("authors") and genre values.
		set theArtist to (metaItem's valueForAttribute:(|⌘|'s NSMetadataItemAuthorsKey))
		set moveItArtist to (theArtist is not missing value)
		if (theArtist is missing value) then
			set theArtist to "(no artist)"
		else
			set theArtist to (theArtist's componentsJoinedByString:(","))
			set theArtist to my decodeText(theArtist)
		end if
		
		set theGenre to (metaItem's valueForAttribute:(|⌘|'s NSMetadataItemMusicalGenreKey))
		set moveItGenre to (theGenre is not missing value) # MOVED
		if (theGenre is missing value) then set theGenre to "(no genre)"
		
		-- Get the key, tempo, and title values.
		set theKey to (metaItem's valueForAttribute:(|⌘|'s NSMetadataItemKeySignatureKey))
		set moveItKey to (theKey is not missing value) # MOVED
		if (theKey is missing value) then set theKey to "(no key signature)"
		
		set theTempo to (metaItem's valueForAttribute:(|⌘|'s NSMetadataItemTempoKey))
		set moveItTempo to (theTempo is not missing value)
		
		
		# Instructions useful to get a script running flawlessly on my machine!
		if run4YK then
			# Here theKey metadata is NEVER defined so this instruction forbid every move.
			--set moveForbidden to (moveItArtist is false) or (moveItGenre is false) or (moveItKey is false)
			# With this one move is often allowed
			set moveForbidden to (moveItArtist is false) or (moveItGenre is false)
		else
			# The test below matches what you asked in the thread
			# If one of the four flags is false we don't move the file.
			set moveForbidden to (moveItArtist is false) or (moveItGenre is false) or (moveItKey is false) or (moveItTempo is false)
		end if
		
		if moveForbidden then
			log "Don't move : " & thePath & linefeed & "because at least one of these flags is false --> moveItArtist = " & moveItArtist & ", moveItGenre = " & moveItGenre & ", moveItKey = " & moveItKey & ", moveItTempo = " & moveItTempo # don't move the file
			(newArray's addObject:thePath)
		else
			-- Derive a path to the destination folder from the root path, genre, and artist.
			set destinationFolderPath to destinationRootPath's stringByAppendingFormat_("%@/%@", theGenre, theArtist)
			-- Create the folder, if necessary.
			
			my createFolder(destinationFolderPath) -- as text)
			
			set theTitle to (metaItem's valueForAttribute:(|⌘|'s NSMetadataItemTitleKey))
			if (theTitle is missing value) then
				--set theTitle to "(no title)"
				-- Derive a destination path for the file with a new name made up from these details.
				# but replace theTtle by the original fileName
				set destinationFileName to (|⌘|'s NSString's stringWithFormat_("%@-%@ %@", theTempo, theKey, theName))
			else
				# CAUTION, if the original title contained underscores they are replaced by slashes in theTitle.
				# We must revert that
				set theTitle to (theTitle's stringByReplacingOccurrencesOfString:"/" withString:"_")
				-- Derive a destination path for the file with a new name made up from these details.
				set destinationFileName to (|⌘|'s NSString's stringWithFormat_("%@-%@ %@.%@", theTempo, theKey, theTitle, theExtension))
			end if
			
			if not testIt then
				# Move the file to the new destination. It'll be renamed in the process.
				# DISABLED DURING TESTS
				(my moveThisFile:thePath uniquelyToPath:destinationFolderPath newName:destinationFileName)
			else
				log (get destinationFolderPath as text) & ",  " & destinationFileName
				log "theArtist (Authors) : " & theArtist
				log "theTitle : " & theTitle
				log "theGenre : " & theGenre
				if theKey is not missing value then log "theKey : " & theKey
			end if # not testIt
		end if # (moveItTitle .
	end repeat
	
	if (newArray's |count|()) as integer > 0 then
		set outDoc to (newArray's componentsJoinedByString:linefeed)
		set outPath to (path to desktop as text) & "report Mp3_3pMtroper.txt"
		set outPath to (|⌘|'s NSString's stringWithString:(POSIX path of outPath))
		set theResult to outDoc's writeToFile:outPath atomically:true encoding:(current application's NSUTF8StringEncoding) |error|:(missing value)
	end if
end mainBusiness

#=====

-- Creates a new folder. There is no error if the folder already exists, and it will also create intermediate folders if required
on createFolder(POSIXPath)
	log "PosixPath : " & POSIXPath
	set |⌘| to current application
	set theFolderURL to |⌘|'s |NSURL|'s fileURLWithPath:POSIXPath
	set theFileManager to |⌘|'s NSFileManager's defaultManager()
	set {theResult, theError} to theFileManager's createDirectoryAtURL:theFolderURL withIntermediateDirectories:true attributes:(missing value) |error|:(reference)
	if not (theResult as boolean) then error (theError's |localizedDescription|() as text)
end createFolder

# Called with sourceString defined as NSString
on replaceSeveralStrings:sourceString existingStrings:listOfExistingStrings newStrings:listOfNewStrings
	if (count listOfExistingStrings) > (count listOfNewStrings) then error "The first list of strings is longer than the second one !" number 1789
	--set sourceString to current application's NSString's stringWithString:sourceString
	repeat with i from 1 to count listOfExistingStrings
		set sourceString to (sourceString's stringByReplacingOccurrencesOfString:(listOfExistingStrings's item i) withString:(listOfNewStrings's item i))
	end repeat
	return sourceString as text
end replaceSeveralStrings:existingStrings:newStrings:

# Called with sourceString defined as NSString
on decodeText(theText) # Handler written by Nigel GARVEY
	set |⌘| to current application
	
	--set theText to |⌘|'s class "NSString"'s stringWithString:(theText)
	-- If the string contains at least two consecutive 8+bit characters, assume it's a mangled result.
	if ((theText's rangeOfString:("[\\u0080-\\U0010ffff]{2}") options:(|⌘|'s NSRegularExpressionSearch))'s |length|() > 0) then
		set dataObj to (theText's dataUsingEncoding:(|⌘|'s NSISOLatin1StringEncoding))
		set theText to (|⌘|'s class "NSString"'s alloc()'s initWithData:(dataObj) encoding:(|⌘|'s NSUTF8StringEncoding))
	end if
	return theText as text
end decodeText

# Modified version of a Shane STANLEY's handler borrowed from File Manager.scptd
on moveThisFile:aFileOrPath uniquelyToPath:folderOrPath newName:destName
	# makes a NSURL from aFileOrPath
	set theSourceURL to my makeURLFromFileOrPath:aFileOrPath
	# makes a NSURL from folderOrPath
	set theFolderURL to my makeURLFromFileOrPath:folderOrPath
	# Drops the name extension from the proposed name
	set destNameLessExt to destName's |stringByDeletingPathExtension|()
	set theExtension to theSourceURL's |pathExtension|()
	# Builds the URL pointing to the final file
	set theDestURL to theFolderURL's URLByAppendingPathComponent:destName
	set theFileManager to current application's NSFileManager's |defaultManager|()
	set i to 2
	repeat
		set {theResult, theError} to (theFileManager's moveItemAtURL:theSourceURL toURL:theDestURL |error|:(reference))
		if theResult as boolean then exit repeat
		if (theError's code() as integer = current application's NSFileWriteFileExistsError as integer) then -- it already exists, so change name
			set proposedName to (destNameLessExt's stringByAppendingString:(copyString & i))'s stringByAppendingPathExtension:theExtension
			set theDestURL to theFolderURL's URLByAppendingPathComponent:proposedName
			set i to i + 1
		else -- an error other than file already exists, so return error
			error (theError's |localizedDescription|() as text)
		end if
	end repeat
	-- return theDestURL's |path|() as text
end moveThisFile:uniquelyToPath:newName:

# Shane STANLEY's handler borrowed from File Manager.scptd
-- This handler is called by moveItem
on makeURLFromFileOrPath:theFileOrPathInput
	set |⌘| to current application
	-- make it into a Cocoa object for easier comparison
	set theFileOrPath to item 1 of (|⌘|'s NSArray's arrayWithObject:theFileOrPathInput)
	if (theFileOrPath's isKindOfClass:(|⌘|'s NSString)) as boolean then
		if (theFileOrPath's hasPrefix:"/") as boolean then -- full POSIX path
			return |⌘|'s class "NSURL"'s fileURLWithPath:theFileOrPath
		else if (theFileOrPath's hasPrefix:"~") as boolean then -- POSIX path needing ~ expansion
			return |⌘|'s class "NSURL"'s fileURLWithPath:(theFileOrPath's |stringByExpandingTildeInPath|())
		else -- must be HFS path
			return |⌘|'s class "NSURL"'s fileURLWithPath:(POSIX path of theFileOrPathInput)
		end if
	else if (theFileOrPath's isKindOfClass:(|⌘|'s class "NSURL")) as boolean then -- happens with files and aliases in 10.11
		return theFileOrPath
	else -- must be a file or alias
		return |⌘|'s class "NSURL"'s fileURLWithPath:(POSIX path of theFileOrPathInput)
	end if
end makeURLFromFileOrPath: