Requested and applied a full review of the AV1 transcode implementation.
Findings and fixes:
- Season-pack import bypassed upgrade_locked entirely: a season pack
scored higher than a locally-transcoded file's stale release score
would silently overwrite it. Fixed in import_season_pack_file (and
mirrored into import_one for defense-in-depth) to check
upgrade_locked before the score comparison, not after.
- The post-import enqueue hook only checked anime, silently skipping
the HDR/2160p exclusions find_backlog_candidates applies to the
backfill -- a freshly-grabbed HDR file would have gone through the
unverified HDR-via-VAAPI path. Centralized all eligibility rules
(anime, already-av1, HDR, height) into transcode::should_enqueue,
used by both import_one and the newly-added season-pack enqueue
hook (season packs previously had no transcode hook at all, despite
being the actual headline use case -- 100GB+ season packs).
- find_backlog_candidates: a NULL-height row was included as a
candidate but could never actually be claimed (claim_pending_jobs
requires non-null height), permanently stuck pending. Fixed the
WHERE clause.
- encode_and_verify now probes the real input file first and skips
the encode entirely if it's already AV1 -- closes a narrow crash
window where a rename-succeeded-but-DB-update-failed job would
otherwise re-encode an already-transcoded file on retry.
- finalize_job's success path could leak a verified temp file and
strand a job in 'running' forever if a filesystem operation failed
partway through; now wrapped so any failure there cleans up and
marks the job failed like every other error path.
- reset_orphaned_running_jobs now also sweeps each reset job's
leftover temp file (job-id-scoped paths, so this lookup is
unambiguous) rather than leaking them on a disk that's usually
already tight on space.
- Added a unique index preventing two active jobs for the same file
ever existing at once -- closes the remaining gap in last commit's
concurrency fix (a daemon restart's reset could otherwise race a
still-alive transcode-library backfill onto the same file).
- Made the VAAPI rate-control mode explicit (VBR) instead of
driver-inferred.
- The daemon's transcode ticker awaited each cycle inline in the
tokio::select! loop, blocking every other cycle (import, search,
upgrade, reconcile) for the full multi-minute duration of an
encode. Now spawns each cycle detached with a try-lock guard so
overlapping ticks skip cleanly rather than stacking (the
concurrency cap from the previous commit makes this safe).
Two items reviewed and deliberately left as documented, not fixed:
mp4 sources with mov_text subtitles will fail the encode cleanly (no
data loss, just no space saved) since Matroska can't hold that codec
via stream copy -- fixing this needs per-stream codec probing that
wasn't safe to add untested at this hour. Renaming an mp4 source's
extension to .mkv after transcoding is cosmetic (Jellyfin
content-sniffs fine) and left alone.