Phase 12: frame-accurate timecode via an overscan band — vgstrip encoder/decoder, sweep writes tmcd + creation_time + sidecar, dumpd /time, Caddy /time routes, MediaMTX microsecond names, /dock/clock/ page, dock band setup via obs-websocket, Go Live band composite + toggle, portal crops the band

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
2026-10-31 16:07:56 -05:00
parent 89841c3d2a
commit 3fcb8fbe99
18 changed files with 515 additions and 25 deletions

View File

@@ -104,9 +104,32 @@ while IFS= read -r -d '' src; do
fi
tmp="$out.part"
log "$verdict $src ($reason)"
tcargs=(); tcjson=""
if (( live )); then
# timecode: decode the overscan strip (server clock) or fall back to the server arrival time in the filename
stem="$(basename "${src%.*}")"
arrival_ms=$(python3 - "$stem" <<'PYEOF'
import re, sys
from datetime import datetime
from zoneinfo import ZoneInfo
m = re.search(r"(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})(?:-(\d{1,6}))?", sys.argv[1])
if not m: sys.exit(0)
y, mo, d, h, mi, s, us = m.groups()
us = int((us or "0").ljust(6, "0"))
t = datetime(int(y), int(mo), int(d), int(h), int(mi), int(s), us, tzinfo=ZoneInfo("America/New_York"))
print(int(t.timestamp() * 1000))
PYEOF
)
eval "$(python3 /usr/local/bin/vgstrip.py plan "$src" "${arrival_ms:-}" 2>/dev/null || true)"
if [[ -n ${TC_TIMECODE:-} ]]; then
tcargs=(-timecode "$TC_TIMECODE" -metadata "creation_time=$TC_CREATION" -write_tmcd 1)
tcjson="${TC_JSON:-}"
log "tc $src source=$TC_SOURCE timecode=$TC_TIMECODE"
fi
fi
if [[ $verdict == remux ]]; then
nice -n 15 ionice -c 3 ffmpeg -nostdin -hide_banner -loglevel error -y -i "$src" \
-map 0 -c copy -movflags +faststart -f mp4 "$tmp"
-map 0 -c copy "${tcargs[@]}" -movflags +faststart -f mp4 "$tmp"
else
# scale down into the cap (never up), keep aspect, even dimensions; cap fps; CFR; all audio -> AAC
vf="scale='min(iw,$MAX_W)':'min(ih,$MAX_H)':force_original_aspect_ratio=decrease:force_divisible_by=2"
@@ -117,13 +140,16 @@ while IFS= read -r -d '' src; do
-c:v libx264 -preset veryfast -crf 18 -maxrate 30M -bufsize 60M -pix_fmt yuv420p -profile:v high \
-vf "$vf" -fps_mode cfr "${fpsargs[@]}" \
-c:a aac -b:a 160k \
-movflags +faststart -f mp4 "$tmp"
"${tcargs[@]}" -movflags +faststart -f mp4 "$tmp"
fi
rc=$?
d1=$(dur "$src"); d2=$(dur "$tmp")
if (( rc == 0 )) && [[ -n $d1 && -n $d2 ]] && (( d2 >= d1 - 2 && d2 <= d1 + 2 )); then
if (( live )); then
mv -f "$tmp" "$out"; chown 1000:1000 "$out" 2>/dev/null
if [[ -n $tcjson ]]; then # sidecar: exact capture time (read by the Jellyfin plugin) + drift samples
printf '%s\n' "$tcjson" > "${out%.*}.json"; chown 1000:1000 "${out%.*}.json" 2>/dev/null
fi
rm -f "$src"; rmdir "$(dirname "$src")" "$titledir" 2>/dev/null || true # drop .live and the empty title folder
log "done $out"; continue
elif (( synced )); then