refactor(core): migrate to Bun and converge acquisition policies and Agent boundaries
This commit is contained in:
1 parent
3f1c6d02f6
commit
27c0f27434
268 files changed
+7468
-7852
No files matched your search
@@ -0,0 +1,356 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
evaluateCandidate,
|
||||
type ParsedRelease,
|
||||
parseRelease,
|
||||
parseRuleString,
|
||||
type QualityFacts,
|
||||
type RuleGroupSpec,
|
||||
rankForSlot,
|
||||
type SlotSpec,
|
||||
seasonReleaseKey,
|
||||
selectAcquisitionPolicy,
|
||||
selectSeasonRelease,
|
||||
} from "../src/index.ts";
|
||||
|
||||
const release = (title: string, facts: Partial<ParsedRelease> = {}): ParsedRelease => ({
|
||||
...parseRelease(title),
|
||||
...facts,
|
||||
});
|
||||
const group = (name: string, rule: string): RuleGroupSpec => ({ name, layers: parseRuleString(rule).layers });
|
||||
const current: QualityFacts = release("Show.S01E01.1080p.WEB-DL.H265-OTHER");
|
||||
const target = release("Show.S01E02.1080p.WEB-DL.H265-CHD");
|
||||
const consistent: SlotSpec = {
|
||||
name: "正片",
|
||||
hard: { resolutions: ["1080p", "2160p"] },
|
||||
rules: { groups: [group("允许收录", "1080P | 4K")] },
|
||||
upgrade: { enabled: true, consistency: "season_release" },
|
||||
};
|
||||
|
||||
describe("按分类选择默认收录策略", () => {
|
||||
const policies = [
|
||||
{ id: "global", scope: {} },
|
||||
{ id: "series", scope: { mediaKinds: ["series" as const] } },
|
||||
{ id: "animation", scope: { categories: { tv: ["动漫剧集"] } } },
|
||||
];
|
||||
|
||||
it("订阅显式指定的策略覆盖类型和分类范围", () => {
|
||||
expect(
|
||||
selectAcquisitionPolicy(policies, { explicitId: "series", mediaKind: "movie", category: "动画电影" })?.id,
|
||||
).toBe("series");
|
||||
});
|
||||
|
||||
it("显式指定的策略不存在时不悄悄回退", () => {
|
||||
expect(
|
||||
selectAcquisitionPolicy(policies, { explicitId: "missing", mediaKind: "series", category: "动漫剧集" }),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("分类匹配优先于类型默认,类型默认优先于全局默认", () => {
|
||||
expect(selectAcquisitionPolicy(policies, { mediaKind: "series", category: "动漫剧集" })?.id).toBe("animation");
|
||||
expect(selectAcquisitionPolicy(policies, { mediaKind: "series", category: "华语剧集" })?.id).toBe("series");
|
||||
expect(selectAcquisitionPolicy(policies, { mediaKind: "movie", category: "动画电影" })?.id).toBe("global");
|
||||
});
|
||||
|
||||
it.each(["movie", "series", "variety"] as const)("%s 不串用另一类型的同名分类策略", (mediaKind) => {
|
||||
const scoped = [
|
||||
{ id: "variety", scope: { mediaKinds: ["variety" as const], categories: { tv: ["同名分类"] } } },
|
||||
{ id: "movie", scope: { categories: { movie: ["同名分类"] } } },
|
||||
{ id: "series", scope: { mediaKinds: ["series" as const], categories: { tv: ["同名分类"] } } },
|
||||
];
|
||||
expect(selectAcquisitionPolicy(scoped, { mediaKind, category: "同名分类" })?.id).toBe(mediaKind);
|
||||
});
|
||||
|
||||
it("同一范围按传入的最新发布顺序取第一个", () => {
|
||||
const latest = { id: "latest", scope: { categories: { tv: ["动漫剧集"] } } };
|
||||
const old = { id: "old", scope: { categories: { tv: ["动漫剧集"] } } };
|
||||
expect(selectAcquisitionPolicy([latest, old], { mediaKind: "series", category: "动漫剧集" })).toBe(latest);
|
||||
expect(selectAcquisitionPolicy([old, latest], { mediaKind: "series", category: "动漫剧集" })).toBe(old);
|
||||
});
|
||||
|
||||
it("分类未知时跳过分类限定策略,仍可使用类型默认", () => {
|
||||
expect(selectAcquisitionPolicy(policies, { mediaKind: "series", category: null })?.id).toBe("series");
|
||||
});
|
||||
|
||||
it("类型或分类没有匹配且无默认时返回 undefined", () => {
|
||||
const scoped = policies.slice(1);
|
||||
expect(selectAcquisitionPolicy(scoped, { mediaKind: "movie", category: "动漫剧集" })).toBeUndefined();
|
||||
expect(selectAcquisitionPolicy([policies[2]!], { mediaKind: "series", category: null })).toBeUndefined();
|
||||
expect(selectAcquisitionPolicy([], { mediaKind: "variety", category: "综艺" })).toBeUndefined();
|
||||
});
|
||||
|
||||
it("空的分类列表仍按类型默认处理", () => {
|
||||
const typeDefault = { id: "type", scope: { mediaKinds: ["series" as const], categories: { movie: [], tv: [] } } };
|
||||
expect(selectAcquisitionPolicy([policies[0]!, typeDefault], { mediaKind: "series", category: null })).toBe(
|
||||
typeDefault,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("整季同套的规格与目标选择", () => {
|
||||
it("发布组大小写、联合组顺序、HDR 顺序不产生新的版本身份", () => {
|
||||
const first = {
|
||||
...target,
|
||||
releaseGroup: { name: "CHD@FLUX", source: "suffix" as const },
|
||||
hdr: ["DV", "HDR10"] as const,
|
||||
};
|
||||
const second = {
|
||||
...target,
|
||||
releaseGroup: { name: "flux@chd", source: "known" as const },
|
||||
hdr: ["HDR10", "DV"] as const,
|
||||
};
|
||||
expect(seasonReleaseKey({ ...first, hdr: [...first.hdr] })).toBe(
|
||||
seasonReleaseKey({ ...second, hdr: [...second.hdr] }),
|
||||
);
|
||||
});
|
||||
|
||||
it.each(["resolution", "source", "videoCodec", "releaseGroup"] as const)(
|
||||
"缺少 %s 时不声称属于完整成套版本",
|
||||
(field) => {
|
||||
expect(seasonReleaseKey({ ...target, [field]: undefined })).toBeNull();
|
||||
},
|
||||
);
|
||||
|
||||
it("来源、分辨率、编码和剪辑不同分别是不同的成套版本", () => {
|
||||
for (const change of [
|
||||
{ source: "BluRay" as const },
|
||||
{ resolution: "2160p" as const },
|
||||
{ videoCodec: "H.264" as const },
|
||||
{ cut: "Extended" as const },
|
||||
{ hdr: ["DV" as const] },
|
||||
]) {
|
||||
expect(seasonReleaseKey({ ...target, ...change })).not.toBe(seasonReleaseKey(target));
|
||||
}
|
||||
});
|
||||
|
||||
const unrestricted: SlotSpec = { name: "主版本", hard: {} };
|
||||
it.each([
|
||||
{
|
||||
name: "来源等级优先于更高分辨率和软偏好",
|
||||
spec: { ...unrestricted, soft: { groups: ["CHD"] } },
|
||||
weaker: release("Show.S01E01.2160p.WEB-DL.H265-CHD"),
|
||||
better: release("Show.S01E02.1080p.BluRay.H264-OTHER"),
|
||||
},
|
||||
{
|
||||
name: "同来源时分辨率优先于软偏好",
|
||||
spec: { ...unrestricted, soft: { groups: ["CHD"] } },
|
||||
weaker: target,
|
||||
better: release("Show.S01E02.2160p.WEB-DL.H265-OTHER"),
|
||||
},
|
||||
{
|
||||
name: "同档规格按发布组软偏好排序",
|
||||
spec: { ...unrestricted, soft: { groups: ["CHD", "OTHER"] } },
|
||||
weaker: release("Show.S01E01.1080p.WEB-DL.H265-OTHER"),
|
||||
better: target,
|
||||
},
|
||||
{
|
||||
name: "同档规格按 HDR 软偏好排序",
|
||||
spec: { ...unrestricted, soft: { hdr: ["DV" as const, "HDR10" as const] } },
|
||||
weaker: release("Show.S01E01.1080p.WEB-DL.HDR.H265-CHD"),
|
||||
better: release("Show.S01E02.1080p.WEB-DL.DV.H265-CHD"),
|
||||
},
|
||||
{
|
||||
name: "同档规格按编码软偏好排序",
|
||||
spec: { ...unrestricted, soft: { codecs: ["H.265" as const, "H.264" as const] } },
|
||||
weaker: release("Show.S01E01.1080p.WEB-DL.H264-CHD"),
|
||||
better: target,
|
||||
},
|
||||
])("$name,成套选择与候选排序一致", ({ spec, weaker, better }) => {
|
||||
expect(rankForSlot(spec, [weaker, better])[0]?.candidate).toBe(better);
|
||||
expect(selectSeasonRelease(spec, [weaker, better])).toBe(better);
|
||||
expect(selectSeasonRelease(spec, [better, weaker])).toBe(better);
|
||||
});
|
||||
|
||||
it("组合优先级先于来源和分辨率等级", () => {
|
||||
const spec: SlotSpec = { ...unrestricted, rules: { groups: [group("来源偏好", "WEBDL > BLURAY")] } };
|
||||
const blue = release("Show.S01E01.2160p.BluRay.H265-OTHER");
|
||||
expect(rankForSlot(spec, [blue, target])[0]?.candidate).toBe(target);
|
||||
expect(selectSeasonRelease(spec, [blue, target])).toBe(target);
|
||||
});
|
||||
|
||||
it("规格不完整的版本不参与成套选择", () => {
|
||||
const incomplete = { ...target, videoCodec: undefined, pri: 1000 };
|
||||
expect(selectSeasonRelease(unrestricted, [incomplete, target])).toBe(target);
|
||||
expect(selectSeasonRelease(unrestricted, [incomplete])).toBeUndefined();
|
||||
});
|
||||
|
||||
it("同档没有偏好时目标不随数据库返回顺序反复变化", () => {
|
||||
const other = release("Show.S01E02.1080p.WEB-DL.H265-OTHER");
|
||||
expect(selectSeasonRelease(unrestricted, [target, other])).toBe(selectSeasonRelease(unrestricted, [other, target]));
|
||||
});
|
||||
});
|
||||
|
||||
describe("追更和洗版分别使用规则", () => {
|
||||
const phased: SlotSpec = {
|
||||
name: "主版本",
|
||||
hard: { resolutions: ["1080p", "2160p"] },
|
||||
rules: { groups: [group("追更", "WEBDL")] },
|
||||
upgradeRules: { groups: [group("洗版", "BLURAY > WEBDL")] },
|
||||
upgrade: { enabled: true },
|
||||
};
|
||||
const blue = release("Show.S01E02.1080p.BluRay.H265-CHD");
|
||||
|
||||
it("补齐缺集按追更规则,洗版规则不提前过滤", () => {
|
||||
expect(evaluateCandidate(phased, target)).toMatchObject({ decision: "accept", pri: 100 });
|
||||
expect(evaluateCandidate(phased, blue)).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ field: "rule", expected: "追更" })],
|
||||
});
|
||||
});
|
||||
|
||||
it("已有当前资产时改用洗版规则,并按洗版规则重算当前档位", () => {
|
||||
expect(evaluateCandidate(phased, blue, current)).toMatchObject({ decision: "upgrade", pri: 100, fromPri: 99 });
|
||||
expect(evaluateCandidate(phased, target, current)).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ code: "not_higher_priority" })],
|
||||
});
|
||||
});
|
||||
|
||||
it("洗版专用硬条件不阻止追更,但在已有资产时生效", () => {
|
||||
const spec: SlotSpec = { ...phased, upgradeHard: { resolutions: ["2160p"] } };
|
||||
expect(evaluateCandidate(spec, target).decision).toBe("accept");
|
||||
expect(evaluateCandidate(spec, blue, current)).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ field: "resolution", code: "not_allowed" })],
|
||||
});
|
||||
});
|
||||
|
||||
it.each(["1080p", "2160p"] as const)("允许分辨率 %s 在追更和洗版阶段均可使用", (resolution) => {
|
||||
const spec: SlotSpec = { name: "主版本", hard: phased.hard, upgrade: { enabled: true } };
|
||||
const candidate = release(`Show.S01E02.${resolution}.BluRay.H265-CHD`);
|
||||
expect(evaluateCandidate(spec, candidate).decision).toBe("accept");
|
||||
expect(evaluateCandidate(spec, candidate, current).decision).toBe("upgrade");
|
||||
});
|
||||
|
||||
it.each(["720p", "4320p"] as const)("范围外的分辨率 %s 不因更优来源或整季对齐而放行", (resolution) => {
|
||||
const candidate = release(`Show.S01E02.${resolution}.BluRay.H265-CHD`);
|
||||
expect(evaluateCandidate(consistent, candidate).decision).toBe("reject");
|
||||
expect(evaluateCandidate(consistent, candidate, current, { seasonReleaseTarget: candidate })).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: expect.arrayContaining([expect.objectContaining({ field: "resolution", code: "not_allowed" })]),
|
||||
});
|
||||
});
|
||||
|
||||
it("分辨率未知时保持待补充,不把未知当作允许范围", () => {
|
||||
expect(evaluateCandidate(phased, { ...target, resolution: undefined })).toMatchObject({
|
||||
decision: "unknown_field",
|
||||
missing: ["resolution"],
|
||||
});
|
||||
});
|
||||
|
||||
it("组合条件的编码未知时,不能因 NOT 自动命中低档", () => {
|
||||
const spec: SlotSpec = { name: "主版本", hard: {}, rules: { groups: [group("编码", "H265 > !H265")] } };
|
||||
expect(evaluateCandidate(spec, release("Show.S01E02.1080p.WEB-DL-CHD"))).toMatchObject({
|
||||
decision: "unknown_field",
|
||||
missing: ["codec"],
|
||||
});
|
||||
});
|
||||
|
||||
it("高档分辨率已明确不满足时,无关的未知编码不阻止已匹配的低档", () => {
|
||||
const spec: SlotSpec = {
|
||||
name: "主版本",
|
||||
hard: {},
|
||||
rules: { groups: [group("组合档位", "4K & H265 > 1080P")] },
|
||||
};
|
||||
expect(evaluateCandidate(spec, release("Show.S01E02.1080p.WEB-DL-CHD"))).toMatchObject({
|
||||
decision: "accept",
|
||||
pri: 99,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("整季同套的同档对齐不绕过升级限制", () => {
|
||||
it("同档的不同发布组可以逐集对齐到选定的整季版本", () => {
|
||||
expect(evaluateCandidate(consistent, target, current, { seasonReleaseTarget: target })).toMatchObject({
|
||||
decision: "upgrade",
|
||||
pri: 100,
|
||||
fromPri: 100,
|
||||
reasons: expect.arrayContaining(["season_release_aligned"]),
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ name: "来源", source: "BluRay" as const, resolution: "1080p" as const },
|
||||
{ name: "分辨率", source: "WEB-DL" as const, resolution: "2160p" as const },
|
||||
])("同档对齐不能降低当前文件的$name", ({ source, resolution }) => {
|
||||
expect(
|
||||
evaluateCandidate(consistent, target, { ...current, source, resolution }, { seasonReleaseTarget: target }),
|
||||
).toMatchObject({ decision: "reject", violations: [expect.objectContaining({ code: "lower_tier" })] });
|
||||
});
|
||||
|
||||
it("当前文件已经同套时不重复整理或下载", () => {
|
||||
expect(evaluateCandidate(consistent, target, target, { seasonReleaseTarget: target }).decision).toBe("reject");
|
||||
const normalizedCurrent = { ...target, releaseGroup: { name: "chd", source: "known" as const } };
|
||||
expect(evaluateCandidate(consistent, target, normalizedCurrent, { seasonReleaseTarget: target }).decision).toBe(
|
||||
"reject",
|
||||
);
|
||||
});
|
||||
|
||||
it("另一套同档资源不能替换已选定的当季目标", () => {
|
||||
const other = release("Show.S01E02.1080p.WEB-DL.H265-FLUX");
|
||||
expect(evaluateCandidate(consistent, other, current, { seasonReleaseTarget: target })).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ code: "different_season_release" })],
|
||||
});
|
||||
});
|
||||
|
||||
it("关闭升级时,同档对齐也不能发起替换", () => {
|
||||
const spec = { ...consistent, upgrade: { ...consistent.upgrade!, enabled: false } };
|
||||
expect(evaluateCandidate(spec, target, current, { seasonReleaseTarget: target })).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ code: "upgrade_disabled" })],
|
||||
});
|
||||
});
|
||||
|
||||
it("全集洗版不能因同档对齐而接受单集或播出日期资源", () => {
|
||||
const spec: SlotSpec = { ...consistent, upgrade: { ...consistent.upgrade!, mode: "full_pack" } };
|
||||
for (const candidate of [target, { ...target, episodes: undefined, airDate: "20261013" }]) {
|
||||
expect(evaluateCandidate(spec, candidate, current, { seasonReleaseTarget: candidate })).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ code: "not_full_pack" })],
|
||||
});
|
||||
}
|
||||
const pack = release("Show.S01.1080p.WEB-DL.H265-CHD");
|
||||
expect(pack.episodes).toBeUndefined();
|
||||
expect(evaluateCandidate(spec, pack, current, { seasonReleaseTarget: pack }).decision).toBe("upgrade");
|
||||
});
|
||||
|
||||
it("不合格蓝光压制组不能因同档对齐绕过名单", () => {
|
||||
const spec: SlotSpec = {
|
||||
...consistent,
|
||||
upgrade: { ...consistent.upgrade!, encodeGroupAllowlist: ["CHD"] },
|
||||
};
|
||||
const old = release("Show.S01E01.1080p.BluRay.x265-OTHER");
|
||||
const unqualified = release("Show.S01E02.1080p.BluRay.x265-BADGRP");
|
||||
expect(unqualified.isEncode).toBe(true);
|
||||
expect(evaluateCandidate(spec, unqualified, old, { seasonReleaseTarget: unqualified })).toMatchObject({
|
||||
decision: "reject",
|
||||
violations: [expect.objectContaining({ code: "encode_not_qualified" })],
|
||||
});
|
||||
const qualified = release("Show.S01E02.1080p.BluRay.x265-chd");
|
||||
expect(evaluateCandidate(spec, qualified, old, { seasonReleaseTarget: qualified }).decision).toBe("upgrade");
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ field: "resolution", missing: "resolution" },
|
||||
{ field: "source", missing: "source" },
|
||||
{ field: "videoCodec", missing: "codec" },
|
||||
{ field: "releaseGroup", missing: "group" },
|
||||
] as const)("候选缺少 $field 时不执行成套替换", ({ field, missing }) => {
|
||||
const candidate = { ...target, [field]: undefined };
|
||||
expect(evaluateCandidate(consistent, candidate, current, { seasonReleaseTarget: target })).toMatchObject({
|
||||
decision: "unknown_field",
|
||||
missing: expect.arrayContaining([missing]),
|
||||
});
|
||||
});
|
||||
|
||||
it("季目标缺失或规格不完整时等待,不自行认定当前候选是目标", () => {
|
||||
expect(evaluateCandidate(consistent, target, current)).toMatchObject({
|
||||
decision: "unknown_field",
|
||||
missing: ["current_asset"],
|
||||
});
|
||||
expect(
|
||||
evaluateCandidate(consistent, target, current, { seasonReleaseTarget: { ...target, videoCodec: undefined } }),
|
||||
).toMatchObject({ decision: "unknown_field", missing: ["current_asset"] });
|
||||
});
|
||||
});
|
||||
@@ -194,7 +194,7 @@ describe("MP 过滤规则差分(filter-cases.json)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
/** 生成/更新登记时用:UMT_FILTER_DUMP=1 deno task test 打印当前不一致 */
|
||||
/** 生成/更新登记时用:UMT_FILTER_DUMP=1 bun run test 打印当前不一致 */
|
||||
if (process.env.UMT_FILTER_DUMP) {
|
||||
const rows: Record<string, unknown> = {};
|
||||
for (const c of fx.cases) {
|
||||
|
||||
Reference in new issue
Block a user