#!/usr/bin/env python3
"""
assemble.py — 動画と静止画を、短いクロスフェードで 1 本につなぐ（ffmpeg を呼ぶだけ）

FLF2V で作った動画は、端のコマがそろっていれば短いクロスフェードでつながります。
ロゴのように「最後は元の画像そのもの」を見せたい所には、静止画を挟みます。

  python3 assemble.py --out keyvisual.mp4 --fade 0.3 \
      still:white.png:0.6 s1-white-logo.mp4 still:logo.png:1.8 s2-logo-center.mp4 \
      s3-center-right.mp4 loop.mp4 loop.mp4 s5-right-white.mp4 still:white.png:0.8

  動画は「パス」、静止画は「still:パス:秒」と書きます。
  --size を出力の大きさにする（既定 1280x720）。静止画はその大きさで用意すると、ロゴがくっきり出る。
  音は外します（BGM は編集で足す）。ffmpeg が要ります。
"""
import argparse, subprocess, json


def duration(path):
    out = subprocess.run(["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "json", path],
                         capture_output=True, text=True, check=True).stdout
    return float(json.loads(out)["format"]["duration"])


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--out", required=True)
    ap.add_argument("--fade", type=float, default=0.3)
    ap.add_argument("--fps", type=int, default=24)
    ap.add_argument("--crf", type=int, default=18, help="小さいほど高画質。ロゴを含むなら 18 前後")
    ap.add_argument("--size", default="1280x720")
    ap.add_argument("parts", nargs="+")
    a = ap.parse_args()
    w, h = a.size.split("x")

    inputs, lengths = [], []
    for p in a.parts:
        if p.startswith("still:"):
            _, path, sec = p.split(":")
            inputs += ["-loop", "1", "-t", sec, "-framerate", str(a.fps), "-i", path]
            lengths.append(float(sec))
        else:
            inputs += ["-i", p]
            lengths.append(duration(p))

    norm = [f"[{i}:v]fps={a.fps},scale={w}:{h}:flags=lanczos,format=yuv420p,setsar=1[v{i}]" for i in range(len(lengths))]
    chain, prev, t = [], "v0", lengths[0]
    for i in range(1, len(lengths)):
        out = f"x{i}"
        chain.append(f"[{prev}][v{i}]xfade=transition=fade:duration={a.fade}:offset={t - a.fade:.3f}[{out}]")
        prev, t = out, t + lengths[i] - a.fade
    graph = ";".join(norm + chain)
    subprocess.run(["ffmpeg", "-loglevel", "error", "-y", *inputs, "-filter_complex", graph, "-map", f"[{prev}]",
                    "-an", "-c:v", "libx264", "-crf", str(a.crf), "-pix_fmt", "yuv420p", "-movflags", "+faststart", a.out],
                   check=True)
    print(f"{a.out}: {t:.1f} 秒（{len(lengths)} 個をつないだ）")


if __name__ == "__main__":
    main()
