app
Premiere Pro Bridge
Public Made by Adomby adom
Let the AI edit video in Adobe Premiere Pro on your desktop (import, cut, trim, razor, effects, audio, previews, export) with no mouse or keyboard. Check adom-bridge bridge_list for 'premiere'; install with bridge_install + adom-wiki pkg install adom/premiere-bridge, then start with premiere_status.
main
anastasia
Premiere Pro Bridge 0.1.0: Rust bridge, UXP plugin, CEP helper, skills, macOS manifest
32fb583
10d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
//! Calling Adom Bridge back over its loopback direct API (ADOM_DIRECT_API_URL, fallback
//! ~/.adom/direct-api-port). Used for things only Adom Bridge can do — e.g. a read-only
//! window capture of Premiere's Program Monitor. Minimal HTTP/1.1 client: one POST, JSON.
use serde_json::{json, Value};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
fn base() -> Option<String> {
if let Ok(u) = std::env::var("ADOM_DIRECT_API_URL") {
return Some(u.trim_end_matches('/').to_string());
}
let p = crate::host::home_dir().join(".adom").join("direct-api-port");
let s = std::fs::read_to_string(p).ok()?;
let s = s.trim();
Some(if s.contains(':') { format!("http://{s}") } else { format!("http://127.0.0.1:{s}") })
}
pub async fn command(verb: &str, args: Value) -> Result<Value, String> {
let base = base().ok_or("Adom Bridge direct API not found (ADOM_DIRECT_API_URL unset)")?;
let hostport = base.strip_prefix("http://").ok_or("direct API must be http://")?.to_string();
let body = json!({"command": verb, "args": args}).to_string();
let token = std::env::var("ADOM_BRIDGE_TOKEN").unwrap_or_default();
let mut req = format!(
"POST /command HTTP/1.1\r\nHost: {hostport}\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n",
body.len()
);
if !token.is_empty() {
req.push_str(&format!("X-Adom-Bridge-Token: {token}\r\n"));
}
req.push_str("\r\n");
req.push_str(&body);
let fut = async {
let mut s = tokio::net::TcpStream::connect(&hostport).await.map_err(|e| e.to_string())?;
s.write_all(req.as_bytes()).await.map_err(|e| e.to_string())?;
let mut buf = Vec::new();
s.read_to_end(&mut buf).await.map_err(|e| e.to_string())?;
Ok::<Vec<u8>, String>(buf)
};
let buf = tokio::time::timeout(std::time::Duration::from_secs(60), fut).await.map_err(|_| "Adom Bridge timed out".to_string())??;
let text = String::from_utf8_lossy(&buf);
let (head, rest) = text.split_once("\r\n\r\n").ok_or("bad HTTP response")?;
let body = if head.to_ascii_lowercase().contains("transfer-encoding: chunked") { dechunk(rest) } else { rest.to_string() };
let mut v: Value = serde_json::from_str(&body).map_err(|e| format!("bad JSON from Adom Bridge: {e}"))?;
// Adom Bridge returns the verb's own JSON as a string in `output`.
if let Some(inner) = v["output"].as_str().and_then(|s| serde_json::from_str::<Value>(s).ok()) {
v["output"] = inner;
}
Ok(v)
}
fn dechunk(s: &str) -> String {
let mut out = String::new();
let mut rest = s;
while let Some((len, after)) = rest.split_once("\r\n") {
let n = usize::from_str_radix(len.trim(), 16).unwrap_or(0);
if n == 0 || after.len() < n {
break;
}
out.push_str(&after[..n]);
rest = after[n..].trim_start_matches("\r\n");
}
out
}