I cinque video «Come si gioca» dentro il gioco: pulsante «Guarda il video» nell'aiuto di briscola, tressette, scopa, bocce e biliardo, player a tutto schermo con l'audio (il gioco e la musica si fermano, Esc torna al tavolo). video/pubblica.py li taglia dall'arrivo nel posto, li comprime per il web (~4,5 MB l'uno) e fa la copertina. Il favicon e i video copiati anche nell'immagine Docker (il Regolino online dava 404); test che ogni cartella di assets usata dal gioco sia nel Dockerfile
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A1dxvtsZx8NE9fwjXUNDBr
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Porta i video «Come si gioca» nel gioco (assets/video/, story.tutorials): da quando si arriva nel posto del gioco
|
||||
(la prima battuta del narratore), più piccoli e compressi per il web, con una copertina.
|
||||
|
||||
python3 video/pubblica.py briscola tressette scopa bocce biliardo
|
||||
|
||||
Prima la ripresa e il montaggio (video/SCALETTA-CARTE.md): legge video/out/tutorial-<gioco>.mp4 e il cues.json della
|
||||
ripresa. Il titolo del gioco all'inizio della ripresa non serve, e col ritaglio dei tavoli verrebbe tagliato ai lati.
|
||||
"""
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
VIDEO = Path(__file__).resolve().parent
|
||||
GIOCO = VIDEO.parent
|
||||
RIPRESE = Path.home() / "Workspaces/qemu/qemu-iso-lab/artifacts/tour/out"
|
||||
|
||||
|
||||
def durata(f: Path) -> float:
|
||||
return float(subprocess.run(["ffprobe", "-v", "error", "-show_entries", "format=duration", "-of", "csv=p=0", str(f)],
|
||||
capture_output=True, text=True, check=True).stdout)
|
||||
|
||||
|
||||
for gioco in sys.argv[1:]:
|
||||
ripresa = RIPRESE / f"tutorial-{gioco}"
|
||||
cues = json.loads((ripresa / "cues.json").read_text())["cues"]
|
||||
# Lo stesso scarto di monta.py: la ripresa parte un po' prima del copione.
|
||||
scarto = max(0.0, durata(ripresa / "raw.mkv") - (cues[-1]["end"] + 1.2))
|
||||
inizio = max(0.0, cues[0]["start"] + scarto - 0.4)
|
||||
dentro, fuori = VIDEO / "out" / f"tutorial-{gioco}.mp4", GIOCO / "assets" / "video" / f"{gioco}.mp4"
|
||||
fuori.parent.mkdir(exist_ok=True)
|
||||
subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-ss", f"{inizio:.2f}", "-i", str(dentro),
|
||||
"-vf", "scale=trunc(iw*0.75/2)*2:-2", "-c:v", "libx264", "-preset", "slow", "-crf", "27", "-pix_fmt", "yuv420p",
|
||||
"-af", "afade=t=in:d=0.4", "-c:a", "aac", "-b:a", "96k", "-movflags", "+faststart", str(fuori)], check=True)
|
||||
# La copertina: un momento al tavolo, a un terzo del video.
|
||||
subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-ss", f"{durata(fuori) / 3:.1f}", "-i", str(fuori), "-frames:v", "1",
|
||||
"-q:v", "4", str(fuori.with_suffix(".jpg"))], check=True)
|
||||
for f in (fuori, fuori.with_suffix(".jpg")):
|
||||
f.chmod(0o644)
|
||||
print(f"-> {fuori} ({durata(fuori):.0f} s, {fuori.stat().st_size / 1e6:.1f} MB), da {inizio:.1f} s")
|
||||
Reference in New Issue
Block a user