Drive a recording from a script
Start a recording, sleep through the meeting, stop it, then list meetings and export the newest summary, all from a script that shells out to the meetily-pro CLI.
This workflow drives a full recording from a script: start a recording, let it run, stop it, then list meetings and export the newest one's summary. Every step shells out to the meetily-pro CLI on the same machine, so the script itself never touches a token. The CLI resolves the local token on its own.
The one gap: the CLI has no recording-state or wait command. There is no meetily-pro recording wait and nothing to poll for "is it still recording." So the script just sleeps for roughly the length of the meeting between recording start and recording stop, instead of waiting on an event.
Shell
A plain bash version. It uses jq to pull the id of the newest meeting out of the JSON list.
#!/usr/bin/env bash
set -euo pipefail
meetily-pro recording start
# No recording-state or wait command exists, so sleep instead of polling.
sleep 1800
meetily-pro recording stop
# meetings list --json returns the newest meeting first.
newest_id=$(meetily-pro meetings list --json | jq -r '.meetings[0].id')
meetily-pro meetings export "$newest_id" --format md > "$newest_id.md"
meetily-pro summary get "$newest_id"Wrap it in code
The same five commands, called as a subprocess from Python, Node, or Rust instead of a shell script.
import json
import subprocess
import time
def cli(*args):
result = subprocess.run(["meetily-pro", *args], capture_output=True, text=True, check=True)
return result.stdout
cli("recording", "start")
# No recording-state or wait command exists, so sleep instead of polling.
time.sleep(1800)
cli("recording", "stop")
meetings = json.loads(cli("meetings", "list", "--json"))["meetings"]
newest_id = meetings[0]["id"]
cli("meetings", "export", newest_id, "--format", "md")
print(cli("summary", "get", newest_id))const { execFileSync } = require("node:child_process");
function cli(...args) {
return execFileSync("meetily-pro", args, { encoding: "utf8" });
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function main() {
cli("recording", "start");
// No recording-state or wait command exists, so sleep instead of polling.
await sleep(1800 * 1000);
cli("recording", "stop");
const { meetings } = JSON.parse(cli("meetings", "list", "--json"));
const newestId = meetings[0].id;
cli("meetings", "export", newestId, "--format", "md");
console.log(cli("summary", "get", newestId));
}
main();Add one dependency to Cargo.toml: serde_json = "1".
use serde_json::Value;
use std::process::Command;
use std::thread::sleep;
use std::time::Duration;
fn cli(args: &[&str]) -> String {
let output = Command::new("meetily-pro")
.args(args)
.output()
.expect("failed to run meetily-pro");
String::from_utf8(output.stdout).expect("non-utf8 output")
}
fn main() {
cli(&["recording", "start"]);
// No recording-state or wait command exists, so sleep instead of polling.
sleep(Duration::from_secs(1800));
cli(&["recording", "stop"]);
let list_json = cli(&["meetings", "list", "--json"]);
let parsed: Value = serde_json::from_str(&list_json).expect("invalid json");
let newest_id = parsed["meetings"][0]["id"].as_str().expect("no meetings");
cli(&["meetings", "export", newest_id, "--format", "md"]);
println!("{}", cli(&["summary", "get", newest_id]));
}recording start and recording stop need the Record scope on the token the CLI resolves. Starting a recording captures your microphone, so only run this script when that is what you intend.
Last updated on
