import type { SourceReleaseRow } from "@umt/db"; import { describe, expect, it } from "vitest"; import { HookRegistry } from "../../src/hooks/index.ts"; import { selectResources } from "../../src/modules/acquisition-organize/services/acquisition.ts"; // 链式钩子 resource.selection(ADR-006,对照 MP ChainEventType.ResourceSelection):订阅重评时调整候选顺序 / 过滤, // 只能重排与删减,不能加入新候选。 const rel = (id: string, title: string) => ({ id, title, parsed: null }) as unknown as SourceReleaseRow; const rels = [ rel("r1", "Show.S01E01.1080p.WEB-DL"), rel("r2", "Show.S01E01.2160p.WEB-DL"), rel("r3", "Show.S01E01.720p"), ]; const context = { mediaEntityId: "e", subscriptionId: "s", slotId: null }; const ctxOf = (hooks?: HookRegistry) => ({ d: { ctx: { hooks } } }) as never; describe("resource.selection 钩子", () => { it("没有钩子时原样返回同一个数组", async () => { expect(await selectResources(ctxOf(), rels, context)).toBe(rels); expect(await selectResources(ctxOf(new HookRegistry()), rels, context)).toBe(rels); }); it("重排与过滤生效;不认识的 ID 忽略、重复的只取一次", async () => { const hooks = new HookRegistry(); const seen: unknown[] = []; hooks.forModule("test").rewrite("resource.selection", (cands, c) => { seen.push({ ids: cands.map((x) => x.sourceReleaseId), c }); const by = new Map(cands.map((x) => [x.sourceReleaseId, x])); // 2160p 优先、去掉 720p,夹带一个不存在的候选和一个重复 return [by.get("r2")!, { ...by.get("r1")!, sourceReleaseId: "intruder" }, by.get("r1")!, by.get("r2")!]; }); const out = await selectResources(ctxOf(hooks), rels, context); expect(out.map((r) => r.id)).toEqual(["r2", "r1"]); expect(seen).toEqual([{ ids: ["r1", "r2", "r3"], c: context }]); }); it("钩子出错时沿用原顺序", async () => { const hooks = new HookRegistry(); hooks.forModule("test").rewrite("resource.selection", () => { throw new Error("坏了"); }); expect((await selectResources(ctxOf(hooks), rels, context)).map((r) => r.id)).toEqual(["r1", "r2", "r3"]); }); });