#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""make_stills.py — 为「不走 H3 的静帧镜头」用 ffmpeg 做运镜（推/拉/摇/仰拍/特写）。

输入：05-分镜脚本/shots.json（每镜 dur / camera）、05-分镜脚本/关键帧/可爱版/SXX.png
输出：06-H3片段/stills/SXX.mp4（1920×1080，24fps，H.264，时长 = 该镜时长）
用法：python3 make_stills.py [--only S04,S09] [--force]
"""
import argparse, json, os, subprocess, sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent
os.chdir(ROOT)
KF = ROOT / "05-分镜脚本/关键帧/可爱版"
OUT = ROOT / "06-H3片段/stills"
OUT.mkdir(parents=True, exist_ok=True)
FPS = 24


def move_filter(camera, dur):
    """按运镜文字生成 zoompan 表达式（先放大到 3840 宽再裁到 1920×1080，保证平滑）。"""
    f = max(int(dur * FPS), 24)
    z_in = "min(1.0+0.10*on/%d,1.10)" % f
    z_out = "max(1.10-0.10*on/%d,1.00)" % f
    c = camera or ""
    if "拉" in c or "拉远" in c or "淡出" in c:
        z = z_out
        x = "iw/2-(iw/zoom/2)"
        y = "ih/2-(ih/zoom/2)"
    elif "特写" in c:
        z = "min(1.0+0.16*on/%d,1.16)" % f
        x = "iw/2-(iw/zoom/2)"
        y = "ih/2-(ih/zoom/2)"
    elif "摇" in c or "横移" in c or "长卷" in c or "跟" in c:
        z = "1.08"
        x = "(iw-iw/zoom)*on/%d" % f
        y = "ih/2-(ih/zoom/2)"
    elif "仰拍" in c or "上升" in c:
        z = "min(1.0+0.10*on/%d,1.10)" % f
        x = "iw/2-(iw/zoom/2)"
        y = "(ih-ih/zoom)*(1-on/%d)" % f
    else:  # 默认缓推
        z = z_in
        x = "iw/2-(iw/zoom/2)"
        y = "ih/2-(ih/zoom/2)"
    return (f"scale=3840:-2,zoompan=z='{z}':x='{x}':y='{y}':d={f}:s=1920x1080:fps={FPS},"
            f"eq=saturation=1.06:contrast=1.03,format=yuv420p")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--only", default=None)
    ap.add_argument("--force", action="store_true")
    ap.add_argument("--include-h3", action="store_true",
                    help="连 H3 镜也生成占位静帧片段（做全片预演版用；合片时 H3 成片优先）")
    a = ap.parse_args()

    shots = json.load(open("05-分镜脚本/shots.json", encoding="utf-8"))["shots"]
    h3 = set(json.load(open("prompts/h3/batch.json", encoding="utf-8"))[i]["shot"]
             for i in range(len(json.load(open("prompts/h3/batch.json", encoding="utf-8")))))
    want = {x.strip() for x in a.only.split(",")} if a.only else None

    made = skipped = 0
    for s in shots:
        sid = s["id"]
        if (sid in h3 and not a.include_h3) or (want and sid not in want):
            continue
        src = KF / f"{sid}.png"
        dst = OUT / f"{sid}.mp4"
        if dst.exists() and not a.force:
            skipped += 1
            continue
        if not src.exists():
            print("!! 缺关键帧", sid); continue
        cmd = ["ffmpeg", "-v", "error", "-y", "-loop", "1", "-i", str(src),
               "-t", f"{s['dur']:.3f}", "-vf", move_filter(s["camera"], s["dur"]),
               "-r", str(FPS), "-c:v", "libx264", "-preset", "medium", "-crf", "18",
               "-pix_fmt", "yuv420p", "-an", str(dst)]
        r = subprocess.run(cmd, capture_output=True, text=True)
        if r.returncode == 0:
            made += 1
            print(f"[ok] {sid} {s['dur']:.1f}s  {s['camera'][:18]}")
        else:
            print(f"[FAIL] {sid}: {r.stderr[-200:]}")
    print(f"静帧运镜：新生成 {made}，跳过 {skipped}（共 {len(shots)-len(h3)} 个静帧镜）")


if __name__ == "__main__":
    main()
