make done plans terminal, add ffprobe preflight to skip already-processed files
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m34s
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m34s
root cause of duplicate pipeline entries: rescan.ts flipped done plans back to pending whenever a post-job jellyfin refresh returned stale metadata, putting the item back in review and letting a second jobs row pile up in done. done is now sticky across rescans (error still re-opens for retries). second line of defense: before spawning ffmpeg, ffprobe the file and compare audio count/language/codec order + embedded subtitle count against the plan. if it already matches, mark the job done with the reason in jobs.output and skip the spawn. prevents corrupting a post-processed file with a stale stream-index command.
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
waitForProcessWindow,
|
||||
} from "../services/scheduler";
|
||||
import { loadLibrary as loadSonarrLibrary, isUsable as sonarrUsable } from "../services/sonarr";
|
||||
import { verifyDesiredState } from "../services/verify";
|
||||
import type { Job, MediaItem, MediaStream } from "../types";
|
||||
|
||||
function parseLanguageList(raw: string | null | undefined, fallback: string[]): string[] {
|
||||
@@ -403,6 +404,31 @@ async function runJob(job: Job): Promise<void> {
|
||||
db.prepare("UPDATE review_plans SET status = 'error' WHERE item_id = ?").run(job.item_id);
|
||||
return;
|
||||
}
|
||||
|
||||
// Preflight: if the file already matches the plan, skip ffmpeg. Cheap
|
||||
// guard against re-running a stream-index-based command against a file
|
||||
// that's already been processed — which would either error out or
|
||||
// silently corrupt the file.
|
||||
try {
|
||||
const verify = await verifyDesiredState(db, job.item_id, itemRow.file_path);
|
||||
if (verify.matches) {
|
||||
const msg = `Preflight check: ${verify.reason}\nSkipping FFmpeg — no work needed.`;
|
||||
log(`Job ${job.id} ${msg.replace(/\n/g, " ")}`);
|
||||
db.transaction(() => {
|
||||
db
|
||||
.prepare(
|
||||
"UPDATE jobs SET status = 'done', exit_code = 0, output = ?, completed_at = datetime('now') WHERE id = ?",
|
||||
)
|
||||
.run(msg, job.id);
|
||||
db.prepare("UPDATE review_plans SET status = 'done' WHERE item_id = ?").run(job.item_id);
|
||||
})();
|
||||
emitJobUpdate(job.id, "done", msg);
|
||||
return;
|
||||
}
|
||||
log(`Job ${job.id} preflight: ${verify.reason} — running FFmpeg`);
|
||||
} catch (err) {
|
||||
warn(`Job ${job.id} preflight check errored: ${String(err)} — proceeding with FFmpeg`);
|
||||
}
|
||||
}
|
||||
|
||||
emitJobUpdate(job.id, "running");
|
||||
|
||||
Reference in New Issue
Block a user