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
"""Dense contact sheets — LOOK at the footage before planning anything.
One PNG grid per clip, frames sampled evenly across the FULL duration.
This is how you catch what probe metadata can't: talking heads, burned-in
captions/lyrics (often intermittent — mid-clip only), screen recordings,
misnamed files, shaky/unusable sections, and where the actual action lives.
Frames are laid out row-major. No timestamps are burned in (Homebrew ffmpeg
lacks drawtext), so use the printed "frame N ≈ N x interval" mapping — the
script prints the sampling interval per clip.
Usage:
contact_sheet.py work/clips.json --outdir work/sheets
contact_sheet.py work/clips.json --outdir work/sheets --interval 1.0 # denser
"""
import argparse, json, math, subprocess, sys
from pathlib import Path
COLS = 6
MIN_FRAMES, MAX_FRAMES = 12, 60
def sheet_for(clip, outdir, interval):
src = Path(clip["file"])
dur = clip["duration"]
n = max(MIN_FRAMES, min(MAX_FRAMES, math.ceil(dur / interval)))
step = dur / n
rows = math.ceil(n / COLS)
dst = outdir / f"{src.stem}_sheet.png"
tmp = outdir / f"{src.stem}_sheet.tmp.png"
vf = f"fps=1/{step:.4f},scale=320:-2,tile={COLS}x{rows}:padding=2"
r = subprocess.run(
["ffmpeg", "-y", "-v", "error", "-i", str(src),
"-vf", vf, "-frames:v", "1", str(tmp)],
capture_output=True, text=True)
if r.returncode != 0 or not tmp.exists():
tmp.unlink(missing_ok=True)
print(f" FAILED {src.name}: {r.stderr.strip()[-300:]}", file=sys.stderr)
return None
tmp.rename(dst)
print(f" {dst.name}: {n} frames, 1 every {step:.1f}s "
f"(frame N is at ~N x {step:.1f}s, row-major)")
return dst
def main():
ap = argparse.ArgumentParser()
ap.add_argument("clips_json")
ap.add_argument("--outdir", default="work/sheets")
ap.add_argument("--interval", type=float, default=2.0,
help="Target seconds between sampled frames (default 2.0; "
"capped at %d frames for very long clips — outliers "
"get coarser sampling, extract a segment first)" % MAX_FRAMES)
args = ap.parse_args()
clips = [c for c in json.loads(Path(args.clips_json).read_text())["clips"]
if "error" not in c]
outdir = Path(args.outdir)
outdir.mkdir(parents=True, exist_ok=True)
print(f"Contact sheets -> {outdir}/")
made = [sheet_for(c, outdir, args.interval) for c in clips]
ok = [m for m in made if m]
print(f"\n{len(ok)}/{len(clips)} sheets written. VIEW EVERY SHEET before "
f"building a cut plan: reject clips with burned-in text, talking "
f"heads, or screen content; note where the best action moments are "
f"(for in-points, hook, and closer).")
if len(ok) < len(clips):
sys.exit(1)
if __name__ == "__main__":
main()