748145a372
Build and Push Docker Image / build (push) Successful in 3m57s
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.
172 lines
5.4 KiB
TypeScript
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");
|
|
});
|
|
});
|