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"); }); });