Wait for Pro Tools to Open Session
After much toil and trouble trying to get a script to wait for Pro Tools to launch to start other actions, I discovered this little bit of code.
sf.ui.proTools.appWaitForActive();
while (!sf.ui.proTools.invalidate().hasValidUI) {
sf.wait({ intervalMs: 200 })
}
while (sf.ui.proTools.invalidate().windows.filter(w => w.title.value.match(/^(Edit:|Mix:)/)).length.valueOf() == 0) {
sf.wait({ intervalMs: 200 })
}
It took me SO long to realize I had to use the below bit to wait for Pro Tools to fully launch and have valid UI ↓
while (!sf.ui.proTools.invalidate().hasValidUI) {
sf.wait({ intervalMs: 200 })
}
I hope this helps someone else someday!
Linked from:
- Chad Wahlbrink @Chad2022-01-25 14:29:48.995Z
Updated this with an even more robust way to handle this!
Ryan DeRemer @Ryan_DeRemer
Hey @chadwahlbrink ,
Awesome bit of code, thanks for sharing! I have a question. What exactly is the "valid UI" the code is waiting for?
I just copy/pasted this code and put a Finder action after it, and the Finder action triggered while the initial loading popup was still going. Should this code be waiting for that loading popup to go away? I'm wondering if it's another quirk in my system.
Chris Shaw @Chris_Shaw2022-04-08 00:01:15.358Z
This line of code:
while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) }
is saying "AS long asPT doesn't have a valid UI (User Interface - ie. an open window and valid menubar), wait 200 ms and check again.
So your Finder action is triggered as soon as a PT window of any sort appears onscreen.
What you need to do is put this after the code above and before your Finder action:
sf.ui.proTools.waitForNoModals();
This will wait for all loading and activity windows to close before proceeding.
Depending on how long it takes for PT to open a session the you may have to repeat it a couple of timesRyan DeRemer @Ryan_DeRemer
@Chris_Shaw so the
sf.ui.proTools.waitForNoModals();
command specifically targets this loading dialog?I ended up finding this bit of code for checking for the "Create New.." to be enabled. Working so far. You have to put a wait command before it to wait for the loading to begin so the PT menu bar is accessible. Yours seems a bit more direct so I'll give it a try.
//WAIT FOR PRO TOOLS TO LAUNCH function waitForProTools() { var i = 0 while (!sf.ui.proTools.getMenuItem('File', 'Create New...').isEnabled) { if (i++ <= 100) sf.wait({ intervalMs: 100 }); } }
Ryan DeRemer @Ryan_DeRemer
@Chris_Shaw now I'm torn.
After the Finder action, the script goes back to PT to do other stuff.
When I used this code, the script triggers the Finder actions before the PT loading screen is done, BUT it still waits until PT is done loading before moving onto the PT stuff, without throwing any errors. Actually kind of nice, but I'm hesitant to trust it.
function waitForProTools() { while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) } sf.ui.proTools.waitForNoModals(); }
When I use this code, the Finder action waits until PT is fully done loading, which SEEMS more stable in my mind, but takes more time.
function waitForProTools() { while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) } for (var i = 0; i < 10; i++) { sf.ui.proTools.waitForNoModals(); } }
Thoughts?
- In reply toChris_Shaw⬆:SScott Robinson @Scott_Robinson
Hey Chris, I’m trying to figure out how to dismiss any dialogues that might pop up during PT load. I’m sure it’ll be impossible to cover ALL possibilities, but the goal is to at least get to the playback engine dialogue.
One, what would be a good way to stress test this and get PT to throw as many dialogues as possible in order to see what order they appear in?
Two, this code will obviously pause just once. Here’s what I’m working with to dismiss the HUI dialogue:
// 1) Grab the dialog by matching its text //const dlg = sf.ui.proTools.windows.whoseTitle.contains("Peripherals").first.dialogs.whose(message.startsWith("The original MIDI device")).first; const dlg = sf.ui.proTools.confirmationButtonDialog.children.whoseRole.is("AXStaticText").whoseValue.is("The original MIDI device associated with the MIDI controller \"HUI\" could not be located. Please choose an existing MIDI device in the MIDI controller section of the peripherals dialog.").first; while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) log("waiting for PT..."); } dlg.elementWaitFor({ timeout: timeout, pollingInterval: interval, onError: "Continue" }); if (dlg.exists) { sf.ui.proTools.confirmationButtonDialog.buttons.whoseTitle.is("OK").first.elementClick(); } log("Dismissed HUI dialog"); }
And this in my main function:
function main() { sf.app.launch({ path: "/Applications/Pro Tools.app", }); sf.ui.proTools.appActivate(); // possible select the audio device dialogue // sf.ui.proTools.confirmationDialog // const selectDeviceDlg = sf.ui.proTools.confirmationDialog.children.whoseRole.is("AXStaticText").whoseValue.is("Please select the audio device (Playback Engine).\n\nYou can change this at any time in the Playback Engine dialog (Setup menu > Playback Engine).").first // sf.ui.proTools.confirmationDialog.buttons.whoseTitle.is("Next").first // selectDeviceDlg.elementWaitFor({}); dismissHUIDialog(5000); sf.ui.proTools.appEnsureIsRunningAndActive({timeout: 15000,}); // close the dashboard window sf.ui.proTools.windows.whoseTitle.is("Dashboard").first.elementWaitFor({ waitType: "Appear"}); if (sf.ui.proTools.windows.whoseTitle.is("Dashboard").first.buttons.whoseTitle.is("Cancel").first.exists) { sf.ui.proTools.appActivateMainWindow(); sf.ui.proTools.windows.whoseTitle.is("Dashboard").first.buttons.whoseTitle.is("Cancel").first.elementClick(); } selectPlaybackEngine(TARGET_PLAYBACK_ENGINES); sf.ui.proTools.menuClick({ menuPath: ['File', 'Dashboard...'] });
As you can see in the comments I started trying to deal with the “select the audio device” dialogue but I started thinking there must be a better way to do this.
What would your strategy be or how would you go about this?
- In reply toRyan_DeRemer⬆:
Chad Wahlbrink @Chad2022-05-22 14:34:46.753Z2022-05-23 14:38:09.267Z
Hey @Ryan_DeRemer!
Glad @Chris_Shaw was able to explain the "valid UI" bit - that part tripped me up when I was getting started.
Here's an extended function that will open a Pro Tools session and dismiss all dialogs, which is my typical use case:
// Function - Dismiss Missing Files Dialog /** * @param {Object} obj * @param {"Skip All"|"Manually Find & Relink"|"Automatically Find & Relink"} obj.radioButton} */ function dismissMissingFilesDialog({ radioButton }) { const dlg = sf.ui.proTools.windows.whoseTitle.is("Missing Files").first; //Wait for dialog box to appear dlg.elementWaitFor({ timeout: 300, pollingInterval: 10, onError: "Continue", }); if (dlg.exists) { dlg.radioButtons.whoseTitle.is(radioButton).first.elementClick(); dlg.buttons.whoseTitle.is("Ok").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", timeout: 100, pollingInterval: 10, onError: "Continue", }); } } function waitForSessionToOpen() { try { while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }); } while (sf.ui.proTools.invalidate().windows.filter(w => w.title.value.match(/^(Edit:|Mix:)/)).length.valueOf() === 0) { // Ignore Missing I/O if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } catch (ex) { sf.wait({ intervalMs: 500 }); while (sf.ui.proTools.invalidate().windows.filter(w => w.title.value.match(/^(Edit:|Mix:)/)).length.valueOf() === null) { // Ignore Missing I/O if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } }
It's a bit hacky using the "try" / "catch," but there seems to be one moment when loading that CAN trip up the while loop otherwise.
I should retry using the "menu item enabled" bit you are using now! I had tried that at one point.
Ryan DeRemer @Ryan_DeRemer
@chadwahlbrink this is epic dude! I'm gonna give this a go.
I will say that the "menu item enabled" way is working great while waiting for a session to open, but I believe when I was working it out I couldn't find a way to universally wait for PT that works for both opening a session AND launching the app. I found that having 2 separate functions was more stable. I built Session Creator to be able to launch PT if it's not already open (my keyboard command runs the script in both PT and Finder), and it was a real struggle to figure that part out. The 2 different functions work beautifully so far.
I do have to say I LOVE the inclusion of dismissing the dialogs in your script. Very elegantly handled sir! Will definitely be adding this to the existing code. I'll post the result when I get a chance.
Chad Wahlbrink @Chad2022-05-23 02:12:43.924Z2022-05-23 14:38:20.040Z
I’ve been there! Yeah, the valid ui bit usually does great for launching, and the second part gets me through the loading dialogs.
I forgot to include one of the functions I was using courtesy of @Kitch. My original post is now updated.
// Function - Dismiss Missing Files Dialog /** * @param {Object} obj * @param {"Skip All"|"Manually Find & Relink"|"Automatically Find & Relink"} obj.radioButton} */ function dismissMissingFilesDialog({ radioButton }) { const dlg = sf.ui.proTools.windows.whoseTitle.is("Missing Files").first; //Wait for dialog box to appear dlg.elementWaitFor({ timeout: 300, pollingInterval: 10, onError: "Continue", }); if (dlg.exists) { dlg.radioButtons.whoseTitle.is(radioButton).first.elementClick(); dlg.buttons.whoseTitle.is("Ok").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", timeout: 100, pollingInterval: 10, onError: "Continue", }); } }
- TTristan Hoogland @Tristan
Hey @chadwahlbrink !
I've been using this with pretty decent success, but I do run into an issues with the
dismissMissingFilesDialog
function, which I realize has @Kitch OG status on.In a few cases I'm having it not selecting the "Skip All". I think I can catch the mouse move to select it, but it misses then stays on auto find & relink.
My workaround is to just auto find & relink at the dialog, then cancel it in task manager, but that's not ideal for a host of reasons as you can imagine.
Any ideas or experience on your end with this not working?
Great script!!
- In reply toTristan⬆:
Kitch Membery @Kitch2023-01-17 09:21:42.242Z
Hi @Tristan,
Legend, I'm not sure I have enough information to answer, or I'm not understanding the question. (Probably the latter)
What are you trying to achieve when dismissing the "Missing Files" dialog when it appears?
Are you trying to relink specific missing files? If so, manually relinking some files and not others would most probably constitute the need for an in-depth script written for the "Relink" window.
If that's not what you are trying to achieve...
When you say 'In a few cases I'm having it not selecting the "Skip All"' Do you mean that you are selecting one of the other options? (ie "Manually Find & Relink" or "Automatically Find & Relink"). If so can you paste the function call you are using here?
Image for reference
I'm also unsure what you mean by "I think I can catch the mouse move to select it, but it misses then stays on auto find & relink." Can you explain the order of events for this workflow?
Thanks in advance. :-)
- TTristan Hoogland @Tristan
Sorry for the vague question @Kitch (I should know better than to ask questions around midnight after a big day!)
In all cases I want it to select "Skip All" when the missing files dialog appears. The issue is it's been somewhat unreliable at doing that and thus doesn't always successfully make that selection (just stays on Auto find & relink) - but it also doesn't select OK, the missing files dialog just hangs along with the script.
My comment about the mouse was that sometimes I'll catch the mouse move over to attempt to select "Skip All" but misses then it ghosts quickly back to wherever it was before it tried.
It might have something to do with the way it's integrated with the rest of the script rather than on its own.
Hope that clears it up! Thanks brother!
- TTristan Hoogland @Tristan
There's a good chance it might have something to do with a confirmation dialog that's appearing a few lines before all this, standby (likely a tristan user error as per usual!). Will report back if it doesn't turn out to be a false alarm of an idiot.
- TTristan Hoogland @Tristan
Looks like I worked it out. I think the double while loop at the top of the original script was tripping up, if I replace it with just wait for the create new to be enabled it seems stable now!
Always the obvious things.
function waitForSessionToOpen() { try { while (!sf.ui.proTools.getMenuItem('File', 'Create New...').isEnabled) { sf.wait({ intervalMs: 100 }); // Ignore Missing I/O if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } catch (ex) { sf.wait({ intervalMs: 500 }); while (sf.ui.proTools.invalidate().windows.filter(w => w.title.value.match(/^(Edit:|Mix:)/)).length.valueOf() === null) { // Ignore Missing I/O if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } }
- TIn reply toChad⬆:Thomas Gloor @Thomas_Gloor
Hey @Ryan_DeRemer ,
I'm not sure I completely get if your code waits for Pro Tools to launch or for a session to be opened.
I've been trying to write (as a begginer...) a piece of script that would wait for a PT session to be opened to proceed with other tasks.
Is there a way to adapt your script to do so?Best,
T.
Ryan DeRemer @Ryan_DeRemer
@Thomas_Gloor The script I have on the store does both. Just search for RPD Session Creator, it may solve some issues for you in and of itself. :)
if you look at the source code, there are a couple of functions labelled as "Wait for Pro Tools to Launch" and "Wait for Session to Open". They're slightly different in how I decided to code them. The codes I posted above were early iterations of waiting for PT to launch.
sf.ui.proTools.waitForNoModals();
is a tricky beast, since sometimes PT produces multiple "Modals" in sequence, and you have to take into considertion whatsf.ui.proTools.invalidate().hasValidUI
actually means. As @Chris_Shaw pointed out, Pro Tools considers the launch loading screen to be a valid UI, thus the.hasValidUI
command ends too early, so that's why I'm using the commands below in sequence wrapped in a function. It waits for the loading screen to appear, then waits for that "modal" to go away. Hope this helps!function waitForPtLaunch() { while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) } for (var i = 0; i < 10; i++) { sf.ui.proTools.waitForNoModals(); } }
- TThomas Gloor @Thomas_Gloor
Hey @Ryan_DeRemer !
Thank you for the answer! I wasn't aware of your Session Creator! It's awsome
Just to be sure, for example, if I wanted to write a script that opens the "New session" dialog that I would setup manually (without your script, simply because I deal with all sorts of sessions, so presets rarely work at that stage) then press OK and wait for the session to be open, I could just add this to the code?function waitForPtLaunch() { while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) } for (var i = 0; i < 10; i++) { sf.ui.proTools.waitForNoModals(); } }
Sorry If my question sounds stupid. I'm deep into learning more about Javascript, and Soundflow, but it's a lot to take in. Im extremely thankful of anyone who answers my "Javascript 101" (should I say 000?) questions :D
Ryan DeRemer @Ryan_DeRemer
All good man! This community is great. That code is waiting for Pro Tools to launch, as in launching the app from the dock or Launchpad. Again, it's a little different because the UI is different. You'd want something like this for waiting for a session to open. (This is the code I use in Session Creator. FYI if you install it and click on the "Create New Session" directory, at the top right you should see a button that says "View Source", and you can see all the source code that I used.) The modals (progress bars) are different when opening a session, usually coming and going depending on the size and nature of the session. That's why I opted for waiting for a menu item to be enabled (menu items are generally disabled during loading).
function waitForPtSession() { sf.wait({ intervalMs: 500 }) while (!sf.ui.proTools.getMenuItem('File', 'Create New...').isEnabled) { sf.wait({ intervalMs: 100 }); } while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) } }
- TTristan Hoogland @Tristan
just thanking you for this one Ryan!
- In reply toChad⬆:Randy Brown @Randy_Brown
Hey all!
I decided to try plugging Ryan's waitForPtSession() function into Tristans because I loved the dialog handling idea and am getting some behavior in which Pro Tools opens, but sits in a stall after the session opens. No log or error messages; just a blue Soundflow icon at the top of my screen. The sessions open as expected, but my larger main() function never moves forward after this step.
Any help would be appreciated! Thanks all!
function waitForSessionToOpen() { try { sf.wait({ intervalMs: 500 }) while (!sf.ui.proTools.getMenuItem('File', 'Create New...').isEnabled) { sf.wait({ intervalMs: 100 }); } while (!sf.ui.proTools.invalidate().hasValidUI) { sf.wait({ intervalMs: 200 }) } while (!sf.ui.proTools.getMenuItem('File', 'Create New...').isEnabled) { sf.wait({ intervalMs: 100 }); // Ignore Missing I/O if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } catch (ex) { sf.wait({ intervalMs: 500 }); while (sf.ui.proTools.invalidate().windows.filter(w => w.title.value.match(/^(Edit:|Mix:)/)).length.valueOf() === null) { // Ignore Missing I/O if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plug-ins").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } } function dismissMissingFilesDialog({ radioButton }) { const dlg = sf.ui.proTools.windows.whoseTitle.is("Missing Files").first; //Wait for dialog box to appear dlg.elementWaitFor({ timeout: 300, pollingInterval: 10, onError: "Continue", }); if (dlg.exists) { dlg.radioButtons.whoseTitle.is(radioButton).first.elementClick(); dlg.buttons.whoseTitle.is("Ok").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", timeout: 100, pollingInterval: 10, onError: "Continue", }); } }
Chad Wahlbrink @Chad2025-02-07 23:09:40.736Z
Hi @Randy_Brown!
Thanks for the question. I made a quick video to demonstrate how I would revive this script:
The key points are:
- The "File" > "Create New..." menu command was changed to "File" > "New..." as of Pro Tools 2023.9. You can find the most up-to-date changes to UI that affect old scripts here: Pro Tools Scripting: Changes and Known Issues
- The UI for the "Missing AAX Plug-ins" dialog was changed to "Missing AAX Plugins" at some point - likely in Pro Tools 2024.10 where most instance of "Plug-in" changed to "Plugin"
- The UI for the "No" button on the "Missing AAX Plugins" dialog was changed to "OK" at some point as well.
Regardless, here is the script I would use in 2025 with Pro Tools 2024.10+:
// Wait for the Pro Tools To become active sf.ui.proTools.appActivate(); sf.ui.proTools.appWaitForActive(); // Invalidate the UI sf.ui.proTools.invalidate(); function waitForSessionToOpen() { // Wait for the "File" > "New" Menu item to be enabled while (!sf.ui.proTools.getMenuItem('File', 'New...').isEnabled) { // Ignore Missing I/O - If Window exists, click "No" if (sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Session Notes").first.buttons.whoseTitle.is("No").first.elementWaitFor({ waitType: "Disappear" }); } // Ignore Missing Plug-ins - If Window exists, click "OK" if (sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plugins").first.exists) { sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plugins").first.buttons.whoseTitle.is("OK").first.elementClick(); sf.ui.proTools.windows.whoseTitle.is("Missing AAX Plugins").first.buttons.whoseTitle.is("OK").first.elementWaitFor({ waitType: "Disappear" }); } // Dismiss missing files..."" dialog if it appears dismissMissingFilesDialog({ radioButton: "Skip All", }); // Dismiss generic alert if (sf.ui.proTools.windows.whoseDescription.is("alert").first.exists) { sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementClick(); sf.ui.proTools.windows.whoseDescription.is("alert").first.getElement("AXDefaultButton").elementWaitFor({ waitType: "Disappear" }); } sf.wait({ intervalMs: 200 }); } } function dismissMissingFilesDialog({ radioButton }) { const dlg = sf.ui.proTools.windows.whoseTitle.is("Missing Files").first; //Wait for dialog box to appear dlg.elementWaitFor({ timeout: 300, pollingInterval: 10, onError: "Continue", }); if (dlg.exists) { dlg.radioButtons.whoseTitle.is(radioButton).first.elementClick(); dlg.buttons.whoseTitle.is("Ok").first.elementClick(); dlg.elementWaitFor({ waitType: "Disappear", timeout: 100, pollingInterval: 10, onError: "Continue", }); } } waitForSessionToOpen(); log('Your Session is now open');
Randy Brown @Randy_Brown
Ahhh wow thank you brother! My first encounter with dinosaur-script hahahah. Oldie but goodie, won’t make that mistake again!
- SIn reply toChad⬆:Scott Robinson @Scott_Robinson
I was looking for a way to dismiss the “Missing HUI…” dialogue and this worked! Thanks!