# -*- coding: utf-8 -*- """Selbsttest der Pipeline OHNE echte Clips. Erzeugt Dummy-Clips (testsrc2, 1280x720, 5 s) und Dummy-Audio (sine) in schnitt\\test\\, rendert je einen Short in crop und blur (3 Sprachen), eine Dummy-Folge in 3 Sprachen, holt ein letztes Bild und prueft alles mit ffprobe (Aufloesung, Dauer, Lautheit). python -I testlauf.py Schreibt nur nach schnitt\\test\\ (und Berichte nach schnitt\\berichte\\). """ import os import subprocess import sys from pathlib import Path sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # noetig bei python -I import pinolib as P # noqa: E402 T = P.SCHNITT / "test" PY = [sys.executable, "-I"] PIPE = P.SCHNITT / "pipeline" ok_alle = True zeilen = [] def log(s=""): print(s) zeilen.append(s) def ff(args): P.ffmpeg_lauf(args, was="Testdatei") def dummy_clip(pfad, nr): if pfad.exists(): return pfad.parent.mkdir(parents=True, exist_ok=True) ff(["-f", "lavfi", "-i", f"testsrc2=size=1280x720:rate=24:duration=5", "-vf", f"hue=h={(nr * 29) % 360},format=yuv420p", "-c:v", "libx264", "-crf", "20", "-pix_fmt", "yuv420p", str(pfad)]) def dummy_audio(pfad, sek, freq, db, stereo=False): if pfad.exists(): return pfad.parent.mkdir(parents=True, exist_ok=True) quelle = f"sine=frequency={freq}:duration={sek}:sample_rate=44100,tremolo=f=3:d=0.6,volume={db}dB" ff(["-f", "lavfi", "-i", quelle, "-ac", "2" if stereo else "1", str(pfad)]) def starte(name, args): log(f"$ {name}") r = subprocess.run(PY + [str(PIPE / name)] + [str(a) for a in args], capture_output=True) out = (r.stdout.decode("utf-8", "replace") + r.stderr.decode("utf-8", "replace")).strip() for z in out.splitlines(): log(" " + z) return r.returncode def pruefe(bedingung, text): global ok_alle log((" OK " if bedingung else " FEHL ") + text) ok_alle = ok_alle and bool(bedingung) def main(): P.init_konsole() clips = T / "clips" # --- Dummy-Material for i in range(1, 13): dummy_clip(clips / "folge01" / f"f01_c{i:02d}.mp4", i) dummy_clip(clips / "bausteine" / "k_05.mp4", 5) ton = T / "ton" for l, f, d in (("de", 220, -26), ("es", 247, -24), ("fr", 262, -28)): dummy_audio(ton / "shorts" / f"T001_{l}.wav", {"de": 24, "es": 27, "fr": 25}[l], f, d, stereo=(l == "es")) dummy_audio(ton / "shorts" / f"T002_{l}.wav", {"de": 26, "es": 30, "fr": 28}[l], f, d) dummy_audio(ton / "f01" / f"f01_{l}.wav", {"de": 52, "es": 61, "fr": 57}[l], f, d, stereo=(l == "es")) dummy_audio(ton / "shorts" / "musik.wav", 20, 110, -10, stereo=True) (T / "katalog_test.csv").write_text( "id;quelle;clips;tempo;start_s;ende_s;modus;crop_x;musik;thema\n" "T001;Dummy;f01_c01-05;1.0;0;;crop;0.3|0.5|0.7|0.5|0.5;;Crop-Test (5 Clips)\n" "T002;Dummy;f01_c06-10;0,85;0;;blur;;musik.wav;Blur-Test mit Musik (5 Clips, Tempo 0,85)\n", encoding="utf-8-sig") (T / "schnittliste_f01.csv").write_text( "clip;in_s;out_s;tempo;halten_s;uebergang_s;notiz\n" "f01_c01;;;;;1.0;Buch auf, lange Blende\n" "f01_c02;;;0.8;3;0.5;verlangsamt + 3 s Mitmachpause\n" "f01_c03-05;;;;;0.5;Bereich\n" "k_05;;;;;0.5;Baustein\n" "f01_c06;1;4;1;0;0.5;nur Sekunde 1-4\n" "f01_c07-12;;;;;0.5;\n", encoding="utf-8-sig") gemeinsam = ["--clips-ordner", clips, "--ausgabe", T / "ausgabe", "--ueberschreiben"] log("== 1. Short crop + blur, 3 Sprachen") rc = starte("short_rendern.py", ["--katalog", T / "katalog_test.csv", "--id", "T001,T002", "--audio-ordner", ton / "shorts", "--musik-db", "-20"] + gemeinsam) pruefe(rc == 0, "short_rendern beendet ohne Fehler") erwartet = {"T001": {"de": 24, "es": 27, "fr": 25}, "T002": {"de": 26, "es": 30, "fr": 28}} for sid, d in erwartet.items(): for l, a in d.items(): f = T / "ausgabe" / "shorts" / f"{sid}_{l}.mp4" if not f.exists(): pruefe(False, f"{f.name} fehlt") continue i = P.probe(f) v, au = i["video"], i["audio"] lau = P.messe_lautheit(f) soll = max({"T001": 23.0, "T002": 27.4}[sid], a + 0.8) # Clipfolge oder Ton + Nachlauf pruefe((v["width"], v["height"]) == (1080, 1920), f"{f.name}: Aufloesung {v['width']}x{v['height']}") pruefe(abs(i["dauer"] - soll) < 0.3, f"{f.name}: Dauer {i['dauer']:.2f} s (soll ca. {soll:.1f})") pruefe(au is not None and au["sample_rate"] == "48000", f"{f.name}: Audio {au['codec_name']} {au['sample_rate']} Hz") pruefe(lau["lufs"] is not None and abs(lau["lufs"] + 14) <= 1.0, f"{f.name}: Lautheit {lau['lufs']} LUFS, TP {lau['tp']} dBFS") log("== 2. Folge f01 in 3 Sprachen (gemeinsame Bildspur, laengste Sprache fuehrt)") rc = starte("folge_exportieren.py", ["--name", "f01", "--schnittliste", T / "schnittliste_f01.csv", "--audio-ordner", ton / "f01"] + gemeinsam) pruefe(rc == 0, "folge_exportieren beendet ohne Fehler") dauern = [] for l in P.SPRACHEN: f = T / "ausgabe" / "folgen" / f"f01_{l}.mp4" if not f.exists(): pruefe(False, f"{f.name} fehlt") continue i = P.probe(f) v = i["video"] lau = P.messe_lautheit(f) dauern.append(i["dauer"]) pruefe((v["width"], v["height"]) == (1280, 720), f"{f.name}: Aufloesung {v['width']}x{v['height']}") pruefe(abs(i["dauer"] - 62.0) < 0.5, f"{f.name}: Dauer {i['dauer']:.2f} s (laengster Ton es 61 s + 1 s Nachlauf)") pruefe(abs(lau["lufs"] + 14) <= 1.0, f"{f.name}: Lautheit {lau['lufs']} LUFS, TP {lau['tp']} dBFS") if dauern: pruefe(max(dauern) - min(dauern) < 0.1, "alle Sprachen gleich lang") log("== 3. Letztes Bild") rc = starte("letztes_bild.py", ["--clip", "f01_c04"] + gemeinsam) png = T / "ausgabe" / "startbilder" / "f01_c04_ende.png" pruefe(rc == 0 and png.exists() and png.stat().st_size > 10000, f"PNG vorhanden ({png.stat().st_size if png.exists() else 0} Bytes)") if png.exists(): v = P.probe(png)["video"] pruefe((v["width"], v["height"]) == (1280, 720), f"PNG-Aufloesung {v['width']}x{v['height']}") log("== 4. Laengen-Check (vorab + nach Export)") rc = starte("laengen_check.py", ["--name", "f01", "--schnittliste", T / "schnittliste_f01.csv", "--audio-ordner", ton / "f01", "--clips-ordner", clips, "--export-ordner", T / "ausgabe" / "folgen"]) pruefe(rc in (0, 1), "laengen_check lief durch (Warnungen sind erwartet: Sprachen weichen ab)") log("== 5. Schutz: Ausgabe ausserhalb schnitt\\ wird verweigert") rc = starte("short_rendern.py", ["--katalog", T / "katalog_test.csv", "--id", "T001", "--audio-ordner", ton / "shorts", "--clips-ordner", clips, "--ausgabe", P.PROJEKT / "shorts"]) pruefe(rc != 0 and not (P.PROJEKT / "shorts" / "shorts").exists(), "Ablehnung ohne --ausserhalb") log() log("GESAMT: " + ("ALLES OK" if ok_alle else "FEHLER VORHANDEN")) (T / "testergebnis.txt").write_text("\n".join(zeilen) + "\n", encoding="utf-8") sys.exit(0 if ok_alle else 1) if __name__ == "__main__": try: main() except P.Fehler as e: print(f"FEHLER: {e}") sys.exit(1)