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.