Add catalog numbers with alternate versions

I’m working on adding catalog numbers to a large number of files for a music library. Some songs only have one version, but others have alternate versions. Here’s an example:

Song1-Main.wav
Song2-Main.wav
Song2-Alt1.wav
Song2-Alt2.wav
Song3-Main.wav
Song3-Piano_Only.wav
Song4-Main.wav

The catalog ID protocol in place includes a code for the composer, a 4-digit number, then “a”. If there are alternate versions, “a” is changed to “b”, “c” etc.

Final naming for the above files would be as follows:
AM0001a-Song1-Main.wav
AM0002a-Song2-Main.wav
AM0002b-Song2-Alt1.wav
AM0002c-Song2-Alt2.wav
AM0003a-Song3-Main.wav
AM0003b-Song3-Piano_Only.wav
AM0004a-Song4-Main.wav

The important thing is that the numeric part of the code is the same for all versions of a song. Only the letter at the end of the catalog ID changes

I’ve written a re-naming script that will take care of everything except the a,b,c versioning. I’m hoping someone can help me with some code that will look at the text before the dash in the original file name (e.g. “Song1”), identify whether it’s a unique name or whether there are alternates, then add the new catalog number to the files.

Here’s where I’m at thus far. This would be perfect if there were no alternate versions!

on open theDroppedItems
	
	set all_files to every item of theDroppedItems as list
	tell application "Finder"
		display dialog "Composer code:" default answer "e.g. AM"
		set composer_code to text returned of result
		
		--I'm adding to an existing list, so the following lets me set a starting number for my new files.
		display dialog "Enter the numeric value of the last existing song ID for this composer." default answer "e.g. If the track ID was AM0026a, enter 26"
		set PrevID to text returned of result as number
		repeat with index from 1 to the count of all_files
			set this_file to item index of all_files
			set index to index as number
			set one to PrevID
			set two to index
			set answer to one + two
			if answer is less than 10 then
				set index_prefix to "000"
			else
				if answer is less than 100 then
					set index_prefix to "00"
				else
					if answer is less than 1000 then
						set index_prefix to "0"
					else
						set index_prefix to ""
					end if
				end if
			end if
			
			set the name of this_file to composer_code & index_prefix & answer & "a" & "-" & itemName as string
		end repeat
		
		display alert "All done! Renamed " & index & "files with " & composer_code & " ID number."
	end tell
end open

Any help is appreciated!!!

I extracted the useful infos to build a script which I may test.
Doing that I got :



set all_files to paragraphs of "Song1-Main.wav
Song2-Main.wav
Song2-Alt1.wav
Song2-Alt2.wav
Song3-Main.wav
Song3-Piano_Only.wav
Song4-Main.wav"

--display dialog "Composer code:" default PrevID "e.g. AM"
--set composer_code to text returned of result
set composer_code to "AM"
--I'm adding to an existing list, so the following lets me set a starting number for my new files.
--display dialog "Enter the numeric value of the last existing song ID for this composer." default PrevID "e.g. If the track ID was AM0026a, enter 26"
--set PrevID to text returned of result as number
set PrevID to 26
set oldBare to ""

repeat with indx from 1 to count all_files
	set this_file to item indx of all_files
	# set itemName to name of this_file # missed in your code
	copy this_file to itemName # because here I pass only a list of names
	set bareName to item 1 of my decoupe(itemName, "-")
	if bareName ≠ oldBare then
		set letterID to 96
		copy bareName to oldBare
		set PrevID to PrevID + 1
	end if
	if PrevID is less than 1000 then
		set kode to text -4 thru -1 of ("00000" & PrevID)
	else
		set kode to ""
	end if
	set letterID to letterID + 1
	log composer_code & kode & character id letterID & "-" & itemName # as composer_code is a string there is no need for "as string"
	--set the name of this_file to composer_code & index_prefix & PrevID & "a" & "-" & itemName as string
end repeat

display alert "All done! Renamed " & indx & " files with " & composer_code & " ID number."

#=====

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

I renamed the variable which you named index because this is a reserved word used by the language. I replaced it by indx.

According to that, the usable script would be:

