No internet connection
  1. Home
  2. Support

Using an API of another program in Soundflow - AIRTABLE

By Mitch Willard @Mitch_Willard_the2nd
    2023-10-13 00:37:49.162Z

    Hey @Kitch

    We currently use a program called Airtable, which is where we have all our Mix Projects request come in to see what is needed, who is working on the mix etc etc.

    We currently have successfully been using Soundflow to trigger things in the program, as an example, we have a macro that bounces/exports/emails when a job is complete, which will then also in turn mark off the relevant fields we need to fill out in Airtable.

    I was wondering if you could give me an insight into whether we could get better access to the program through the API through Soundflow?

    At the moment we are using UI elements, but the elements line of code are very very long.

    Is there a way for me to have the API in Soundflow to better write and implement the code similar to the Pro Tools API?

    Apologies if I’m not explain very well.

    Cheers

    Mitch

    Solved in post #7, click to view
    • 8 replies
    1. S
      SoundFlow Bot @soundflowbot
        2023-10-13 00:37:51.909Z

        Thanks for contacting SoundFlow support.

        Please note, that the best way to get help with a script, macro or other content installed from the Store or content that you've made yourself, is to select the script/macro, then click the red Need help button, and then click "Get help with this script or macro".
        By using this method, we will get access to more information and so should be able to help you quicker.
        You can read more about how this works here: bit.ly/sfscripthelp

        If you're seeing an error that isn't related to scripts or macros, and you think this is a bug in SoundFlow, please file a Help/Issue bug report.
        You can see how to do this by going to bit.ly/sfhelpissue

        1. Kitch Membery @Kitch2023-10-13 00:48:08.095Z

          Hi Mitch,

          Can you provide an example of some code that you are working with where the lines are very long?

          Thanks in advance.

          1. Mitch Willard @Mitch_Willard
              2023-10-13 00:58:21.901Z

              Sure thing @Kitch

              Here it is below.

              Having no trouble with the script, however, AIRTABLE will update semi regularly and the lines change ever so slightly. sometimes in the middle of the line which can be a matter of deleting something tiny like groups.first or changing .first to allItems[0] or allItems[1] etc

              Would having access to the API help this issue at all?

              function updateAirtableTicket(mixer, audioUpdate, sessionPath, ticketName, ticketNumber, ticketsLength) {
              
                  function openHiddenAirtableFields() {
                      const mixerFieldHeader = sf.ui.app("com.FormaGrid.Airtable").mainWindow.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO").first.groups.first.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO - Airtable").first.groups.first.groups.allItems[1].groups.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[4].buttons.first.groups.allItems[1].children.whoseRole.is("AXStaticText").first;
                      const hiddenFieldsOpen = sf.ui.app("com.FormaGrid.Airtable").mainWindow.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO").first.groups.first.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO - Airtable").first.groups.first.groups.allItems[1].groups.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].buttons.allItems[2].children.whoseRole.is("AXStaticText").first;
              
                      if (!mixerFieldHeader.exists) {
                          try {
                              hiddenFieldsOpen.elementClick();
                          } catch (err) {
                              hiddenFieldsOpen.elementClick();
                          } finally { sf.wait({ intervalMs: 2000 }) }
                      };
                  };
              
                  function updateAirtableTicket(mixer, audioUpdate, sessionPath) {
              
                      const airtable = sf.ui.app("com.FormaGrid.Airtable").mainWindow.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO").first.groups.first.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO - Airtable").first.groups.first.groups.allItems[1].groups;
                      const airtableTicket = airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups;
                      const airtableMixerBtn = airtableTicket.allItems[4].groups.allItems[1].groups.first.groups.first.buttons.first
                      const airtableMixerfield = airtableTicket.allItems[4].groups.allItems[1].groups.first.groups.first.buttons.first.groups.first.groups.first.children.whoseRole.is("AXStaticText").first;
                      const airtableAudioUpdatesBtn = airtableTicket.allItems[4].groups.allItems[3].groups.first.groups.first.buttons.first
                      const airtableAudioUpdatesfield = airtableTicket.allItems[4].groups.allItems[3].groups.first.groups.first.buttons.first.groups.first.groups.first.children.whoseRole.is("AXStaticText").first;
              
                      function updateAirtableElement(update, field, btn) {
              
                          const airtable = sf.ui.app("com.FormaGrid.Airtable").mainWindow.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO").first.groups.first.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO - Airtable").first.groups.first.groups.allItems[1].groups;
                          const airtableUpdateText = airtable.allItems[35].groups.first.comboBoxes.first;
                          const airtableUpdateSelect = airtable.allItems[35].groups.first.children.whoseRole.is("AXList").first.groups.first.children.whoseRole.is("AXStaticText").allItems[0]
              
                          function updateField(update, field, btn) {
                              btn.elementClick();
                              sf.wait({ intervalMs: 200 })
                              airtableUpdateText.elementSetTextFieldWithAreaValue({
                                  value: update,
                              });
                              if (airtableUpdateText.value.value != update) {
                                  sf.wait({ intervalMs: 200 })
                                  airtableUpdateText.elementSetTextFieldWithAreaValue({
                                      value: update,
                                  });
                              }
                              sf.wait({ intervalMs: 500 })
                              airtableUpdateSelect.elementClick();
                          };
              
                          if (field.exists) {
              
                              if (field.value.value != update) {
                                  try {
                                      updateField(update, field, btn);
                                  } catch (err) {
                                      sf.wait({ intervalMs: 500 });
                                      updateField(update, field, btn);
                                  } finally { }
                              };
              
                          } else if (!field.exists) {
                              try {
                                  updateField(update, field, btn);
                              } catch (err) {
                                  sf.wait({ intervalMs: 500 });
                                  updateField(update, field, btn);
                              } finally { }
              
                          };
              
                      };
              
                      try {
                          if (mixer != null)
                              updateAirtableElement(mixer, airtableMixerfield, airtableMixerBtn);
              
                          if (audioUpdate != null)
                              updateAirtableElement(audioUpdate, airtableAudioUpdatesfield, airtableAudioUpdatesBtn)
              
                          if (sessionPath != null) {
              
                              airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[3].groups.first.groups.first.textAreas.first.elementSetTextFieldWithAreaValue({
                                  value: sessionPath
                              });
              
                              sf.wait({ intervalMs: 200 });
              
                              if (airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[3].groups.first.groups.first.textAreas.first.value.value != sessionPath) {
                                  airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[3].groups.first.groups.first.textAreas.first.elementSetTextFieldWithAreaValue({
                                      value: sessionPath
                                  });
                              };
              
                          };
                      } catch (err) {
                          if (mixer != null)
                              updateAirtableElement(mixer, airtableMixerfield, airtableMixerBtn);
              
                          if (audioUpdate != null)
                              updateAirtableElement(audioUpdate, airtableAudioUpdatesfield, airtableAudioUpdatesBtn)
              
                          if (sessionPath != null) {
              
                              airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[3].groups.first.groups.first.textAreas.first.elementSetTextFieldWithAreaValue({
                                  value: sessionPath
                              });
              
                              sf.wait({ intervalMs: 200 });
              
                              if (airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[3].groups.first.groups.first.textAreas.first.value.value != sessionPath) {
                                  airtable.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.allItems[1].groups.allItems[3].groups.first.groups.first.textAreas.first.elementSetTextFieldWithAreaValue({
                                      value: sessionPath
                                  });
                              };
              
                          };
                      } finally { }
              
                  };
              
                  const airtable = sf.ui.app("com.FormaGrid.Airtable");
                  const airtableMainWindow = airtable.mainWindow.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO").first.groups.first.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO - Airtable").first.groups.first.groups.allItems[1].groups
                  const allTicketsInColumns = airtableMainWindow.allItems[2].groups.first.groups.allItems[1].groups.allItems[1].groups.first
                      .groups.first.groups.first.groups.first.groups.first.groups.first;
              
              
                  sf.app.launch({
                      path: "/Applications/Airtable.app",
                  });
              
                  airtable.appActivate();
                  airtable.appActivateMainWindow();
              
                  sf.wait({ intervalMs: 200 });
              
              
                  for (var i = 0; i < ticketsLength; i++) {
              
                      if (allTicketsInColumns.groups.allItems[+ticketNumber].groups.first.groups.first.groups.first.groups.first.groups.allItems[i].children.whoseRole.is("AXHeading").first.children.whoseRole.is("AXLink").first.children.whoseRole.is("AXStaticText").whoseValue.is(ticketName).first.exists) {
                          allTicketsInColumns.groups.allItems[+ticketNumber].groups.first.groups.first.groups.first.groups.first.groups.allItems[i].children.whoseRole.is("AXHeading").first.children.whoseRole.is("AXLink").first.children.whoseRole.is("AXStaticText").whoseValue.is(ticketName).first.elementClick();
                          break;
                      };
                  };
              
              
                  sf.wait({ intervalMs: 2000 });
              
                  openHiddenAirtableFields();
              
                  updateAirtableTicket(mixer, audioUpdate, sessionPath);
              
                  sf.wait({ intervalMs: 200 });
              
                  sf.ui.app("com.FormaGrid.Airtable").mainWindow.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO").first.groups.first.groups.first.groups.first.groups.first.groups.first.children.whoseRole.is("AXWebArea").whoseTitle.is("AUDIO LIST: AUDIO - Airtable").first.groups.first.groups.allItems[1].groups.allItems[34].groups.first.groups.whoseDescription.is("Detail view dialog").first.groups.first.groups.first.buttons.whoseDescription.is("Close dialog").first.children.whoseRole.is("AXImage").first.elementClick();
              
              };
              
              1. Kitch Membery @Kitch2023-10-13 02:26:13.924Z

                Thanks for providing that Mitch.

                I can see that AIRTABLE's UI element paths are quite bloated and have many children to deal with. There is however still a lot of room for refactoring your script, which would make the code much easier to manage.

                With that said, I understand your desire to have access to the AIRTABLE API through SoundFlow.

                Do you know if AIRTABLE has a REST API with good documentation? If so we may be able to help.

                @chrscheuer do you have any thoughts on this?

                1. Mitch Willard @Mitch_Willard
                    2023-10-13 03:27:12.346Z

                    Cheers @Kitch

                    You're right, very bloated, and seems to change all the time., wrote it only a few weeks ago and working on getting it down to be easier to manage, but any suggests would be awesome.

                    Airtable does in fact have a REST API
                    https://airtable.com/developers/web/api/introduction

                    If there is anyway to help, it would be much appreciated.

                    Cheers

                    Mitch

                    1. You can generally talk to a REST API through sf.net.httpRequest

                      Reply3 LikesSolution
                      1. Mitch Willard @Mitch_Willard
                          2023-10-17 01:22:21.966Z

                          OMG! this has saved me a world of pain!
                          Thanks @chrscheuer and @Kitch

                          1. Kitch Membery @Kitch2023-10-17 01:46:30.048Z

                            Awesome, Mitch!! Go get em!