#!/usr/bin/env python3
"""Rend un template HyperFrames du Motion Deck avec ses variables, à la bonne durée, avec ou sans voix.

Usage : python3 rendre_template.py <template> <vars.json | -> <sortie.mp4> [--voix <son.wav>]
  <template>  un dossier de templates-hf/ (typo-cinetique, ...) ou son chemin
  <vars.json> les variables (voir le README du template) ; « - » = les valeurs par défaut

Pourquoi ce lanceur : hyperframes render lit la durée dans l'attribut data-duration du HTML AVANT
d'exécuter le script de la composition ; une variable « duree » ne change donc pas la longueur du MP4
(mesuré le 29/09/2026 : duree=10 rendait 15 s). On copie le template, on y écrit la durée, on rend,
puis la voix se pose par ffmpeg (le template n'a pas de piste audio, il reste muet et réutilisable).
"""
import json, os, re, shutil, subprocess, sys, tempfile

ICI = os.path.dirname(os.path.abspath(__file__))
HF = 'hyperframes@0.8.73'


def main():
    a = sys.argv[1:]
    voix = None
    if '--voix' in a:
        i = a.index('--voix'); voix = os.path.abspath(a[i + 1]); del a[i:i + 2]
    if len(a) != 3:
        sys.exit(__doc__)
    tpl, vfile, out = a
    tpl = tpl if os.path.isdir(tpl) else os.path.join(ICI, tpl)
    out = os.path.abspath(out)
    vars_ = json.load(open(vfile)) if vfile != '-' else {}
    html = open(os.path.join(tpl, 'index.html')).read()
    defaut = re.search(r'"id":"duree"[^}]*"default":([0-9.]+)', html)
    duree = float(vars_.get('duree', defaut.group(1) if defaut else 15))
    tmp = tempfile.mkdtemp(prefix='hf-template-')
    try:
        dst = os.path.join(tmp, 'c')
        shutil.copytree(tpl, dst, ignore=shutil.ignore_patterns('node_modules', '.hyperframes', '*.mp4'))
        p = os.path.join(dst, 'index.html')
        h, n = re.subn(r'(data-composition-id="main"[^>]*?data-duration=")[0-9.]+(")', rf'\g<1>{duree:g}\g<2>', html)
        if n != 1:
            sys.exit('data-duration de la composition main introuvable')
        open(p, 'w').write(h)
        cmd = ['npx', '-y', HF, 'render', '--fps', '30', '--quality', 'delivery', '--workers', '4']
        if vars_:
            vf = os.path.join(tmp, 'vars.json'); json.dump(vars_, open(vf, 'w'), ensure_ascii=False); cmd += ['--variables-file', vf]
        muet = os.path.join(tmp, 'muet.mp4') if voix else out
        subprocess.run(cmd + ['-o', muet], cwd=dst, check=True)
        if voix:
            subprocess.run(['ffmpeg', '-v', 'error', '-y', '-i', muet, '-i', voix, '-map', '0:v', '-map', '1:a', '-c:v', 'copy',
                            '-c:a', 'aac', '-b:a', '192k', '-ar', '48000', '-af', f'apad,atrim=0:{duree:g}', '-t', f'{duree:g}',
                            '-movflags', '+faststart', out], check=True)
        print(f'rendu : {out} ({duree:g} s{", voix " + os.path.basename(voix) if voix else ", muet"})')
    finally:
        shutil.rmtree(tmp, ignore_errors=True)


if __name__ == '__main__':
    main()
