#!/usr/bin/env python3
"""MelonTV trial builder (v3): produced look.
Features: animated INTRO title card, KEN BURNS zoom on the still panel,
warm colour GRADE + vignette, and KINETIC pop-in captions.
Layout per segment = still image (Ken Burns, left) + animated video (right).
Every ffmpeg render is hard-capped to 20% CPU / 8G RAM (systemd scope).
Run from melontv/:  python3 scripts/build_trial.py
"""
import subprocess, os

CROP     = "crop=1880:2120:980:20"      # strip side bars -> portrait content
HALF     = "scale=960:1080,setsar=1,format=yuv420p"
CLIP_LEN = 4.9667
TRANS    = 1.0
STEP     = CLIP_LEN - TRANS
INTRO_LEN = 4.0
SOURCES  = ["input/clip1.mp4", "input/clip2.mp4"]
SEQ      = [0, 1] * 6
TRANSITIONS = ["fade", "wipeleft", "slideright", "circleopen", "smoothleft",
               "fadeblack", "wiperight", "slideup", "circleclose", "dissolve",
               "radial"]
# warm, saturated "kids TV" grade + gentle vignette
GRADE = ("eq=saturation=1.18:contrast=1.06:brightness=0.02,"
         "colorbalance=rs=0.04:gs=0.01:bs=-0.04,vignette=PI/5")

# hard cap: 20% of 12 cores (240%), 8G RAM ceiling, lowest priority
CAP = ["systemd-run", "--scope", "--quiet",
       "-p", "CPUQuota=240%", "-p", "MemoryMax=8G", "nice", "-n", "19"]

def run(cmd):
    subprocess.run(CAP + cmd, check=True)

def compose_segments():
    """seg0/seg1 : Ken Burns still (left) + animated video (right) -> 1920x1080."""
    for i, src in enumerate(SOURCES):
        still = "work/still%d.png" % i
        run(["ffmpeg", "-y", "-loglevel", "error", "-ss", "0", "-i", src,
             "-vf", "%s,scale=960:1080" % CROP, "-frames:v", "1", still])
        kb = ("zoompan=z='min(zoom+0.0006,1.10)':d=150:"
              "x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=960x1080:fps=30,"
              "setsar=1,format=yuv420p")
        run(["ffmpeg", "-y", "-loglevel", "error",
             "-loop", "1", "-i", still, "-i", src,
             "-filter_complex",
             "[1:v]%s,%s,fps=30[vid];[0:v]%s[img];[img][vid]hstack=inputs=2[out]"
             % (CROP, HALF, kb),
             "-map", "[out]", "-t", str(CLIP_LEN), "-r", "30",
             "-c:v", "libx264", "-crf", "18", "-preset", "veryfast", "-an",
             "work/seg%d.mp4" % i])
        print("composed work/seg%d.mp4 (Ken Burns still | video)" % i)

def stitch_grade_caption():
    """Crossfade 12 segments, then apply grade + kinetic captions in one pass."""
    inputs = []
    for idx in SEQ:
        inputs += ["-i", "work/seg%d.mp4" % idx]
    fc, prev = [], "[0:v]"
    for k in range(1, len(SEQ)):
        offset = round(STEP * k, 3)
        trans = TRANSITIONS[(k - 1) % len(TRANSITIONS)]
        out = "[v%d]" % k
        fc.append("%s[%d:v]xfade=transition=%s:duration=%s:offset=%s%s"
                  % (prev, k, trans, TRANS, offset, out))
        prev = out
    fc.append("%s%s,ass=captions/trial_kinetic.ass:fontsdir=/usr/share/fonts,"
              "format=yuv420p[vout]" % (prev, GRADE))
    print("stitching %d segments + grade + kinetic captions" % len(SEQ))
    run(["ffmpeg", "-y", "-loglevel", "error"] + inputs +
        ["-filter_complex", ";".join(fc), "-map", "[vout]",
         "-c:v", "libx264", "-crf", "19", "-preset", "medium",
         "-pix_fmt", "yuv420p", "work/main_final.mp4"])
    print("wrote work/main_final.mp4")

def build_intro():
    """Animated title card: blurred zooming bg + animated MelonTV title."""
    run(["ffmpeg", "-y", "-loglevel", "error", "-ss", "0", "-i", SOURCES[0],
         "-vf", "%s,scale=1920:1080:force_original_aspect_ratio=increase,"
                "crop=1920:1080,gblur=sigma=18,eq=brightness=-0.10:saturation=1.15"
                % CROP, "-frames:v", "1", "work/introbg.png"])
    n = int(INTRO_LEN * 30)
    run(["ffmpeg", "-y", "-loglevel", "error", "-loop", "1", "-i", "work/introbg.png",
         "-vf", "zoompan=z='min(zoom+0.0009,1.18)':d=%d:"
                "x='iw/2-(iw/zoom/2)':y='ih/2-(ih/zoom/2)':s=1920x1080:fps=30,"
                "fade=t=in:st=0:d=0.6,"
                "ass=captions/intro.ass:fontsdir=/root/.fonts/chess_shorts,"
                "format=yuv420p" % n,
         "-frames:v", str(n), "-r", "30",
         "-c:v", "libx264", "-crf", "19", "-preset", "medium", "work/intro.mp4"])
    print("wrote work/intro.mp4")

def finalize():
    """Crossfade intro into the main video -> final output."""
    off = round(INTRO_LEN - TRANS, 3)
    run(["ffmpeg", "-y", "-loglevel", "error",
         "-i", "work/intro.mp4", "-i", "work/main_final.mp4",
         "-filter_complex",
         "[0:v][1:v]xfade=transition=fade:duration=%s:offset=%s[vout]" % (TRANS, off),
         "-map", "[vout]", "-c:v", "libx264", "-crf", "19", "-preset", "medium",
         "-pix_fmt", "yuv420p", "-r", "30", "output/melontv_trial_1080p.mp4"])
    print("wrote output/melontv_trial_1080p.mp4")

if __name__ == "__main__":
    os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
    compose_segments()
    stitch_grade_caption()
    build_intro()
    finalize()
