#!/usr/bin/env python3
"""quotecard_render.py — premium HIGH LVL quote card (1080x1350) from a video frame + a quote."""
import argparse, json, subprocess, tempfile, urllib.parse
from pathlib import Path
HERE = Path(__file__).resolve().parent; STUDIO = HERE.parent
TPL = STUDIO / "dashboard" / "styles" / "quotecard.html"
FF = "/opt/homebrew/opt/ffmpeg-full/bin/ffmpeg"
def render(video, t, quote, out, by="19 KEYS", kick="MASTERCLASS · LONDON"):
out = Path(out); out.parent.mkdir(parents=True, exist_ok=True)
from playwright.sync_api import sync_playwright
with tempfile.TemporaryDirectory() as td:
frame = Path(td) / "f.jpg"
subprocess.run([FF, "-y", "-ss", str(float(t)), "-i", str(video), "-frames:v", "1",
"-vf", "scale=1080:1350:force_original_aspect_ratio=increase,crop=1080:1350",
"-q:v", "3", str(frame)], capture_output=True)
params = {"q": quote, "by": by, "kick": kick, "bg": frame.as_uri()}
url = TPL.as_uri() + "?" + urllib.parse.urlencode(params)
with sync_playwright() as pw:
b = pw.chromium.launch()
pg = b.new_page(viewport={"width": 1080, "height": 1350}, device_scale_factor=1)
pg.goto(url, wait_until="networkidle"); pg.wait_for_timeout(550)
pg.screenshot(path=str(out), clip={"x": 0, "y": 0, "width": 1080, "height": 1350})
b.close()
if not out.exists():
raise RuntimeError("card render failed")
return str(out)
if __name__ == "__main__":
a = argparse.ArgumentParser()
for x in ("video", "out", "quote"): a.add_argument("--" + x, required=True)
a.add_argument("--t", type=float, required=True); a.add_argument("--by", default="19 KEYS")
p = a.parse_args(); print(render(p.video, p.t, p.quote, p.out, p.by))