Duplicate and Rename Playlist Script
Hi Geniuses
I am trying (and failing!) to modify some existing scripts to do what I know is easy...
Duplicate a playlist on a track(s) and then rename with a specific suffix.
I want to:
- Have a track selection (one or more)
- Duplicate playlist on those tracks (there will not be a new playlist dialog in this case because it's multiple tracks)
- Rename those tracks to be the "Original Track Name" + "Pre-Process"
- Go back to the original playlist on the original track selection (would be OK for this to be the top playlist)
- That's it!
This is my standard "manual" process for duplicating playlists before i bring audio into RX Connect (or other applications) for processing. Makes it easy to step back into the clean audio....
Any help?
Thank you!
Philip
- Chris Shaw @Chris_Shaw2024-09-07 19:09:20.936Z2024-09-10 21:53:05.465Z
Try this.
This script is assuming you are using PT 2024.3 or above as it uses the newest PT SDK.sf.ui.proTools.mainWindow.invalidate(); // Ensure groups are suspended var groupListPopup = sf.ui.proTools.groupsOpenListPopupMenu({}).popupMenu; groupListPopup.menuClickPopupMenu({ menuPath: ["Suspend All Groups"], targetValue: 'Enable', }); // Hack to close gropup popup menu sf.ui.proTools.appActivateMainWindow(); // Get selected tracks and ensure first track is visible const selectedTracks = sf.ui.proTools.trackGetSelectedTracks().trackHeaders; const originalSelectedTrackNames = sf.ui.proTools.selectedTrackNames; // Scroll selected tracks into view selectedTracks[0].trackScrollToView(); const playlistSelector = selectedTracks[0].popupButtons.whoseTitle.is("Playlist selector").first; const selectorItems = playlistSelector.popupMenuFetchAllItems({dismissMenu:true}).menuItems; const duplicateMenuPath = selectorItems.filter(i => i.path[0].startsWith("Duplicate"))[0].path // Duplicate playlists playlistSelector.popupMenuSelect({ menuPath: duplicateMenuPath, isShift: true, isOption: true, }) // Dismiss conf window if only one track was originally selected if (originalSelectedTrackNames.length == 1) { try{ let confWin = sf.ui.proTools.confirmationDialog confWin.elementWaitFor({ waitType: "Appear",timeout:500 }) sf.keyboard.press({ keys: "return" }) confWin.elementWaitFor({ waitType: "Disappear",timeout:500 }) }catch(err){} } // Invalidate now that we've got new track names / playlists sf.ui.proTools.mainWindow.invalidate(); // Pause to wait for invalidation to take effect sf.wait({ intervalMs: 500 }) // Get new selected track names let newSelectedTrackNames = sf.ui.proTools.selectedTrackNames // iterate through track names and rename them via PT SDK newSelectedTrackNames.forEach((n, index) => { sf.app.proTools.renameTrack({ oldName: n, newName: originalSelectedTrackNames[index] + " Pre-Process" }) }) // Get menu item name of original first selected track function getPlaylistMenuItem(playlistSelector, playlistName) { let menuItem = playlistSelector.popupMenuFetchAllItems({ dismissMenu: true }) .menuItems .filter((i) => i.path[0].startsWith(playlistName + " (") )[0].path[0]; return menuItem } let originalPlaylistMenuItem = getPlaylistMenuItem(playlistSelector, originalSelectedTrackNames[0]) // Switch to original playlists playlistSelector.popupMenuSelect({ menuPath: [originalPlaylistMenuItem], isShift: true, isOption: true, }) sf.ui.proTools.mainWindow.invalidate() // Pause to wait for invalidation to take effect sf.wait({ intervalMs: 500 }) // ====Ensure all playlists are set to original playlist=== // newSelectedTrackNames = sf.ui.proTools.selectedTrackNames; // Check if all tracks have switched by comparing new selected track names to orig track names let unswitchedTrackNames = {}; newSelectedTrackNames.forEach((name, index) => { if (originalSelectedTrackNames[index] !== name) { unswitchedTrackNames[name] = (originalSelectedTrackNames[index]) } }) let keys = Object.keys(unswitchedTrackNames) // If there are unswitched playlist names then select original playlists individually if (keys.length > 0) { keys.forEach(key => { let unswitchedTrack = sf.ui.proTools.trackGetByName({ name: key }).track; unswitchedTrack.trackScrollToView(); let playlistSelector = unswitchedTrack.popupButtons.whoseTitle.is("Playlist selector").first; let origPlaylistName = unswitchedTrackNames[key]; getPlaylistMenuItem(playlistSelector, origPlaylistName) // // Switch to original playlist playlistSelector.popupMenuSelect({ menuPath: [getPlaylistMenuItem(playlistSelector, origPlaylistName)], }) sf.ui.proTools.mainWindow.invalidate() sf.wait({ intervalMs: 250 }) }); // Re-select orignal selected tracks sf.app.proTools.selectTracksByName({ trackNames: originalSelectedTrackNames }) }
Chris Shaw @Chris_Shaw2024-09-07 19:22:06.063Z
I've re-edited this a few times - should be good now
Chris Shaw @Chris_Shaw2024-09-07 19:39:16.000Z
Oops!, one more edit to account for a single track selected
- PPhilip weinrobe @Philip_weinrobe
thank you, Chris! you are a legend!
will be back at the mixing desk monday morning and will give this a spin :)
- PIn reply toPhilip_weinrobe⬆:Philip weinrobe @Philip_weinrobe
Hi Chris!
just tried the script. failing at line 23?10.09.2024 14:20:03.47 <info> [Backend]: !! Command Error: Duplicate for Render - Chris Shaw [user:cktj8p6a80003y610qt32zw39:cm0wr7xx40003h210a0bpmj6b]: Could not click popup menu item (Duplicate for Render - Chris Shaw: Line 23) Could not find menu item with name: Duplicate Main Playlist...
Chris Shaw @Chris_Shaw2024-09-10 21:31:26.934Z
Which Version of PT are you running?
Specifically, when you click on the playlist selector does the menu look like this?- PPhilip weinrobe @Philip_weinrobe
pro tools studio 2024.6
- In reply toChris_Shaw⬆:
Chris Shaw @Chris_Shaw2024-09-10 21:49:01.803Z
Your duplicate menu path must be different.
I've edited the above to work with any recent version of PT.- PPhilip weinrobe @Philip_weinrobe
- RIn reply toPhilip_weinrobe⬆:Reinhard Gross @Reinhard_Gross
Just checked it, because I needed this one, too. Works smoothly, and I'm on PT 2023.9. Would be possible to enter a variable name for the suffix? Like + " alternate 1"
Chris Shaw @Chris_Shaw2024-10-09 18:48:21.821Z
@Reinhard_Gross,
I've added dialogs to enter both prefixes and suffixes to the newly created tracks as well as an option to have either the new or original tracks displayed when the script finishes.sf.ui.proTools.mainWindow.invalidate(); // Get new track name prefixes and suffixes let trackNamePrefix = "", trackNameSuffix = ""; while (!trackNamePrefix && !trackNameSuffix) { trackNamePrefix = sf.interaction.displayDialog({ title: "Track Name Prefix", prompt: "Enter track name prefix \n(Include any separators - click OK to leave blank)", defaultAnswer: "", }).text trackNameSuffix = sf.interaction.displayDialog({ title: "Track Name Suffix", prompt: "Enter track name suffix \n(Include any separators - click OK to leave blank)", defaultAnswer: "" }).text if (!trackNamePrefix && !trackNameSuffix) { sf.interaction.displayDialog({ prompt: "Either a track name prefix or a track name suffix must be used" }) } } const tracksToDisplay = sf.interaction.displayDialog({ prompt: "Switch to newly created tracks or show original tracks?", buttons: ["Cancel", "New Tracks", "Original Tracks"], defaultButton: "New Tracks" }).button // Ensure groups are suspended var groupListPopup = sf.ui.proTools.groupsOpenListPopupMenu({}).popupMenu; groupListPopup.menuClickPopupMenu({ menuPath: ["Suspend All Groups"], targetValue: 'Enable', }); // Hack to close gropup popup menu sf.ui.proTools.appActivateMainWindow(); // Get selected tracks and ensure first track is visible const selectedTracks = sf.ui.proTools.trackGetSelectedTracks().trackHeaders; const originalSelectedTrackNames = sf.ui.proTools.selectedTrackNames; // Scroll selected tracks into view selectedTracks[0].trackScrollToView(); const playlistSelector = selectedTracks[0].popupButtons.whoseTitle.is("Playlist selector").first; const selectorItems = playlistSelector.popupMenuFetchAllItems({ dismissMenu: true }).menuItems; const duplicateMenuPath = selectorItems.filter(i => i.path[0].startsWith("Duplicate"))[0].path // Duplicate playlists playlistSelector.popupMenuSelect({ menuPath: duplicateMenuPath, isShift: true, isOption: true, }) // Dismiss conf window if only one track was originally selected if (originalSelectedTrackNames.length == 1) { try { let confWin = sf.ui.proTools.confirmationDialog confWin.elementWaitFor({ waitType: "Appear", timeout: 500 }) sf.keyboard.press({ keys: "return" }) confWin.elementWaitFor({ waitType: "Disappear", timeout: 500 }) } catch (err) { } } // Invalidate now that we've got new track names / playlists sf.ui.proTools.mainWindow.invalidate(); // Pause to wait for invalidation to take effect sf.wait({ intervalMs: 500 }) // Get new selected track names let newSelectedTrackNames = sf.ui.proTools.selectedTrackNames // iterate through track names and rename them via PT SDK newSelectedTrackNames.forEach((n, index) => { sf.app.proTools.renameTrack({ oldName: n, newName: `${trackNamePrefix}${originalSelectedTrackNames[index]}${trackNameSuffix}` }) }) // Get menu item name of original first selected track function getPlaylistMenuItem(playlistSelector, playlistName) { let menuItem = playlistSelector.popupMenuFetchAllItems({ dismissMenu: true }) .menuItems .filter((i) => i.path[0].startsWith(playlistName + " (") )[0].path[0]; return menuItem } let originalPlaylistMenuItem = getPlaylistMenuItem(playlistSelector, originalSelectedTrackNames[0]) if (tracksToDisplay == "Original Tracks") { // Switch to original playlists playlistSelector.popupMenuSelect({ menuPath: [originalPlaylistMenuItem], isShift: true, isOption: true, }) sf.ui.proTools.mainWindow.invalidate() // Pause to wait for invalidation to take effect sf.wait({ intervalMs: 500 }) // ====Ensure all playlists are set to original playlist=== // newSelectedTrackNames = sf.ui.proTools.selectedTrackNames; // Check if all tracks have switched by comparing new selected track names to orig track names let unswitchedTrackNames = {}; newSelectedTrackNames.forEach((name, index) => { if (originalSelectedTrackNames[index] !== name) { unswitchedTrackNames[name] = (originalSelectedTrackNames[index]) } }) let keys = Object.keys(unswitchedTrackNames) // If there are unswitched playlist names then select original playlists individually if (keys.length > 0) { keys.forEach(key => { let unswitchedTrack = sf.ui.proTools.trackGetByName({ name: key }).track; unswitchedTrack.trackScrollToView(); let playlistSelector = unswitchedTrack.popupButtons.whoseTitle.is("Playlist selector").first; let origPlaylistName = unswitchedTrackNames[key]; getPlaylistMenuItem(playlistSelector, origPlaylistName) // // Switch to original playlist playlistSelector.popupMenuSelect({ menuPath: [getPlaylistMenuItem(playlistSelector, origPlaylistName)], }) sf.ui.proTools.mainWindow.invalidate() sf.wait({ intervalMs: 250 }) }); // Re-select orignal selected tracks sf.app.proTools.selectTracksByName({ trackNames: originalSelectedTrackNames }) } }