Files
rootandClaude Opus 5.5 abc69886ea feat(contracts,server,web): files G6–G8 fields and identify S-7 contract
- 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]>
2026-09-28 20:09:29 +08:00

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();
});
});