Question about scripting for Finder App
Hi Geniuses
I'm trying to make a kind of complex finder script to help me collect approved mix and stem assets for delivery.
My mix and stem folders often have many versions in them, and I need to extract only the approved versions for each song, collect them in a master folder, and send that to the client.
Here's what i'm trying to do.
Soundflow asks: "Select the Destination for Approved Mixes" -- I then select a folder
Soundflow asks: "Select the first Song Folder" -- I then select the first songs folder in finder
Soundflow asks: "What mix version is approved -- I then type in a number value (ex: 1.6)
Soundflow then: Goes to the folder inside the "selected" folder called MIXES and copies all the mixes that contain the number 1.6
Soundflow then: Pastes those files into the "Destination" folder
Soundflow then: Goes to the folder inside the "selected song" folder called STEMS and copies any folders within that contain the number 1.6
Soundflow asks: "Continue" or "Finished"
If "Continue", it repeats process from step 2, allowing me to copy another Songs mixes and stems.
If "Finished", zip the "Destination" folder
Is the above process possible with soundflow??
- Kitch Membery @Kitch2024-04-09 00:03:59.994Z
I hope all is well with you!
And... yes, this can be done. Try the following script out! :-)
function moveApprovedMixes(destinationFolder) { // Get the song Folder const songFolder = sf.interaction.selectFolder({ prompt: "Choose the First Song Folder", }).path; // Establish a path to the "MIXES" folder const firstSongMixesFolder = songFolder + "/STEMS/"; // Prompt for the Approved Mix Version. const mixVersionNumber = sf.interaction.displayDialog({ buttons: ["Ok", "Cancel"], cancelButton: "Cancel", prompt: "What mix version is approved", defaultAnswer: "", defaultButton: "Ok", onCancel: "Abort", }).text; // Filter the MIXES folder paths by the approved mix version number const approvedMixPaths = sf.file.directoryGetFiles({ path: firstSongMixesFolder }).paths.filter(path => path.includes(mixVersionNumber)); // Copy approved mixes to the Destination Folder approvedMixPaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${destinationFolder}/${fileName}`; // Copy File to desination if the file does not exist their already. if (!sf.file.exists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); // Ask if you'd like to Continue or if you are Finished const doZipFolder = sf.interaction.displayDialog({ buttons: ["Continue", "Finished"], defaultButton: "Continue", prompt: `To move more files press "Continue", or press "Finished" to zip the Destination Folder`, onCancel: "Abort", }).button; if (doZipFolder === "Continue") { // Move more files moveApprovedMixes(destinationFolder); } } function zipDirectory(destinationFolder) { // Zip the files with logged progress sf.file.zipDirectory({ sourcePath: destinationFolder, archivePath: `~/Desktop/Approved MIXES.zip`, onProgress: progressMessage => { let percentageComplete = (progressMessage['progress'] * 100).toFixed(0); log(`Processing: ${percentageComplete} %`); }, progressIntervalMs: 500 }); // Done log("Your approved mixes have been zipped"); } function main() { // Get the Destination Folder const destinationFolder = sf.interaction.selectFolder({ prompt: "Choose Destination Folder", }).path; // Move Mixes moveApprovedMixes(destinationFolder) // Zip Destination Folder zipDirectory(destinationFolder); } main();
I hope that helps. :-)
- PPhilip weinrobe @Philip_weinrobe
ok holy moly this is incredible.
it is SO CLOSE to perfect, and the issues were with my description of the functions.so your script as written grabs individual files perfectly...just did it for a whole record!
and to do that i had to modify the location to be "_MIXES"// Establish a path to the "MIXES" folder const firstSongMixesFolder = songFolder + "/_MIXES/";
however, i need the script, in addition to grabbing the mixes, to grab the Stem Folders.
to do this, the script can go to the same root folder that contained the _MIXES sub folder, and there it will find an _STEMS sub folder.
In that sub folder are more folders, and I would love for the script to get any folders with the same user-entered version number.
I just tested it and it seems the script as written will only get files, not folders. Possible to just add this piece in?
does that make sense? probably does since you were able to figure everything else out you genius you kitch!THANK YOU SO MUCH!
philip- PPhilip weinrobe @Philip_weinrobe
oh, and one other small tweak:
could the location of the archive (zip) be in the same root folder as the original destination folder? so it would essentially just land right next to the original destination folder in finder. and could naming convention be the name of the folder that the destination folder resides in?
For example:
Artist Folder: Philip Weinrobe
Destination Folder: Philip Weinrobe/_MIX DELIVERY
Archive Name: _MIX DELIVERY_Philip Weinrobe.zip
Archive Location: Philip Weinrobe/ - In reply toPhilip_weinrobe⬆:
Kitch Membery @Kitch2024-04-11 22:10:27.541Z
Nice! I knew there was more to it... I said to myself "Phillip... where are the stems???!!!" :-)
To help with this can you take a screenshot of the session folder structure for a song? That include the Artist Folder, Destination Folder, _MIXES sub folder and _STEMS sub folder.
- PPhilip weinrobe @Philip_weinrobe
- PPhilip weinrobe @Philip_weinrobe
- P
Kitch Membery @Kitch2024-04-11 22:26:43.310Z
Perfect! Will take a look at it in the next couple of days. :-)
- PPhilip weinrobe @Philip_weinrobe
amazing thank you kitch!
Kitch Membery @Kitch2024-04-11 22:53:39.553Z
Is your folder structure always set up like this... If so I may be able to reduce the amount of mouse clicks involved.
If you were to select the song folders in the finder and then run the script I could make it ask for each song 'What is the approved mix number for "XX Song Name" from the selected folder paths'... the script could then find the "_MIX DELIVERY" folder without you needing for you to select it.
So the user steps would be
- Select all the song folders you'd like to collect mixes and stems from in the finder.
- Run the script
- Follow the prompts for each selected track and enter the approved mix numbers.
- Confirm if you'd like to Zip.
Happy to keep it the way it is though if that suits your flow. :-)
- PPhilip weinrobe @Philip_weinrobe
yes, always setup like this.
that is PERFECT. thank you for seeing me ;)Kitch Membery @Kitch2024-04-11 23:20:09.846Z
While you're waiting...
@Chad and I got to talking a while back about a Secret Sonics podcast you were on, where you were talking about listening to short bursts of audio, we thought the concept was interesting and so I sent him this script. I thought you may dig it.
const burstLengthInMilliseconds = 80; /** * Play a short burst of the Pro Tools timeline with burst length in milliseconds * @param{Object} obj * @param{Number} obj.burstLength */ function playMicroBurstInMilliseconds({ burstLength }) { const proTools = sf.ui.proTools; const mainWindow = proTools.mainWindow; mainWindow.invalidate(); const transportViewCluster = mainWindow.transportViewCluster; const transportButtons = transportViewCluster.transportButtons; const { playButton, stopButton } = transportButtons; // Ensure the Transport controls are visible proTools.transportEnsureCluster(); const isPlaying = proTools.invalidate().isPlaying; // If protools is playing, click stop button if (isPlaying) stopButton.elementClick(); // Click play button playButton.elementClick(); // Wait for burst length sf.wait({ intervalMs: burstLength }); // Click Stop button stopButton.elementClick(); } playMicroBurstInMilliseconds({ burstLength: burstLengthInMilliseconds, });
- PPhilip weinrobe @Philip_weinrobe
omg i love this so much
- PPhilip weinrobe @Philip_weinrobe
holy moly this is extremely useful. you ROCK
Kitch Membery @Kitch2024-04-11 23:29:05.641Z
Awesome!
- In reply toPhilip_weinrobe⬆:
Kitch Membery @Kitch2024-04-12 02:24:15.721Z
Hi @Philip_weinrobe,
Request for one more screenshot if I may. Of the content of the
"_MIX DELIVERY" folder content once all the files have been moved in there?- PPhilip weinrobe @Philip_weinrobe
Hi Kitch
Check this out. In a perfect world the script could also create this folder.All it would have to do is name the folder artistName_projectName_MIX DELIVERY
whereas projectName is the name of the folder with the songs in it
artist name is the name of the folder one up from projectNameThen inside the Mix Delivery folder is a folder for each of the songs
Inside each folder are the collected assets with the approved number
this make sense?
thanks for being so helpful!
PhilipKitch Membery @Kitch2024-04-12 09:10:41.052Z
Hi @Philip_weinrobe,
Ok... Here we go :-)
If the parent folder of the numbered track names is the "Project Name", that would require updating the script to work for both scenarios, which I don't have time for right now. But the following script will work if the parent folder to the numbered songs folders is the "Artist Name" as in your original screenshots.
const MIXES_FOLDER_NAME = "_MIXES"; const STEMS_FOLDER_NAME = "_STEMS"; const MIXES_DELIVERY_FOLDER_NAME = "_MIX DELIVERY"; function promptForApprovedVersionNumber(songName) { return sf.interaction.displayDialog({ buttons: ["Ok", "Cancel"], cancelButton: "Cancel", prompt: `What mix version is approved for the following track...\n\n${songName}`, defaultAnswer: "", defaultButton: "Ok", onCancel: "Abort", }).text; } function zipDirectoryWithProgress({ sourcePath, archivePath }) { sf.file.zipDirectory({ sourcePath, archivePath, onProgress: progressMessage => { let percentageComplete = (progressMessage['progress'] * 100).toFixed(0); log(`Processing: ${percentageComplete} %`); }, progressIntervalMs: 500 }); } function copyMixFiles({ mixesFolderPath, approvedVersionNumber, songDestinationFolder }) { // Filter the MIXES folder paths by the approved mix version number const approvedMixFilePaths = sf.file.directoryGetFiles({ path: mixesFolderPath }).paths .filter(path => path.includes(approvedVersionNumber)); approvedMixFilePaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${songDestinationFolder}/${fileName}`; // Copy File to destination if the file does not exist there already. if (!sf.file.exists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); } function copyStemDirectories({ stemsFolderPath, approvedVersionNumber, songDestinationFolder }) { // Filter the STEM Folder paths by the approved version number const approvedStemFolderPaths = sf.file.directoryGetDirectories({ path: stemsFolderPath }).paths .filter(path => path.includes(approvedVersionNumber)); approvedStemFolderPaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${songDestinationFolder}/${fileName}`; // Copy the song Stems Folder if the folder does not exist there already. if (!sf.file.directoryExists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); } function main() { // Get the selected folder paths from the finder and sort them const selectedFolderPaths = sf.ui.finder.selectedPaths.sort((a, b) => { const songNumberA = parseInt(a.match(/\/(\d{2}) /)[1], 10); const songNumberB = parseInt(b.match(/\/(\d{2}) /)[1], 10); return songNumberA - songNumberB; }); // Convert the first folder path into an array const folderPathArray = selectedFolderPaths[0].split("/").filter(Boolean); const artistName = folderPathArray.slice(-2, -1).join("/"); const rootDestinationFolderPath = `${folderPathArray.slice(0, -1).join("/")}`; selectedFolderPaths.forEach(sourcePath => { const mixesFolderPath = `${sourcePath}${MIXES_FOLDER_NAME}/`; const stemsFolderPath = `${sourcePath}${STEMS_FOLDER_NAME}/`; // Get the song name based on the song folder name removing the nummbers and spaces at the beginning of the name. const songName = sourcePath.split("/").filter(Boolean)[sourcePath.split("/").filter(Boolean).length - 1].replace(/^(\d+\s+)/, ''); // Ask for approved mix number const approvedVersionNumber = promptForApprovedVersionNumber(songName); // Create the "_MIX DELIVERY" directory if it does not exist sf.file.directoryCreate({ path: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}` }); // Make the song destination Folder path const songDestinationFolder = `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}/${songName}`; // Create song destination Folder sf.file.directoryCreate({ path: songDestinationFolder }); // Copy Mixes to "_MIX DELIVERY/SONG NAME/" copyMixFiles({ mixesFolderPath, approvedVersionNumber, songDestinationFolder }); // Copy Stem Folders to "_MIX DELIVERY/SONG NAME/" copyStemDirectories({ stemsFolderPath, approvedVersionNumber, songDestinationFolder }); }); // Ask to Zip? YES OR NO const doZipFolder = sf.interaction.displayDialog({ buttons: ["No", "Yes"], defaultButton: "Yes", prompt: `Would you like to zip the Destination Folder?`, onCancel: "Abort", }).button; if (doZipFolder === "Yes") { // Zip Destination Folder zipDirectoryWithProgress({ sourcePath: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}`, archivePath: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}_${artistName}.zip` }); sf.interaction.displayDialog({ prompt: `The Mixes and Stems for "${artistName}" have been Zipped!` }); } // Open and select the Zip file in the finder. sf.file.open({ path: rootDestinationFolderPath }); sf.ui.finder.appActivate(); } main();
The steps are as follows.
- Select all the numbered song folders you'd like to collect mixes and stems for in the frontmost finder window.
- Run the script.
- Follow the prompts for each selected track and enter the approved mix numbers.
- If the "_MIX DELIVERY" folder does not exist it will be created.
- Confirm if you'd like to Zip the "_MIX DELIVERY" folder.
- If yes the Zip progress will be logged.
- If yes the Zip file will be in the same folder as the numbered song folders.
- The finder will be activated.
Note: If any MIX files or STEMS Folders exist in the "_MIX DELIVERY" folder already, they won't be overwritten.
I hope that helps! :-)
- In reply toPhilip_weinrobe⬆:
Kitch Membery @Kitch2024-04-12 09:32:21.811Z
Here it is in action with dummy files and folders.
- PPhilip weinrobe @Philip_weinrobe
this is fantastic.
the only thing now is that it seems to prompt for each song, one at a time, only after moving the files.
it takes a while to move the files sometimes, so i am sitting and babysitting the script...and then at the end choosing the zip yes/no.is it possible to have it loop through and ask for all the approved version numbers and the .zip yes/no right at the top, then go ahead and execute those decisions?
is this possible?
thank you!
Kitch Membery @Kitch2024-04-15 17:26:03.937Z2024-04-15 18:22:39.302Z
Ah yes... Having to babysit defeats the purpose.
I've not had a chance to test this with large audio files but give this updated version a go. This one asks all the questions up front.
const MIXES_FOLDER_NAME = "_MIXES"; const STEMS_FOLDER_NAME = "_STEMS"; const MIXES_DELIVERY_FOLDER_NAME = "_MIX DELIVERY"; function promptForApprovedVersionNumber(songName) { return sf.interaction.displayDialog({ buttons: ["Ok", "Cancel"], cancelButton: "Cancel", prompt: `What mix version is approved for the following track...\n\n${songName}`, defaultAnswer: "", defaultButton: "Ok", onCancel: "Abort", }).text; } function zipDirectoryWithProgress({ sourcePath, archivePath }) { sf.file.zipDirectory({ sourcePath, archivePath, onProgress: progressMessage => { let percentageComplete = (progressMessage['progress'] * 100).toFixed(0); log(`Processing: ${percentageComplete} %`); }, progressIntervalMs: 500 }); } function copyFiles({ songName, mixesFolderPath, stemsFolderPath, approvedVersionNumber, songDestinationFolder }) { log(`Copying Mixes for ${songName}`); // Create song destination Folder sf.file.directoryCreate({ path: songDestinationFolder }); // Filter the MIXES folder paths by the approved mix version number const approvedMixFilePaths = sf.file.directoryGetFiles({ path: mixesFolderPath }).paths .filter(path => path.includes(approvedVersionNumber)); approvedMixFilePaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${songDestinationFolder}/${fileName}`; // Copy File to destination if the file does not exist there already. if (!sf.file.exists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); // Filter the STEM Folder paths by the approved version number const approvedStemFolderPaths = sf.file.directoryGetDirectories({ path: stemsFolderPath }).paths .filter(path => path.includes(approvedVersionNumber)); log(`Copying Stems for ${songName}`); approvedStemFolderPaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${songDestinationFolder}/${fileName}`; // Copy the song Stems Folder if the folder does not exist there already. if (!sf.file.directoryExists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); log(`Finished copying Mixes and Stems for ${songName}`); } function main() { // Get the selected folder paths from the finder and sort them const selectedFolderPaths = sf.ui.finder.selectedPaths.sort((a, b) => { const songNumberA = parseInt(a.match(/\/(\d{2}) /)[1], 10); const songNumberB = parseInt(b.match(/\/(\d{2}) /)[1], 10); return songNumberA - songNumberB; }); // Convert the first folder path into an array const folderPathArray = selectedFolderPaths[0].split("/").filter(Boolean); const artistName = folderPathArray.slice(-2, -1).join("/"); const rootDestinationFolderPath = `${folderPathArray.slice(0, -1).join("/")}`; const deliverablesToProcess = []; selectedFolderPaths.forEach(sourcePath => { const mixesFolderPath = `${sourcePath}${MIXES_FOLDER_NAME}/`; const stemsFolderPath = `${sourcePath}${STEMS_FOLDER_NAME}/`; // Get the song name based on the song folder name removing the numbers and spaces at the beginning of the name. const songName = sourcePath.split("/").filter(Boolean)[sourcePath.split("/").filter(Boolean).length - 1].replace(/^(\d+\s+)/, ''); // Ask for approved mix number const approvedVersionNumber = promptForApprovedVersionNumber(songName); // Make the song destination Folder path const songDestinationFolder = `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}/${songName}`; // Copy Mixes to "_MIX DELIVERY/SONG NAME/" deliverablesToProcess.push({ songName, mixesFolderPath, stemsFolderPath, approvedVersionNumber, songDestinationFolder }); }); // Ask to Zip? YES OR NO const doZipFolder = sf.interaction.displayDialog({ buttons: ["No", "Yes"], defaultButton: "Yes", prompt: `Would you like to zip the Destination Folder?`, onCancel: "Abort", }).button; // Create the "_MIX DELIVERY" directory if it does not exist sf.file.directoryCreate({ path: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}` }); // Copy All Mixes deliverablesToProcess.forEach(song => { copyFiles({ songName: song.songName, mixesFolderPath: song.mixesFolderPath, stemsFolderPath: song.stemsFolderPath, approvedVersionNumber: song.approvedVersionNumber, songDestinationFolder: song.songDestinationFolder }); }); if (doZipFolder === "Yes") { // Zip Destination Folder zipDirectoryWithProgress({ sourcePath: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}`, archivePath: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}_${artistName}.zip` }); // Display message to say the files have been zipped. sf.interaction.displayDialog({ prompt: `The Mixes and Stems for "${artistName}" have been Zipped!` }); } // Open and select the Zip file in the finder. sf.file.open({ path: rootDestinationFolderPath }); sf.ui.finder.appActivate(); } main();
Rock on!
- PPhilip weinrobe @Philip_weinrobe
hey kitch!
been living with this script and it is amazing.
two little tweaks would be incredible.1: the script currently fails if there is not an _STEMS folder. can we make it so the script keeps going if there is no _STEMS folder? Not every song gets stems...
2: Currently the script requires the song folder to start with a number. Can we remove that necessity?
Thank you!
Kitch Membery @Kitch2024-05-06 17:42:10.474Z
I have a busy week this week, but I'll see if I can make some time to implement these updates. :-)
Will keep you posted, legend!
- In reply toPhilip_weinrobe⬆:
Kitch Membery @Kitch2024-05-07 07:44:08.742Z
Try this version @Philip_weinrobe :-)
const MIXES_FOLDER_NAME = "_MIXES"; const STEMS_FOLDER_NAME = "_STEMS"; const MIXES_DELIVERY_FOLDER_NAME = "_MIX DELIVERY"; function promptForApprovedVersionNumber(songName) { return sf.interaction.displayDialog({ buttons: ["Ok", "Cancel"], cancelButton: "Cancel", prompt: `What mix version is approved for the following track...\n\n${songName}`, defaultAnswer: "", defaultButton: "Ok", onCancel: "Abort", }).text; } function zipDirectoryWithProgress({ sourcePath, archivePath }) { sf.file.zipDirectory({ sourcePath, archivePath, onProgress: progressMessage => { let percentageComplete = (progressMessage['progress'] * 100).toFixed(0); log(`Processing: ${percentageComplete} %`); }, progressIntervalMs: 500 }); } function copyFiles({ songName, mixesFolderPath, stemsFolderPath, approvedVersionNumber, songDestinationFolder }) { log(`Copying Mixes for ${songName}`); // Create song destination Folder sf.file.directoryCreate({ path: songDestinationFolder }); // Filter the MIXES folder paths by the approved mix version number const approvedMixFilePaths = sf.file.directoryGetFiles({ path: mixesFolderPath }).paths .filter(path => path.includes(approvedVersionNumber)); approvedMixFilePaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${songDestinationFolder}/${fileName}`; // Copy File to destination if the file does not exist there already. if (!sf.file.exists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); if (sf.file.directoryExists({ path: stemsFolderPath }).exists) { // Filter the STEM Folder paths by the approved version number const approvedStemFolderPaths = sf.file.directoryGetDirectories({ path: stemsFolderPath }).paths .filter(path => path.includes(approvedVersionNumber)); log(`Copying Stems for ${songName}`); approvedStemFolderPaths.forEach(sourcePath => { const fileName = sourcePath.split("/").slice(-1).join("/"); const destinationPath = `${songDestinationFolder}/${fileName}`; // Copy the song Stems Folder if the folder does not exist there already. if (!sf.file.directoryExists({ path: destinationPath }).exists) { sf.file.copy({ sourcePath, destinationPath }); } }); } log(`Finished copying Mixes and Stems for ${songName}`); } function main() { // Get the selected folder paths from the finder and sort them const selectedFolderPaths = sf.ui.finder.invalidate().selectedPaths; const folderNames = selectedFolderPaths.map(path => path.split("/").filter(Boolean).slice(-1)[0]) function allStartWithNumber(arr) { const regex = /^\d/; return arr.every((str) => regex.test(str)); } const foldersAreNumerical = allStartWithNumber(folderNames) // Sort all Folders by number if they are numbered if (foldersAreNumerical) { selectedFolderPaths.sort((a, b) => { const songNumberA = parseInt(a.match(/\/(\d{2}) /)[1], 10); const songNumberB = parseInt(b.match(/\/(\d{2}) /)[1], 10); return songNumberA - songNumberB; }); } // Convert the first folder path into an array const folderPathArray = selectedFolderPaths[0].split("/").filter(Boolean); const artistName = folderPathArray.slice(-2, -1).join("/"); const rootDestinationFolderPath = `${folderPathArray.slice(0, -1).join("/")}`; const deliverablesToProcess = []; selectedFolderPaths.forEach(sourcePath => { const mixesFolderPath = `${sourcePath}${MIXES_FOLDER_NAME}/`; const stemsFolderPath = `${sourcePath}${STEMS_FOLDER_NAME}/`; // Get the song name based on the song folder name removing the numbers and spaces at the beginning of the name. const songName = sourcePath.split("/").filter(Boolean)[sourcePath.split("/").filter(Boolean).length - 1].replace(/^(\d+\s+)/, ''); // Ask for approved mix number const approvedVersionNumber = promptForApprovedVersionNumber(songName); // Make the song destination Folder path const songDestinationFolder = `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}/${songName}`; // Copy Mixes to "_MIX DELIVERY/SONG NAME/" deliverablesToProcess.push({ songName, mixesFolderPath, stemsFolderPath, approvedVersionNumber, songDestinationFolder }); }); // Ask to Zip? YES OR NO const doZipFolder = sf.interaction.displayDialog({ buttons: ["No", "Yes"], defaultButton: "Yes", prompt: `Would you like to zip the Destination Folder?`, onCancel: "Abort", }).button; // Create the "_MIX DELIVERY" directory if it does not exist sf.file.directoryCreate({ path: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}` }); // Copy All Mixes deliverablesToProcess.forEach(song => { copyFiles({ songName: song.songName, mixesFolderPath: song.mixesFolderPath, stemsFolderPath: song.stemsFolderPath, approvedVersionNumber: song.approvedVersionNumber, songDestinationFolder: song.songDestinationFolder }); }); if (doZipFolder === "Yes") { // Zip Destination Folder zipDirectoryWithProgress({ sourcePath: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}`, archivePath: `${rootDestinationFolderPath}/${MIXES_DELIVERY_FOLDER_NAME}_${artistName}.zip` }); // Display message to say the files have been zipped. sf.interaction.displayDialog({ prompt: `The Mixes and Stems for "${artistName}" have been Zipped!` }); } // Open and select the Zip file in the finder. sf.file.open({ path: rootDestinationFolderPath }); sf.ui.finder.appActivate(); } main();
- PPhilip weinrobe @Philip_weinrobe
kitch, this is truly amazing. thank you.
a significant improvement to my life on an almost daily basis.
not subtle!Kitch Membery @Kitch2024-05-17 18:59:06.643Z
You're welcome, that's what SoundFlow's all about.
More time to focus on the fun stuff! :-)
Have a great weekend, when you get there!