clean media stream titles, verify metadata preflight
This commit is contained in:
+18
-10
@@ -2,20 +2,20 @@ import { unlinkSync } from "node:fs";
|
||||
import { Hono } from "hono";
|
||||
import { getAllConfig, getConfig, getDb } from "../db/index";
|
||||
import { log, error as logError } from "../lib/log";
|
||||
import { parsePath } from "../services/path-parser";
|
||||
import { probeFile } from "../services/probe";
|
||||
import { upsertScannedItem } from "../services/rescan";
|
||||
import { isOneOf, parseId } from "../lib/validate";
|
||||
import { analyzeItem, assignTargetOrder } from "../services/analyzer";
|
||||
import { buildCommand, LANG_NAMES } from "../services/ffmpeg";
|
||||
import { buildCommand, LANG_NAMES, trackTitle } from "../services/ffmpeg";
|
||||
import { type LanguageResolverConfig, resolveLanguage } from "../services/language-resolver";
|
||||
import { normalizeLanguage } from "../services/language-utils";
|
||||
import { parsePath } from "../services/path-parser";
|
||||
import { probeFile } from "../services/probe";
|
||||
import {
|
||||
loadLibrary as loadRadarrLibrary,
|
||||
type RadarrLibrary,
|
||||
isUsable as radarrUsable,
|
||||
triggerMovieRefetch,
|
||||
} from "../services/radarr";
|
||||
import { upsertScannedItem } from "../services/rescan";
|
||||
import {
|
||||
loadLibrary as loadSonarrLibrary,
|
||||
type SonarrLibrary,
|
||||
@@ -151,9 +151,9 @@ export async function processInbox(
|
||||
// Also pick up noop items that have never been analyzed with the reasons
|
||||
// system (reasons IS NULL). Reanalyze may flip them to non-noop if the
|
||||
// title/language/default checks now catch something the old code missed.
|
||||
const staleNoops = db
|
||||
.prepare("SELECT item_id FROM review_plans WHERE is_noop = 1 AND reasons IS NULL")
|
||||
.all() as { item_id: number }[];
|
||||
const staleNoops = db.prepare("SELECT item_id FROM review_plans WHERE is_noop = 1 AND reasons IS NULL").all() as {
|
||||
item_id: number;
|
||||
}[];
|
||||
for (const { item_id } of staleNoops) {
|
||||
reanalyze(db, item_id, audioLanguages);
|
||||
}
|
||||
@@ -483,12 +483,13 @@ function recomputePlanAfterToggle(db: ReturnType<typeof getDb>, itemId: number):
|
||||
if (!plan) return;
|
||||
const decisions = db
|
||||
.prepare(
|
||||
"SELECT stream_id, action, target_index, custom_language, transcode_codec FROM stream_decisions WHERE plan_id = ?",
|
||||
"SELECT stream_id, action, target_index, custom_title, custom_language, transcode_codec FROM stream_decisions WHERE plan_id = ?",
|
||||
)
|
||||
.all(plan.id) as {
|
||||
stream_id: number;
|
||||
action: "keep" | "remove";
|
||||
target_index: number | null;
|
||||
custom_title: string | null;
|
||||
custom_language: string | null;
|
||||
transcode_codec: string | null;
|
||||
}[];
|
||||
@@ -516,12 +517,19 @@ function recomputePlanAfterToggle(db: ReturnType<typeof getDb>, itemId: number):
|
||||
const updateIdx = db.prepare("UPDATE stream_decisions SET target_index = ? WHERE plan_id = ? AND stream_id = ?");
|
||||
for (const d of decWithIdx) updateIdx.run(d.target_index, plan.id, d.stream_id);
|
||||
|
||||
// Recompute is_noop: audio removed OR reordered OR subs exist OR transcode needed
|
||||
// Recompute is_noop: audio removed OR reordered OR subs exist OR transcode/metadata needed
|
||||
const anyAudioRemoved = streams.some(
|
||||
(s) => s.type === "Audio" && decWithIdx.find((d) => d.stream_id === s.id)?.action === "remove",
|
||||
);
|
||||
const hasSubs = streams.some((s) => s.type === "Subtitle");
|
||||
const needsTranscode = decWithIdx.some((d) => d.transcode_codec != null && d.action === "keep");
|
||||
const titleMismatch = streams.some((s) => {
|
||||
if (s.type !== "Video" && s.type !== "Audio") return false;
|
||||
const d = decisions.find((dec) => dec.stream_id === s.id);
|
||||
if (d?.action !== "keep") return false;
|
||||
const expected = d.custom_title ?? trackTitle(s, d.custom_language);
|
||||
return expected != null && s.title !== expected;
|
||||
});
|
||||
|
||||
const keptAudio = streams
|
||||
.filter((s) => s.type === "Audio" && decWithIdx.find((d) => d.stream_id === s.id)?.action === "keep")
|
||||
@@ -535,7 +543,7 @@ function recomputePlanAfterToggle(db: ReturnType<typeof getDb>, itemId: number):
|
||||
}
|
||||
}
|
||||
|
||||
const isNoop = !anyAudioRemoved && !audioOrderChanged && !hasSubs && !needsTranscode;
|
||||
const isNoop = !anyAudioRemoved && !audioOrderChanged && !hasSubs && !needsTranscode && !titleMismatch;
|
||||
|
||||
// Only flip is_noop to 1 when the plan is unsorted (inbox). If the user is
|
||||
// actively reviewing a sorted plan, marking all tracks "keep" should NOT
|
||||
|
||||
Reference in New Issue
Block a user