Add a 36-second cutdown of the trailer

cut.py --short builds a social-length version from the same takes: one
line per witness cut inside their takes, then the challengers beat,
"Quiet, please", "Play", the splat and Reg's stinger. Each cut keeps its
own build folder and output file, so cut 2, cut 3 and the short all stay.
words.py gives local Whisper word timestamps for cutting inside lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
wuwiandClaude Opus 5.5 committed 2026-10-05 11:09:05 +02:00
1 parent 5fba837ead
commit 2de45510a3
4 files changed
+69 -11

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
"""Word timestamps for takes, from a local Whisper — the cutdown cuts INSIDE lines, and the QA
listener's timestamps drift too much for that.
uv run --with faster-whisper python tools/trailer/words.py <take|file>... (take names in promo/trailer/clips)
"""
import os, subprocess, sys
import numpy as np
from faster_whisper import WhisperModel
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
m = WhisperModel('small.en', compute_type='int8')
for name in sys.argv[1:]:
# decode with ffmpeg ourselves: faster-whisper's PyAV path breaks on newer av releases
src = name if os.path.exists(name) else os.path.join(ROOT, 'promo', 'trailer', 'clips', name + '.mp4')
raw = subprocess.run(['ffmpeg', '-v', 'error', '-i', src,
'-ac', '1', '-ar', '16000', '-f', 's16le', '-'], capture_output=True).stdout
segs, _ = m.transcribe(np.frombuffer(raw, np.int16).astype(np.float32) / 32768, word_timestamps=True)
print(name + ':', ' '.join(f'{w.word.strip()}[{w.start:.2f}-{w.end:.2f}]' for s in segs for w in s.words))