Files
netfelix-audio-fix/server/services/__tests__/rescan.test.ts
T
felixfoertsch 748145a372
Build and Push Docker Image / build (push) Successful in 3m57s
detect dirty container title and comment, rewrite to canonical form
Track format.tags.title and format.tags.comment on media_items via a new
containerTitle() helper producing "Name (Year)" for movies and
"Series (Year) - S01E02 - Title" for episodes. Analyzer and
recomputePlanAfterToggle now flag non-canonical container title and
non-empty comment as non-noop ("Fix container title", "Clear comment"),
and verifyDesiredState checks them post-ffmpeg. buildStreamFlags writes
the canonical title and clears comment on every run.

Existing libraries need a rescan to populate the new columns.
2026-04-24 21:45:39 +02:00

172 lines
5.4 KiB
TypeScript

import { Database } from "bun:sqlite";
import { describe, expect, test } from "bun:test";
import { SCHEMA } from "../../db/schema";
import type { ParsedPath } from "../path-parser";
import type { ProbeResult } from "../probe";
import { upsertScannedItem } from "../rescan";
function freshDb(): Database {
const db = new Database(":memory:");
db.exec(SCHEMA);
return db;
}
const PARSED: ParsedPath = {
type: "Movie",
name: "Hot Fuzz",
year: 2007,
seriesName: null,
seasonNumber: null,
episodeNumber: null,
imdbId: "tt0425112",
tmdbId: null,
tvdbId: null,
container: "mkv",
};
const PROBE: ProbeResult = {
fileSize: 5_000_000_000,
durationSeconds: 7200,
container: "matroska",
containerTitle: "Hot.Fuzz.2007.1080p.BluRay.x264-RARBG",
containerComment: "rarbg",
streams: [
{
streamIndex: 0,
type: "Video",
codec: "h264",
profile: "High",
language: null,
title: null,
isDefault: 1,
isForced: 0,
isHearingImpaired: 0,
channels: null,
channelLayout: null,
bitRate: null,
sampleRate: null,
bitDepth: null,
width: 1920,
height: 1080,
},
{
streamIndex: 1,
type: "Audio",
codec: "dts",
profile: "DTS-HD MA",
language: "eng",
title: "English 5.1",
isDefault: 1,
isForced: 0,
isHearingImpaired: 0,
channels: 6,
channelLayout: "5.1(side)",
bitRate: 1509000,
sampleRate: 48000,
bitDepth: 24,
width: null,
height: null,
},
],
};
describe("upsertScannedItem", () => {
test("inserts new item with streams", () => {
const db = freshDb();
const result = upsertScannedItem(db, "/movies/Hot Fuzz (2007)/Hot Fuzz (2007).mkv", PARSED, PROBE);
expect(result.itemId).toBeGreaterThan(0);
expect(result.isNew).toBe(true);
const item = db.prepare("SELECT * FROM media_items WHERE id = ?").get(result.itemId) as any;
expect(item.name).toBe("Hot Fuzz");
expect(item.type).toBe("Movie");
expect(item.imdb_id).toBe("tt0425112");
expect(item.file_size).toBe(5_000_000_000);
expect(item.duration_seconds).toBe(7200);
expect(item.scan_status).toBe("scanned");
expect(item.container_title).toBe("Hot.Fuzz.2007.1080p.BluRay.x264-RARBG");
expect(item.container_comment).toBe("rarbg");
const streams = db.prepare("SELECT * FROM media_streams WHERE item_id = ?").all(result.itemId);
expect(streams).toHaveLength(2);
expect((streams[0] as any).width).toBe(1920);
expect((streams[0] as any).height).toBe(1080);
});
test("upserts on same file_path", () => {
const db = freshDb();
upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
const updated = { ...PROBE, fileSize: 6_000_000_000 };
const result = upsertScannedItem(db, "/movies/test.mkv", PARSED, updated);
expect(result.isNew).toBe(false);
const item = db.prepare("SELECT * FROM media_items WHERE id = ?").get(result.itemId) as any;
expect(item.file_size).toBe(6_000_000_000);
});
test("preserves manual language override on rescan", () => {
const db = freshDb();
const result = upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
db
.prepare("UPDATE media_items SET original_language = 'fra', orig_lang_source = 'manual' WHERE id = ?")
.run(result.itemId);
const result2 = upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
const item = db
.prepare("SELECT original_language, orig_lang_source FROM media_items WHERE id = ?")
.get(result2.itemId) as any;
expect(item.original_language).toBe("fra");
expect(item.orig_lang_source).toBe("manual");
});
test("creates review_plan stub", () => {
const db = freshDb();
const result = upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
const plan = db.prepare("SELECT * FROM review_plans WHERE item_id = ?").get(result.itemId) as any;
expect(plan).toBeDefined();
expect(plan.status).toBe("pending");
});
test("does not reset approved plan on rescan", () => {
const db = freshDb();
const result = upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
db.prepare("UPDATE review_plans SET status = 'approved' WHERE item_id = ?").run(result.itemId);
upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
const plan = db.prepare("SELECT status FROM review_plans WHERE item_id = ?").get(result.itemId) as any;
expect(plan.status).toBe("approved");
});
test("resets error plan to pending on rescan", () => {
const db = freshDb();
const result = upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
db.prepare("UPDATE review_plans SET status = 'error' WHERE item_id = ?").run(result.itemId);
upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
const plan = db.prepare("SELECT status FROM review_plans WHERE item_id = ?").get(result.itemId) as any;
expect(plan.status).toBe("pending");
});
test("guesses original language from default audio track", () => {
const db = freshDb();
const result = upsertScannedItem(db, "/movies/test.mkv", PARSED, PROBE);
expect(result.origLang).toBe("eng");
expect(result.origLangSource).toBe("probe");
});
test("sets series_key for episodes", () => {
const db = freshDb();
const episodeParsed: ParsedPath = {
...PARSED,
type: "Episode",
name: "Pilot",
seriesName: "Breaking Bad",
year: 2008,
seasonNumber: 1,
episodeNumber: 1,
};
const result = upsertScannedItem(db, "/tv/Breaking Bad (2008)/Season 01/file.mkv", episodeParsed, PROBE);
const item = db.prepare("SELECT series_key FROM media_items WHERE id = ?").get(result.itemId) as any;
expect(item.series_key).toBe("Breaking Bad|2008");
});
});