help quicky produce instagram reels and youtube shorts
80
93%
Does it follow best practices?
Impact
47%
1.95xAverage score across 1 eval scenario
Passed
No known issues
#!/usr/bin/env python3
"""Export platform variants from the master render.
All platforms want 1080x1920 H.264 + AAC, but tuned:
tiktok - CRF 19, loudness -14 LUFS, <=287s
ig_reels - CRF 18, loudness -14 LUFS (IG recompresses hard; feed it quality)
yt_shorts - CRF 18, loudness -14 LUFS, BT.709 tags explicit
Also grabs a thumbnail JPEG at --thumb-at seconds, and — when a Gemini API
key is present (GEMINI_API_KEY / GOOGLE_AI_API_KEY / GOOGLE_API_KEY) — asks
stylize_thumbnail.py for sport-magazine variants (modern + 80s) so the human
can pick a cover from all three. Styled thumbs are a bonus: any failure there
warns and continues, never blocks the export.
Usage: export_variants.py work/master.mp4 --outdir exports/ --thumb-at 1.5 \
[--thumb-text "HOOK LINE"] [--no-stylize]
"""
import argparse, os, subprocess, sys
from pathlib import Path
PLATFORMS = {
"tiktok": {"crf": "19"},
"ig_reels": {"crf": "18"},
"yt_shorts": {"crf": "18"},
}
def run(cmd, label):
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0:
sys.exit(f"{label} failed:\n{r.stderr[-800:]}")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("master")
ap.add_argument("--outdir", default="exports")
ap.add_argument("--thumb-at", type=float, default=1.5)
ap.add_argument("--thumb-text", help="Cover headline for the stylized "
"thumbnails (magazine-cover mode)")
ap.add_argument("--no-stylize", action="store_true",
help="Skip Nano Banana thumbnail styling even if an API "
"key is present")
args = ap.parse_args()
outdir = Path(args.outdir)
outdir.mkdir(parents=True, exist_ok=True)
# write to .tmp.mp4 and rename on success so a partial export can never
# be mistaken for a deliverable
for name, cfg in PLATFORMS.items():
dst = outdir / f"{name}.mp4"
tmp = outdir / f"{name}.tmp.mp4"
print(f"Exporting {name}...", flush=True)
run(["ffmpeg", "-y", "-i", args.master,
"-c:v", "libx264", "-preset", "medium", "-crf", cfg["crf"],
"-profile:v", "high", "-level", "4.1", "-pix_fmt", "yuv420p",
"-colorspace", "bt709", "-color_primaries", "bt709", "-color_trc", "bt709",
"-c:a", "aac", "-b:a", "192k", "-ar", "48000",
"-af", "loudnorm=I=-14:TP=-1.0:LRA=11",
"-movflags", "+faststart", str(tmp)], name)
tmp.rename(dst)
thumb = outdir / "thumbnail.jpg"
thumb_tmp = outdir / "thumbnail.tmp.jpg"
run(["ffmpeg", "-y", "-ss", str(args.thumb_at), "-i", args.master,
"-frames:v", "1", "-q:v", "2", str(thumb_tmp)], "thumbnail")
thumb_tmp.rename(thumb)
# optional: sport-magazine styled variants of the same frame
has_key = any(os.environ.get(v) for v in
("GEMINI_API_KEY", "GOOGLE_AI_API_KEY", "GOOGLE_API_KEY"))
if args.no_stylize:
pass
elif not has_key:
print("(no Gemini API key — skipping stylized thumbnails; plain "
"frame grab only)")
else:
cmd = [sys.executable, str(Path(__file__).parent / "stylize_thumbnail.py"),
str(thumb), "--style", "all", "--outdir", str(outdir)]
if args.thumb_text:
cmd += ["--text", args.thumb_text]
r = subprocess.run(cmd)
if r.returncode != 0:
print("WARNING: thumbnail styling failed — continuing with the "
"plain frame grab", file=sys.stderr)
print(f"\nDeliverables in {outdir}/:")
for f in sorted(outdir.iterdir()):
print(f" {f.name} ({f.stat().st_size/1e6:.1f} MB)")
if __name__ == "__main__":
main()