on open theDroppedItems
	
	set all_files to every item of theDroppedItems as list
	tell application "Finder"
		display dialog "Composer code:" default answer "e.g. AM"
		set composer_code to text returned of result
		--I'm adding to an existing list, so the following lets me set a starting number for my new files.
		display dialog "Enter the numeric value of the last existing song ID for this composer." default answer "e.g. If the track ID was AM0026a, enter 26"
		set PrevID to text returned of result as number
		
		set oldBare to ""
		repeat with indx from 1 to count all_files
			set this_file to item indx of all_files
			set itemName to name of this_file # missed in your code
			set bareName to item 1 of my decoupe(itemName, "-")
			if bareName ≠ oldBare then
				set letterID to 96
				copy bareName to oldBare
				set PrevID to PrevID + 1
			end if
			if PrevID is less than 1000 then
				set kode to text -4 thru -1 of ("00000" & PrevID)
			else
				set kode to ""
			end if
			set letterID to letterID + 1
			set the name of this_file to composer_code & kode & character id letterID & "-" & itemName # as composer_code is a string there is no need for "as string"
		end repeat
		
		display alert "All done! Renamed " & indx & " files with " & composer_code & " ID number."
		
	end tell
end open

#=====

on decoupe(t, d)
	local oTIDs, l
	set {oTIDs, AppleScript's text item delimiters} to {AppleScript's text item delimiters, d}
	set l to text items of t
	set AppleScript's text item delimiters to oTIDs
	return l
end decoupe

#=====

Yvan KOENIG running High Sierra 10.13.6 in French (VALLAURIS, France) mardi 27 aout 2019 18:05:54

The main problem of the droplet is:

Sorting the items by Song is easy but how do you extend the sorting that -Main is the first item of a new song

Here’s an effort which works as far as I understand the problem. To ensure that the files are in the right order for renaming, it requires one of my customisable sorts — say this one, which (if you decide to use it) should be compiled and saved as ~/Library/Script Libraries/Custom Iterative Ternary Merge Sort.scpt before attempting to compile the script below.

use sorter : script "Custom Iterative Ternary Merge Sort" -- Requires one of my customisable sorts, say this one: <https://macscripter.net/viewtopic.php?pid=194430#p194430>.
use scripting additions

on open theDroppedItems
	-- tell application "Finder" to set theDroppedItems to files of (choose folder) as alias list -- For testing in Script Editor.
	
	set all_files to every item of theDroppedItems as list
	tell application "Finder"
		display dialog "Composer code:" default answer "e.g. AM"
		set composer_code to text returned of result
		
		--I'm adding to an existing list, so the following lets me set a starting number for my new files.
		display dialog "Enter the numeric value of the last existing song ID for this composer." default answer "e.g. If the track ID was AM0026a, enter 26"
		set PrevID to text returned of result as number
		
		-- Build a list of the items' current names.
		set nameList to {}
		repeat with thisItem in theDroppedItems
			set end of nameList to thisItem's name
		end repeat
	end tell
	
	-- A sort customiser to sort texts in generally ascending order, but with texts ending with "Main.wav" coming before similar texts with other endings.
	script catalogueOrder
		property primaryEnding : "Main.wav"
		
		on isGreater(a, b)
			if (text 1 thru text item -2 of a = text 1 thru text item -2 of b) then
				return ((b ends with primaryEnding) or ((a does not end with primaryEnding) and (a > b)))
			else
				return (a > b)
			end if
		end isGreater
	end script
	
	-- Sort the name list in the required manner and the dropped-item list in parallel with it.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "-"
	tell sorter to sort(nameList, 1, -1, {comparer:catalogueOrder, slave:{theDroppedItems}})
	
	-- Doctor the sorted names as required and apply them to the corresponding files.
	set currentSongTitle to text 1 thru text item -2 of beginning of nameList
	set currentSongIndex to PrevID + 1
	set suffixLetters to "abcdefghijklmnopqrstuvwxyz"
	set c to 0
	repeat with i from 1 to (count nameList)
		set thisName to item i of nameList
		set thisSongTitle to text 1 thru text item -2 of thisName
		if (thisSongTitle = currentSongTitle) then
			-- Same as the preceding song. Use the same index number, but the next suffix letter.
			set c to c + 1
		else
			-- Different song. Increment the index number and go back to the first suffix letter.
			set currentSongIndex to currentSongIndex + 1
			set c to 1
			set currentSongTitle to thisSongTitle
		end if
		-- Construct the new name.
		set newName to composer_code & (text 2 thru -1 of ((10000 + currentSongIndex) as text)) & (character c of suffixLetters) & "-" & thisName
		-- Apply it to the corresponding file. (The dropped-item list was sorted in parallel with the name list, so the indices still correspond.)
		tell application "Finder" to set name of item i of theDroppedItems to newName
	end repeat
	set AppleScript's text item delimiters to astid
	
