Hey @samuel_henriques I had an idea about the next step in automating background editing after this awesome script you wrote for Jake How to write an "exclude memory locations with this name" #post-5
Wondering if this workflow is possible.
Select all clips on Guide Track
Get names of all clips in Guide - filter out duplicate names - (create an array?)
Prompt user to choose a Name via sf.Prompt
User chooses a clip name
for each clip of that name - select clip - navigate to user defined track/tracks Paste to fill selection
So you could load any specific location's BG build into your clipboard and then run the script to fill that location across the whole show.
Thoughts?
I don't even know if you can scrape clip names like memory locations, or how you would feels possible though, as long as you don't have a search enabled 😂
- OOwen Granich-Young @Owen_Granich_Young
Ok, so I did the easy legwork part. Can anybody help me with the hard Filtering part? I realized starting on the destination tracks was a better approach as then the user doesn't have to pre-define those.
Or is the filtering not really possible with do for each selected clip? Does it have to instead have a 'read the title of the clip if correct title do action if not continue' ? That feels like it would be a slower process but maybe that's what it has to be as doForEachSelectedClip can't pre filter?
//Activate Pro Tools main window; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); //Original Track Names const originalTrackNames = sf.ui.proTools.selectedTrackNames; sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect(); sf.ui.proTools.clipDoForEachSelectedClip({ action: () => { sf.ui.proTools.trackSelectByName({ names: originalTrackNames }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste Special", "Repeat to Fill Selection"], }); sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect(); }, onError: "Continue", });
- OOwen Granich-Young @Owen_Granich_Young
Ok, so I'm getting closer to scanning the clip names and selecting from them, (thanks to this post Get selected Clip Name @raphaelsepulveda ) The array it generates looks right and the select goes through, but for some reason my log comes up undefined, what simple thing am I missing?
function getSelectedClipNamesFromClipList() { const clipsTable = sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first; // Get all selected clips const selectedClips = clipsTable.children.whoseRole.is("AXRow").allItems.map(row => row.children[1].children.first.value.value).filter(c => c.startsWith('Selected. ')); // Extract clip names const clipNames = selectedClips.map(c => c.split('"')[1]); return clipNames }; const selectedClip = getSelectedClipNamesFromClipList(); const chosenBackground = selectedClip[sf.interaction.popupSearch({ title: `Select Background Name`, items: selectedClip.map(item => ({ name: item })), onCancel: 'Abort', }).item.name] log(chosenBackground)
nvm...
Found a better solution that also filters :
function getSelectedClipNamesFromClipList() { const clipsTable = sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first; // Get all selected clips const selectedClips = clipsTable.children.whoseRole.is("AXRow").allItems.map(row => row.children[1].children.first.value.value).filter(c => c.startsWith('Selected. ')); // Extract clip names const clipNames = selectedClips.map(c => c.split('"')[1]); return clipNames }; const selectedClip = getSelectedClipNamesFromClipList(); //Filter out Memory location name duplicates let uniqueBackgroundLocations = [...new Set(selectedClip)]; //Popup Search let targetBackgroundLocation = sf.interaction.popupSearch({ items: uniqueBackgroundLocations.map(name => ({ name: name })), }).item.name log(targetBackgroundLocation)
- OIn reply toOwen_Granich_Young⬆:Owen Granich-Young @Owen_Granich_Young
Ok I feel like I'm so close to unlocking the last little piece with this post here Is there a way to search by region name and color all named "X" a specified color?
However this does nothing now... can someone push me over the finish line?
function getSelectedClipNamesFromClipList() { const clipsTable = sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first; // Get all selected clips const selectedClips = clipsTable.children.whoseRole.is("AXRow").allItems.map(row => row.children[1].children.first.value.value).filter(c => c.startsWith('Selected. ')); // Extract clip names const clipNames = selectedClips.map(c => c.split('"')[1]); return clipNames }; function getClipName() { sf.ui.proTools.menuClick({ menuPath: ["Clip", "Rename..."] }); const renameWin = sf.ui.proTools.windows.whoseTitle.is("Name").first.elementWaitFor({}, 'Rename Clip Window Not Found.').element; const clipName = renameWin.groups.first.textFields.first.value.invalidate().value; renameWin.buttons.whoseTitle.is("Cancel").first.elementClick(); renameWin.elementWaitFor({ waitType: "Disappear" }, 'Rename Clip Window Failed to Close.'); return clipName; }; //Activate Pro Tools main window; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); //Original Track Names const originalTrackNames = sf.ui.proTools.selectedTrackNames; sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect(); const selectedClip = getSelectedClipNamesFromClipList(); //Filter out Memory location name duplicates let uniqueBackgroundLocations = [...new Set(selectedClip)]; //Popup Search let targetBackgroundLocation = sf.interaction.popupSearch({ items: uniqueBackgroundLocations.map(name => ({ name: name })), }).item.name function pasteBackground(name) { if (name in targetBackgroundLocation) { sf.ui.proTools.trackSelectByName({ names: originalTrackNames }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste Special", "Repeat to Fill Selection"], }); sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect(); } }; // Color each selected clip sf.ui.proTools.clipDoForEachSelectedClip({ action: () => { pasteBackground(getClipName()) }, onError: "Continue" })
Is there an IS instead of an IN for the if statement? Have I just completely mis ordered?
- OOwen Granich-Young @Owen_Granich_Young
Got it.... Needed an extra invalidate. And to simply the get and if. Coooooool! I'm sure the code could use refactoring as I've just been cobbling it together, but pretty stoked! I'll also have to build in some error handling for 'crossfades for repeat to fill selection and so forth'
function getSelectedClipNamesFromClipList() { const clipsTable = sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first; // Get all selected clips const selectedClips = clipsTable.children.whoseRole.is("AXRow").allItems.map(row => row.children[1].children.first.value.value).filter(c => c.startsWith('Selected. ')); // Extract clip names const clipNames = selectedClips.map(c => c.split('"')[1]); return clipNames }; function getClipName() { sf.ui.proTools.menuClick({ menuPath: ["Clip", "Rename..."] }); const renameWin = sf.ui.proTools.windows.whoseTitle.is("Name").first.elementWaitFor({}, 'Rename Clip Window Not Found.').element; const clipName = renameWin.groups.first.textFields.first.value.invalidate().value; renameWin.buttons.whoseTitle.is("Cancel").first.elementClick(); renameWin.elementWaitFor({ waitType: "Disappear" }, 'Rename Clip Window Failed to Close.'); return clipName; }; function main(){ //Activate Pro Tools main window; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); //Original Track Names const originalTrackNames = sf.ui.proTools.selectedTrackNames; sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect(); const selectedClip = getSelectedClipNamesFromClipList(); //Filter out Memory location name duplicates let uniqueBackgroundLocations = [...new Set(selectedClip)]; //Popup Search let targetBackgroundLocation = sf.interaction.popupSearch({ items: uniqueBackgroundLocations.map(name => ({ name: name })), }).item.name sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); sf.ui.proTools.clipDoForEachSelectedClip({ action: () => { getClipName() if (getClipName() == targetBackgroundLocation) { sf.ui.proTools.trackSelectByName({ names: originalTrackNames }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste Special", "Repeat to Fill Selection"], }); sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect() } }, onError: "Continue", }); } main();
samuel henriques @samuel_henriques
Hey Owen, awesome work. Sorry I missed all your questions.
How is it working now, do you need help on any more bits?- OOwen Granich-Young @Owen_Granich_Young
This one is working! I've moved onto one that I'm trying to get to read the clip name then go and get the matching 'selection memory location' paste it and move onto the next clip. Basically 'build my backgrounds' script. It's a bit fragile though, and last time I gave it a run it just broke. Taking a break for a little while before I revisit it.
TBH my biggest problem with this one is it seems to be erroring out on @Jake_Carter much larger session, not 100% sure what kind of redundancy we can build into it to wait for it to actually process but I think the 'get clip names from Clip List' with his ENORMOUS clip list is really throwing it for a loop.
samuel henriques @samuel_henriques
If you can predict what are the clip names, you can make a list and ask from that list which ones you want to paste, that would make it faster.
Another way is If you have a set of backgrounds in the session, you could start by doing a doForEachSelectedClip and take the background names and locations. Then choosing the "=SCENE=" track and location find the clip names that mach the backgrounds you just "scanned" and it would go to background, copy, go to where clip at =scene= was found and paste. This would automate it completely
Tweaked some bits, not major
function getSelectedClipNamesFromClipList() { const clipsTable = sf.ui.proTools.mainWindow.tables.whoseTitle.is('CLIPS').first; // Get all selected clips const selectedClips = clipsTable.children.whoseRole.is("AXRow").allItems.map(row => row.children[1].children.first.value.value).filter(c => c.startsWith('Selected. ')); // Extract clip names const clipNames = selectedClips.map(c => c.split('"')[1]); return clipNames }; function getClipName() { sf.ui.proTools.menuClick({ menuPath: ["Clip", "Rename..."] }); const renameWin = sf.ui.proTools.windows.whoseTitle.is("Name").first.elementWaitFor({}, 'Rename Clip Window Not Found.').element; const clipName = renameWin.groups.first.textFields.first.value.invalidate().value; renameWin.buttons.whoseTitle.is("Cancel").first.elementClick(); renameWin.elementWaitFor({ waitType: "Disappear" }, 'Rename Clip Window Failed to Close.'); return clipName; }; function main() { //Activate Pro Tools main window; sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.mainWindow.invalidate(); //Original Track Names const originalTrackNames = sf.ui.proTools.selectedTrackNames; sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect(); const selectedClip = getSelectedClipNamesFromClipList(); //Filter out Memory location name duplicates let uniqueBackgroundLocations = selectedClip.filter((n, i) => selectedClip.indexOf(n) === i) //Popup Search let targetBackgroundLocation = sf.interaction.popupSearch({ items: uniqueBackgroundLocations.map(name => ({ name: name })), }).item.name sf.ui.proTools.clipDoForEachSelectedClip({ action: () => { const clipName = getClipName() if (clipName === targetBackgroundLocation) { sf.ui.proTools.trackSelectByName({ names: originalTrackNames }); sf.ui.proTools.menuClick({ menuPath: ["Edit", "Paste Special", "Repeat to Fill Selection"], }); sf.ui.proTools.trackGetByName({ name: '=SCENE=', makeVisible: true }).track.trackSelect() } }, onError: "Continue", }); } main();
- OOwen Granich-Young @Owen_Granich_Young
Thanks boss! I think I got it! Although untested in an actual session...