CtrlK
BlogDocsLog inGet started
Tessl Logo

gamussa/reels-producer-skill

help quicky produce instagram reels and youtube shorts

94

2.12x
Quality

96%

Does it follow best practices?

Impact

87%

2.12x

Average score across 3 eval scenarios

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

export_variants.pyskills/reel-builder/scripts/

#!/usr/bin/env python3
"""Export platform variants from the master render.

Vertical masters (9:16) go to the short-form platforms:
  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

A landscape master (16:9) is not a reel. Those three targets are skipped and a
single `youtube` variant is written instead — exporting a 16:9 cut as a Short
would letterbox it into a vertical frame.

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

VERTICAL = {
    "tiktok":    {"crf": "19"},
    "ig_reels":  {"crf": "18"},
    "yt_shorts": {"crf": "18"},
}
LANDSCAPE = {"youtube": {"crf": "18"}}


def master_dims(path):
    r = subprocess.run(["ffprobe", "-v", "error", "-select_streams", "v:0",
                        "-show_entries", "stream=width,height",
                        "-of", "csv=p=0:s=x", str(path)],
                       capture_output=True, text=True)
    if r.returncode != 0 or "x" not in r.stdout:
        sys.exit(f"Cannot read dimensions from {path}")
    w, h = (int(n) for n in r.stdout.strip().split("x")[:2])
    return w, h


def platforms_for(w, h):
    """Short-form targets only make sense for a taller-than-wide master."""
    return (VERTICAL, "vertical") if h > w else (LANDSCAPE, "landscape")


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)

    w, h = master_dims(args.master)
    platforms, shape = platforms_for(w, h)
    print(f"Master is {w}x{h} ({shape}) -> "
          f"{', '.join(platforms)}\n", flush=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()

.mcp.json

tile.json