Removes genuinely dead code (unused import, no-op cast, an unused
PendingGrab accessor, and TmdbClient's TV-search methods now that TVDB
fully covers that path), tightens len()>0 checks to is_empty(), swaps
two fixed-size test vec!s for arrays, restructures a match to avoid an
unnecessary unwrap_err, fixes doc-comment list indentation, and hoists
a locked-connection call out of a match scrutinee. Struct fields/enum
variants that are still meaningful but not read by current callers
(TorrentInfo::save_path, GrabCycleStats::items_seen, X1337 fallback
route, BacklogCandidate::path) get #[allow(dead_code)] rather than
deletion, same for the two 8-argument functions (too_many_arguments).
- Atomic claim on review-queue approval, closing a double-approve race
that could grab the same release twice (scheduler.rs)
- Constant-time comparison for the daemon API token, closing a timing
side channel
- RSS items wrapped in CDATA (common for titles with '&') were
silently dropped - only Event::Text was ever handled
- Reject malformed apibay info_hash values before building a magnet
link that extract_btih can't parse back out
- Parse sizes with no space before the unit ("38.1GiB")
- Fix "Season N - NN" episode parsing and stop misreading a
YYYY-MM-DD date as a bare episode range
- Query embeddings are no longer cached, fixing unbounded cache growth
over the daemon's lifetime (only library-side candidates need caching)
Post-grab async background swap, upgrade_locked flag to prevent the
upgrade loop from re-inflating a locally-transcoded file, and a
transcode-library CLI backfill for the existing catalog. Bitrate model
calibrated against Silicon Valley's real HEVC bitrate, scaled by
resolution and AV1's encoding efficiency. HDR/2160p and anime excluded
from this first pass. Jellyfin session polling throttles batch
encoding back to 1 stream during active playback.
The "reject sub-1080p when a better resolution exists in this batch" gate
(and every other quality gate) only ran on the confident auto-match path —
a low-confidence match skipped straight to queue_for_review before ever
reaching it. A human review decision is about whether this is genuinely
the right show, not a backdoor around quality standards; a title match
being ambiguous is no reason to let a worse-quality release through
untested. Verified live: several 720p season-pack releases were sitting in
the review queue for shows that also had 1080p+ alternatives in the same
search batch. Moved the gate check ahead of the review-queue branch so it
applies uniformly.
process_item queued anything landing in the matcher's "needs review"
confidence band immediately, without ever checking whether the show/
season/episode/movie actually needed anything — that check only ran on
the auto-match path. A low-confidence match against an already-complete
show gained nothing from a human's yes/no, it was just noise that
reappeared every cycle the source kept re-listing the same old release
(verified live: fully-complete shows' season-pack re-releases piling up
in the review queue indefinitely). Reordered so the eligibility check
(movie/season-pack/episode) runs first regardless of confidence, and only
a genuinely-needed release ever reaches the queue-for-review decision.
Search results were sorted purely by seeder count, so a season pack only
won out over a single-episode release by accident. Season packs already
clear every missing episode of that season in one grab and go through the
same seeder/quality gate as anything else (an unviable pack still gets
rejected there and iteration falls through to the next candidate) — so
sorting packs first, seeders as the tiebreaker, is a strict improvement
with no new risk. Shared by both the automated search cycle and the
manual-search candidate list.