end open

Or here’s an alternative version which does some massaging of the data to allow the sort to be done with ASObjC. No external script required, but your system must be El Capitan or later:

use AppleScript version "2.5" -- El Capitan (10.11) or later
use framework "Foundation"
use scripting additions

on open theDroppedItems
	-- tell application "Finder" to set theDroppedItems to files of (choose folder) as alias list -- For testing in Script Debugger.
	
	tell application "Finder"
		display dialog "Composer code:" default answer "e.g. AM"
		set composer_code to text returned of result
		
		--I'm adding to an existing list, so the following lets me set a starting number for my new files.
		display dialog "Enter the numeric value of the last existing song ID for this composer." default answer "e.g. If the track ID was AM0026a, enter 26"
		set PrevID to text returned of result as number
	end tell
	
	(* ASObjC section. *)
	-- Get the dropped items and their names as ObjC objects.
	set theDroppedItems to current application's class "NSArray"'s arrayWithArray:(theDroppedItems)
	set theNames to theDroppedItems's valueForKey:("lastPathComponent")
	-- Insert an extra dash before "-Main.wav" in any names which end with this. The doctored names will have a lower sorting value than similar names ending with a single dash and something else.
	set theNames to theNames's componentsJoinedByString:(linefeed)
	set theNames to theNames's stringByReplacingOccurrencesOfString:("(?m)-Main\\.wav$") withString:("--Main.wav") options:(current application's NSRegularExpressionSearch) range:({0, theNames's |length|()})
	set theNames to theNames's componentsSeparatedByString:(linefeed)
	
	-- Build an array of dictionaries, each containing a (possibly doctored) name and the URL from which it was derived.
	set sortingArray to current application's class "NSMutableArray"'s new()
	repeat with i from 1 to (count theNames)
		set nameURLPair to (current application's class "NSDictionary"'s dictionaryWithObjects:({item i of theNames, item i of theDroppedItems}) forKeys:({"name", "URL"}))
		tell sortingArray to addObject:(nameURLPair)
	end repeat
	-- Sort the array on the dictionaries' "name" keys.
	set sortDescriptor to current application's class "NSSortDescriptor"'s sortDescriptorWithKey:("name") ascending:(true) selector:("localizedStandardCompare:")
	tell sortingArray to sortUsingDescriptors:({sortDescriptor})
	
	-- Extract the names from the now-sorted dictionaries and restore the doctored "-Main.wav" ones to their original forms.
	set theNames to sortingArray's valueForKey:("name")
	set theNames to theNames's componentsJoinedByString:(linefeed)
	set theNames to theNames's stringByReplacingOccurrencesOfString:("(?m)--Main\\.wav$") withString:("-Main.wav") options:(current application's NSRegularExpressionSearch) range:({0, theNames's |length|()})
	set nameList to (theNames's componentsSeparatedByString:(linefeed)) as list
	-- Extract the URLs from the sorted dictionaries as a list of file specifiers.
	set theDroppedItems to (sortingArray's valueForKey:("URL")) as list
	(* *)
	
	-- Modify the sorted names as required and apply them to the corresponding files.
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to "-"
	set currentSongTitle to text 1 thru text item -2 of beginning of nameList
	set currentSongIndex to PrevID + 1
	set suffixLetters to "abcdefghijklmnopqrstuvwxyz"
	set c to 0
	repeat with i from 1 to (count nameList)
		set thisName to item i of nameList
		set thisSongTitle to text 1 thru text item -2 of thisName
		if (thisSongTitle = currentSongTitle) then
			-- Same as the preceding song. Use the same index number, but the next suffix letter.
			set c to c + 1
		else
			-- Different song. Increment the index number and go back to the first suffix letter.
			set currentSongIndex to currentSongIndex + 1
			set c to 1
			set currentSongTitle to thisSongTitle
		end if
		-- Construct the new name.
		set newName to composer_code & (text 2 thru -1 of ((10000 + currentSongIndex) as text)) & (character c of suffixLetters) & "-" & thisName
		-- Apply it to the corresponding file.
		tell application "Finder" to set name of (item i of theDroppedItems as alias) to newName
	end repeat
	set AppleScript's text item delimiters to astid
	
end open

Thanks so much for your help Nigel! I was able to implement your second idea and it’s working brilliantly.