Add native GPU-accelerated AV1 transcode capability

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.
This commit is contained in:
Breadway 2026-07-24 23:57:58 +08:00
parent 691fb39cbb
commit d533301880
10 changed files with 924 additions and 15 deletions

View file

@ -222,7 +222,22 @@ fn movie_eligible_for_upgrade(conn: &Connection, media_item_id: i64) -> Result<b
params![media_item_id],
|row| row.get(0),
)?;
Ok(in_flight == 0)
if in_flight > 0 {
return Ok(false);
}
// Same reasoning as the `upgrade_locked` check in
// `enumerate_upgrade_targets`: a locally AV1-transcoded file is a
// deliberate shrink, not something the upgrade loop should try to
// replace with the next bigger HEVC/x264 release it finds.
let upgrade_locked: i64 = conn
.query_row(
"SELECT upgrade_locked FROM episode_file
WHERE media_item_id = ?1 AND episode_id IS NULL",
params![media_item_id],
|row| row.get(0),
)
.unwrap_or(0);
Ok(upgrade_locked == 0)
}
fn is_anime(conn: &Connection, tvdb_id: i64) -> Result<bool> {
@ -1170,6 +1185,7 @@ fn enumerate_upgrade_targets(
(SELECT tvdb_id FROM anime_mapping WHERE tvdb_id IS NOT NULL))
AND NOT EXISTS (SELECT 1 FROM release r WHERE r.episode_id = e.id
AND r.status IN ('grabbed','downloading'))
AND (ef.upgrade_locked IS NULL OR ef.upgrade_locked = 0)
AND (us.last_checked_at IS NULL OR {})",
UPGRADE_DUE_CLAUSE
.replace("last_checked_at", "us.last_checked_at")
@ -2317,6 +2333,22 @@ mod tests {
assert_eq!(targets[1].episode_id, Some(1));
}
#[test]
fn enumerate_upgrade_targets_excludes_an_upgrade_locked_episode() {
let conn = seeded_upgrade_conn_with_one_flagged_episode();
// Episode 2 is the probe-flagged one that would otherwise sort
// first — lock it (as a completed local AV1 transcode would) and
// confirm it drops out entirely rather than just losing priority.
conn.execute(
"UPDATE episode_file SET upgrade_locked = 1 WHERE episode_id = 2",
[],
)
.unwrap();
let targets = enumerate_upgrade_targets(&conn, 10, 5.0).unwrap();
assert_eq!(targets.len(), 1);
assert_eq!(targets[0].episode_id, Some(1));
}
#[test]
fn record_grab_writes_both_a_release_row_and_a_torrent_fetch_audit_row() {
let conn = seeded_conn();
@ -2586,6 +2618,20 @@ mod tests {
assert!(movie_eligible_for_upgrade(&conn, 1).unwrap());
}
#[test]
fn movie_eligible_for_upgrade_is_false_once_upgrade_locked() {
let conn = seeded_movie_conn();
conn.execute(
"INSERT INTO episode_file (media_item_id, episode_id, path, size_bytes, upgrade_locked)
VALUES (1, NULL, '/tmp/movie.mkv', 100, 1)",
[],
)
.unwrap();
// A locally AV1-transcoded file is a deliberate shrink, not
// something the upgrade loop should try to replace.
assert!(!movie_eligible_for_upgrade(&conn, 1).unwrap());
}
#[test]
fn movie_eligible_for_upgrade_is_false_when_unmonitored() {
let conn = seeded_movie_conn();