/** * ID-3:站点列表 / 详情页给出的外部 ID(trustedIds)作为强证据。 * 差分组:packages/domain/test/differential/identity/site-ids-*.json(MP search/result.py `_match_source`, * 由 gen-site-ids-mp.py 生成)。MP 只要种子 IMDb 与作品一致就判命中;我们年份冲突 / 类型冲突时只作候选(登记的偏离)。 */ import { readFileSync } from "node:fs"; import { describe, expect, it } from "vitest"; import { type IdentityCandidate, parseRelease, resolveIdentity, scoreCandidate } from "../src/index.ts"; const DIR = new URL("./differential/identity/", import.meta.url); const read = (name: string): T => JSON.parse(readFileSync(new URL(name, DIR), "utf8")) as T; interface Sample { id: string; note: string; torrent: { title: string; subtitle?: string; imdbId?: string }; work: { type: "movie" | "tv"; tmdbId: number; title: string; originalTitle?: string; year: number; imdbId?: string }; expectOurs: "auto" | "ambiguous" | "no_match"; } const samples = read<{ samples: Sample[] }>("site-ids-samples.json").samples; const mp = read<{ results: Record }>("site-ids-mp.json").results; const deviations = read<{ deviations: Record }>( "site-ids-deviations.json", ).deviations; const candidateOf = (w: Sample["work"]): IdentityCandidate => ({ provider: "tmdb", entityType: w.type, externalId: String(w.tmdbId), titles: [...new Set([w.title, ...(w.originalTitle ? [w.originalTitle] : [])])], year: w.year, aliases: [], ...(w.imdbId ? { linkedExternalIds: [{ provider: "imdb", id: w.imdbId }] } : {}), }); const ours = (s: Sample) => { const p = parseRelease(s.torrent.title, s.torrent.subtitle ? { subtitle: s.torrent.subtitle } : {}); const trustedIds = s.torrent.imdbId ? [{ provider: "imdb", id: s.torrent.imdbId }] : []; return resolveIdentity(p, [candidateOf(s.work)], { trustedIds }); }; describe("差分:站点外部 ID(MP _match_source)", () => { it("样本与 MP 输出一一对应", () => { expect(samples.length).toBeGreaterThanOrEqual(6); for (const s of samples) expect(mp[s.id], s.id).toBeDefined(); }); for (const s of samples) { it(`${s.id} ${s.note}`, () => { const r = ours(s); expect(r.status, s.id).toBe(s.expectOurs); const mpMatched = mp[s.id]!.match !== null; const oursMatched = r.status === "auto"; if (mpMatched === oursMatched) expect(deviations[s.id], `${s.id} 已一致,请删除登记`).toBeUndefined(); else expect(deviations[s.id]?.kind, `${s.id} 与 MP 不一致但没有登记`).toBe("intentional"); }); } }); describe("trustedIds 评分", () => { const movie: IdentityCandidate = { provider: "tmdb", entityType: "movie", externalId: "872585", titles: ["Oppenheimer", "奥本海默"], year: 2023, aliases: [], linkedExternalIds: [{ provider: "imdb", id: "tt15398776" }], }; it("标题对不上:trusted → multi_evidence(auto);不 trusted 仍是 rejected", () => { const p = parseRelease("Something Else 2023 1080p WEB-DL"); expect(scoreCandidate(p, movie).level).toBe("rejected"); const r = scoreCandidate(p, movie, { trustedIds: [{ provider: "imdb", id: "tt15398776" }] }); expect(r.level).toBe("multi_evidence"); expect(r.evidence).toContain("site_id"); }); it("TMDB ID 直接对上候选同样算", () => { const p = parseRelease("Something Else 2023 1080p WEB-DL"); expect(scoreCandidate(p, movie, { trustedIds: [{ provider: "tmdb", id: "872585" }] }).level).toBe("multi_evidence"); }); it("标题也对上时不降级(rule_confirmed 保留)", () => { const p = parseRelease("Oppenheimer 2023 1080p WEB-DL"); expect(scoreCandidate(p, movie, { trustedIds: [{ provider: "imdb", id: "tt15398776" }] }).level).toBe( "rule_confirmed", ); }); it("别的 ID 不影响", () => { const p = parseRelease("Something Else 2023 1080p WEB-DL"); expect(scoreCandidate(p, movie, { trustedIds: [{ provider: "imdb", id: "tt0000001" }] }).level).toBe("rejected"); }); it("年份冲突 → needs_confirm(ID 可能挂错)", () => { const p = parseRelease("Oppenheimer 1990 1080p WEB-DL"); const r = scoreCandidate(p, movie, { trustedIds: [{ provider: "imdb", id: "tt15398776" }] }); expect(r.level).toBe("needs_confirm"); expect(r.evidence).toContain("site_id_year_conflict"); }); });