import { describe, expect, it } from "vitest"; import { cnToInt, evalEpisodeOffset, expandEpisodes, fileKindOf, OffsetExpressionError, type ParsedRelease, parseRelease, parseReleasePath, splitReleasePath, } from "../src/release-parser/index.ts"; type Expect = Partial & { group?: string; groupSource?: string }; interface Sample { id: string; input: string; subtitle?: string; expect: Expect; /** 与 MoviePilot 行为不同的地方,写明原因 */ deviation?: string; } function check(r: ParsedRelease, e: Expect) { const { group, groupSource, ...rest } = e; for (const [k, v] of Object.entries(rest)) { expect(r[k as keyof ParsedRelease], `${r.raw} → ${k}`).toEqual(v); } if (group !== undefined) expect(r.releaseGroup?.name, `${r.raw} → group`).toBe(group); if (groupSource !== undefined) expect(r.releaseGroup?.source).toBe(groupSource); } // M-xx 编号对应 docs/porting/moviepilot-metadata-recognition.md §9.1 const TITLES: Sample[] = [ { id: "M-01", input: "Oppenheimer.2023.2160p.UHD.BluRay.REMUX.DV.HDR.HEVC.TrueHD.7.1.Atmos-FraMeSToR", expect: { titleEn: "Oppenheimer", year: 2023, resolution: "2160p", source: "REMUX", isEncode: false, videoCodec: "H.265", hdr: ["DV", "HDR10"], audio: ["TrueHD 7.1", "Atmos"], group: "FraMeSToR", confidence: "rule_confirmed", }, deviation: "MP 发布组表无 FraMeSToR 时 grp=None;本项目种子表收录", }, { id: "M-02", input: "奥本海默 Oppenheimer 2023 2160p UHD Blu-ray HEVC DV TrueHD 7.1-MTeam", expect: { title: "奥本海默", titleCn: "奥本海默", titleEn: "Oppenheimer", // Blu-ray + HEVC 且没有 x265/H.265 → 原盘(对照 MP 内置规则 BLU) source: "BluRay-Disc", isEncode: false, uhd: true, hdr: ["DV"], group: "MTeam", groupSource: "known", }, }, { id: "M-03", input: "The.Last.of.Us.S01.2023.1080p.WEB-DL.H264.DDP5.1.Atmos-ADWeb", expect: { titleEn: "The Last of Us", season: 1, episodes: undefined, year: 2023, audio: ["DDP 5.1", "Atmos"], group: "ADWeb", isSeasonPack: true, packHint: "season_pack", }, }, { id: "M-04", input: "The.Last.of.Us.S01E03.Long.Long.Time.2160p.MAX.WEB-DL.DDP5.1.Atmos.DV.HDR.H.265-FLUX", expect: { titleEn: "The Last of Us", season: 1, episodes: { start: 3, end: 3 }, webSource: "Max", videoCodec: "H.265", hdr: ["DV", "HDR10"], packHint: "single", }, }, { id: "M-05", input: "Breaking.Bad.S01-S05.Complete.1080p.BluRay.x264-ROVERS", expect: { season: 1, seasonEnd: 5, packHint: "multi_season_pack", isSeasonPack: true, encoder: "x264" }, }, { id: "M-06", input: "庆余年 第二季 Joy of Life S02 2024 2160p WEB-DL H265 60fps DDP5.1-HHWEB", expect: { titleCn: "庆余年", titleEn: "Joy of Life", season: 2, fps: 60, group: "HHWEB" }, }, { id: "M-07", input: "庆余年.Joy.of.Life.S02E01-E06.2024.2160p.WEB-DL.H265.AAC-ADWeb", expect: { season: 2, episodes: { start: 1, end: 6 }, packHint: "multi_episode", isSeasonPack: false }, }, { id: "M-08", input: "The.Lord.of.the.Rings.The.Fellowship.of.the.Ring.2001.Extended.Edition.2160p.UHD.BluRay.x265.10bit.HDR.DTS-HD.MA.6.1-CHD", expect: { titleEn: "The Lord of the Rings The Fellowship of the Ring", cut: "Extended", bitDepth: 10, audio: ["DTS-HD MA 6.1"], group: "CHD", }, deviation: "MP 把 Extended.Edition 当干扰词删除;本项目保留为 cut", }, { id: "M-09", input: "Kill.Bill.Vol.1.2003.Part.1.1080p.BluRay.x264-CHD", expect: { titleEn: "Kill Bill Vol 1", year: 2003, part: "Part1" }, }, { id: "M-10", input: "Avatar.The.Way.of.Water.2022.2160p.WEB-DL.DDP5.1.Atmos.HDR10Plus.HEVC-CMCT", expect: { hdr: ["HDR10+"], group: "CMCT", source: "WEB-DL" }, }, { id: "M-11", input: "奔跑吧 第十二季 20240426 第1期 1080p WEB-DL H264 AAC-HHWEB", expect: { titleCn: "奔跑吧", season: 12, issue: 1, airDate: "20240426", episodes: undefined, packHint: "single", mediaTypeHint: "tv", }, deviation: "MP 把第1期当 episode、忽略 20240426;本项目 issue/airDate 分开保存", }, { id: "M-12", input: "奔跑吧.Keep.Running.S12.2024.04.26.1080p.WEB-DL.H264.AAC-HHWEB", expect: { season: 12, airDate: "20240426", year: undefined, isSeasonPack: false, packHint: "single" }, deviation: "MP 删除日期后判成整季包;本项目有日期即单期", }, { id: "M-13", input: "向往的生活 第八季 全12期 2024 1080p WEB-DL", expect: { titleCn: "向往的生活", season: 8, totalEpisodes: 12, year: 2024, isSeasonPack: true }, deviation: "MP 负向前瞻导致季号丢失", }, { id: "M-14", input: "[喵萌奶茶屋&LoliHouse] 葬送的芙莉莲 / Sousou no Frieren - 12 [WebRip 1080p HEVC-10bit AAC][简繁日内封字幕]", expect: { titleCn: "葬送的芙莉莲", titleEn: "Sousou no Frieren", episodes: { start: 12, end: 12 }, season: 1, seasonInferred: true, group: "喵萌奶茶屋@LoliHouse", bitDepth: 10, source: "WEBRip", subtitles: ["zh-Hans", "zh-Hant", "ja"], confidence: "multi_evidence", }, deviation: "MP 季号为空;本项目推定 1 并标 seasonInferred", }, { id: "M-15", input: "Frieren.S01E12.1080p.NF.WEB-DL.DDP2.0.H.264-VARYG", expect: { webSource: "Netflix", audio: ["DDP 2.0"], group: "VARYG", videoCodec: "H.264" }, }, { id: "M-16", input: "黑暗荣耀 The Glory 2022 S01 Complete 1080p NF WEB-DL x264 DDP5.1-HHWEB", subtitle: "黑暗荣耀 第一季 全8集 宋慧乔", expect: { season: 1, totalEpisodes: 8, isSeasonPack: true, confidence: "multi_evidence" }, }, { id: "M-17", input: "Dune.Part.Two.2024.2160p.UHD.BluRay.REMUX.HDR.HEVC.Atmos-MTeam", expect: { titleEn: "Dune Part Two", part: undefined, audio: ["Atmos"], source: "REMUX" }, }, { id: "M-18", input: "Some.Show.S02E05E06.1080p.WEB-DL-GRP", expect: { season: 2, episodes: { start: 5, end: 6 }, group: "GRP", groupSource: "suffix" }, }, { id: "M-19", input: "狂飙 The Knockout 2023 全39集 1080p WEB-DL H264 AAC-OurTV", expect: { season: 1, seasonInferred: true, totalEpisodes: 39, packHint: "season_pack" }, }, { id: "M-20", input: "Some.Show.2019.1080p.WEB-DL-GRP", subtitle: "第1-10集 全10集", expect: { episodes: { start: 1, end: 10 }, totalEpisodes: 10 }, }, { id: "M-21", input: "[Nekomoe kissaten][Oshi no Ko][01-11 Fin][1080p]", expect: { titleEn: "Oshi no Ko", episodes: { start: 1, end: 11 }, season: 1, group: "Nekomoe kissaten" }, }, { id: "M-22", input: "Show.Name.2019-2020.1080p.WEB-DL", expect: { titleEn: "Show Name", year: 2019 } }, // ---- 国际/观众/馒头风格电影 { id: "X-01", input: "Blade.Runner.2049.2017.1080p.BluRay.x264-SPARKS", expect: { titleEn: "Blade Runner 2049", year: 2017, isEncode: true }, }, { id: "X-02", input: "Dune.Part.Two.2024.1080p.BluRay.x264.DTS-HD.MA.7.1-ADE", expect: { group: "ADE", audio: ["DTS-HD MA 7.1"], isEncode: true }, }, { id: "X-03", input: "流浪地球2 The Wandering Earth II 2023 2160p UHD BluRay REMUX HEVC DV TrueHD 7.1 Atmos-MTeam", expect: { titleCn: "流浪地球2", titleEn: "The Wandering Earth II", source: "REMUX" }, }, { id: "X-04", input: "Interstellar.2014.IMAX.1080p.BluRay.x264.DTS-HD.MA.5.1-HDS", expect: { cut: "IMAX", group: "HDS", titleEn: "Interstellar" }, }, { id: "X-05", input: "Blade.Runner.1982.The.Final.Cut.2160p.UHD.BluRay.x265.10bit.HDR.DTS-HD.MA.5.1-CiNEPHiLES", expect: { cut: "Final Cut", titleEn: "Blade Runner", year: 1982 }, }, { id: "X-06", input: "Apocalypse.Now.1979.Theatrical.Cut.1080p.BluRay.x264-AMIABLE", expect: { cut: "Theatrical", group: "AMIABLE", groupSource: "suffix" }, deviation: "未知组 MP 为 None;本项目末段兜底", }, { id: "X-07", input: "Oppenheimer.2023.1080p.BluRay.DD+5.1.x264-EbP", expect: { audio: ["DDP 5.1"], group: "EbP" }, }, { id: "X-08", input: "Oppenheimer.2023.COMPLETE.UHD.BLURAY-SURCODE", expect: { source: "BluRay-Disc", isEncode: false, group: "SURCODE" }, }, { id: "X-09", input: "Some.Movie.2021.BD50.1080p.AVC.DTS-HD.MA.5.1", expect: { source: "BluRay-Disc", isEncode: false, videoCodec: "H.264" }, }, { id: "X-10", input: "Some.Movie.2021.1080p.HDTV.x264-GRP", expect: { source: "HDTV" } }, { id: "X-11", input: "Some.Movie.2021.720p.WEBRip.x264.AAC-YTS", expect: { source: "WEBRip", resolution: "720p", audio: ["AAC"] }, }, { id: "X-12", input: "Some.Movie.2021.DVDRip.XviD-GRP", expect: { source: "DVDRip", videoCodec: "XviD" } }, { id: "X-13", input: "Movie.2020.3840x2160.WEB-DL.HEVC", expect: { resolution: "2160p", titleEn: "Movie" } }, { id: "X-14", input: "Movie.2020.4K.WEB-DL.HEVC-GRP", expect: { resolution: "2160p" } }, { id: "X-15", input: "Mission.Impossible.Dead.Reckoning.Part.One.2023.2160p.UHD.BluRay.x265.10bit.HDR.TrueHD.7.1.Atmos-MTeam", expect: { titleEn: "Mission Impossible Dead Reckoning Part One", part: undefined, audio: ["TrueHD 7.1", "Atmos"] }, }, { id: "X-16", input: "Harry.Potter.and.the.Deathly.Hallows.Part.2.2011.1080p.BluRay.x264-SPARKS", expect: { titleEn: "Harry Potter and the Deathly Hallows Part 2", year: 2011 }, }, { id: "X-17", input: "Movie.Title.2021.1080p.BluRay.Remux.AVC.DTS-HD.MA.5.1-FGT", expect: { source: "REMUX", isEncode: false }, }, { id: "X-18", input: "The.Matrix.1999.Remastered.1080p.BluRay.x264-GRP", expect: { cut: "Remastered" } }, { id: "X-19", input: "Movie.2020.Unrated.1080p.BluRay.x264-GRP", expect: { cut: "Unrated" } }, { id: "X-20", input: "Movie.Name.2019.Directors.Cut.1080p.BluRay.x264-FOO", expect: { cut: "Director's Cut", titleEn: "Movie Name" }, }, { id: "X-21", input: "银翼杀手 导演剪辑版 1982 1080p BluRay x264", expect: { titleCn: "银翼杀手", cut: "Director's Cut", year: 1982 }, }, { id: "X-22", input: "让子弹飞.Let.the.Bullets.Fly.2010.1080p.BluRay.x264.DTS-CMCT", expect: { titleCn: "让子弹飞", titleEn: "Let the Bullets Fly", audio: ["DTS"], group: "CMCT" }, }, { id: "X-23", input: "长安三万里.Chang.An.2023.2160p.WEB-DL.H265.HDR.DDP5.1-OurTV", expect: { titleCn: "长安三万里", hdr: ["HDR10"], group: "OurTV" }, }, { id: "X-24", input: "Movie.2020.1080p.BluRay.x264-GRP 12.5GB", expect: { sizeBytes: Math.round(12.5 * 1024 ** 3), group: "GRP" }, }, { id: "X-25", input: "Movie 2020 1080p WEB-DL 中英字幕", expect: { subtitles: ["zh", "en"] } }, { id: "X-26", input: "Movie 2020 1080p 国语中字 WEB-DL", expect: { subtitles: ["zh"], titleEn: "Movie" } }, { id: "X-27", input: "[简繁英字幕] Movie 2020 1080p WEB-DL", expect: { subtitles: ["zh-Hans", "zh-Hant", "en"], releaseGroup: undefined }, }, { id: "X-28", input: "The Movie 2021", expect: { titleEn: "The Movie", year: 2021, confidence: "rule_confirmed" } }, { id: "X-29", input: "The Movie 1080p WEB-DL", expect: { year: undefined, confidence: "needs_confirm" } }, // ---- 剧集 { id: "T-01", input: "三体 Three-Body S01E05 2023 1080p WEB-DL H264 AAC-OurTV", expect: { titleCn: "三体", titleEn: "Three Body", season: 1, episodes: { start: 5, end: 5 } }, }, { id: "T-02", input: "Loki.S02E01.2160p.DSNP.WEB-DL.DDP5.1.Atmos.DV.HDR.H.265-FLUX", expect: { webSource: "Disney+", hdr: ["DV", "HDR10"] }, }, { id: "T-03", input: "The.Bear.S03.1080p.DSNP.WEB-DL.DDP5.1.H.264-MWeb", expect: { season: 3, isSeasonPack: true, group: "MWeb" }, }, { id: "T-04", input: "Beyond.the.Clouds.2024.S01.1080p.WEB-DL.H264.AAC-ADWeb", expect: { titleEn: "Beyond the Clouds", year: 2024, season: 1 }, }, { id: "T-05", input: "The.Office.US.S05E13-E14.720p.HDTV.x264", expect: { titleEn: "The Office US", episodes: { start: 13, end: 14 }, source: "HDTV" }, }, { id: "T-06", input: "Friends.1x05.720p", expect: { season: 1, episodes: { start: 5, end: 5 } } }, { id: "T-07", input: "Show.Season.2.1080p.BluRay.x264-GRP", expect: { season: 2, isSeasonPack: true } }, { id: "T-08", input: "Show.S01E01.Pilot.1080p.WEB-DL.mkv", expect: { isFile: true, fileKind: "video", extension: "mkv", titleEn: "Show", packHint: "single" }, }, { id: "T-09", input: "Show.S01E01.chs.srt", expect: { fileKind: "subtitle", subtitles: ["zh-Hans"] } }, { id: "T-10", input: "Show.S01E01E02E03.1080p.WEB-DL", expect: { episodes: { start: 1, end: 3 } } }, { id: "T-11", input: "Show.Name.S01.E01.1080p", expect: { season: 1, episodes: { start: 1, end: 1 } } }, { id: "T-12", input: "Show.S01D02.1080p.BluRay", expect: { season: 1, part: "Disc2" } }, { id: "T-13", input: "Planet.Earth.III.S01.2160p.iP.WEB-DL.AAC2.0.HLG.H.265-GRP", expect: { titleEn: "Planet Earth III", hdr: ["HLG"], audio: ["AAC 2.0"] }, }, { id: "T-14", input: "天下长河 第1集 1080p WEB-DL", expect: { titleCn: "天下长河", segment: undefined } }, { id: "T-15", input: "庆余年 第二季 第1集 范闲入京 1080p WEB-DL", expect: { titleCn: "庆余年", season: 2, episodes: { start: 1, end: 1 } }, }, { id: "T-16", input: "[tmdbid=94997] House.of.the.Dragon.S01E03.1080p.mkv", expect: { explicitIds: [{ provider: "tmdb", id: "94997" }], season: 1, titleEn: "House of the Dragon" }, }, { id: "T-17", input: "[tmdbid=0]Foo.2020", expect: { explicitIds: [], titleEn: "Foo" } }, // ---- 动漫 { id: "A-01", input: "[ANi] 葬送的芙莉蓮 - 13 [1080P][Baha][WEB-DL][AAC AVC][CHT].mp4", expect: { group: "ANi", episodes: { start: 13, end: 13 }, subtitles: ["zh-Hant"], titleCn: "葬送的芙莉蓮" }, }, { id: "A-02", input: "[Lilith-Raws] Sousou no Frieren - 01 [Baha][WEB-DL][1080p][AVC AAC][CHT][MP4]", expect: { group: "Lilith-Raws", titleEn: "Sousou no Frieren", episodes: { start: 1, end: 1 } }, }, { id: "A-03", input: "[UnknownSub][Some Anime][05][1080p]", expect: { group: "UnknownSub", groupSource: "bracket", episodes: { start: 5, end: 5 }, titleEn: "Some Anime" }, }, { id: "A-04", input: "[Sub] Show - 26 Fin [1080p]", expect: { episodes: { start: 26, end: 26 } }, }, { id: "A-05", input: "Show 01-26 Fin 1080p", expect: { episodes: { start: 1, end: 26 }, isSeasonPack: true } }, // ---- 综艺 { id: "V-01", input: "快乐大本营 20210903 1080p WEB-DL H264 AAC-HHWEB", expect: { airDate: "20210903", season: undefined, confidence: "needs_confirm", packHint: "single" }, }, { id: "V-02", input: "乘风2024 第5期 下 20240524 1080p WEB-DL", expect: { titleCn: "乘风2024", issue: 5, segment: "lower", airDate: "20240524" }, }, { id: "V-03", input: "披荆斩棘 第三季 第12期 加更版 1080p WEB-DL-HHWEB", expect: { season: 3, issue: 12, contentType: "extra", titleCn: "披荆斩棘" }, }, { id: "V-04", input: "歌手2024 第1期 会员版 1080p", expect: { variantTags: ["会员版"], confidence: "needs_confirm", issue: 1 }, }, { id: "V-05", input: "声生不息 纯享版 20220501 1080p WEB-DL", expect: { contentType: "performance_only", airDate: "20220501" }, }, { id: "V-06", input: "The.Voice.2024.05.03.1080p.WEB.h264-GRP", expect: { titleEn: "The Voice", airDate: "20240503", source: "WEB-DL", year: undefined }, }, { id: "V-07", input: "Late.Night.2024.05.03.Guest.Name.1080p.WEB.h264-GRP", expect: { titleEn: "Late Night", airDate: "20240503" }, }, { id: "V-08", input: "极限挑战 第十季 20240505 第2期 上 1080p WEB-DL", expect: { season: 10, issue: 2, segment: "upper" }, }, { id: "V-09", input: "声生不息 第2期(上) 1080p", expect: { issue: 2, segment: "upper" } }, { id: "V-10", input: "奔跑吧 第十二季 第3期 下 1080p", expect: { issue: 3, segment: "lower", season: 12 } }, { id: "V-11", input: "某综艺 2024年5月3日 完整版 1080p", expect: { airDate: "20240503", segment: "full" } }, { id: "V-12", input: "某综艺 第1期 花絮", expect: { contentType: "behind_the_scenes" } }, { id: "V-13", input: "某综艺 先导片", expect: { contentType: "preview" } }, { id: "V-14", input: "某综艺 第3期 陪看", expect: { contentType: "reaction" } }, { id: "V-15", input: "某综艺 第3期 正片", expect: { contentType: "main" } }, { id: "V-16", input: "某剧 全3季 1080p", expect: { season: 1, seasonEnd: 3, packHint: "multi_season_pack" } }, { id: "V-17", input: "某剧 第1-3季 1080p", expect: { season: 1, seasonEnd: 3 } }, { id: "V-18", input: "某剧 第1-10集 1080p", expect: { episodes: { start: 1, end: 10 } } }, ]; // W5-D:按 MP 差分报告(docs/porting/mp-rust-logic-parity.md §2)补迁的写法,编号对应报告 B/M 条目 const MP_PARITY: Sample[] = [ { id: "B1", input: "【爪爪字幕组】★7月新番[欢迎来到实力至上主义的教室 第二季/Youkoso Jitsuryoku Shijou Shugi no Kyoushitsu e S2][11][1080p][HEVC][GB][MP4]", expect: { titleCn: "欢迎来到实力至上主义的教室", season: 2, episodes: { start: 11, end: 11 }, group: "爪爪字幕组" }, }, { id: "B1b", input: "[GM-Team][国漫][寻剑 第1季][Sword Quest Season 1][2002][02][AVC][GB][1080P]", expect: { titleCn: "寻剑" }, }, { id: "B1c", input: "【幻月字幕组】【22年日剧】【据幸存的六人所说】【04】【1080P】", expect: { titleCn: "据幸存的六人所说" }, }, { id: "B2", input: "[桜都字幕组] 异世界归来的舅舅 / Isekai Ojisan [01][1080p][简体内嵌]", expect: { titleEn: "Isekai Ojisan", episodes: { start: 1, end: 1 }, mediaTypeHint: "tv" }, }, { id: "B3", input: "[秋叶原冥途战争][Akiba Maid Sensou][2022][WEB-DL][1080][TV Series][第01话][LeagueWEB]", expect: { titleCn: "秋叶原冥途战争", resolution: "1080p", group: "LeagueWEB" }, }, { id: "B3b", input: "[某动画][Some Anime][2022][WEB-DL][1080p][TV 03][NewSub]", expect: { titleCn: "某动画", episodes: { start: 3, end: 3 }, group: "NewSub", groupSource: "bracket" }, }, { id: "B4", input: "[Caligula.The.Ultimate.Cut.2023.2160p.UHD.Blu-ray.HEVC.DTS-HD.MA.5.1-BHYS@OurBits][DIY中字原盘] [罗马帝国艳情史][91.86GB].iso", expect: { titleEn: "Caligula", year: 2023, resolution: "2160p", source: "BluRay-Disc", cut: "Ultimate" }, }, { id: "B5", input: "The Long Season 2017 2160p WEB-DL H265 120FPS AAC-XXX", expect: { titleEn: "The Long Season", year: 2017, season: undefined }, }, { id: "B6", input: "2022.8.2.Twelve.Monkeys.1995.GBR.4K.REMASTERED.BluRay.1080p.X264.DTS", expect: { titleEn: "Twelve Monkeys", year: 1995, airDate: undefined, mediaTypeHint: "unknown" }, }, { id: "B7", input: "[YTS.MX] The Shawshank Redemption 1994 1080p BluRay x264", expect: { titleEn: "The Shawshank Redemption", group: "YTS.MX" }, }, { id: "B8", input: "[猎户不鸽发布组] 组长女儿与照料专员 / 组长女儿与保姆 Kumichou Musume to Sewagakari [09] [1080p+]", expect: { titleCn: "组长女儿与保姆", group: "猎户不鸽发布组" }, }, { id: "B8b", input: "[xyx98]传颂之物/Utawarerumono/うたわれるもの[BDrip][1920x1080][TV 01-26 Fin]", expect: { titleCn: "传颂之物", titleEn: "Utawarerumono", episodes: { start: 1, end: 26 } }, }, { id: "B9", input: "哆啦A梦:大雄的宇宙小战争 2021 (2022) - 1080p.mp4", expect: { titleEn: undefined, year: 2022 } }, { id: "B10", input: "[Gal to Kyouryuu][02][BDRIP][1080P][H264_FLAC].mkv", expect: { titleEn: "Gal to Kyouryuu", episodes: { start: 2, end: 2 }, releaseGroup: undefined }, }, { id: "B11", input: "The 355 2022 BluRay 1080p DTS-HD MA5.1 X265.10bit-BeiTai", expect: { audio: ["DTS-HD MA 5.1"] }, }, { id: "B11b", input: "The Heart of Genius E13-14 2022 1080p WEB-DL H264 AAC", expect: { episodes: { start: 13, end: 14 } }, }, { id: "B11c", input: "【极影字幕社】★1月新番 Metallic Rouge/金属口红 第13话 GB 1080P MP4", expect: { titleEn: "Metallic Rouge", titleCn: "金属口红", group: "极影字幕社", subtitles: ["zh-Hans"] }, }, { id: "M1", input: "{[tmdbid=94997;type=tv;s=1;e=3-4]}House.of.the.Dragon.1080p.mkv", expect: { titleEn: "House of the Dragon", explicitIds: [{ provider: "tmdb", id: "94997" }], season: 1, episodes: { start: 3, end: 4 }, mediaTypeHint: "tv", }, }, { id: "M2", input: "Sousou no Frieren - 05 [1080p] [bangumiid=400602].mkv", expect: { explicitIds: [{ provider: "bangumi", id: "400602" }] }, }, { id: "M3a", input: "[AI-Raws] 逆境無頼カイジ #13 (BD HEVC 1920x1080 FLAC)[7CFEE642].mkv", expect: { titleCn: "逆境無頼カイジ", episodes: { start: 13, end: 13 } }, }, { id: "M3b", input: "西部世界 12.mkv", expect: { titleCn: "西部世界", episodes: { start: 12, end: 12 } } }, { id: "M3c", input: "The Heart of Genius S01 13-14 2022 1080p WEB-DL H264 AAC", expect: { season: 1, episodes: { start: 13, end: 14 } }, }, { id: "M3d", input: "流浪地球 2.mkv", expect: { episodes: undefined } }, { id: "M4", input: "Mai Xiang S01 2019 2160p WEB-DL H.265 DDP2.0-HHWEB", subtitle: "麦香 | 全36集 | 4K", expect: { titleCn: "麦香", title: "麦香" }, }, { id: "M4b", input: "Blade Runner 2017 1080p WEB-DL", subtitle: "银翼杀手 | 科幻", expect: { titleCn: undefined } }, { id: "M5", input: "Thor Love and Thunder (2022) [1080p] [WEBRip] [5.1]", expect: { audio: ["5.1"] } }, { id: "M6", input: "Planet.Earth.III.S01.2160p.iP.WEB-DL.AAC2.0.HLG.H.265-GRP", expect: { webSource: "BBC iPlayer" }, }, { id: "M6b", input: "Some Anime S01E02 2022 1080p B-Global WEB-DL X264 AAC-AnimeS@ADWeb[2022年10月新番]", expect: { webSource: "B-Global", titleEn: "Some Anime" }, }, { id: "M7", input: "Sense8 S2E1 2015-2017 1080P WEB-DL X265 AC3£cXcY@FRDS", expect: { group: "cXcY@FRDS", audio: ["AC3"] }, }, { id: "M7b", input: "指环王三部曲合集 The Lord of the Rings Trilogy 2001-2003 Extended 2160p UHD BluRay REMUX", expect: { titleCn: "指环王三部曲" }, }, { id: "DISC", input: "Some.Movie.2021.1080p.Blu-ray.AVC.DTS-HD.MA.5.1-GRP", expect: { source: "BluRay-Disc", isEncode: false }, }, { id: "DISC-x264", input: "Some.Movie.2021.1080p.BluRay.AVC.x264-GRP", expect: { source: "BluRay", isEncode: true } }, { id: "DISC-rip", input: "Some.Movie.2021.1080p.BDRip.AVC-GRP", expect: { source: "BluRay", isEncode: true } }, { id: "SUB-latin", input: "Oppenheimer.2023.2160p.BluRay.x265-GRP", subtitle: "奥本海默 CHS/ENG", expect: { subtitles: ["zh-Hans"] }, }, { id: "SUB-size", input: "Oppenheimer.2023.2160p.BluRay.x265-GRP", subtitle: "奥本海默 60 GB", expect: { subtitles: undefined }, }, ]; describe("MP 差分补迁写法", () => { for (const s of MP_PARITY) { it(`${s.id} ${s.input}`, () => check(parseRelease(s.input, s.subtitle ? { subtitle: s.subtitle } : {}), s.expect)); } it("父目录只有日期不把电影合并成剧集", () => { const r = parseReleasePath( "/movies/Mixed.Collection.20240501.FRDS/12.Years.a.Slave.2013.BluRay.1080p.x265-FRDS/12.Years.a.Slave.2013.BluRay.1080p.x265-FRDS.mkv", ); expect(r.mediaTypeHint).toBe("unknown"); }); }); describe("parseRelease 样本表", () => { it("样本数量 ≥ 60", () => { expect(TITLES.length).toBeGreaterThanOrEqual(60); }); for (const s of TITLES) { it(`${s.id} ${s.input}${s.deviation ? ` [deviation: ${s.deviation}]` : ""}`, () => { const r = parseRelease(s.input, s.subtitle ? { subtitle: s.subtitle } : {}); check(r, s.expect); expect(r.parserVersion).toBe(1); expect(r.raw).toBe(s.input); }); } }); // P-xx 对应迁移文档 §9.2 const PATHS: Sample[] = [ { id: "P-01", input: "/downloads/The.Last.of.Us.S01.2023.1080p.WEB-DL-ADWeb/The.Last.of.Us.S01E03.1080p.WEB-DL-ADWeb.mkv", expect: { season: 1, episodes: { start: 3, end: 3 }, year: 2023, confidence: "multi_evidence" }, }, { id: "P-02", input: "/downloads/庆余年 第二季 Joy of Life S02 2024 2160p WEB-DL H265 DDP5.1-HHWEB/01.mp4", expect: { title: "庆余年", season: 2, year: 2024, episodes: { start: 1, end: 1 }, seasonInferred: undefined }, }, { id: "P-03", input: "/downloads/庆余年 第二季 Joy of Life S02 2024 2160p WEB-DL H265 DDP5.1-HHWEB/第02集.mkv", expect: { episodes: { start: 2, end: 2 }, season: 2, group: "HHWEB", audio: ["DDP 5.1"] }, }, { id: "P-04", input: "/downloads/Breaking.Bad.S01-S05.1080p.BluRay.x264-ROVERS/S03/07.mkv", expect: { title: "Breaking Bad", season: 3, episodes: { start: 7, end: 7 }, seasonEnd: undefined }, }, { id: "P-05", input: "/d/Oppenheimer.2023.2160p.UHD.BluRay.REMUX-FraMeSToR/Featurettes/Making.Of.mkv", expect: { title: "Oppenheimer", contentType: "extra", confidence: "needs_confirm" }, deviation: "MP 把附加内容识别成名为 Making Of 的电影", }, { id: "P-07", input: "/downloads/The Glory 2022 S01 1080p NF WEB-DL-HHWEB/简体.srt", expect: { auxiliaryOnly: true, title: "The Glory", confidence: "needs_confirm", fileKind: "subtitle" }, deviation: "MP 取到根目录名 Downloads", }, { id: "P-08", input: "/downloads/奔跑吧 第十二季 1080p WEB-DL-HHWEB/奔跑吧.20240426.第1期.mp4", expect: { season: 12, issue: 1, airDate: "20240426", episodes: undefined }, }, { id: "P-09", input: "/downloads/奔跑吧 第十二季 1080p WEB-DL-HHWEB/奔跑吧.2024.05.03.mp4", expect: { mediaTypeHint: "tv", season: 12, airDate: "20240503", year: undefined, confidence: "multi_evidence" }, deviation: "MP 文件无类型、不与 TV 目录合并", }, { id: "P-10", input: "/downloads/奔跑吧 第十二季 1080p WEB-DL-HHWEB/奔跑吧.20240503.加更版.mp4", expect: { contentType: "extra", airDate: "20240503", season: 12 }, }, { id: "P-11", input: "/downloads/Kill.Bill.2003.1080p.BluRay.x264-CHD/CD1.mkv", expect: { part: "CD1", title: "Kill Bill", year: 2003 }, deviation: "MP 因 Part 门槛丢失 CD1", }, { id: "P-12", input: "/media/tv/庆余年 (2019)/Season 2/庆余年 - S02E03 - 第 3 集.mkv", expect: { season: 2, episodes: { start: 3, end: 3 }, year: 2019 }, }, { id: "P-13", input: "/dl/[LoliHouse] Sousou no Frieren [01-28][WebRip 1080p]/[LoliHouse] Sousou no Frieren - 13 [WebRip 1080p].mkv", expect: { episodes: { start: 13, end: 13 }, titleEn: "Sousou no Frieren" }, }, { id: "P-14", input: "/dl/Some.Show.S01.1080p/Making.Of.Special.mkv", expect: { mediaTypeHint: "tv", season: 1, confidence: "needs_confirm" }, deviation: "文件无剧集信号、目录是剧集:合并但降级为 needs_confirm", }, { id: "P-15", input: "/dl/Collection.1080p/The.Matrix.Reloaded.2003.1080p.BluRay.x264.mkv", expect: { year: 2003, confidence: "rule_confirmed" }, }, { id: "P-16", input: "/dl/The.Matrix.1999.1080p/The.Matrix.Reloaded.2003.1080p.mkv", expect: { year: 2003, confidence: "needs_confirm" }, }, { id: "P-17", input: "/dl/Show.S01.1080p.WEB-DL-GRP/Sample/show.s01e01.sample.mkv", expect: { season: 1 }, }, ]; describe("parseReleasePath 目录 + 文件名合并", () => { for (const s of PATHS) { it(`${s.id} ${s.input}${s.deviation ? ` [deviation: ${s.deviation}]` : ""}`, () => { check(parseReleasePath(s.input), s.expect); }); } it("接受已拆分的路径段", () => { const r = parseReleasePath({ file: "E05.mkv", parent: "Show.S02.1080p.WEB-DL-GRP" }); expect(r.season).toBe(2); expect(r.episodes).toEqual({ start: 5, end: 5 }); expect(r.title).toBe("Show"); }); it("sample 目录打证据", () => { const r = parseReleasePath("/dl/Show.S01/Sample/x.mkv"); expect(r.evidence).toContain("dir:sample"); }); it("splitReleasePath 跳过附加内容目录", () => { expect(splitReleasePath("/a/b/Extras/c.mkv")).toEqual({ file: "c.mkv", parent: "b", grandParent: "a", extrasDir: "Extras", }); expect(splitReleasePath("c.mkv")).toEqual({ file: "c.mkv" }); }); }); describe("集号偏移(安全求值)", () => { it("W-03: 按表达式偏移集号", () => { const r = parseRelease("[Sub] Kimetsu no Yaiba - 45 [1080p].mkv", { episodeOffset: "EP-44" }); expect(r.episodes).toEqual({ start: 1, end: 1 }); expect(r.evidence).toContain("episode:offset"); expect(r.confidence).toBe("multi_evidence"); }); it("负结果被拒绝,保留原集号", () => { const r = parseRelease("Show.S01E03.1080p", { episodeOffset: "-10" }); expect(r.episodes).toEqual({ start: 3, end: 3 }); expect(r.evidence).toContain("episode:offset_rejected"); }); it("各运算符", () => { expect(evalEpisodeOffset("EP-12", 13)).toBe(1); expect(evalEpisodeOffset("+1", 1)).toBe(2); expect(evalEpisodeOffset("*2", 3)).toBe(6); expect(evalEpisodeOffset("5", 3)).toBe(8); expect(evalEpisodeOffset("(EP+1)//2", 5)).toBe(3); expect(evalEpisodeOffset("EP%4", 10)).toBe(2); expect(evalEpisodeOffset("EP/2", 5)).toBe(2); expect(evalEpisodeOffset("2**3+ep", 1)).toBe(9); expect(evalEpisodeOffset("-EP+20", 5)).toBe(15); expect(evalEpisodeOffset("+(EP)", 5)).toBe(5); }); it("拒绝非白名单输入", () => { for (const bad of ["", "EP; process.exit()", "EP+", "(EP+1", "EP/0", "EP 1", "a".repeat(80), "EP)", "2**2000"]) { expect(() => evalEpisodeOffset(bad, 1), bad).toThrow(OffsetExpressionError); } }); }); describe("辅助函数", () => { it("cnToInt", () => { expect(cnToInt("十二")).toBe(12); expect(cnToInt("二十")).toBe(20); expect(cnToInt("二十三")).toBe(23); expect(cnToInt("一百零五")).toBe(105); expect(cnToInt("两")).toBe(2); expect(cnToInt("08")).toBe(8); expect(cnToInt("abc")).toBeUndefined(); expect(cnToInt("")).toBeUndefined(); }); it("fileKindOf", () => { expect(fileKindOf("a.MKV")).toBe("video"); expect(fileKindOf("a.ass")).toBe("subtitle"); expect(fileKindOf("a.mka")).toBe("audio"); expect(fileKindOf("a.nfo")).toBe("nfo"); expect(fileKindOf("a.jpg")).toBe("image"); expect(fileKindOf("a.txt")).toBe("other"); expect(fileKindOf("a")).toBeUndefined(); }); it("expandEpisodes", () => { expect(expandEpisodes({ start: 2, end: 4 })).toEqual([2, 3, 4]); expect(expandEpisodes(undefined)).toEqual([]); }); it("自定义发布组扩展", () => { const r = parseRelease("Movie.2020.1080p.WEB-DL-MyGroup", { releaseGroups: ["MyGroup"] }); expect(r.releaseGroup).toEqual({ name: "MyGroup", source: "known" }); }); it("纯数字/Exx 文件名", () => { expect(parseRelease("05.mkv").episodes).toEqual({ start: 5, end: 5 }); expect(parseRelease("E07.mkv").episodes).toEqual({ start: 7, end: 7 }); expect(parseRelease("EP07.mp4").episodes).toEqual({ start: 7, end: 7 }); expect(parseRelease("S03").season).toBe(3); expect(parseRelease("Season 2").season).toBe(2); }); it("isFile 选项", () => { expect(parseRelease("12", { isFile: true }).episodes).toEqual({ start: 12, end: 12 }); expect(parseRelease("12").episodes).toBeUndefined(); }); });