- 版本目标 → 收录版本(前后端用户可见字符串、能力描述、给模型的提示) - Agent 上游 / 上游 → 模型服务;界面上的 Agent / Agent 会话 → 智能体 / 智能体会话 - 身份歧义 / 识别有歧义 / 无法确定作品 → 没识别出作品;待识别(池) → 未识别 - 建档 → 加入媒体库;资产 → 文件;库根 → 媒体库目录;纳管 → 本工具 / 外部任务; 哨兵 → 标记文件 / 检查目录;站点快照 → 抓取;Feed / RSS 订阅 / 来源健康 → RSS - 代码标识符、API 字段名、迁移文件不改;glossary.md 同步;smoke 选择器跟随 Co-Authored-By: Claude Opus 5.5 <[email protected]>
95 lines
4.0 KiB
TypeScript
95 lines
4.0 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
currentPri,
|
|
evaluateCandidate,
|
|
parseRelease,
|
|
parseRuleString,
|
|
type RuleGroupSpec,
|
|
rankForSlot,
|
|
type SlotSpec,
|
|
} from "../src/index.ts";
|
|
|
|
const group = (name: string, s: string, extra: Partial<RuleGroupSpec> = {}): RuleGroupSpec => ({
|
|
name,
|
|
layers: s ? parseRuleString(s).layers : [],
|
|
...extra,
|
|
});
|
|
const base = (groups: RuleGroupSpec[], extra: Partial<SlotSpec> = {}): SlotSpec => ({
|
|
name: "main",
|
|
hard: {},
|
|
rules: { groups },
|
|
...extra,
|
|
});
|
|
const rel = (t: string, subtitle?: string) => parseRelease(t, subtitle ? { subtitle } : {});
|
|
|
|
describe("收录版本接入规则组", () => {
|
|
it("硬排除命中 → reject(rule.hard_exclude),trace 带组名与修订号", () => {
|
|
const g = group("不要原盘", "", {
|
|
id: "g1",
|
|
revision: 3,
|
|
hardExcludes: parseRuleString("BLU | REMUX").layers.map((l) => l.expr),
|
|
});
|
|
const ev = evaluateCandidate(base([g]), rel("Movie.2023.1080p.BluRay.REMUX.AVC-EPSiLON"));
|
|
expect(ev.decision).toBe("reject");
|
|
if (ev.decision !== "reject") return;
|
|
expect(ev.violations).toEqual([
|
|
{ field: "rule", code: "hard_exclude", expected: "不要原盘", actual: ["BLU | REMUX"] },
|
|
]);
|
|
expect(ev.trace?.join("\n")).toContain("规则组「不要原盘」@r3 硬排除 BLU | REMUX 命中");
|
|
});
|
|
|
|
it("多组串联取交集,pri 取最后一个带层的组", () => {
|
|
const spec = base([group("分辨率", "4K > 1080P"), group("字幕", "CNSUB > !CNSUB"), group("空组", "")]);
|
|
const a = evaluateCandidate(spec, rel("Dune.2024.1080p.WEB-DL.H264-HHWEB", "中字"));
|
|
expect(a).toMatchObject({ decision: "accept", pri: 100 });
|
|
const b = evaluateCandidate(spec, rel("Dune.2024.2160p.WEB-DL.H265-FLUX"));
|
|
expect(b).toMatchObject({ decision: "accept", pri: 99 });
|
|
const c = evaluateCandidate(spec, rel("Dune.2024.720p.WEBRip.x264-GRP"));
|
|
expect(c.decision).toBe("reject");
|
|
if (c.decision === "reject")
|
|
expect(c.violations[0]).toMatchObject({ code: "no_layer_matched", expected: "分辨率" });
|
|
});
|
|
|
|
it("ladderRequired=false 的软偏好组不中只降 pri,不拒绝", () => {
|
|
const spec = base([group("偏好", "SPECSUB", { ladderRequired: false })]);
|
|
const r = rel("X.2024.1080p.WEB-DL.H264-G", "特效中字");
|
|
expect(evaluateCandidate(spec, r, null, { subtitle: "特效中字" })).toMatchObject({ pri: 100 });
|
|
expect(evaluateCandidate(spec, rel("X.2024.1080p.WEB-DL.H264-G"))).toMatchObject({ decision: "accept", pri: 0 });
|
|
});
|
|
|
|
it("有规则组阶梯时升级按 pri 严格提升(洗版)", () => {
|
|
const spec = base([group("洗版", "REMUX > BLURAY > WEBDL")], { upgrade: { enabled: true } });
|
|
const up = evaluateCandidate(spec, rel("M.2023.1080p.BluRay.REMUX.AVC-E"), {
|
|
source: "WEB-DL",
|
|
resolution: "1080p",
|
|
pri: 98,
|
|
});
|
|
expect(up).toMatchObject({ decision: "upgrade", pri: 100, fromPri: 98 });
|
|
const same = evaluateCandidate(spec, rel("M.2023.1080p.WEB-DL.H264-G"), { source: "WEB-DL", pri: 98 });
|
|
expect(same.decision).toBe("reject");
|
|
expect(currentPri(spec, { source: "REMUX", resolution: "1080p" })).toBe(100);
|
|
});
|
|
|
|
it("作品原语言中文时 CNSUB 放行(MP tmdb 条件)", () => {
|
|
const spec = base([group("中字", "CNSUB")]);
|
|
const r = rel("Movie.2023.1080p.WEB-DL.H264-G");
|
|
expect(evaluateCandidate(spec, r).decision).toBe("reject");
|
|
expect(evaluateCandidate(spec, r, null, { originalLanguage: "zh" })).toMatchObject({ decision: "accept" });
|
|
});
|
|
|
|
it("rankForSlot 按规则组 pri 排序", () => {
|
|
const spec = base([group("阶梯", "4K > 1080P > 720P")]);
|
|
const ranked = rankForSlot(spec, [
|
|
rel("A.720p.WEB-DL.x264-G"),
|
|
rel("A.2160p.WEB-DL.x265-G"),
|
|
rel("A.1080p.WEB-DL.x264-G"),
|
|
]);
|
|
expect(ranked.map((x) => x.evaluation.decision === "accept" && x.evaluation.pri)).toEqual([100, 99, 98]);
|
|
});
|
|
|
|
it("没有规则组时行为不变", () => {
|
|
const r = rel("Movie.2023.1080p.WEB-DL.H264-G");
|
|
expect(evaluateCandidate(base([]), r)).toEqual(evaluateCandidate({ name: "main", hard: {} }, r));
|
|
});
|
|
});
|