Six Colors
Six Colors

by Jason Snell & Dan Moren

Support this Site

Become a Six Colors member to read exclusive posts, get our weekly podcast, join our community, and more!

By Jason Snell

Automating Audio Hijack 4 with Shortcuts and JavaScript

automation
An Audio Hijack 4 automation switches blocks on and off and starts a session.

Rogue Amoeba’s Audio Hijack 4 is here, and while it’s got a bunch of interesting new features, my favorite is its support for automation via JavaScript and Shortcuts. While not quite everything in Audio Hijack is controllable (yet), most of it is—and it leads to some really interesting possibilities for users.

Audio Hijack can be controlled by scripts saved within the app itself (the app includes several built-in scripts as samples, and more are available on Rogue Amoeba’s website), via scripts saved as .ahcommand text files on your Mac, and via scripts sent directly from Shortcuts. Individual Sessions can run scripts via the new Scripting tab in each session; automations can fire off when a recording, session, or timer stops or starts. One script provided by Rogue Amoeba, Discard Small Files, will delete any recording less than five seconds in length. It’s a perfect match for the Session Stop event.

But Audio Hijack really unfolds when you integrate it with Shortcuts. Right now, the app provides three Shortcuts actions: Run a Script, Run JavaScript, and Run/Stop Session. Run a Script will run a script stored within the Audio Hijack app; Run JavaScript will run a script passed to the app from the shortcut, and Run/Stop Session lets you turn a particular session on or off. (There’s an “allow execution of external scripts” setting in Audio Hijack’s preferences that you’ll need to turn on first.)

That’s a very limited set of actions. But even if only the Run Javascript in Audio Hijack was available, all things would be possible. That’s because Audio Hijack 4’s initial JavaScript implementation allows you to detect the status of sessions and of individual blocks within sessions, and then turn them on and off. You can also affect some, but not all, of the variables within a block. You can set the filename and destination of a recording block, for instance, so a shortcut or script can adaptively name and place a file.

Simple examples

Here’s a simple example: I built a shortcut that toggles a particular Audio Hijack session on or off. The Run/Stop Session action has no awareness of the current state of the session, so first the shortcut runs a one-line JavaScript:

return (app.sessionWithName('Podcast lossless').running)

When Audio Hijack runs that script, it will return a result of true if the session is running, and false if it isn’t. At that point, my shortcut can handle what happens next.

Or say you want to build a shortcut that needs a list of what sessions are currently running. You’d use this script:

var sessionNames = [ ];
try {
app.runningSessions.forEach( session =>
{
    sessionNames.push(session.name);
})
return sessionNames;
}
catch(err){
return '';
}

What your shortcut does with that information is up to you.

Three-way switch

I wrote a shortcut that creates a three-way switch for when I’m recording and live-streaming The Incomparable. The shortcut detects the current state of the Incomparable session—whether it’s not running, streaming music live before the actual show begins, or streaming and recording our voices.

Every time the shortcut is activated, it updates the Audio Hijack session so that everything is in the right position for the next step in the workflow. If the shortcut runs when nothing is happening, it activates the session, turns off my microphone and ensures that recording is off, and flips an A/B switch to the music-streaming portion of the session. That script looks like this:

app.sessionWithName("Live - Incomparable").blocks.forEach( block =>
{
    if (block.name == "Recorder") {
block.disabled = true;
}})
app.sessionWithName("Live - Incomparable").blockWithName("musicapp").disabled = false;
app.sessionWithName("Live - Incomparable").blockWithName("USBPre").disabled = true;
app.sessionWithName("Live - Incomparable").blockWithName("Switch").switchPosition = 'A';
app.sessionWithName("Live - Incomparable").start()

If the shortcut detects that the session is running in music mode, it runs a different script that turns my microphone and all recording blocks on and disables the music.

app.sessionWithName("Live - Incomparable").blocks.forEach( block =>
{
    if (block.name == "Recorder"){
        block.disabled = false;
}})
app.sessionWithName("Live - Incomparable").blockWithName("musicapp").disabled = true;
app.sessionWithName("Live - Incomparable").blockWithName("USBPre").disabled = false;
app.sessionWithName("Live - Incomparable").blockWithName("Switch").switchPosition = 'B';

And of course, if the session is live streaming and recording, the next run of the shortcut turns the session off. If I have the Audio Hijack session window open when the scripts are running—no longer required in Audio Hijack 4!—the app puts on quite a show. Blocks turn on and off and switches flip, all without me doing a thing (except running the shortcut).

Integrating with Stream Deck

A portion of the Keyboard Maestro macro that updates a Stream Deck button.

I built my Incomparable three-way shortcut to be connected to a Stream Deck button, of course. But the problem with most Stream Deck buttons is that they don’t change based on the current state. So I altered my shortcut to output a variable called status when it finishes running, indicating the current status of my recording session.

Then, in Keyboard Maestro, I built a macro that runs my shortcut when I push the right button. That macro updates the image on the button based on the variable returned by the shortcut. Now when my live stream is in music mode, there’s an overlay of musical notes. And when we’re streaming live, a broadcasting symbol appears. When we’re off the air, there’s no overlay.

I also made a Keyboard Maestro macro for the simple toggle on/off shortcut I mentioned at the top of this article. The shortcut asks Audio Hijack the current status of the session and outputs that information to the Keyboard Maestro macro. The Keyboard Maestro macro updates the Stream Deck button accordingly. Now when I press that recording button, it lights up in red when it’s recording and goes back to black when it’s not.

Integrating with… anything, really

Since Audio Hijack 4’s JavaScript API includes app.runShortcut() and app.runShellCommand() commands, and since the app will run arbitrary JavaScript scripts from the filesystem, there’s almost nothing you can’t integrate with Audio Hijack 4. Kick off a python script from within Audio Hijack. Run an AppleScript that tells Audio Hijack to open a specific script file. Yes, everything needs to get passed through JavaScript (and no, JavaScript is not my favorite), but if you can hack your way through some basic scripting, you can do pretty much any job.

With that said, there’s still work to be done. I’d like to see Rogue Amoeba add JavaScript access to all variables in all blocks. (I’d like a script to be able to supply metadata to a Broadcast block, for instance.) And there should be more Shortcuts actions for the app. Yes, you can do almost anything via the Run JavaScript command, but not everyone is comfortable with JavaScript. It’s nice that Rogue Amoeba added Run/Stop Session as an action, rather than forcing everyone to use app.sessionWithName("session").start() every time, but there are probably other common use cases that could be made a bit more friendly to people who think in Shortcuts, not JavaScript.

Still! Audio Hijack was already one of my most vital Mac utilities, and now with scripting support, it’s already even more useful. I can’t wait to see what Audio Hijack 4 users build with the new automation tools.

If you appreciate articles like this one, support us by becoming a Six Colors subscriber. Subscribers get access to an exclusive podcast, members-only stories, and a special community.


Search Six Colors