No internet connection
  1. Home
  2. How to

Duplicate and Rename Playlist Script

By Philip weinrobe @Philip_weinrobe
    2024-09-05 20:46:33.070Z

    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:

    1. Have a track selection (one or more)
    2. Duplicate playlist on those tracks (there will not be a new playlist dialog in this case because it's multiple tracks)
    3. Rename those tracks to be the "Original Track Name" + "Pre-Process"
    4. Go back to the original playlist on the original track selection (would be OK for this to be the top playlist)
    5. 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

    • 11 replies

    There are 11 replies. Estimated reading time: 15 minutes

    1. 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 })
      }
      
      1. I've re-edited this a few times - should be good now

        1. Oops!, one more edit to account for a single track selected

          1. PPhilip weinrobe @Philip_weinrobe
              2024-09-08 00:52:56.577Z

              thank you, Chris! you are a legend!

              will be back at the mixing desk monday morning and will give this a spin :)

        2. P
          In reply toPhilip_weinrobe:
          Philip weinrobe @Philip_weinrobe
            2024-09-10 18:21:15.899Z

            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...
            
            1. Which Version of PT are you running?
              Specifically, when you click on the playlist selector does the menu look like this?

              1. PPhilip weinrobe @Philip_weinrobe
                  2024-09-10 21:38:09.415Z

                  pro tools studio 2024.6

                  1. In reply toChris_Shaw:

                    Your duplicate menu path must be different.
                    I've edited the above to work with any recent version of PT.

                    1. PPhilip weinrobe @Philip_weinrobe
                        2024-09-10 21:54:37.346Z

                        hell yeah! works perfect now!

                        a thing of beauty.

                        you are the best, @Chris_Shaw

                  2. R
                    In reply toPhilip_weinrobe:
                    Reinhard Gross @Reinhard_Gross
                      2024-10-09 10:53:30.069Z

                      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"

                      1. @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 })
                            }
                        }