The repo is still being assembled as a templated workspace, so the branch
conventions are the intended end state rather than a current rule. Recording
that in the README so the 'master is protected and immutable' line is not read
as an active restriction while the template is still taking shape.
Replaces the scattered TypeScript/shell helpers with one Python toolchain that
runs as plain files (`python3 scripts/tools.py <tool> ...`) with no third-party
dependencies.
New tools
- `_common.py` shared plumbing (Report, run, ffmpeg discovery, argparse ergonomics)
- `hwprobe.py` what this machine can actually encode (software + hardware)
- `srt2ass.py` SRT -> ASS, the missing step between lrc2srt and baking
- `ffmpeg_tools.py` mux / bake / still / strip / probe, with hardware encode
- `bom_gen.py` BOM generator, ported from scripts/bom-gen.ts
- `tools.py` dispatcher so any tool is one command away
- `README.md` usage for all of the above
Rewritten
- `lrc2srt.py` now handles multiple timestamps per line, timestamp-less cue lines
and blank/comment lines, and survives malformed input. The legacy version
emitted an empty cue plus a stray cue for every line.
Hardware encoding
This host is AMD (Strix Halo, VCN 4.0.5), so nvenc in the legacy notes is
reference only. `hwprobe.py` probes and reports what genuinely works here:
VA-API via /dev/dri/renderD128 gives h264_vaapi, hevc_vaapi and av1_vaapi.
`ffmpeg_tools.py --video auto` picks the hardware encoder when the render node
is usable and falls back to libx264/libx265 when it is not.
Two bugs found and fixed while wiring this up:
- the VA-API capability probe fed frames straight to the encoder without
`format=nv12,hwupload`, so ffmpeg failed with "Function not implemented" and
the toolchain silently fell back to software on a machine where hardware
works. VA-API encoders only accept GPU-resident frames; the probe now uploads.
- `bake --video copy` only failed when the copied stream happened to be VA-API.
Burning subtitles always changes pixels, so it now refuses `copy` outright
with a clear message.
Also makes -q/-n usable on either side of the mode word, and ignores
__pycache__ in .gitignore.