- G6: FileRoot.pendingCount/pendingPartial for download roots (same rule as the unidentified filter, recursive, cached 5 min, invalidated by files.changed) - G7: FileEntry.parsedHint from parseReleasePath (file + parent dirs); the web subline uses it and no longer parses names itself - G8: FileIdentifyCandidate.posterUrl (TMDB poster_path via adapter and catalog.lookup, local entities from metadata.posterPath); thumbnails in the identify panel - S-7 contract: FilesIdentifyResult.remoteTaskId/remotePending, MediaServerInventory.partial, EventType identify.completed with IdentifyCompletedPayload; identify panel (useIdentifyLive) and organize wizard merge remote results by root + path, buffering events that beat the response Co-Authored-By: Claude Opus 5.5 <[email protected]>
73 lines
3.5 KiB
TypeScript
73 lines
3.5 KiB
TypeScript
import { mkdir, writeFile } from "node:fs/promises";
|
|
import { join } from "node:path";
|
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
import { parsedHintOf } from "../../src/modules/file-manager/hint.ts";
|
|
import { posterUrlOf } from "../../src/modules/file-manager/identify.ts";
|
|
import { createFmHarness, type FmHarness, pgAvailable, READ_KEY, seedDownload } from "./harness.ts";
|
|
|
|
// C1-C 契约收尾:G6 下载目录待识别计数 / G7 列表轻量解析 parsedHint / G8 候选海报 posterUrl。
|
|
|
|
describe("G7 parsedHintOf / G8 posterUrlOf(纯函数)", () => {
|
|
it("剧集:标题 · 季集 · 分辨率;父目录补标题", () => {
|
|
expect(parsedHintOf("The.Last.of.Us.S01E02.1080p.WEB-DL.mkv")).toBe("The Last of Us · S01E02 · 1080p");
|
|
expect(parsedHintOf("The.Bear.S01.1080p/The.Bear.S01E01.1080p.WEB-DL-GRP.mkv")).toMatch(
|
|
/^The Bear · S01E01 · 1080p$/,
|
|
);
|
|
});
|
|
it("电影带年份;解析不出标题为 null", () => {
|
|
expect(parsedHintOf("Oppenheimer.2023.2160p.BluRay.x265.mkv")).toBe("Oppenheimer (2023) · 2160p");
|
|
expect(parsedHintOf("")).toBeNull();
|
|
});
|
|
it("posterUrl:相对 poster_path 拼 w154,完整 URL 原样,空为 null", () => {
|
|
expect(posterUrlOf("/abc.jpg")).toBe("https://image.tmdb.org/t/p/w154/abc.jpg");
|
|
expect(posterUrlOf("https://img.example/x.jpg")).toBe("https://img.example/x.jpg");
|
|
expect(posterUrlOf(null)).toBeNull();
|
|
expect(posterUrlOf("")).toBeNull();
|
|
});
|
|
});
|
|
|
|
const skip = !(await pgAvailable());
|
|
|
|
// biome-ignore lint/suspicious/noExplicitAny: 测试断言直接读响应 JSON
|
|
type Loose = any;
|
|
|
|
describe.skipIf(skip)("files G6/G7(列表与根)", () => {
|
|
let h: FmHarness;
|
|
beforeAll(async () => {
|
|
h = await createFmHarness("g678");
|
|
await writeFile(join(h.dl, "The.Last.of.Us.S01E02.1080p.WEB-DL.mkv"), "v");
|
|
await writeFile(join(h.dl, "notes.txt"), "t");
|
|
await writeFile(join(h.dl, "Half.Done.2024.1080p.mkv.!qB"), "p");
|
|
await mkdir(join(h.dl, "Show.S02"), { recursive: true });
|
|
await writeFile(join(h.dl, "Show.S02", "Show.S02E01.720p.mkv"), "v");
|
|
// 纳管下载任务内容(做种)不算待识别
|
|
await mkdir(join(h.dl, "Seeding.Film.2020.1080p"), { recursive: true });
|
|
await writeFile(join(h.dl, "Seeding.Film.2020.1080p", "Seeding.Film.2020.1080p.mkv"), "v");
|
|
await seedDownload(h.db, h, { name: "Seeding.Film.2020.1080p", status: "completed" });
|
|
});
|
|
afterAll(async () => {
|
|
await h?.close();
|
|
});
|
|
|
|
it("G6:下载目录带 pendingCount(递归、排除临时与做种),库根为 null", async () => {
|
|
const r = await h.api("GET", "/files/roots", undefined, READ_KEY);
|
|
expect(r.status).toBe(200);
|
|
const dl = r.body.data.items.find((x: Loose) => x.id === h.dlRoot);
|
|
const lib = r.body.data.items.find((x: Loose) => x.id === h.libRoot);
|
|
expect(dl).toMatchObject({ pendingCount: 2, pendingPartial: false });
|
|
expect(lib).toMatchObject({ pendingCount: null, pendingPartial: false });
|
|
});
|
|
|
|
it("G7:待识别视频行带 parsedHint,其它行为 null", async () => {
|
|
const r = await h.api("GET", `/files?root=${encodeURIComponent(h.dlRoot)}`, undefined, READ_KEY);
|
|
expect(r.status).toBe(200);
|
|
const by = (n: string) => r.body.data.entries.find((x: Loose) => x.name === n);
|
|
expect(by("The.Last.of.Us.S01E02.1080p.WEB-DL.mkv")).toMatchObject({
|
|
status: "unidentified",
|
|
parsedHint: "The Last of Us · S01E02 · 1080p",
|
|
});
|
|
expect(by("notes.txt").parsedHint).toBeNull();
|
|
expect(by("Show.S02").parsedHint).toBeNull();
|
|
});
|
|
});
|