I have a macro for creating markers based on the name of a Video file in my Pro Tools session. It works great but I have to trigger it for each video in the session. Sometimes I will have 10+ videos and I would like to automate the process. Here is my macro:

//Calling command "Next Clip" from package "Glenn PT" (installed from user/pkg/version "cC8lEkgySCUgl4chMHut9tysKdy1/cl44nzq020000rq10ouciq4gh/cl6ffsb5j000c6s104wtrhmxk")
sf.soundflow.runCommand({
commandId: 'user:cl6fa659600000610lggi0qif:cl5ii0n9q000d5t10fc0terze',
props: {}
});
//Calling command "Rename..." from package "Pro Tools" (installed from user/pkg/version "srAasovvDiQacRZ2mcId4RrOA8R2/ckp49i4j60000a2100yfwywgf/cln0nxiji0000yp102352fxp9")
sf.soundflow.runCommand({
commandId: 'user:ckp49i4j60000a2100yfwywgf:ckw2p6vpz0002ik10txjjtvhs#ckw2wdejo000uik103hef958b',
props: {}
});
sf.keyboard.press({
keys: "cmd+c",
});
sf.keyboard.press({
keys: "return",
});
sf.wait({
intervalMs: 100,
});
sf.keyboard.press({
keys: "numpad enter",
});
sf.wait({
intervalMs: 100,
});
sf.keyboard.press({
keys: "cmd+v",
});
sf.keyboard.press({
keys: "numpad enter",
});
Anyone able to make this script run until there are no more videos or clips in the time line? I'm sure there is a cleaner and more sophisticated way to do this.
- OOwen Granich-Young @Owen_Granich_Young
I thought I had the lego pieces lying around for this so figured I'd look at it. Of NOTE this is for PT pre track markers, so if you're on 2023.6 or later it may or may not work. Be sure to select all the video files before you run the script (see attached movie). I'm sure Icing on the cake would be some functions at the top that go, 'Find Video Track' 'Select all on video track' 'run script' but I've used my allotted hobby time for the day and got to get back to it. If somebody else has those lego pieces at easy reach maybe we can bolt them onto this script.
///Clear Find So You can get Clip Name const clearFind = () => sf.keyboard.press({ keys: "cmd+shift+d", }); ////Create memory location function createMemoryLocationsMarker({ name }) { sf.ui.proTools.appActivateMainWindow(); const dlg = sf.ui.proTools.newMemoryLocationDialog; if (!dlg.exists) { sf.keyboard.press({ keys: "numpad enter" }); } dlg.elementWaitFor(); dlg.radioButtons.whoseTitle.is("Marker").first.elementClick(); dlg.textFields.allItems[1].elementSetTextFieldWithAreaValue({ value: name, }); dlg.buttons.whoseTitle.is("OK").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", }); } ///Get Current Clip Name function getCurrentClipName() { //This gets the current region name in Pro Tools const clipNameWin = sf.ui.proTools.windows.whoseTitle.is('Name').first try { sf.ui.proTools.menuClick({ menuPath: ['Clip', 'Rename...'] }, `could not find rename window`); clipNameWin.elementWaitFor({ onError: "Continue" }); let currentClipName = clipNameWin.groups.whoseTitle.is('Name').first.textFields.first.value.invalidate().value; clipNameWin.buttons.whoseTitle.is('Cancel').first.elementClick({}, `could not click Rename window: cancel button`); return currentClipName } catch (err) { throw `error in getCurrentClipNameWin(): ${err}` } } ///Combine the above functions to get the goal function dropMarkerOfClipName() { createMemoryLocationsMarker({ name: getCurrentClipName() }); } /// Clear Caches and Finds then Do to all clips selected function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); clearFind(); sf.ui.proTools.clipDoForEachSelectedClip({ action: dropMarkerOfClipName }); } main();
Bests,
Owen- BBrandon Jiaconia @Brandon_Jiaconia
Owen, Thank you for your reply. Your script looks great in the video! But your suspicion about PT 2023.6 was correct. This script selects the clips the same way as your video, but does not make the markers for some reason.
- OOwen Granich-Young @Owen_Granich_Young
Ugh, yeah @Chris_Shaw or @Kitch I know it's an easy fix one of you posted around the forum, but I can't seem to get the keywords right to track it back down. If you have a free moment will you remind me? Pretty sure it's as easy as changing line 18 just a little but I can't track it down.
Sorry @Brandon_Jiaconia I've not yet updated here, so I can't trouble shoot myself.
- BBrandon Jiaconia @Brandon_Jiaconia
All good - I really appreciate you taking the time to look at this.
- In reply toOwen_Granich_Young⬆:
Kitch Membery @Kitch2023-11-06 22:59:29.814Z
Try this @Owen_Granich_Young!
/** * Clear Find in the clips list so you can get Clip Name */ function clearFind() { sf.keyboard.press({ keys: "cmd+shift+d", }); } /** * Create memory location * @param {object} obj * @param {string} obj.name */ function createMemoryLocationsMarker({ name }) { sf.ui.proTools.appActivateMainWindow(); const dlg = sf.ui.proTools.newMemoryLocationDialog; if (!dlg.exists) { sf.keyboard.press({ keys: "numpad enter" }); } dlg.elementWaitFor(); dlg.radioButtons.whoseTitle.is("Marker").first.elementClick(); const nameTextField = dlg.textFields.first; nameTextField.elementSetTextFieldWithAreaValue({ value: name, }); dlg.buttons.whoseTitle.is("OK").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", }); } /** * Get Current Clip Name */ function getCurrentClipName() { //This gets the current region name in Pro Tools const clipRenameWin = sf.ui.proTools.windows.whoseTitle.is('Name').first; try { // Open clip rename window sf.ui.proTools.menuClick({ menuPath: ['Clip', 'Rename...'], }, `could not find rename window`); // Wait for clip rename window clipRenameWin.elementWaitFor({ onError: "Continue", }); let currentClipName = clipRenameWin.groups.whoseTitle.is('Name').first.textFields.first.value.invalidate().value; clipRenameWin.buttons.whoseTitle.is('Cancel').first.elementClick({}, `could not click Rename window: cancel button`); return currentClipName } catch (err) { throw `error in getCurrentClipNameWin(): ${err}`; } } /** * Combine the above functions to get the goal */ function createMarkerFromClipName() { // Get current clip name const currentClipName = getCurrentClipName(); // Create memory location createMemoryLocationsMarker({ name: currentClipName, }); } /// Clear Caches and Finds then Do to all clips selected function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); clearFind(); // Do for each selected clip sf.ui.proTools.clipDoForEachSelectedClip({ action: createMarkerFromClipName, }); } main();
I probably didn't need to refactor it but did anyway.
All you needed to change was line 18...
dlg.textFields.allItems[1].elementSetTextFieldWithAreaValue({ value: name, });
to
dlg.textFields.first.elementSetTextFieldWithAreaValue({ value: name, });
as the "Name" text field was the
first
orallItems[0]
not theallItems[1]
textField
.Hope that works.
:-)- OOwen Granich-Young @Owen_Granich_Young
@Brandon_Jiaconia The pros have stepped in you should be good to go. Thanks @Kitch I knew it was something there in 18 I just couldn't remember what. I'll leave the old one un-edited above just in case someone needs it for pre 2023.6
- BBrandon Jiaconia @Brandon_Jiaconia
Owen, I just realized that your original script works with the name of Audio clips, but not with Video clips. Kitchs' update is the same! I also realized I can use the reference audio from the video (which has the same name as the video) to make these markers. Again, really appreciate your help, thanks so much! And Kitch thank you for chiming in! You guys are legends !
- OOwen Granich-Young @Owen_Granich_Young
Innnnnntersting, my bad TBH I never checked against a video file. Will fix tomorrow if somebody doesn't beat me to it.
- OOwen Granich-Young @Owen_Granich_Young
Doubly interesting @Kitch it's the
sf.ui.proTools.clipDoForEachSelectedClip
it doesn't like video clips. If I remove that and just run it it works... log for internal review? Or other workaround?Kitch Membery @Kitch2023-11-07 00:33:48.941Z
Ahhh yes, I don't believe the
sf.ui.proTools.clipDoForEachSelectedClip
method works for video clips. It would best to request in the Ideas section of the forum or upvote the Idea if it's already been requested.- OOwen Granich-Young @Owen_Granich_Young
@Brandon_Jiaconia in the mean time, this script will prompt you to tell it how many clips are in the selection and then run that number of times.
///Clear Find So You can get Clip Name const clearFind = () => sf.keyboard.press({ keys: "cmd+shift+d", }); /// Select Next Clip const cntrlTab = () => sf.keyboard.press({ keys: "ctrl+tab", fast: true, }); ////Create memory location function createMemoryLocationsMarker({ name }) { sf.ui.proTools.appActivateMainWindow(); const dlg = sf.ui.proTools.newMemoryLocationDialog; if (!dlg.exists) { sf.keyboard.press({ keys: "numpad enter" }); } dlg.elementWaitFor(); dlg.radioButtons.whoseTitle.is("Marker").first.elementClick(); dlg.textFields.allItems[0].elementSetTextFieldWithAreaValue({ value: name, }); dlg.buttons.whoseTitle.is("OK").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", }); } ///Get Current Clip Name function getCurrentClipName() { //This gets the current region name in Pro Tools const clipNameWin = sf.ui.proTools.windows.whoseTitle.is('Name').first try { sf.ui.proTools.menuClick({ menuPath: ['Clip', 'Rename...'] }, `could not find rename window`); clipNameWin.elementWaitFor({ onError: "Continue" }); let currentClipName = clipNameWin.groups.whoseTitle.is('Name').first.textFields.first.value.invalidate().value; clipNameWin.buttons.whoseTitle.is('Cancel').first.elementClick({}, `could not click Rename window: cancel button`); return currentClipName } catch (err) { throw `error in getCurrentClipNameWin(): ${err}` } } function dropMarkerOfClipName() { createMemoryLocationsMarker({ name: getCurrentClipName() }); } /// Do to all clips -- this is how you package it to do it to all highlight clips function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); clearFind(); var repeat = prompt("How many tabs would you like to process?"); for (let i = 0; i < +repeat; i++) { cntrlTab(); dropMarkerOfClipName(); } } main();
Sorry @kitch it's not your Refactored - Brandon I did change it to work 2023.6 though... (i think)
- OOwen Granich-Young @Owen_Granich_Young
Ok thought about it some more... here's better yet. You only need to click into your video track now...
///Clear Find So You can get Clip Name const clearFind = () => sf.keyboard.press({ keys: "cmd+shift+d", }); /// Select Next Clip const cntrlTab = () => sf.keyboard.press({ keys: "ctrl+tab", fast: true, }); ////Create memory location function createMemoryLocationsMarker({ name }) { sf.ui.proTools.appActivateMainWindow(); const dlg = sf.ui.proTools.newMemoryLocationDialog; if (!dlg.exists) { sf.keyboard.press({ keys: "numpad enter" }); } dlg.elementWaitFor(); dlg.radioButtons.whoseTitle.is("Marker").first.elementClick(); dlg.textFields.allItems[0].elementSetTextFieldWithAreaValue({ value: name, }); dlg.buttons.whoseTitle.is("OK").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", }); } ///Get Current Clip Name function getCurrentClipName() { //This gets the current region name in Pro Tools const clipNameWin = sf.ui.proTools.windows.whoseTitle.is('Name').first try { sf.ui.proTools.menuClick({ menuPath: ['Clip', 'Rename...'] }, `could not find rename window`); clipNameWin.elementWaitFor({ onError: "Continue" }); let currentClipName = clipNameWin.groups.whoseTitle.is('Name').first.textFields.first.value.invalidate().value; clipNameWin.buttons.whoseTitle.is('Cancel').first.elementClick({}, `could not click Rename window: cancel button`); return currentClipName } catch (err) { throw `error in getCurrentClipNameWin(): ${err}` } } /** * Combine the above functions to get the goal */ function createMarkerFromClipName() { // Get current clip name const currentClipName = getCurrentClipName(); // Create memory location createMemoryLocationsMarker({ name: currentClipName, }); } /// Do to all clips -- this is how you package it to do it to all highlight clips function main() { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.invalidate(); clearFind(); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Select All"] }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Selection", "Move Edit Left"] }); // Get current state of Clip view const isClipListEnabled = sf.ui.proTools.getMenuItem("View", "Other Displays", "Clip List").isMenuChecked // Open Clip List if It's not if (!isClipListEnabled) { sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Clip List"], }); } let selectedClips = sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first.children.whoseRole.is("AXRow").allItems.map(row => row.children[1].children.first.value.value).filter(c => c.startsWith('Selected. ')); for (let i = 0; i < +selectedClips.length; i++) { cntrlTab(); createMarkerFromClipName(); } if (!isClipListEnabled) { sf.ui.proTools.menuClick({ menuPath: ["View", "Other Displays", "Clip List"], }); } } main();
Of note it relies on the videos being different, if you have two copies of the same video in the timeline it won't 'count' them as separate clips so it won't run the correct number of times. If your video track is always named the same thing should be pretty easy to tack a 'select track' onto the front of this.
- BBrandon Jiaconia @Brandon_Jiaconia
Incredible ! Exactly what I was after !
- In reply toOwen_Granich_Young⬆:BBrandon Jiaconia @Brandon_Jiaconia
This is great and works with both audio and video files in 2023.6 ! Thank you so much !