Files
UHD_Media_Tool/packages/domain/test/library-versions.test.ts
T
rootandClaude Opus 5.5 71b129d85a feat(web): merge search filters into one row and tidy episode versions (POLISH-1)
- H&R becomes a quick-filter facet (yes/no/unknown, with counts) on search
  results and the site resources tab; drop the old free/H&R selects, keep
  size range and sort on the same row (mobile: drawer), single clear button
- legacy free/hr URL params migrate into quick filters; stored selections
  keep the same localStorage key
- search timing and query terms move into TechInfo
- library episode versions: click the whole row to expand, versions listed
  as sibling rows, details only under the selected version, raw values in
  TechInfo
- slot comparison gaps get reason codes (matchGapText in contracts
  reasons.ts): "可换成 2160p", "缺 HDR 版本"

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-29 22:06:32 +08:00

205 lines
8.0 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
audioCodecOf,
channelsLabel,
deliveryOfSpec,
type LocalVersion,
languageOf,
matchVersions,
type ProbeLike,
resolutionFromDims,
type SlotSpec,
sidecarLanguageOf,
specFromDelivery,
summarizeVersions,
VERSION_SPEC_VERSION,
versionSpecOf,
} from "../src/index.ts";
const GB = 1e9;
const DV_FILE = "人生切割术 (2022)/Season 1/Severance.S01E01.2160p.ATVP.WEB-DL.DDP5.1.Atmos.DV.HDR.H.265-FLUX.mkv";
const BD_FILE = "人生切割术 (2022)/Season 1/Severance.S01E01.1080p.BluRay.x264.DTS-HD.MA.5.1-CHD.mkv";
const PROBE_DV: ProbeLike = {
status: "ok",
durationSec: 3421.6,
video: [{ codec: "hevc", width: 3840, height: 1606, pixFmt: "yuv420p10le", hdr: "DV" }],
audio: [
{
codec: "eac3",
profile: "Dolby Digital Plus + Dolby Atmos",
channels: 6,
channelLayout: "5.1(side)",
language: "eng",
},
{ codec: "aac", channels: 2, language: "chi", title: "国语" },
],
subtitles: [
{ codec: "subrip", language: "chi", title: "简体" },
{ codec: "subrip", language: "chi", title: "繁體 cht" },
{ codec: "subrip", language: "eng" },
],
};
describe("版本规格:文件名 + 探测", () => {
it("探测优先给技术事实,来源 / 制作组来自文件名", () => {
const s = versionSpecOf({ path: DV_FILE, probe: PROBE_DV });
expect(s).toMatchObject({
resolution: "2160p",
source: "WEB-DL",
isEncode: false,
videoCodec: "H.265",
hdr: ["DV", "HDR10"],
bitDepth: 10,
releaseGroup: "FLUX",
durationSec: 3422,
specFrom: ["name", "probe"],
});
expect(s.audio).toEqual([
{ codec: "DDP Atmos", channels: "5.1", language: "en" },
{ codec: "AAC", channels: "2.0", language: "zh" },
]);
expect(s.subtitleLanguages).toEqual(["zh-Hans", "zh-Hant", "en"]);
});
it("没有探测结果只用文件名;外挂字幕按文件名记语言", () => {
const s = versionSpecOf({
path: BD_FILE,
sidecarSubtitles: ["Severance.S01E01.chs.srt", "Severance.S01E01.eng.ass"],
});
expect(s).toMatchObject({
resolution: "1080p",
source: "BluRay",
isEncode: true,
videoCodec: "H.264",
hdr: [],
releaseGroup: "CHD",
specFrom: ["name"],
});
expect(s.audio).toEqual([{ codec: "DTS-HD MA", channels: "5.1" }]);
expect(s.subtitleLanguages).toEqual(["zh-Hans", "en"]);
expect(s.durationSec).toBeUndefined();
});
it("裁切过的 4K(3840x1600)仍算 2160p;小工具函数", () => {
expect(resolutionFromDims(3840, 1600)).toBe("2160p");
expect(resolutionFromDims(1920, 800)).toBe("1080p");
expect(resolutionFromDims(1280, 536)).toBe("720p");
expect(resolutionFromDims()).toBeUndefined();
expect(audioCodecOf("truehd", undefined, "TrueHD Atmos 7.1")).toBe("TrueHD Atmos");
expect(audioCodecOf("dts", "DTS-HD MA + DTS:X")).toBe("DTS:X");
expect(audioCodecOf("dts", "DTS-HD MA")).toBe("DTS-HD MA");
expect(channelsLabel(8)).toBe("7.1");
expect(channelsLabel(undefined, "stereo")).toBe("2.0");
expect(languageOf("und")).toBeUndefined();
expect(languageOf("jpn")).toBe("ja");
expect(sidecarLanguageOf("x.zh-Hant.ass")).toBe("zh-Hant");
});
it("写回 delivery 与读回互为逆;旧口径返回 null", () => {
const s = versionSpecOf({ path: DV_FILE, probe: PROBE_DV });
const d = deliveryOfSpec(s);
expect(d.specVersion).toBe(VERSION_SPEC_VERSION);
expect(d.sourceType).toBe("WEB-DL");
expect(d.audioCodecs).toEqual(["DDP Atmos", "AAC"]);
expect(specFromDelivery(JSON.parse(JSON.stringify(d)))).toEqual(s);
expect(specFromDelivery({ resolution: "2160p", sourceType: "WEB-DL" })).toBeNull();
});
});
describe("汇总", () => {
it("按 分辨率 + 来源 + HDR 分组,DV 带 HDR10 兜底只算 DV", () => {
const dv = versionSpecOf({ path: DV_FILE, probe: PROBE_DV });
const bd = versionSpecOf({ path: BD_FILE });
const sum = summarizeVersions([
{ spec: dv, sizeBytes: 14.2 * GB },
{ spec: dv, sizeBytes: 13 * GB },
{ spec: bd, sizeBytes: 8 * GB },
]);
expect(sum.versionCount).toBe(3);
expect(sum.sizeBytes).toBe(35.2 * GB);
expect(sum.specs).toEqual([
{ resolution: "2160p", source: "WEB-DL", hdr: ["DV"], count: 2 },
{ resolution: "1080p", source: "BluRay", hdr: [], count: 1 },
]);
});
});
describe("与版本目标比对", () => {
const v = (id: string, path: string, probe?: ProbeLike, size = 10 * GB): LocalVersion => ({
assetId: id,
path,
spec: versionSpecOf({ path, probe: probe ?? null }),
sizeBytes: size,
unitCount: 1,
});
const target: SlotSpec = {
id: "slot-4k",
name: "4K",
hard: { resolutions: ["2160p"], minSeeders: 5, sites: ["only-site"], include: ["FLUX"], maxSizeBytes: 1 },
};
it("没有版本 = missing", () => {
expect(matchVersions(target, [], { isEpisode: true })).toEqual({
slotId: "slot-4k",
state: "missing",
assetId: null,
reasons: [],
codes: [],
});
});
it("两个版本里有一个达标 = satisfied,指向达标的那个;站点/做种/关键词/整包体积条件不参与", () => {
const m = matchVersions(target, [v("bd", BD_FILE), v("dv", DV_FILE, PROBE_DV)], { isEpisode: true });
expect(m).toMatchObject({ state: "satisfied", assetId: "dv" });
});
it("都不达标 = upgradeable,附不达标原因", () => {
const m = matchVersions(target, [v("bd", BD_FILE)], { isEpisode: true });
expect(m.state).toBe("upgradeable");
expect(m.assetId).toBe("bd");
expect(m.reasons.join(" ")).toMatch(/1080p/);
expect(m.codes).toEqual(["version_resolution:2160p"]);
});
it("差距原因码:HDR / 字幕 / 来源带目标参数", () => {
const hdr: SlotSpec = { id: "h", name: "h", hard: { hdr: { anyOf: ["DV", "HDR10"] } } };
expect(matchVersions(hdr, [v("bd", BD_FILE)], { isEpisode: true }).codes).toEqual(["version_hdr"]);
const dvOnly: SlotSpec = { id: "d", name: "d", hard: { hdr: { anyOf: ["DV"] } } };
expect(matchVersions(dvOnly, [v("bd", BD_FILE)], { isEpisode: true }).codes).toEqual(["version_hdr:DV"]);
const remux: SlotSpec = { id: "r", name: "r", hard: { sources: ["REMUX", "BluRay-Disc"] } };
expect(matchVersions(remux, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true }).codes).toEqual([
"version_source:REMUX",
]);
});
it("达标但升级策略还有余量 = upgradeable;到顶 = satisfied", () => {
const up: SlotSpec = { id: "s", name: "x", hard: {}, upgrade: { enabled: true } };
const web = matchVersions(up, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true });
expect(web).toMatchObject({
state: "upgradeable",
assetId: "dv",
reasons: ["来源还能升级"],
codes: ["version_source_upgrade"],
});
const capped: SlotSpec = { ...up, upgrade: { enabled: true, ceilingTier: 2 } };
expect(matchVersions(capped, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true }).state).toBe("satisfied");
const onlyWeb: SlotSpec = { ...up, hard: { sources: ["WEB-DL"] } };
expect(matchVersions(onlyWeb, [v("dv", DV_FILE, PROBE_DV)], { isEpisode: true }).state).toBe("satisfied");
});
it("只凭文件名时字幕未知不判不达标;探测过且缺中字则不达标", () => {
const needZh: SlotSpec = { id: "z", name: "中字", hard: { requiredSubtitles: ["zh"] } };
expect(matchVersions(needZh, [v("bd", BD_FILE)], { isEpisode: true }).state).toBe("satisfied");
const noZh: ProbeLike = { ...PROBE_DV, subtitles: [{ language: "eng" }] };
expect(matchVersions(needZh, [v("dv", DV_FILE, noZh)], { isEpisode: true }).state).toBe("upgradeable");
});
it("电影保留整片体积条件", () => {
const small: SlotSpec = { id: "m", name: "m", hard: { maxSizeBytes: 5 * GB } };
const movie = "Oppenheimer.2023.2160p.UHD.BluRay.REMUX.HDR10.HEVC.TrueHD.7.1.Atmos-FraMeSToR.mkv";
expect(matchVersions(small, [v("r", movie, undefined, 80 * GB)], { isEpisode: false }).state).toBe("upgradeable");
expect(matchVersions(small, [v("r", movie, undefined, 80 * GB)], { isEpisode: true }).state).toBe("satisfied");
});
});