"""vidgod_roto — MODELBEAST wrapper around VIDGOD's vg-roto. Stdlib-only on purpose: runs under the node's system python3 and shells out to ~/Documents/VIDGOD/bin/vg-roto, which brings its own venv (SAM 2.1 + MatAnyone). """ import argparse import json import shutil import subprocess import sys from pathlib import Path ap = argparse.ArgumentParser() ap.add_argument("--input", required=True) ap.add_argument("--outdir", required=True) ap.add_argument("--params", default="{}") args = ap.parse_args() p = json.loads(args.params) vg_roto = Path.home() / "Documents/VIDGOD/bin/vg-roto" if not vg_roto.exists(): sys.exit("VIDGOD not installed on this node — clone gitea monster/vidgod to " "~/Documents/VIDGOD and run setup/setup_venvs.sh") outdir = Path(args.outdir) workdir = outdir / "roto" cmd = [str(vg_roto), args.input, "--out", str(workdir), "--frame", str(int(p.get("frame", 0))), "--mode", p.get("mode", "matte"), "--max-size", str(int(p.get("max_size", -1)))] for pt in str(p.get("points", "")).split(";"): if pt.strip(): cmd += ["--point", pt.strip()] for pt in str(p.get("neg_points", "")).split(";"): if pt.strip(): cmd += ["--neg", pt.strip()] if str(p.get("box", "")).strip(): cmd += ["--box", str(p["box"]).strip()] print("+", " ".join(cmd), flush=True) subprocess.run(cmd, check=True, stderr=sys.stdout) # vg-roto writes _{alpha.mov,matte.mov,green.mp4} into workdir; lift them # to outdir top-level so the runner registers them as job outputs. outputs = [] for f in sorted(workdir.glob("*_*.m*")): dest = outdir / f.name shutil.move(str(f), dest) outputs.append({"path": f.name, "name": f.name}) if not outputs: sys.exit("vg-roto produced no outputs") shutil.rmtree(workdir, ignore_errors=True) (outdir / "result.json").write_text(json.dumps({ "outputs": outputs, "summary": {"mode": p.get("mode", "matte"), "files": [o["name"] for o in outputs]}, })) print("done:", ", ".join(o["name"] for o in outputs), flush=True)