Hello everyone,
this is a script I'm working on to automate the process of importing loads of AAF to a session.
If you see better way to organise, or improve any part, would be great to hear from you and improve it.
One technical "pickle" I encountered is that the "Import Session Data" window must have all tracks visible so SF can see them all, there is no "scroll to track" for the menu, at least I don't know how. For me that means moving the window to a screen rotated 90º, fortunately my setup has one this way.
One thing I'm struggling with is the occasions where a AAF has a track that is not already present on the session. The ideal solution would be to set it to "New Track" but I'm failing miserably on figuring out where in the sequence this should be done. Usually a set of AAF to import will all have the same tracks, but occasionally a new track will be present.
As is, if an AAF has a new track, the script will fail and stop on the function selectPath(i, path)
, witch makes cense since I'm asking to select a path that doesn't exist.
So I tried to do a catch (err)
, this https://forum.soundflow.org/-348#post-11, was very helpful but for reasons I don't understand, there is an error already leaving the function, I see it only in the log file, and it needs to be there. If I catch
the error, I'll be able to set the tracks but will loose the correct sequence of match track.
Any Ideas on what can I do to fix this?
If it becomes too complicated, I think an option could be to cancel the import, moving to the next one and write the name of the AAF on a text file as report of failure. But as I see it now, the place to do any action would be where its fails, and I'm unable to do any action without messing the sequence.
Here's a video of the script in action:
https://we.tl/t-fSZL72JCc4
Thank you all so much !
function letsStartWin() {
const startWin = sf.interaction.displayDialog({
defaultAnswer: "",
buttons: ["Video Location & Go!", "Go!", "Cancel"],
defaultButton: "Go!",
cancelButton: "Cancel",
title: "Batch Import Session Data",
prompt: "Manualy Import the first AAF.\nThis will ensure a set of tracks is in place for eficient Match Track. \nCreate a new video track for the imported video.\n\nBE AWARE !!! \nVideo files will be added on the ONLINE VIDEO TRACK,\nSo make sure the NEW TRACK IS ONLINE! \nOtherwise the imported videos might go to the wrong track and will not end well !!! 😡 \n\n\By default, the script searches for video files in the session video folder, if you want a diferent location choose one.\n\nTo use \"Map Start Time To...\" enter the Time Code of the interval you want.\nLeave blank to use AAF start time.\n\nhh:mm:ss:ff"
});
return startWin
}
function alertSound() {
sf.system.volumeSet({ volume: 0.5 });
sf.system.exec({
commandLine: `afplay /System/Library/Sounds/Glass.aiff`
});
sf.system.volumeSet({ volume: 1.0 });
}
function moveWindowandsize() {
var screenIndex = 2;
var screenFrame = sf.ui.screens.allScreens[screenIndex].frame;
sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.windowMove({
position: { x: screenFrame.x + 0, y: screenFrame.y + 22 },
size: { x: screenFrame.x + 0, y: screenFrame.y + 3300 },
});
}
function importWindow(importMenu, list) {
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.appWaitForActive({
timeout: -1
});
sf.ui.proTools.menuClick({
menuPath: ["File", "Import", importMenu],
});
var win = sf.ui.frontmostApp.focusedWindow;
sf.keyboard.type({ text: '/' });
var sheet = win.sheets.first.elementWaitFor({ timeout: 500 }, 'Could not find "Go to" sheet in the Save/Open dialog').element;
//// //////////////////////////Set Path
sheet.comboBoxes.first.value.value = list;
sheet.buttons.whoseTitle.is('Go').first.elementClick({}, 'Could not click "Go"');
win.sheets.first.elementWaitFor({ waitForNoElement: true, timeout: 500 }, '"Go to" sheet didn\'t close in time');
sf.ui.proTools.windows.whoseTitle.is('Open').first.buttons.whoseTitle.is('Open').first.elementClick();
sf.ui.proTools.children.whoseRole.is("AXWindow").whoseTitle.is('Open').first.elementWaitFor({ waitType: "Disappear" });
if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('OK').first.exists) {
sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('OK').first.elementClick();
sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", onError: "Continue" });
}
}
function dismissSessionNotes() {
var sessionNotesWin = sf.ui.proTools.windows.whoseTitle.is('Session Notes')
if (sessionNotesWin.exists) {
sessionNotesWin.first.buttons.whoseTitle.is('No').first.elementClick();
sessionNotesWin.first.elementWaitFor({
waitType: "Disappear",
});
}
}
function closeImportDataWin() {
var button = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first
button.buttons.allItems[1].elementClick();
button.elementWaitFor({ waitType: "Disappear" });
dismissSessionNotes()
}
function getAafDetails() {
const win = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first
const sourcePanel = win.groups.whoseTitle.is('Source Properties:').invalidate().first;
const tableData = sourcePanel.childrenByRole('AXTable').first.childrenByRole('AXRow')
.map(fields => fields.childrenByRole('AXCell').first.children.first.title.invalidate().value);
return tableData
}
function selectionSetAafStartTime(importingAaf) { ///////////////// THIS WILL CLOSE IMPORT SESSION WINDOW ///////////////////////
let aafDetails = getAafDetails();
let aafStartTime = aafDetails.map(x => x.split("Start time:").slice(1)).join("")
closeImportDataWin()
sf.ui.proTools.selectionSetTimecode({ mainCounter: aafStartTime });
var newMemLocWin = sf.ui.proTools.newMemoryLocationDialog
sf.keyboard.press({ keys: "numpad enter" });
newMemLocWin.elementWaitFor();
newMemLocWin.textFields.allItems[1].elementSetTextFieldWithAreaValue({ value: importingAaf.join().split(".").slice(0, -1).join("") });
newMemLocWin.radioButtons.first.checkboxSet({ targetValue: "Enable" });
newMemLocWin.buttons.whoseTitle.is('OK').first.elementClick();
newMemLocWin.elementWaitFor({ waitType: "Disappear" });
}
function getNextTcStart(intervalStartTime) {
sf.ui.proTools.selectionSetTimecode({ selectionLength: intervalStartTime });
var getEndTimecode = sf.ui.proTools.mainWindow.groups.whoseTitle.is('Counter Display Cluster').first.textFields.whoseTitle.is('Edit Selection End').first.invalidate().value.value;
return getEndTimecode
}
function selectionSetUserInterval(intervalStartTime, importingAaf) { ///////////////// THIS WILL CLOSE IMPORT SESSION WINDOW ///////////////////////
let importSessionWin = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first
importSessionWin.groups.whoseTitle.is('Timecode Mapping Options:').first.popupButtons.first.popupMenuSelect({
menuPath: ["Map start timecode to"]
});
importSessionWin.mouseClickElement({ relativePosition: { "x": 390, "y": 97 } });
sf.keyboard.type({ text: intervalStartTime });
importSessionWin.mouseClickElement({ relativePosition: { "x": 530, "y": 100 } });
closeImportDataWin()
sf.ui.proTools.selectionSetTimecode({ mainCounter: intervalStartTime });
var newMemLocWin = sf.ui.proTools.newMemoryLocationDialog
sf.keyboard.press({ keys: "numpad enter" });
newMemLocWin.elementWaitFor();
newMemLocWin.textFields.allItems[1].elementSetTextFieldWithAreaValue({ value: importingAaf.join().split(".").slice(0, -1).join("") });
newMemLocWin.radioButtons.first.checkboxSet({ targetValue: "Enable" });
newMemLocWin.buttons.whoseTitle.is('OK').first.elementClick();
newMemLocWin.elementWaitFor({ waitType: "Disappear" });
}
function setVideoImportOptions() {
const videoImportOprionsWin = sf.ui.proTools.windows.whoseTitle.is('Video Import Options').first
const radioButtons = videoImportOprionsWin.radioButtons
const checkBoxes = videoImportOprionsWin.checkBoxes
videoImportOprionsWin.elementWaitFor({ waitType: "Appear" });
if (radioButtons.allItems[1].invalidate().isEnabled == true) {
radioButtons.allItems[1].checkboxSet({ targetValue: "Enable" });
} else if (radioButtons.allItems[1].invalidate().isEnabled == false) {
radioButtons.allItems[2].checkboxSet({ targetValue: "Enable" });
}
if (videoImportOprionsWin.popupButtons.first.invalidate().value.value !== "Selection") {
videoImportOprionsWin.popupButtons.first.popupMenuSelect({ menuPath: ["Selection"] });
}
checkBoxes.allItems[0].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[1].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[2].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[3].checkboxSet({ targetValue: "Disable" });
videoImportOprionsWin.buttons.whoseTitle.is('OK').first.elementClick();
videoImportOprionsWin.elementWaitFor({ waitType: "Disappear" });
}
function setDataImportOptions() {
let importSessionButtons = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Session Data').first.checkBoxes
moveWindowandsize()
sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Tracks').first.buttons.whoseTitle.is('Match Tracks').first.elementClick();
importSessionButtons.allItems[3].checkboxSet({ targetValue: "Disable" });
importSessionButtons.first.checkboxSet({ targetValue: "Disable" });
importSessionButtons.allItems[2].checkboxSet({ targetValue: "Disable" });
importSessionButtons.allItems[4].checkboxSet({ targetValue: "Enable" });
importSessionButtons.allItems[1].checkboxSet({ targetValue: "Disable" });
sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.radioButtons.allItems[1].checkboxSet({ targetValue: "Enable" });
var trackDataToImportWin = sf.ui.proTools.windows.whoseTitle.is('Track Data to Import').first
var checkBoxes = trackDataToImportWin.groups.whoseTitle.is('Track Data').first.checkBoxes
sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Session Data').first.buttons.whoseTitle.is('Choose...').first.elementClick();
trackDataToImportWin.elementWaitFor({ waitType: "Appear" });
checkBoxes.allItems[0].checkboxSet({ targetValue: "Enable" });
checkBoxes.allItems[1].checkboxSet({ targetValue: "Enable" });
checkBoxes.allItems[2].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[3].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[4].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[5].checkboxSet({ targetValue: "Disable" });
checkBoxes.allItems[6].checkboxSet({ targetValue: "Disable" });
trackDataToImportWin.buttons.whoseTitle.is('OK').first.elementClick();
trackDataToImportWin.elementWaitFor({ waitType: "Disappear" });
}
function selectPath(i, path) {
try {
let list = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Tracks').first.tables.whoseTitle.is('Source Destination').first.children.whoseRole.is("AXRow")
let poppupMenu = list.allItems[i].children.whoseRole.is("AXCell").allItems[1].children.whoseRole.is("AXMenuButton").first
poppupMenu.popupMenuSelect({
menuPath: [path],
targetValue: "Enable"
});
} catch (err) {
selectPath(i, "New Track")
}
}
function isMonoMenu() {
let tracksTable = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Tracks').first.tables.whoseTitle.is('Source Destination').first.children.whoseRole.is("AXRow")
let numberOfTracks = tracksTable.allItems.count
for (var i = 0; i < numberOfTracks; i++) {
let stereoOrMono = tracksTable.allItems[i].children.whoseRole.is("AXCell").first.children.whoseRole.is("AXStaticText").first.invalidate().value.value.split(" (").splice(1).join()
if (stereoOrMono == "Mono audio)") {
var monoDestinationMenu = tracksTable.allItems[i].children.whoseRole.is("AXCell").allItems[1].children.whoseRole.is("AXMenuButton").first.popupMenuFetchAllItems().menuItems.map(mi => mi.path.join(' -> '));
sf.ui.proTools.appActivateMainWindow();
return monoDestinationMenu
}
}
}
function isStereoMenu() {
let tracksTable = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Tracks').first.tables.whoseTitle.is('Source Destination').first.children.whoseRole.is("AXRow")
let numberOfTracks = tracksTable.allItems.count
for (var i = 0; i < numberOfTracks; i++) {
let stereoOrMono = tracksTable.allItems[i].children.whoseRole.is("AXCell").first.children.whoseRole.is("AXStaticText").first.invalidate().value.value.split(" (").splice(1).join()
if (stereoOrMono == "Stereo audio)") {
var stereoDestinationMenu = tracksTable.allItems[i].children.whoseRole.is("AXCell").allItems[1].children.whoseRole.is("AXMenuButton").first.popupMenuFetchAllItems().menuItems.map(mi => mi.path.join(' -> '));
sf.ui.proTools.appActivateMainWindow();
return stereoDestinationMenu
}
}
}
function autoMatchNext(firstIndex, nameFromSource, numberOfDups) {
let destinationbutton = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Tracks').first.tables.whoseTitle.is('Source Destination').first.children.whoseRole.is("AXRow")
const duplicates = numberOfDups.filter(x => x.startsWith(nameFromSource)).length - 1
for (var i = 0; i < duplicates; i++) {
let dotNumber = 1 + i
let n = firstIndex + i
let nameFromSourcePlusDot = nameFromSource + "." + dotNumber
selectPath(n, nameFromSourcePlusDot);
}
}
function autoMatchFirst() {
let tracksTable = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Tracks').first.tables.whoseTitle.is('Source Destination').first.children.whoseRole.is("AXRow")
let numberOfTracks = tracksTable.allItems.count
let destinationList
let nameFromSource
let stereoMenu = isStereoMenu()
let monoMenu = isMonoMenu()
let destinationMenu = monoMenu.concat(stereoMenu)
let numberOfDups = tracksTable.allItems.slice().map(l => l.children.whoseRole.is("AXCell").first.children.whoseRole.is("AXStaticText").first.invalidate().value.value.split(" (").slice(0, -1).join())
for (var i = 0; i < numberOfTracks; i++) {
var firstIndex = i + 1
destinationList = tracksTable.allItems[i].children.whoseRole.is("AXCell").allItems[1].children.whoseRole.is("AXMenuButton").first.invalidate().value.value
nameFromSource = tracksTable.allItems[i].children.whoseRole.is("AXCell").first.children.whoseRole.is("AXStaticText").first.invalidate().value.value.split(" (").slice(0, -1).join();
var sourcePlusDot = nameFromSource + ".1"
if (destinationList === "(none)" && destinationMenu.indexOf(nameFromSource) !== -1) {
selectPath(i, nameFromSource)
}
if (destinationList === "(none)" && destinationMenu.indexOf(sourcePlusDot) !== -1) {
autoMatchNext(firstIndex, nameFromSource, numberOfDups)
}
if (destinationList === "(none)" && destinationMenu.indexOf(nameFromSource) == -1) {
selectPath(i, "New Track")
}
}
}
function sessionVideoFolder() {
try {
var sessionVFolder = sf.ui.proTools.mainWindow.sessionPath.split('/').slice(0, -1).join('/') + '/Video Files';
var sessionVideoFolder = sf.file.directoryGetFiles({
path: sessionVFolder,
isRecursive: true,
}).paths.filter(p => p.match(/\.(mov|mp4|mxf)$/i));
return sessionVideoFolder
} catch (err) {
alert("Whoops something went wrong!")
throw 0
}
}
function altVideoFolder() {
var sessionVFolder = sf.ui.proTools.mainWindow.sessionPath.split('/').slice(0, -1).join('/') + '/Video Files';
const videoFolderPath = sessionVideoFolder()
var folderPath = sf.interaction.selectFolder({
defaultLocation: sessionVFolder,
prompt: 'Select Video Files Folder',
}).path
try {
var altVideoFolder = sf.file.directoryGetFiles({
path: folderPath,
isRecursive: true,
}).paths.filter(p => p.match(/\.(mov|mp4|mxf)$/i));
return altVideoFolder
} catch (err) {
log("No Files on Selected Folder")
}
}
////////////////////////////////////////////////////
/////////////////// Main /////////////////////
function batchImport() {
//// Start Prompt
const startWinAnswer = letsStartWin()
//// Check if user interval is valid
/////https://gist.github.com/allensarkisyan/5441601
var isValidSMPTETimeCode = /(^(?:(?:[0-1][0-9]|[0-2][0-3]):)(?:[0-5][0-9]:){2}(?:[0-2][0-9])$)/;
if (isValidSMPTETimeCode.test(startWinAnswer.text) == false && startWinAnswer.text.length > 1) {
alert("Time Code Not Valid!")
throw 0
}
/// decide video location
let videoFilePath
if (startWinAnswer.button == "Go!") {
videoFilePath = sessionVideoFolder()
}
if (startWinAnswer.button == "Video Location & Go!") {
videoFilePath = altVideoFolder()
}
/////////////////////////////////////////////////////////////
sf.ui.proTools.appActivateMainWindow();
sf.ui.proTools.invalidate();
/////////////////////////////////////////////////////////////
var aafPath = sf.ui.finder.selectedPaths;
var importSessionData = "Session Data..."
var ImportVideo = "Video..."
for (let i = 0; i < aafPath.length; i++) {
//////////////// AAF ////////////////
let aafList = aafPath[i]
let importingAaf = aafList.split("/").slice(-1)
log("Import Session Data: \n" + importingAaf)
////////////////// VIDEO ///////////////
var getVideoFile = videoFilePath.filter(x => x.includes(aafList.split("/").slice(-1).join("/").split(".").shift()))
if (getVideoFile.length == 0) {
log("No Video Found.")
}
////////////////// Map Start Time To //////////////
let intervalStartTime
if (isValidSMPTETimeCode.test(startWinAnswer.text) == true) {
intervalStartTime = getNextTcStart(startWinAnswer.text)
}
//=================================================================//
importWindow(importSessionData, aafList)
setDataImportOptions()
autoMatchFirst()
if (isValidSMPTETimeCode.test(startWinAnswer.text) == true) {
selectionSetUserInterval(intervalStartTime, importingAaf)
} else {
selectionSetAafStartTime(importingAaf)
}
if (getVideoFile.length == 1) {
importWindow(ImportVideo, getVideoFile.join())
setVideoImportOptions()
}
sf.ui.proTools.menuClick({ menuPath: ["File", "Save"] });
}
alertSound()
alert("Done!")
}
batchImport()
Linked from:
- In reply tosamuel_henriques⬆:samuel henriques @samuel_henriques
In the meantime I fixed the new tracks problem. As soon as I can I'll uptate the script.
Thank you.Kitch Membery @Kitch2020-11-26 02:24:35.554Z
Great work Samuel!
What is the error message when the AAF has a new track?
samuel henriques @samuel_henriques
Hello master Kitch, thank you so much,
When a track to import had no match, it would stop on the "poppup menu select" since there was no name, It made sense because I didn't write anything to account for this, so I was trying to catch the error and do something.
Anyway, I made a new set of rules to account for this and that bit is fixed now. I have a new error only if there the last track to import in a new track :), I will fix it soon. and I want to clean a bit the second loop witch is making popup menu select "track name.1" increment the .1 until there is no more numbers on the popup list, and It doesn't seam good. I will make it know when to stop in a more clean manner. If you are into jumping into this, I can send you some aaf I'm using to test, some without confusion but others with lots of problems. Unfortunately I'm not in position to share them on the forum because there is content on them that is not mine.Thank you so much and thank you to the amazing forum.
samuel henriques @samuel_henriques
Updated, fixed the error (was pretty stupid and I took a few hours to figure) and removed a catch error not needed anymore. I might need help with this later, but I couldn't figure out the rule to implement yet.
samuel henriques @samuel_henriques
Hello everyone,
Updated again above.next step is provide option for a report
and there is still a thing with one of the loops, that should be improved, but i'll need some time to figure the workflow.But, as is, its working pretty well!!
Thank you so much.
samuel henriques @samuel_henriques
solution in question.
samuel henriques @samuel_henriques
New update, I think its working pretty well.
I've been using it for the past weeks and so far....happy monkey!Now I can choose to import the AAF using "Map Start Time To..." and set an interval.
What I know It Doesn't do:
If the AAF has more than one group of tracks with same name, separated by other tracks, the script wont fail, but wont map the tracks to the correct session tracks, for example if AAF is like this:
Track 1
Track 2
Music
Music
Music
Track 3
Track 4
Music
MusicI figured almost how to fix it, but it became apparent (at least to me) that it would become really complicated to figure out a solution for all situations. So I made a different script to help situations like this one.
When I get really doggy and disorganized AAF what I do is create a session for each and then import those to my main session. This way all the sessions will have all the .1, .2, .3 on the duplicates. I used to to this by hand, now I've built an "Batch Open AAF to new session" then, I can use the "Batch import session data to join them" This is still being tested though.So Batch Import Session Data, is updated above,
and batch Open AAF to New Session is here:function alertSound() { sf.system.volumeSet({ volume: 0.5 }); sf.system.exec({ commandLine: `afplay /System/Library/Sounds/Glass.aiff` }); sf.system.volumeSet({ volume: 1.0 }); } function dismissSessionNotes() { var sessionNotesWin = sf.ui.proTools.windows.whoseTitle.is('Session Notes') if (sessionNotesWin.exists) { sessionNotesWin.first.buttons.whoseTitle.is('No').first.elementClick(); sessionNotesWin.first.elementWaitFor({ waitType: "Disappear", }); } } function closeImportDataWin() { var button = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first button.buttons.allItems[1].elementClick(); button.elementWaitFor({ waitType: "Disappear" }); dismissSessionNotes() } function dashboard(sessionName, savePath, aafList) { let dashboardWin = sf.ui.proTools.windows.whoseTitle.is('Dashboard').first dashboardWin.elementWaitFor({ waitType: "Appear", }); dashboardWin.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName }); dashboardWin.radioButtons.allItems[0].checkboxSet({ targetValue: "Disable" }); dashboardWin.radioButtons.allItems[1].checkboxSet({ targetValue: "Enable" }); dashboardWin.checkBoxes.allItems[1].checkboxSet({ targetValue: "Enable" }); dashboardWin.radioButtons.allItems[3].checkboxSet({ targetValue: "Enable" }); if (dashboardWin.popupButtons.allItems[0].invalidate().value.value !== "BWF (.WAV)") { dashboardWin.popupButtons.allItems[0].popupMenuSelect({ menuPath: ["BWF (.WAV)"] }); } if (dashboardWin.popupButtons.allItems[1].invalidate().value.value !== "48 kHz") { dashboardWin.popupButtons.allItems[1].popupMenuSelect({ menuPath: ["48 kHz"] }); } if (dashboardWin.popupButtons.allItems[1].invalidate().value.value !== "24-bit") { dashboardWin.popupButtons.allItems[2].popupMenuSelect({ menuPath: ["24-bit"] }); } dashboardWin.buttons.whoseTitle.is('Create').first.elementClick(); dashboardWin.elementWaitFor({ waitType: "Disappear" }); openSession(sessionName, aafList) } function setDataImportOptions() { let importSessionButtons = sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.groups.whoseTitle.is('Session Data').first sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.elementWaitFor({ waitType: "Appear" }); importSessionButtons.checkBoxes.allItems[3].checkboxSet({ targetValue: "Enable" }); importSessionButtons.checkBoxes.allItems[0].checkboxSet({ targetValue: "Disable" }); importSessionButtons.checkBoxes.allItems[2].checkboxSet({ targetValue: "Disable" }); importSessionButtons.checkBoxes.allItems[4].checkboxSet({ targetValue: "Enable" }); importSessionButtons.checkBoxes.allItems[1].checkboxSet({ targetValue: "Disable" }); if (importSessionButtons.popupButtons.first.invalidate().value.value !== "All") { importSessionButtons.popupButtons.first.popupMenuSelect({ menuPath: ["All"] }); } sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.radioButtons.allItems[2].checkboxSet({ targetValue: "Enable" }); sf.ui.proTools.windows.whoseTitle.is('Import Session Data').first.radioButtons.allItems[1].checkboxSet({ targetValue: "Enable" }); var trackDataToImportWin = sf.ui.proTools.windows.whoseTitle.is('Track Data to Import').first var checkBoxes = trackDataToImportWin.groups.whoseTitle.is('Track Data').first.checkBoxes importSessionButtons.buttons.whoseTitle.is('Choose...').first.elementClick(); trackDataToImportWin.elementWaitFor({ waitType: "Appear" }); checkBoxes.allItems[0].checkboxSet({ targetValue: "Enable" }); checkBoxes.allItems[1].checkboxSet({ targetValue: "Enable" }); checkBoxes.allItems[2].checkboxSet({ targetValue: "Disable" }); checkBoxes.allItems[3].checkboxSet({ targetValue: "Disable" }); checkBoxes.allItems[4].checkboxSet({ targetValue: "Disable" }); checkBoxes.allItems[5].checkboxSet({ targetValue: "Disable" }); checkBoxes.allItems[6].checkboxSet({ targetValue: "Disable" }); trackDataToImportWin.buttons.whoseTitle.is('OK').first.elementClick(); trackDataToImportWin.elementWaitFor({ waitType: "Disappear" }); } function openSession(sessionName, aafList) { sf.ui.proTools.appActivate(); var win = sf.ui.frontmostApp.focusedWindow; sf.keyboard.type({ text: '/' }); var sheet = win.sheets.first.elementWaitFor({ timeout: 500 }, 'Could not find "Go to" sheet in the Save/Open dialog').element; //// //////////////////////////Set Path sheet.comboBoxes.first.value.value = aafList; sheet.buttons.whoseTitle.is('Go').first.elementClick({}, 'Could not click "Go"'); win.sheets.first.elementWaitFor({ waitForNoElement: true, timeout: 500 }, '"Go to" sheet didn\'t close in time'); let openWin = sf.ui.proTools.windows.whoseTitle.is('Open').first.buttons.whoseTitle if (sf.ui.proTools.windows.whoseTitle.is('Save').first.textFields.exists) { sf.ui.proTools.windows.whoseTitle.is('Save').first.textFields.first.elementSetTextFieldWithAreaValue({ value: sessionName, }); } if (openWin.is('Open').exists) { openWin.is('Open').first.elementClick(); } if (sf.ui.proTools.windows.whoseTitle.is('Save').exists) { sf.ui.proTools.windows.whoseTitle.is('Save').first.buttons.allItems[2].elementClick(); } win.sheets.first.elementWaitFor({ waitForNoElement: true, timeout: 500 }, 'Save didn\'t close in time'); } function saveAndClose() { sf.ui.proTools.appActivate(); while (true) { //// wait for complete tasks if (sf.ui.proTools.windows.whoseTitle.is('Task Manager').first.children.whoseRole.is("AXStaticText").first.invalidate().value.value == "0 items") //// save and exit procedures if ((sf.ui.proTools.mainWindow.invalidate().sessionPath !== null || sf.ui.proTools.getMenuItem('File', 'Close Session').isEnabled) || sf.ui.proTools.confirmationDialog.exists) { sf.ui.proTools.waitForNoModals(); sf.ui.proTools.menuClick({ menuPath: ["File", "Save"] }); sf.ui.proTools.menuClick({ menuPath: ["File", "Close Session"] }); if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Save').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Save').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", onError: "Continue" }); } if (sf.ui.proTools.confirmationDialog.invalidate().buttons.whoseTitle.is('Cancel').first.exists) { sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is('Cancel').first.elementClick(); sf.ui.proTools.confirmationDialog.elementWaitFor({ waitType: "Disappear", onError: "Continue" }); } sf.ui.proTools.waitForNoModals(); } else { break } } sf.wait({ intervalMs: 500 }) } ///================== MAIN ====================/// function batchNewSession() { ///////////////////////////////////////////////////////////// sf.ui.proTools.appActivate(); ///////////////////////////////////////////////////////////// var aafPath = sf.ui.finder.selectedPaths; for (let i = 0; i < aafPath.length; i++) { //////////////// AAF //////////////// let aafList = aafPath[i] sf.ui.proTools.menuClick({ menuPath: ["File", "Open Session..."] }); let savePath = aafList.split("/").slice(0, -1).join("/") let sessionName = aafList.split("/").slice(-1).join().split(".").slice(0, -1).join(".") openSession(sessionName, aafList) dashboard(sessionName, savePath, aafList) setDataImportOptions() closeImportDataWin() saveAndClose() } alertSound() alert("Done!") } batchNewSession()
Fixes and lessons on better solutions will be welcome.
Thank you so much everyone.
Kitch Membery @Kitch2020-12-07 10:17:15.385Z
Nice work mate!