No internet connection
  1. Home
  2. Script Sharing

Wait for Pro Tools to Open Session

By Chad Wahlbrink @Chad2022-01-11 19:16:58.823Z2022-01-25 14:29:27.953Z

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!

  • 24 replies

There are 24 replies. Estimated reading time: 45 minutes

  1. Chad Wahlbrink @Chad2022-01-25 14:29:48.995Z

    Updated this with an even more robust way to handle this!

    1. Ryan DeRemer @Ryan_DeRemer
        2022-04-07 17:24:16.699Z

        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.

        1. 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 times

          1. Ryan DeRemer @Ryan_DeRemer
              2022-04-08 02:15:49.997Z

              @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 });
                  }
              }
              
              1. Ryan DeRemer @Ryan_DeRemer
                  2022-04-08 02:53:26.443Z

                  @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
                    2025-04-28 18:47:05.731Z

                    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.

                    1. Ryan DeRemer @Ryan_DeRemer
                        2022-05-22 22:07:06.656Z

                        @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.

                        1. 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",
                                      });
                                  }
                              }
                          
                          1. TTristan Hoogland @Tristan
                              2023-01-17 08:25:47.138Z

                              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!!

                              1. 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. :-)

                                1. TTristan Hoogland @Tristan
                                    2023-01-17 15:50:04.337Z

                                    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!

                                    1. TTristan Hoogland @Tristan
                                        2023-01-17 16:23:43.868Z

                                        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.

                                        1. TTristan Hoogland @Tristan
                                            2023-01-17 16:40:02.904Z

                                            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 });
                                                    }
                                                }
                                            }
                                            
                          2. T
                            In reply toChad:
                            Thomas Gloor @Thomas_Gloor
                              2022-04-18 19:06:14.743Z

                              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.

                              1. Ryan DeRemer @Ryan_DeRemer
                                  2022-04-18 20:10:13.761Z

                                  @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 what sf.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();
                                      }
                                  }
                                  
                                  1. TThomas Gloor @Thomas_Gloor
                                      2022-04-18 20:29:42.185Z

                                      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

                                      1. Ryan DeRemer @Ryan_DeRemer
                                          2022-04-18 22:32:31.550Z

                                          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 })
                                              }
                                          }
                                          
                                          1. TTristan Hoogland @Tristan
                                              2023-01-13 04:28:59.988Z

                                              just thanking you for this one Ryan!

                                      2. In reply toChad:
                                        Randy Brown @Randy_Brown
                                          2025-02-07 09:52:53.247Z

                                          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",
                                                  });
                                              }
                                          }
                                          
                                          1. 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');
                                            
                                            1. Randy Brown @Randy_Brown
                                                2025-02-08 00:15:22.246Z

                                                Ahhh wow thank you brother! My first encounter with dinosaur-script hahahah. Oldie but goodie, won’t make that mistake again!

                                            2. S
                                              In reply toChad:
                                              Scott Robinson @Scott_Robinson
                                                2025-04-27 05:11:02.238Z

                                                I was looking for a way to dismiss the “Missing HUI…” dialogue and this worked! Thanks!