feat(parser,sites): W5-D port title/zhconv/site parsing gaps found by MP differential
Title recognition (parseRelease / parseReleasePath):
- anime prefix tags (★N月新番, [国漫], 【22年日剧】), category lead bracket, `A / B` cn aliases
- `Name [01]`, `[TV 04]`, `#13`, `名称 12.mkv`, `S01 13-14`, `E13-14` episodes
- lead bracket as title vs group, trailing [Group], YTS.MX/Hall_of_C style groups, 字幕组 suffix
- `[dot.release.name][…]` unbracketing, `Season 2017` as year, leading date not airDate,
date-only parent dir does not merge as TV
- original disc: Blu-ray + AVC/HEVC/VC-1/MPEG-2 without x26x/H.26x -> BluRay-Disc
- `{[tmdbid=;type=;s=;e=]}` explicit block, bangumi/anilist ids
- bare [1080]/[5.1], DTS-HD MA5.1, £ multi-group, 合集, pinyin title -> cn from subtitle,
streaming platform table, CHS/CHT/GB/BIG5 in subtitle
zh-map: add 迴滾魷瑯臥駭; document one-to-many chars kept out.
Sites: tbody branch + header-row tightening via movieclaw-import rowSelector (18 definitions),
row-level case/hr/labels include the row itself, subtitle branch (searchType: "subtitles"),
parseSizeMp banker's rounding.
Differential snapshots regenerated; MP test sample sources registered in ledger.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
8352e5e881
commit
36dc048e89
41 files changed
+3111
-2372
No files matched your search
@@ -1,9 +1,18 @@
|
||||
/**
|
||||
* 繁 → 简 简单映射表(只覆盖影视标题常见字,不引第三方库)。
|
||||
* 格式:每两个字符为一对「繁简」。一对多/语境相关的字(乾/著/瞭 等)刻意不收。
|
||||
* 格式:每两个字符为一对「繁简」。
|
||||
*
|
||||
* 一对多/语境相关的字刻意不收(单字表没有词组上下文,收了会把正确用法转错):
|
||||
* - 乾:乾杯→干杯,但 乾隆/乾坤 不转;
|
||||
* - 瞭:瞭解→了解,但 瞭望 读 liào 不转;
|
||||
* - 髮:頭髮/理髮→发,与 發→发 合并后反查不唯一,召回比较时也不需要(TMDB 中文标题极少出现);
|
||||
* - 著:著作 不转,顯著/著名 的 著 与 着 的分工依语境。
|
||||
* MP 的 zhconv_fast 用 MediaWiki 词组表处理这些字,差分里登记为 missing(见 test/differential/zhconv-deviations.json)。
|
||||
*/
|
||||
const PAIRS =
|
||||
"萬万與与專专業业叢丛東东絲丝兩两嚴严喪丧個个豐丰臨临為为麗丽舉举麼么義义烏乌樂乐喬乔習习鄉乡書书買买亂乱爭争於于虧亏雲云亞亚產产親亲億亿僅仅從从倉仓儀仪們们價价眾众優优會会傘伞偉伟傳传傷伤倫伦偽伪體体餘余傭佣俠侠侶侣偵侦側侧僑侨儂侬倆俩儉俭債债傾倾償偿儲储兒儿兇凶黨党蘭兰關关興兴養养獸兽內内岡冈冊册寫写軍军農农馮冯衝冲決决況况凍冻淨净準准涼凉減减湊凑幾几鳳凤憑凭凱凯擊击劃划劉刘則则剛刚創创刪删別别劑剂劍剑剝剥劇剧勸劝辦办務务動动勵励勁劲勞劳勢势勳勋勝胜區区醫医華华協协單单賣卖盧卢衛卫卻却廠厂廳厅曆历厲厉壓压厭厌廁厕廂厢廈厦廚厨縣县參参雙双發发變变敘叙疊叠葉叶號号嘆叹嚇吓呂吕嗎吗啟启吳吴員员響响啞哑嘩哗喚唤噴喷團团園园圍围國国圖图圓圆聖圣場场壞坏塊块堅坚壇坛壩坝墳坟墜坠壘垒墊垫牆墙壯壮聲声殼壳壺壶處处備备復复夠够頭头誇夸夾夹奪夺奮奋獎奖奧奥妝妆婦妇媽妈嬌娇娛娱嬰婴嬸婶孫孙學学寧宁寶宝實实寵宠審审憲宪宮宫寬宽賓宾寢寝對对尋寻導导壽寿將将爾尔塵尘嘗尝堯尧屍尸盡尽層层屆届屬属嶼屿歲岁豈岂崗岗島岛嶺岭峽峡嶄崭巔巅幣币帥帅師师帳帐簾帘幟帜帶带幫帮並并廣广莊庄慶庆廬庐庫库應应廟庙龐庞廢废開开異异棄弃張张彌弥彎弯彈弹強强歸归當当錄录彥彦徹彻徑径憶忆憂忧懷怀態态憐怜總总戀恋懇恳惡恶惱恼悅悦懸悬驚惊懼惧慘惨懲惩慚惭慣惯憤愤願愿懶懒戲戏戰战戶户紮扎撲扑執执擴扩掃扫揚扬擾扰撫抚拋抛搶抢護护報报擔担擬拟擁拥攔拦擇择掛挂揮挥撈捞損损撿捡換换據据擲掷攬揽攜携攝摄擺摆搖摇攤摊撐撑敵敌斂敛數数齋斋鬥斗斬斩斷断無无舊旧時时曠旷晝昼顯显晉晋曬晒曉晓暈晕暉晖暫暂術术樸朴機机殺杀雜杂權权條条來来楊杨傑杰極极構构槍枪楓枫櫃柜標标棧栈棟栋欄栏樹树棲栖樣样檔档橋桥夢梦檢检樓楼欖榄櫻樱櫥橱歡欢歐欧殲歼殘残毀毁畢毕斃毙氣气匯汇漢汉湯汤溝沟沒没淚泪瀉泻潑泼澤泽潔洁灑洒淺浅漿浆濁浊測测濟济渾浑濃浓濤涛漲涨淵渊漸渐漁渔滲渗溫温遊游灣湾濕湿潰溃濺溅滿满濾滤濫滥濱滨灘滩瀟潇潛潜瀾澜瀕濒滅灭燈灯靈灵災灾燦灿爐炉點点煉炼熾炽爍烁爛烂燭烛煙烟煩烦燒烧熱热煥焕愛爱爺爷牽牵犧牺狀状猶犹狹狭獅狮獄狱獨独獵猎豬猪貓猫獻献瑪玛環环現现瓊琼電电畫画暢畅療疗瘋疯癢痒發发皺皱盞盏鹽盐監监蓋盖盜盗盤盘睜睁瞞瞒矯矫礦矿碼码磚砖確确礙碍禮礼禍祸禪禅離离禿秃種种積积稱称穩稳穫获窮穷竊窃窯窑竄窜窩窝豎竖競竞筆笔築筑篩筛籌筹簽签簡简籃篮籬篱類类糧粮糾纠紀纪約约紅红紋纹納纳紐纽純纯紗纱紡纺紛纷級级紙纸細细紳绅終终組组結结繞绕給给絢绚絡络絕绝統统綁绑絹绢繡绣經经綜综綠绿綴缀網网綱纲緒绪續续緊紧維维綿绵緣缘編编緩缓緯纬練练縫缝縮缩織织繩绳繪绘繳缴纖纤羅罗罰罚罷罢羈羁翹翘聳耸恥耻聶聂聾聋職职聯联聰聪肅肃腸肠膚肤腫肿脅胁膽胆朧胧膠胶脈脉腦脑腳脚脫脱臉脸臘腊騰腾輿舆艦舰艙舱艱艰豔艳藝艺節节蕪芜蘆芦葦苇蒼苍蘇苏蘋苹莖茎薦荐莢荚蕩荡榮荣藥药萊莱蓮莲獲获瑩莹鶯莺蘿萝螢萤營营蕭萧薩萨蔥葱蔣蒋藍蓝薔蔷藹蔼蘊蕴虜虏慮虑虛虚蟲虫雖虽蝦虾蝕蚀蟻蚁螞蚂蠶蚕蠻蛮蝸蜗蠟蜡蠅蝇蟬蝉補补襯衬襖袄襪袜襲袭裝装褲裤見见觀观規规覓觅視视覽览覺觉觸触計计訂订認认討讨讓让訓训議议訊讯記记講讲許许論论設设訪访訣诀證证評评識识詐诈訴诉診诊詞词譯译試试詩诗誠诚話话誕诞詭诡詢询該该詳详誤误語语誘诱說说誦诵請请諸诸諾诺讀读課课誰谁調调諒谅談谈誼谊謀谋謊谎諧谐謂谓謎谜謝谢謠谣謙谦謹谨謬谬譜谱貝贝貞贞負负貢贡財财責责賢贤敗败賬账貨货質质販贩貪贪貧贫購购貫贯貼贴貴贵貸贷貿贸費费賀贺賊贼資资賦赋賭赌贖赎賞赏賜赐賠赔賴赖賺赚賽赛贈赠贊赞贏赢趙赵趕赶趨趋躍跃踐践蹤踪躲躲車车軌轨軍军軒轩轉转輪轮軟软轟轰軸轴輕轻載载較较輔辅輛辆輩辈輝辉輸输轄辖辭辞辯辩邊边遼辽達达遷迁過过邁迈運运還还這这進进遠远違违連连遲迟適适選选遜逊遞递邏逻遺遗遙遥鄧邓郵邮鄰邻鬱郁鄭郑醞酝醬酱釀酿釋释裏里鑒鉴針针釘钉鐘钟鋼钢鑰钥鈴铃鐵铁鉛铅銅铜鋁铝銀银鏈链銷销鎖锁鋒锋鋤锄鍋锅錯错錨锚錘锤錦锦鍵键鋸锯鍛锻鏡镜鐮镰鑲镶長长門门閃闪閉闭問问闖闯閑闲間间悶闷閘闸鬧闹閨闺聞闻閣Line truncated
|
||||
"萬万與与專专業业叢丛東东絲丝兩两嚴严喪丧個个豐丰臨临為为麗丽舉举麼么義义烏乌樂乐喬乔習习鄉乡書书買买亂乱爭争於于虧亏雲云亞亚產产親亲億亿僅仅從从倉仓儀仪們们價价眾众優优會会傘伞偉伟傳传傷伤倫伦偽伪體体餘余傭佣俠侠侶侣偵侦側侧僑侨儂侬倆俩儉俭債债傾倾償偿儲储兒儿兇凶黨党蘭兰關关興兴養养獸兽內内岡冈冊册寫写軍军農农馮冯衝冲決决況况凍冻淨净準准涼凉減减湊凑幾几鳳凤憑凭凱凯擊击劃划劉刘則则剛刚創创刪删別别劑剂劍剑剝剥劇剧勸劝辦办務务動动勵励勁劲勞劳勢势勳勋勝胜區区醫医華华協协單单賣卖盧卢衛卫卻却廠厂廳厅曆历厲厉壓压厭厌廁厕廂厢廈厦廚厨縣县參参雙双發发變变敘叙疊叠葉叶號号嘆叹嚇吓呂吕嗎吗啟启吳吴員员響响啞哑嘩哗喚唤噴喷團团園园圍围國国圖图圓圆聖圣場场壞坏塊块堅坚壇坛壩坝墳坟墜坠壘垒墊垫牆墙壯壮聲声殼壳壺壶處处備备復复夠够頭头誇夸夾夹奪夺奮奋獎奖奧奥妝妆婦妇媽妈嬌娇娛娱嬰婴嬸婶孫孙學学寧宁寶宝實实寵宠審审憲宪宮宫寬宽賓宾寢寝對对尋寻導导壽寿將将爾尔塵尘嘗尝堯尧屍尸盡尽層层屆届屬属嶼屿歲岁豈岂崗岗島岛嶺岭峽峡嶄崭巔巅幣币帥帅師师帳帐簾帘幟帜帶带幫帮並并廣广莊庄慶庆廬庐庫库應应廟庙龐庞廢废開开異异棄弃張张彌弥彎弯彈弹強强歸归當当錄录彥彦徹彻徑径憶忆憂忧懷怀態态憐怜總总戀恋懇恳惡恶惱恼悅悦懸悬驚惊懼惧慘惨懲惩慚惭慣惯憤愤願愿懶懒戲戏戰战戶户紮扎撲扑執执擴扩掃扫揚扬擾扰撫抚拋抛搶抢護护報报擔担擬拟擁拥攔拦擇择掛挂揮挥撈捞損损撿捡換换據据擲掷攬揽攜携攝摄擺摆搖摇攤摊撐撑敵敌斂敛數数齋斋鬥斗斬斩斷断無无舊旧時时曠旷晝昼顯显晉晋曬晒曉晓暈晕暉晖暫暂術术樸朴機机殺杀雜杂權权條条來来楊杨傑杰極极構构槍枪楓枫櫃柜標标棧栈棟栋欄栏樹树棲栖樣样檔档橋桥夢梦檢检樓楼欖榄櫻樱櫥橱歡欢歐欧殲歼殘残毀毁畢毕斃毙氣气匯汇漢汉湯汤溝沟沒没淚泪瀉泻潑泼澤泽潔洁灑洒淺浅漿浆濁浊測测濟济渾浑濃浓濤涛漲涨淵渊漸渐漁渔滲渗溫温遊游灣湾濕湿潰溃濺溅滿满濾滤濫滥濱滨灘滩瀟潇潛潜瀾澜瀕濒滅灭燈灯靈灵災灾燦灿爐炉點点煉炼熾炽爍烁爛烂燭烛煙烟煩烦燒烧熱热煥焕愛爱爺爷牽牵犧牺狀状猶犹狹狭獅狮獄狱獨独獵猎豬猪貓猫獻献瑪玛環环現现瓊琼電电畫画暢畅療疗瘋疯癢痒發发皺皱盞盏鹽盐監监蓋盖盜盗盤盘睜睁瞞瞒矯矫礦矿碼码磚砖確确礙碍禮礼禍祸禪禅離离禿秃種种積积稱称穩稳穫获窮穷竊窃窯窑竄窜窩窝豎竖競竞筆笔築筑篩筛籌筹簽签簡简籃篮籬篱類类糧粮糾纠紀纪約约紅红紋纹納纳紐纽純纯紗纱紡纺紛纷級级紙纸細细紳绅終终組组結结繞绕給给絢绚絡络絕绝統统綁绑絹绢繡绣經经綜综綠绿綴缀網网綱纲緒绪續续緊紧維维綿绵緣缘編编緩缓緯纬練练縫缝縮缩織织繩绳繪绘繳缴纖纤羅罗罰罚罷罢羈羁翹翘聳耸恥耻聶聂聾聋職职聯联聰聪肅肃腸肠膚肤腫肿脅胁膽胆朧胧膠胶脈脉腦脑腳脚脫脱臉脸臘腊騰腾輿舆艦舰艙舱艱艰豔艳藝艺節节蕪芜蘆芦葦苇蒼苍蘇苏蘋苹莖茎薦荐莢荚蕩荡榮荣藥药萊莱蓮莲獲获瑩莹鶯莺蘿萝螢萤營营蕭萧薩萨蔥葱蔣蒋藍蓝薔蔷藹蔼蘊蕴虜虏慮虑虛虚蟲虫雖虽蝦虾蝕蚀蟻蚁螞蚂蠶蚕蠻蛮蝸蜗蠟蜡蠅蝇蟬蝉補补襯衬襖袄襪袜襲袭裝装褲裤見见觀观規规覓觅視视覽览覺觉觸触計计訂订認认討讨讓让訓训議议訊讯記记講讲許许論论設设訪访訣诀證证評评識识詐诈訴诉診诊詞词譯译試试詩诗誠诚話话誕诞詭诡詢询該该詳详誤误語语誘诱說说誦诵請请諸诸諾诺讀读課课誰谁調调諒谅談谈誼谊謀谋謊谎諧谐謂谓謎谜謝谢謠谣謙谦謹谨謬谬譜谱貝贝貞贞負负貢贡財财責责賢贤敗败賬账貨货質质販贩貪贪貧贫購购貫贯貼贴貴贵貸贷貿贸費费賀贺賊贼資资賦赋賭赌贖赎賞赏賜赐賠赔賴赖賺赚賽赛贈赠贊赞贏赢趙赵趕赶趨趋躍跃踐践蹤踪躲躲車车軌轨軍军軒轩轉转輪轮軟软轟轰軸轴輕轻載载較较輔辅輛辆輩辈輝辉輸输轄辖辭辞辯辩邊边遼辽達达遷迁過过邁迈運运還还這这進进遠远違违連连遲迟適适選选遜逊遞递邏逻遺遗遙遥鄧邓郵邮鄰邻鬱郁鄭郑醞酝醬酱釀酿釋释裏里鑒鉴針针釘钉鐘钟鋼钢鑰钥鈴铃鐵铁鉛铅銅铜鋁铝銀银鏈链銷销鎖锁鋒锋鋤锄鍋锅錯错錨锚錘锤錦锦鍵键鋸锯鍛锻鏡镜鐮镰鑲镶長长門门閃闪閉闭問问闖闯閑闲間间悶闷閘闸鬧闹閨闺聞闻閣Line truncated
|
||||
// W5-D 按 MP zhconv 差分补字
|
||||
"迴回滾滚魷鱿瑯琅臥卧駭骇";
|
||||
|
||||
export const TRAD_TO_SIMP: ReadonlyMap<string, string> = (() => {
|
||||
const chars = [...PAIRS];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CN_NUM, cnToInt } from "./cn-number.ts";
|
||||
import { evalEpisodeOffset } from "./offset.ts";
|
||||
import { PLATFORMS } from "./platforms.ts";
|
||||
import { buildGroupRegex, defaultGroupRegex } from "./release-groups.ts";
|
||||
import {
|
||||
type Confidence,
|
||||
@@ -38,7 +39,14 @@ export function fileKindOf(name: string): FileKind | undefined {
|
||||
|
||||
// ---------------------------------------------------------------- 可变草稿
|
||||
|
||||
type Draft = ParsedRelease & { _complete?: boolean; _fin?: boolean; _disc?: boolean; _remux?: boolean };
|
||||
type Draft = ParsedRelease & {
|
||||
_complete?: boolean;
|
||||
_fin?: boolean;
|
||||
_disc?: boolean;
|
||||
_remux?: boolean;
|
||||
/** `{[k=v;…]}` 显式身份块里的季/集/类型,finalize 时覆盖推断值 */
|
||||
_explicit?: { season?: number; seasonEnd?: number; episodes?: EpisodeRange; tv?: boolean };
|
||||
};
|
||||
|
||||
function emptyDraft(raw: string): Draft {
|
||||
return {
|
||||
@@ -67,6 +75,9 @@ const MARK_HARD = " 〆 "; // 日期/动漫集号被剥离后的占位:之后不
|
||||
const GROUP_SUFFIX_EXCLUDE =
|
||||
/^(?:DL|HD|MA|HR|RIP|RAY|X|ES|\d+|\d+BIT|\d{3,4}[PI]|[XH]\.?26[45]|HEVC|AVC|AAC|FLAC|DTS|DDP?[\d.]*|ATMOS|WEB|BLURAY|REMUX|HDR\d*|DV|HLG|SDR|FIN|END|S\d+|E\d+|EP\d+|CD\d*|PART\d*|\d+CH|MKV|MP4)$/i;
|
||||
const TECH_IN_BRACKET = /\b(?:\d{3,4}[pi]|x26[45]|hevc|avc|web-?dl|webrip|bluray|bdrip|remux)\b|^\d+$/i;
|
||||
/** 开头方括号里明显是组名的写法:字幕组/汉化组/Raws 等后缀,或 `YTS.MX`、`Hall_of_C` 这种单个点/下划线连接的词元 */
|
||||
const GROUPISH_BRACKET =
|
||||
/(?:字幕[组組社]|[汉漢]化[组組]|[发發][布佈][组組]|[压壓]制[组組]|工作室|搬运[组組]?|Raws?|Subs?|Studio|Fansubs?|Team)$|^(?=.{3,16}$)[A-Za-z0-9]+(?:[._][A-Za-z0-9]+){1,2}$/iu;
|
||||
|
||||
function extractGroup(s: string, extra: readonly string[]): { s: string; group?: ReleaseGroup; ev?: string } {
|
||||
const re = extra.length > 0 ? buildGroupRegex(extra) : defaultGroupRegex();
|
||||
@@ -86,7 +97,23 @@ function extractGroup(s: string, extra: readonly string[]): { s: string; group?:
|
||||
if (lead) {
|
||||
const content = lead[1]!.trim();
|
||||
const rest = s.slice(lead[0].length);
|
||||
if (!TECH_IN_BRACKET.test(content) && (/[[【]/u.test(rest) || /\s-\s\d{1,3}\b/.test(rest))) {
|
||||
// `[片名][01]…`:开头方括号紧跟集号,它就是片名
|
||||
if (/^\s*[[【]\d{1,3}(?:v\d)?[\]】]/u.test(rest)) return { s };
|
||||
// `[中文片名][English Title]…[Group]`:开头是纯中文片名,组名取末尾方括号
|
||||
if (/^\p{Script=Han}+$/u.test(content) && !GROUPISH_BRACKET.test(content)) {
|
||||
const tail = /[[【]([A-Za-z][A-Za-z0-9-]{1,23})[\]】]\s*$/u.exec(rest);
|
||||
if (tail && !TECH_IN_BRACKET.test(tail[1]!) && !GROUP_SUFFIX_EXCLUDE.test(tail[1]!)) {
|
||||
return {
|
||||
s: s.slice(0, s.length - tail[0].length),
|
||||
group: { name: tail[1]!, source: "bracket" },
|
||||
ev: "group:bracket_tail",
|
||||
};
|
||||
}
|
||||
}
|
||||
if (
|
||||
!TECH_IN_BRACKET.test(content) &&
|
||||
(/[[【]/u.test(rest) || /\s-\s\d{1,3}\b/.test(rest) || GROUPISH_BRACKET.test(content))
|
||||
) {
|
||||
return { s: rest, group: { name: content.replace(/&/g, "@"), source: "bracket" }, ev: "group:bracket" };
|
||||
}
|
||||
}
|
||||
@@ -137,6 +164,8 @@ function extractAirDate(s: string): { s: string; airDate?: string; ev?: string }
|
||||
if (!m) continue;
|
||||
const [y, mo, d] = [Number(m[1]), Number(m[2]), Number(m[3])];
|
||||
if (!validDate(y, mo, d)) continue;
|
||||
// 标题开头的日期(`2022.8.2.Twelve.Monkeys.1995`)是发布/收藏日期,不是播出日期
|
||||
if (/^[\s[【(]*$/u.test(s.slice(0, m.index))) return { s: s.slice(m.index + m[0].length) };
|
||||
return {
|
||||
s: s.slice(0, m.index) + MARK_HARD + s.slice(m.index + m[0].length),
|
||||
airDate: `${y}${pad2(mo)}${pad2(d)}`,
|
||||
@@ -267,61 +296,41 @@ export function scanCnMarkers(input: string): { s: string } & CnMarkers {
|
||||
const AUDIO_CODEC_ALT = "DDP|DD|AAC|TrueHD|DTSHDMA|DTSHDHR|DTSHD|DTSX|DTS|FLAC|LPCM|PCM|AC3|EAC3|Opus|Atmos";
|
||||
|
||||
function normalizeCompounds(s: string): string {
|
||||
return s
|
||||
.replace(/'/g, "")
|
||||
.replace(/\bWEB[-. ]?DL\b/gi, " WEBDL ")
|
||||
.replace(/\bWEB[-. ]?Rip\b/gi, " WEBRip ")
|
||||
.replace(/\bBlu[-. ]?Ray\b/gi, " BluRay ")
|
||||
.replace(/\bDTS[-. ]?HD[-. ]?MA\b/gi, " DTSHDMA ")
|
||||
.replace(/\bDTS[-. ]?HD[-. ]?(?:HRA|HR)\b/gi, " DTSHDHR ")
|
||||
.replace(/\bDTS[-. ]?HD\b/gi, " DTSHD ")
|
||||
.replace(/\bDTS[-. :]?X\b/gi, " DTSX ")
|
||||
.replace(/\b([HhXx])[. ]?26([45])\b/g, " $126$2 ")
|
||||
.replace(/\bHDR10(?:\+|Plus|P)(?![A-Za-z0-9])/gi, " HDR10PLUS ")
|
||||
.replace(/\bDD\+/gi, " DDP")
|
||||
.replace(/\bE-?AC-?3\b/gi, " EAC3 ")
|
||||
.replace(/\bAC-?3\b/gi, " AC3 ")
|
||||
.replace(/\bDolby[ .]?Vision\b/gi, " DV ")
|
||||
.replace(/\bVC-?1\b/gi, " VC1 ")
|
||||
.replace(/\bMPEG-?2\b/gi, " MPEG2 ")
|
||||
.replace(/\b(8|10|12)[ .\-_]?bits?\b/gi, " $1BIT ")
|
||||
.replace(
|
||||
new RegExp(`\\b(${AUDIO_CODEC_ALT})[ ._]*([1-9])[ .]([0-2])(?![0-9])`, "gi"),
|
||||
(_all, codec: string, a: string, b: string) => ` ${codec} CH${a}${b} `,
|
||||
)
|
||||
.replace(/(\p{Script=Han})([A-Za-z])/gu, "$1 $2")
|
||||
.replace(/([A-Za-z])(\p{Script=Han})/gu, "$1 $2");
|
||||
return (
|
||||
s
|
||||
.replace(/'/g, "")
|
||||
.replace(/\bWEB[-. ]?DL\b/gi, " WEBDL ")
|
||||
.replace(/\bWEB[-. ]?Rip\b/gi, " WEBRip ")
|
||||
.replace(/\bBlu[-. ]?Ray\b/gi, " BluRay ")
|
||||
.replace(/\bDTS[-. ]?HD[-. ]?MA(?![A-Za-z])/gi, " DTSHDMA ")
|
||||
.replace(/\bDTS[-. ]?HD[-. ]?(?:HRA|HR)\b/gi, " DTSHDHR ")
|
||||
.replace(/\bDTS[-. ]?HD\b/gi, " DTSHD ")
|
||||
.replace(/\bDTS[-. :]?X\b/gi, " DTSX ")
|
||||
.replace(/\b([HhXx])[. ]?26([45])\b/g, " $126$2 ")
|
||||
.replace(/\bHDR10(?:\+|Plus|P)(?![A-Za-z0-9])/gi, " HDR10PLUS ")
|
||||
.replace(/\bDD\+/gi, " DDP")
|
||||
.replace(/\bE-?AC-?3\b/gi, " EAC3 ")
|
||||
.replace(/\bAC-?3\b/gi, " AC3 ")
|
||||
.replace(/\bDolby[ .]?Vision\b/gi, " DV ")
|
||||
.replace(/\bVC-?1\b/gi, " VC1 ")
|
||||
.replace(/\bMPEG-?2\b/gi, " MPEG2 ")
|
||||
.replace(/\b(8|10|12)[ .\-_]?bits?\b/gi, " $1BIT ")
|
||||
.replace(
|
||||
new RegExp(`\\b(${AUDIO_CODEC_ALT})[ ._]*([1-9])[ .]([0-2])(?![0-9])`, "gi"),
|
||||
(_all, codec: string, a: string, b: string) => ` ${codec} CH${a}${b} `,
|
||||
)
|
||||
.replace(/\b(EP?)(\d{1,4})-(?:EP?)?(\d{1,4})\b/gi, " $1$2 $1$3 ")
|
||||
.replace(/\bS(\d{1,2})\s+(\d{1,3})-(\d{1,3})(?![\d.])/gi, " S$1 E$2 E$3 ")
|
||||
.replace(/\bB-Global\b/gi, " BGLOBAL ")
|
||||
.replace(/[[【]\s*(4320|2160|1440|1080|720|576|480)\s*[\]】]/gu, " $1p ")
|
||||
.replace(/[[【(]\s*([2-9])\.([0-2])\s*[\]】)]/gu, " CH$1$2 ")
|
||||
// 汉字之间夹单个拉丁字母(哆啦A梦)不拆开
|
||||
.replace(/(\p{Script=Han})([A-Za-z])(?!\p{Script=Han})/gu, "$1 $2")
|
||||
.replace(/(?<!\p{Script=Han})([A-Za-z])(\p{Script=Han})/gu, "$1 $2")
|
||||
);
|
||||
}
|
||||
|
||||
const TOKEN_SPLIT = /[\s._[\]()【】/~~;&|#「」,,()::"!!??、+\-《》]+/u;
|
||||
|
||||
const PLATFORMS: Record<string, string> = {
|
||||
NF: "Netflix",
|
||||
AMZN: "Amazon",
|
||||
MAX: "Max",
|
||||
HMAX: "HBO Max",
|
||||
DSNP: "Disney+",
|
||||
ATVP: "Apple TV+",
|
||||
IT: "iTunes",
|
||||
HULU: "Hulu",
|
||||
PCOK: "Peacock",
|
||||
PMTP: "Paramount+",
|
||||
CR: "Crunchyroll",
|
||||
IQ: "iQIYI",
|
||||
IQIYI: "iQIYI",
|
||||
TX: "Tencent Video",
|
||||
WETV: "WeTV",
|
||||
YK: "Youku",
|
||||
MGTV: "MGTV",
|
||||
BILI: "Bilibili",
|
||||
BG: "B-Global",
|
||||
VIU: "Viu",
|
||||
KKTV: "KKTV",
|
||||
FRIDAY: "friDay",
|
||||
LINETV: "LINE TV",
|
||||
HBO: "HBO",
|
||||
STAN: "Stan",
|
||||
};
|
||||
const TOKEN_SPLIT = /[\s._[\]()【】/~~;&|#「」,,()::"!!??、+\-《》£]+/u;
|
||||
|
||||
const AUDIO_TOKENS: Record<string, string> = {
|
||||
TRUEHD: "TrueHD",
|
||||
@@ -389,7 +398,14 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
const ev = d.evidence;
|
||||
const en: string[] = [];
|
||||
const cn: string[] = [];
|
||||
/** 纯假名词元(日文原名):不混进英文名,英文名为空时才用 */
|
||||
const ja: string[] = [];
|
||||
let lastTitleList: string[] | undefined;
|
||||
// 原盘判定:Blu-ray 字样 + AVC/HEVC/VC-1/MPEG-2 且没有 x26x/H.26x(对照 MP 内置规则 BLU)
|
||||
let blurayWord = false;
|
||||
let discCodec = false;
|
||||
let encodeCodec = false;
|
||||
let ripWord = false;
|
||||
let stopped = false;
|
||||
let hanClosed = false;
|
||||
let nonYearStops = 0;
|
||||
@@ -398,9 +414,15 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
stopped = true;
|
||||
if (kind !== "year") nonYearStops++;
|
||||
};
|
||||
const hasTitle = () => en.length > 0 || cn.length > 0;
|
||||
const hasTitle = () => en.length > 0 || cn.length > 0 || ja.length > 0;
|
||||
const pushTitle = (t: string) => {
|
||||
const list = /\p{Script=Han}/u.test(t) ? cn : /^\d+$/.test(t) ? (lastTitleList ?? en) : en;
|
||||
const list = /\p{Script=Han}/u.test(t)
|
||||
? cn
|
||||
: /^\d+$/.test(t)
|
||||
? (lastTitleList ?? en)
|
||||
: /^[\p{Script=Hiragana}\p{Script=Katakana}ー・]+$/u.test(t)
|
||||
? ja
|
||||
: en;
|
||||
list.push(t);
|
||||
lastTitleList = list;
|
||||
};
|
||||
@@ -472,7 +494,8 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
stop("season");
|
||||
continue;
|
||||
}
|
||||
if ((u === "SEASON" || u === "EPISODE") && next && /^\d{1,4}$/.test(next)) {
|
||||
// `Season 2017` 是片名 + 年份(The Long Season 2017),季号最多 3 位
|
||||
if ((u === "SEASON" || u === "EPISODE") && next && /^\d{1,3}$/.test(next)) {
|
||||
if (u === "SEASON") {
|
||||
if (d.season === undefined) d.season = Number(next);
|
||||
else if (Number(next) > d.season) d.seasonEnd = Number(next);
|
||||
@@ -556,8 +579,11 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
// 来源
|
||||
if (gate) {
|
||||
let src: ReleaseSource | undefined;
|
||||
if (u === "BLURAY" || u === "BDRIP" || u === "BRRIP" || u === "BD") src = "BluRay";
|
||||
else if (u === "WEBDL") src = "WEB-DL";
|
||||
if (u === "BLURAY" || u === "BDRIP" || u === "BRRIP" || u === "BD") {
|
||||
src = "BluRay";
|
||||
if (u === "BLURAY") blurayWord = true;
|
||||
else if (u !== "BD") ripWord = true;
|
||||
} else if (u === "WEBDL") src = "WEB-DL";
|
||||
else if (u === "WEBRIP") src = "WEBRip";
|
||||
else if (u === "WEB" && (stopped || (next !== undefined && /^\d{3,4}[pi]$/i.test(next)))) src = "WEB-DL";
|
||||
else if (u === "HDTV" || u === "UHDTV") src = "HDTV";
|
||||
@@ -609,6 +635,8 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
if (codec) {
|
||||
d.videoCodec ??= codec;
|
||||
if (u === "X264" || u === "X265") d.encoder ??= u === "X264" ? "x264" : "x265";
|
||||
if (u === "AVC" || u === "HEVC" || u === "VC1" || u === "MPEG2") discCodec = true;
|
||||
else if (/^[XH]26[45]$/.test(u)) encodeCodec = true;
|
||||
ev.push("codec");
|
||||
stop("codec");
|
||||
continue;
|
||||
@@ -626,9 +654,12 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
continue;
|
||||
}
|
||||
m = /^CH(\d)(\d)$/.exec(u);
|
||||
if (m && d.audio.length > 0) {
|
||||
if (m) {
|
||||
const last = d.audio.length - 1;
|
||||
if (!/\d\.\d$/.test(d.audio[last]!)) d.audio[last] = `${d.audio[last]} ${m[1]}.${m[2]}`;
|
||||
// 裸声道 `[5.1]`:没有音频编码时单独记一条
|
||||
if (last < 0) d.audio.push(`${m[1]}.${m[2]}`);
|
||||
else if (!/\d\.\d$/.test(d.audio[last]!)) d.audio[last] = `${d.audio[last]} ${m[1]}.${m[2]}`;
|
||||
stop("audio");
|
||||
continue;
|
||||
}
|
||||
m = /^(\d)AUDIOS?$/.exec(u);
|
||||
@@ -661,12 +692,14 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
stop("platform");
|
||||
continue;
|
||||
}
|
||||
if (stopped && (u === "CHS" || u === "GB")) {
|
||||
if (u === "CHS" || u === "GB") {
|
||||
d.subtitles = [...new Set([...(d.subtitles ?? []), "zh-Hans"])];
|
||||
stop("subtitle");
|
||||
continue;
|
||||
}
|
||||
if (stopped && (u === "CHT" || u === "BIG5")) {
|
||||
if (u === "CHT" || u === "BIG5") {
|
||||
d.subtitles = [...new Set([...(d.subtitles ?? []), "zh-Hant"])];
|
||||
stop("subtitle");
|
||||
continue;
|
||||
}
|
||||
if (stopped && (u === "ENG" || u === "EN")) {
|
||||
@@ -680,20 +713,26 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
if (stopped) continue;
|
||||
if (/\p{Script=Han}/u.test(t)) {
|
||||
if (!hanClosed) {
|
||||
cn.push(t);
|
||||
// 「三部曲合集」「合集」是打包说明,不是片名的一部分
|
||||
const name = t.length > 2 ? t.replace(/合集$/u, "") : t;
|
||||
cn.push(name);
|
||||
lastTitleList = cn;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
pushTitle(t);
|
||||
}
|
||||
if (en.length === 0 && ja.length > 0) en.push(...ja);
|
||||
const enTitle = en.join(" ").trim();
|
||||
const cnTitle = cn.join(" ").trim();
|
||||
if (enTitle) d.titleEn = enTitle;
|
||||
if (cnTitle) d.titleCn = cnTitle;
|
||||
if (d._remux) d.source = "REMUX";
|
||||
else if (d._disc) d.source = "BluRay-Disc";
|
||||
else {
|
||||
else if (blurayWord && discCodec && !encodeCodec && !ripWord && !d.encoder && sources.size === 1) {
|
||||
d.source = "BluRay-Disc";
|
||||
ev.push("source:disc_codec");
|
||||
} else {
|
||||
for (const s of ["BluRay", "WEB-DL", "WEBRip", "HDTV", "HDRip", "DVDRip", "DVD"] as const) {
|
||||
if (sources.has(s)) {
|
||||
d.source = s;
|
||||
@@ -703,6 +742,82 @@ function walkTokens(tokens: string[], d: Draft): void {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- 预处理
|
||||
|
||||
const BRACKET_DOT_TITLE =
|
||||
/^\s*\[([A-Za-z0-9][^\s[\]]*?\.(?:19|20)\d{2}\.[^\s[\]]*?\b(?:\d{3,4}p|Blu-?Ray|WEB-?DL|WEBRip|HDTV|REMUX|UHD)\b[^\s[\]]*)\]/i;
|
||||
const ANIME_TAG_CORE =
|
||||
"(?:(?:\\d{2,4}\\s*年\\s*)?(?:\\d{1,2}\\s*月\\s*)?(?:新番|番剧|番)|(?:\\d{2,4}\\s*年\\s*)?[日美国國韩韓港台][漫剧劇])";
|
||||
const ANIME_TAG_BRACKET = new RegExp(`[[【]\\s*★?\\s*${ANIME_TAG_CORE}\\s*★?\\s*[\\]】]`, "gu");
|
||||
const ANIME_TAG_BARE = new RegExp(`★\\s*${ANIME_TAG_CORE}\\s*★?|(?<![\\p{Script=Han}\\d])\\d{1,2}月新番★?`, "gu");
|
||||
/** 开头方括号是分类词(动画/电影/纪录片/Animation/Movie…),MP 同样整块去掉 */
|
||||
const CATEGORY_LEAD =
|
||||
/^\s*[[【](?:[^\]】]*?(?:Animations?|Movies?|Documentar(?:y|ies)|Anime)\b[^\]】]*|[动動漫画畫纪紀录錄片电電影视視连連续續剧劇集日美韩韓中港台海外亚亞洲华華语語大陆陸综綜艺藝原盘盤高清]{2,})[\]】]\s*(?=[[【])/iu;
|
||||
const CN_ALIAS_SLASH =
|
||||
/(?<=^|[\s\]】])[^\s/[\]【】]*\p{Script=Han}[^\s/[\]【】]*\s*\/\s*(?=[^\s/[\]【】]*\p{Script=Han})/u;
|
||||
|
||||
function addExplicit(d: Draft, x: ExplicitId): void {
|
||||
if (x.id === "0" || d.explicitIds.some((e) => e.provider === x.provider)) return;
|
||||
d.explicitIds.push(x);
|
||||
d.evidence.push(`explicit:${x.provider}`);
|
||||
}
|
||||
|
||||
const BLOCK_PROVIDERS: Record<string, ExplicitId["provider"]> = {
|
||||
tmdbid: "tmdb",
|
||||
tmdb: "tmdb",
|
||||
doubanid: "douban",
|
||||
douban: "douban",
|
||||
imdbid: "imdb",
|
||||
imdb: "imdb",
|
||||
tvdbid: "tvdb",
|
||||
tvdb: "tvdb",
|
||||
bangumiid: "bangumi",
|
||||
bangumi: "bangumi",
|
||||
anilistid: "anilist",
|
||||
anilist: "anilist",
|
||||
};
|
||||
|
||||
/** `{[tmdbid=94997;type=tv;s=1;e=3-4;g=…]}`:返回 ID 与季/集/类型;没有任何可识别键时返回 undefined(原样保留) */
|
||||
function parseExplicitBlock(body: string): { ids: ExplicitId[]; meta: NonNullable<Draft["_explicit"]> } | undefined {
|
||||
const ids: ExplicitId[] = [];
|
||||
const meta: NonNullable<Draft["_explicit"]> = {};
|
||||
let hit = false;
|
||||
const range = (v: string) => {
|
||||
const m = /^(\d{1,4})(?:\s*-\s*(\d{1,4}))?$/.exec(v.trim());
|
||||
return m ? { start: Number(m[1]), end: Number(m[2] ?? m[1]) } : undefined;
|
||||
};
|
||||
for (const part of body.split(";")) {
|
||||
const kv = /^\s*([A-Za-z]+)\s*=\s*(.*?)\s*$/.exec(part);
|
||||
if (!kv) continue;
|
||||
const key = kv[1]!.toLowerCase();
|
||||
const val = kv[2]!;
|
||||
const provider = BLOCK_PROVIDERS[key];
|
||||
if (provider) {
|
||||
if (/^[A-Za-z0-9]+$/.test(val)) ids.push({ provider, id: val });
|
||||
hit = true;
|
||||
} else if (key === "type") {
|
||||
if (/^(tv|电视剧|電視劇)$/i.test(val)) meta.tv = true;
|
||||
hit = true;
|
||||
} else if (key === "s") {
|
||||
const r = range(val);
|
||||
if (r) {
|
||||
meta.season = r.start;
|
||||
if (r.end > r.start) meta.seasonEnd = r.end;
|
||||
}
|
||||
hit = true;
|
||||
} else if (key === "e") {
|
||||
const r = range(val);
|
||||
if (r) meta.episodes = r;
|
||||
hit = true;
|
||||
} else if (key === "g") hit = true;
|
||||
}
|
||||
return hit ? { ids, meta } : undefined;
|
||||
}
|
||||
|
||||
/** 常见拼音音节(不含声调);用于判断英文名是否其实是拼音 */
|
||||
const PINYIN_SYLLABLE =
|
||||
/^(?:[bpmfdtnlgkhjqxrzcsyw]|zh|ch|sh)?(?:iang|iong|uang|ueng|ang|eng|ing|ong|ian|iao|uai|uan|ai|ei|ao|ou|an|en|in|un|ia|ie|iu|ua|uo|ui|ue|er|a|o|e|i|u|v)$/i;
|
||||
|
||||
// ---------------------------------------------------------------- 主入口
|
||||
|
||||
/**
|
||||
@@ -724,19 +839,31 @@ export function parseRelease(input: string, opts: ParseOptions = {}): ParsedRele
|
||||
s = s.slice(0, -(ext.length + 1));
|
||||
} else if (opts.isFile) d.isFile = true;
|
||||
|
||||
// 2. 显式身份标签
|
||||
// 2. 显式身份标签:先取 `{[k=v;…]}` 块(季/集/类型一并给出),再取单个 `[tmdbid=…]`
|
||||
s = s.replace(/\{\[([^\]{}]*)\]\}/g, (all, body: string) => {
|
||||
const block = parseExplicitBlock(body);
|
||||
if (!block) return all;
|
||||
for (const x of block.ids) addExplicit(d, x);
|
||||
d._explicit = block.meta;
|
||||
ev.push("explicit:block");
|
||||
return " ";
|
||||
});
|
||||
s = s.replace(
|
||||
/[[{]\s*(tmdbid|tmdb|imdbid|imdb|doubanid|douban|tvdbid|tvdb)\s*[=-]\s*([A-Za-z0-9]+)\s*[\]}]/gi,
|
||||
/[[{]\s*(tmdbid|tmdb|imdbid|imdb|doubanid|douban|tvdbid|tvdb|bangumiid|bangumi|anilistid|anilist)\s*[=-]\s*([A-Za-z0-9]+)\s*[\]}]/gi,
|
||||
(_all, key: string, id: string) => {
|
||||
const k = key.toLowerCase().replace(/id$/, "") as ExplicitId["provider"];
|
||||
if (id !== "0" && !d.explicitIds.some((x) => x.provider === k)) {
|
||||
d.explicitIds.push({ provider: k, id });
|
||||
ev.push(`explicit:${k}`);
|
||||
}
|
||||
addExplicit(d, { provider: key.toLowerCase().replace(/id$/, "") as ExplicitId["provider"], id });
|
||||
return " ";
|
||||
},
|
||||
);
|
||||
|
||||
// 2b. 开头方括号里是完整的点分隔发布名(`[Name.2023.2160p.UHD.Blu-ray…-GRP][DIY中字原盘]…`):去括号保留内容
|
||||
s = s.replace(BRACKET_DOT_TITLE, " $1 ");
|
||||
// 2c. 动漫前缀标签(★7月新番★、[国漫]、【22年日剧】、[2022年7月番])与开头的分类方括号([Animations(动画片)])
|
||||
s = s.replace(ANIME_TAG_BRACKET, " ").replace(ANIME_TAG_BARE, " ");
|
||||
s = s.replace(CATEGORY_LEAD, "");
|
||||
// 2d. `中文名A / 中文名B`:同一作品的两个中文译名只留后一个(与 MP 取法一致),避免拼成一个名字
|
||||
s = s.replace(CN_ALIAS_SLASH, "");
|
||||
|
||||
// 3. 纯数字文件名 → 集号
|
||||
if (d.isFile && /^\s*\d{1,4}\s*$/.test(s)) {
|
||||
const n = Number(s.trim());
|
||||
@@ -765,9 +892,11 @@ export function parseRelease(input: string, opts: ParseOptions = {}): ParsedRele
|
||||
for (const [re, cut] of CUT_RULES) {
|
||||
s = s.replace(re, () => {
|
||||
d.cut ??= cut;
|
||||
return " ";
|
||||
return "\uE001";
|
||||
});
|
||||
}
|
||||
// `Caligula.The.Ultimate.Cut` 去掉剪辑版本后,紧挨着的冠词 The 一并去掉
|
||||
s = s.replace(/\bThe[ .\-_]*\uE001/gi, " ").replace(/\uE001/g, " ");
|
||||
if (d.cut) ev.push("cut");
|
||||
|
||||
// 7. 综艺播出日期(在年份识别之前,避免被当成年份或被丢弃)
|
||||
@@ -786,7 +915,26 @@ export function parseRelease(input: string, opts: ParseOptions = {}): ParsedRele
|
||||
// 9. 年份区间 2019-2020 只保留前者
|
||||
s = s.replace(/(?<!\d)((?:19|20)\d{2})\s*[-~]\s*(?:19|20)\d{2}(?!\d)/, "$1");
|
||||
|
||||
// 10. 动漫式集号:" - 12 "、"[01-11 Fin]"、"[12]"
|
||||
// 10. 动漫式集号:" - 12 "、"[01-11 Fin]"、"[12]"、"[TV 04]"、"#13"
|
||||
s = s.replace(
|
||||
/[[【]\s*TV\s*(\d{1,4})(?:\s*[-~]\s*(\d{1,4}))?(\s*(?:Fin|END|完))?\s*[\]】]/iu,
|
||||
(all, a: string, b, fin) => {
|
||||
if (d.episodes) return all;
|
||||
d.episodes = { start: Number(a), end: Number(b ?? a) };
|
||||
ev.push("episode:bracket_tv");
|
||||
if (fin) {
|
||||
d._fin = true;
|
||||
ev.push("pack:fin");
|
||||
}
|
||||
return MARK_HARD;
|
||||
},
|
||||
);
|
||||
s = s.replace(/(?<=\S\s+)#(\d{1,4})(?=\s|[[((]|$)/u, (all, n: string) => {
|
||||
if (d.episodes) return all;
|
||||
d.episodes = { start: Number(n), end: Number(n) };
|
||||
ev.push("episode:hash");
|
||||
return MARK_HARD;
|
||||
});
|
||||
s = s.replace(
|
||||
/[[【]\s*(\d{1,4})\s*[-~]\s*(\d{1,4})(\s*(?:Fin|END|完))?\s*[\]】]/iu,
|
||||
(all, a: string, b: string, fin) => {
|
||||
@@ -814,11 +962,18 @@ export function parseRelease(input: string, opts: ParseOptions = {}): ParsedRele
|
||||
}
|
||||
return MARK_HARD;
|
||||
});
|
||||
if (d.releaseGroup?.source === "bracket") {
|
||||
s = s.replace(/[[【](\d{1,3})(?:v\d)?[\]】]/u, (all, n: string) => {
|
||||
if (d.episodes) return all;
|
||||
// `[Group][Name][05]`、`Name [01][1080p]`:名称后的方括号纯数字是集号
|
||||
s = s.replace(/(?<=\S\s*)[[【](\d{1,3})(?:v\d)?[\]】]/u, (all, n: string) => {
|
||||
if (d.episodes) return all;
|
||||
d.episodes = { start: Number(n), end: Number(n) };
|
||||
ev.push("episode:anime_bracket");
|
||||
return MARK_HARD;
|
||||
});
|
||||
// 文件名 `西部世界 12`:中文名后空格加 2~3 位数字
|
||||
if (d.isFile && !d.episodes) {
|
||||
s = s.replace(/(?<=\p{Script=Han})\s+(\d{2,3})\s*$/u, (_all, n: string) => {
|
||||
d.episodes = { start: Number(n), end: Number(n) };
|
||||
ev.push("episode:anime_bracket");
|
||||
ev.push("episode:cn_name_number");
|
||||
return MARK_HARD;
|
||||
});
|
||||
}
|
||||
@@ -837,7 +992,22 @@ export function parseRelease(input: string, opts: ParseOptions = {}): ParsedRele
|
||||
|
||||
// 13. 副标题补缺
|
||||
if (opts.subtitle) {
|
||||
// 英文名其实是拼音(Mai Xiang ↔ 麦香):中文名取副标题第一个词
|
||||
if (!d.titleCn && d.titleEn) {
|
||||
const words = d.titleEn.split(/\s+/);
|
||||
const first = /^\s*(\p{Script=Han}{2,12})(?=[\s||/,,]|$)/u.exec(opts.subtitle)?.[1];
|
||||
if (first && words.length === [...first].length && words.every((w) => PINYIN_SYLLABLE.test(w))) {
|
||||
d.titleCn = first;
|
||||
ev.push("subtitle:title_cn_pinyin");
|
||||
}
|
||||
}
|
||||
const sub = scanCnMarkers(opts.subtitle);
|
||||
// 副标题里的拉丁字幕标记 CHS/CHT/GB/BIG5(`60 GB` 这类体积不算)
|
||||
for (const m of opts.subtitle.matchAll(/(?<![A-Za-z0-9])(?<!\d\s?)(CHS|CHT|GB|BIG5)(?![A-Za-z0-9])/gi)) {
|
||||
const lang = /^(CHS|GB)$/i.test(m[1]!) ? "zh-Hans" : "zh-Hant";
|
||||
sub.subtitles = [...new Set([...(sub.subtitles ?? []), lang])];
|
||||
if (!sub.evidence.includes("subtitle:latin")) sub.evidence.push("subtitle:latin");
|
||||
}
|
||||
applyCnMarkers(d, sub, "subtitle:");
|
||||
if (!d.airDate) {
|
||||
const sad = extractAirDate(opts.subtitle);
|
||||
@@ -900,13 +1070,22 @@ function finalize(d: Draft, opts: ParseOptions): ParsedRelease {
|
||||
} else ev.push("episode:offset_rejected");
|
||||
}
|
||||
if (d.totalEpisodes !== undefined && d.episodes === undefined && d.isFile) d.totalEpisodes = undefined;
|
||||
// 显式身份块的季/集最后覆盖(对照 MP _apply_explicit_metainfo)
|
||||
const x = d._explicit;
|
||||
if (x?.season !== undefined) {
|
||||
d.season = x.season;
|
||||
d.seasonEnd = x.seasonEnd;
|
||||
d.seasonInferred = undefined;
|
||||
}
|
||||
if (x?.episodes) d.episodes = x.episodes;
|
||||
|
||||
const tvSignals =
|
||||
d.season !== undefined ||
|
||||
d.episodes !== undefined ||
|
||||
d.airDate !== undefined ||
|
||||
d.issue !== undefined ||
|
||||
d.totalEpisodes !== undefined;
|
||||
d.totalEpisodes !== undefined ||
|
||||
d._explicit?.tv === true;
|
||||
d.mediaTypeHint = tvSignals ? "tv" : "unknown";
|
||||
|
||||
// 季号推定:有集号/总集数但无季号,且不是综艺日期/期号
|
||||
@@ -929,7 +1108,7 @@ function finalize(d: Draft, opts: ParseOptions): ParsedRelease {
|
||||
d.title = d.titleCn ?? d.titleEn;
|
||||
d.confidence = confidenceOf(d);
|
||||
|
||||
const { _complete, _fin, _disc, _remux, ...out } = d;
|
||||
const { _complete, _fin, _disc, _remux, _explicit, ...out } = d;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,14 @@ export function mergeParsed(
|
||||
evidence: [...primary.evidence],
|
||||
};
|
||||
const used: string[] = [];
|
||||
const fbTv = fallback.mediaTypeHint === "tv";
|
||||
// 目录只有日期(`…Collection.20240501.FRDS` 这类收藏/打包日期)不算剧集信号,不参与类型合并
|
||||
const dateOnly =
|
||||
fallback.airDate !== undefined &&
|
||||
fallback.season === undefined &&
|
||||
fallback.episodes === undefined &&
|
||||
fallback.issue === undefined &&
|
||||
fallback.totalEpisodes === undefined;
|
||||
const fbTv = fallback.mediaTypeHint === "tv" && !dateOnly;
|
||||
const deviation = primary.mediaTypeHint !== "tv" && fbTv;
|
||||
|
||||
if (!primary.title) {
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
/**
|
||||
* 流媒体平台简称 → 展示名(scene 命名惯例,事实数据)。
|
||||
* 条目对照 MoviePilot `streamingplatform.py` 的简称表补齐;只收单词元简称(含 `-` 的写法在 normalizeCompounds 里先合并),
|
||||
* 与英文常用词/其他技术词冲突的简称(FREE、NOW、PLAY、LIFE、MA、AS、SE、TEN…)刻意不收,避免误判。
|
||||
* 词元只在 WEB 来源词前后 2 个位置内才当作平台(见 walkTokens 的 nearWeb)。
|
||||
* 与 MP 的表示差异:HMAX 记 "HBO Max"(MP 记 "Max"),差分登记为 representation。
|
||||
*/
|
||||
export const PLATFORMS: Readonly<Record<string, string>> = {
|
||||
NF: "Netflix",
|
||||
AMZN: "Amazon",
|
||||
MAX: "Max",
|
||||
HMAX: "HBO Max",
|
||||
DSNP: "Disney+",
|
||||
DSNY: "Disney Networks",
|
||||
ATVP: "Apple TV+",
|
||||
IT: "iTunes",
|
||||
HULU: "Hulu",
|
||||
HULUJP: "Hulu",
|
||||
PCOK: "Peacock",
|
||||
PMTP: "Paramount+",
|
||||
PMNT: "Paramount Network",
|
||||
CR: "Crunchyroll",
|
||||
FUNI: "Funimation",
|
||||
HIDI: "HIDIVE",
|
||||
IQ: "iQIYI",
|
||||
IQIYI: "iQIYI",
|
||||
TX: "Tencent Video",
|
||||
WETV: "WeTV",
|
||||
YK: "Youku",
|
||||
MGTV: "MGTV",
|
||||
BILI: "Bilibili",
|
||||
BG: "B-Global",
|
||||
BGLOBAL: "B-Global",
|
||||
BAHA: "Baha",
|
||||
VIU: "Viu",
|
||||
KKTV: "KKTV",
|
||||
FRIDAY: "friDay",
|
||||
LITV: "LiTV",
|
||||
MYVIDEO: "MyVideo",
|
||||
OFIII: "ofiii",
|
||||
HAMI: "Hami Video",
|
||||
HAMIVIDEO: "Hami Video",
|
||||
LINETV: "LINE TV",
|
||||
CATCHPLAY: "CATCHPLAY+",
|
||||
CPP: "CATCHPLAY+",
|
||||
CTHP: "CATCHPLAY+",
|
||||
MYTVS: "MyTVSuper",
|
||||
NOWE: "Now E",
|
||||
NOWPLAYER: "NowPlayer",
|
||||
GAGA: "GagaOOLala",
|
||||
HBO: "HBO",
|
||||
HBOGO: "HBO GO",
|
||||
STAN: "Stan",
|
||||
HS: "Hotstar",
|
||||
APPS: "Disney+ MENA",
|
||||
BCORE: "Bravia Core",
|
||||
SHO: "Showtime",
|
||||
SKST: "SkyShowtime",
|
||||
FXTL: "Foxtel Now",
|
||||
BNGE: "Binge",
|
||||
CRKL: "Crackle",
|
||||
RKTN: "Rakuten TV",
|
||||
VIKI: "Rakuten Viki",
|
||||
ALL4: "Channel 4",
|
||||
MY5: "Channel 5",
|
||||
ITVX: "ITV",
|
||||
IP: "BBC iPlayer",
|
||||
BBC: "BBC",
|
||||
BRITBOX: "BritBox",
|
||||
UKTV: "UKTV",
|
||||
CNLP: "Canal+",
|
||||
CRIT: "Criterion Channel",
|
||||
DSCP: "Discovery+",
|
||||
DISC: "Discovery Channel",
|
||||
MUBI: "Mubi",
|
||||
YT: "YouTube",
|
||||
MW: "meWATCH",
|
||||
ABMA: "Abema",
|
||||
ABEMATV: "Abema",
|
||||
UNXT: "U-NEXT",
|
||||
DMM: "DMM",
|
||||
LEMINO: "Lemino",
|
||||
TVER: "TVer",
|
||||
WAKA: "Wakanim",
|
||||
WAKANIM: "Wakanim",
|
||||
AOD: "Anime on Demand",
|
||||
BCH: "Bandai Channel",
|
||||
VMJ: "VideoMarket",
|
||||
LFTL: "Laftel",
|
||||
LFTLNET: "Laftel",
|
||||
AO: "AnimeOnegai",
|
||||
"9NOW": "9Now",
|
||||
"7PLUS": "7plus",
|
||||
SBS: "SBS",
|
||||
AUBC: "ABC iview",
|
||||
SHAHID: "Shahid",
|
||||
OSN: "OSN+",
|
||||
TOU: "Ici TOU.TV",
|
||||
ROKU: "Roku",
|
||||
KNPY: "Kanopy",
|
||||
SNXT: "Sun NXT",
|
||||
CUR: "Curiosity Stream",
|
||||
AHA: "aha",
|
||||
WOWP: "WOW Presents Plus",
|
||||
JC: "JioCinema",
|
||||
ZEE5: "ZEE5",
|
||||
HOICHOI: "Hoichoi",
|
||||
PLEX: "Plex",
|
||||
SHDR: "Shudder",
|
||||
CRAV: "Crave",
|
||||
CPE: "Cineplex Entertainment",
|
||||
VIAP: "Viaplay",
|
||||
TUBI: "TubiTV",
|
||||
PLUTOTV: "Pluto TV",
|
||||
PBSK: "PBS KIDS",
|
||||
PBS: "PBS",
|
||||
LGP: "Lionsgate Play",
|
||||
STZ: "STARZ",
|
||||
FUBO: "fuboTV",
|
||||
CBC: "CBC Gem",
|
||||
CW: "The CW",
|
||||
CWS: "CW Seed",
|
||||
CMAX: "Cinemax",
|
||||
HLMK: "Hallmark",
|
||||
AMC: "AMC",
|
||||
USAN: "USA Network",
|
||||
BRAV: "BravoTV",
|
||||
TNT: "TNT",
|
||||
TCM: "TCM",
|
||||
TLC: "TLC",
|
||||
HGTV: "HGTV",
|
||||
ANPL: "Animal Planet",
|
||||
TRVL: "Travel Channel",
|
||||
NATG: "National Geographic",
|
||||
STRP: "Star+",
|
||||
CNNP: "CNN+",
|
||||
EPIX: "EPIX MGM+",
|
||||
HIST: "History Channel",
|
||||
NICK: "Nickelodeon",
|
||||
SYFY: "SyFy",
|
||||
DCU: "DC Universe",
|
||||
QIBI: "Quibi",
|
||||
VRV: "VRV",
|
||||
VMEO: "Vimeo",
|
||||
WTCH: "Watcha",
|
||||
WAVVE: "Wavve",
|
||||
TVING: "TVING",
|
||||
ODK: "OnDemandKorea",
|
||||
VIDIO: "Vidio",
|
||||
FPT: "FPT Play",
|
||||
FPTP: "FPT Play",
|
||||
JOYN: "Joyn",
|
||||
RTL: "RTL+",
|
||||
ARTE: "Arte",
|
||||
ZDF: "ZDF",
|
||||
ARD: "ARD",
|
||||
SVT: "Sveriges Television",
|
||||
VIAPLAY: "Viaplay",
|
||||
CMOR: "C More",
|
||||
FTV: "France.tv",
|
||||
GLBO: "Globoplay",
|
||||
A3P: "Atresplayer",
|
||||
FILMIN: "Filmin",
|
||||
OKKO: "Okko",
|
||||
IVI: "Ivi",
|
||||
VOYO: "Voyo",
|
||||
DANT: "DANET",
|
||||
SMNS: "SAMANSA",
|
||||
};
|
||||
@@ -11,7 +11,8 @@ export const RELEASE_GROUP_SEED: Readonly<Record<string, readonly string[]>> = {
|
||||
hdsky: ["HDSky", "HDS", "HDSWEB", "HDSTV", "HDSPad"],
|
||||
pthome: ["PTHome", "PTH", "PTHweb"],
|
||||
cmct: ["CMCT", "CMCTV"],
|
||||
frds: ["FRDS"],
|
||||
frds: ["FRDS", "cXcY"],
|
||||
league: ["LeagueWEB", "LeagueTV", "LeagueHD", "LeagueNF", "LeagueCD"],
|
||||
ttg: ["TTG", "WiKi", "NGB", "DoA"],
|
||||
hdchina: ["HDChina", "HDC"],
|
||||
beitai: ["BeiTai"],
|
||||
@@ -54,12 +55,12 @@ export const RELEASE_GROUP_SEED: Readonly<Record<string, readonly string[]>> = {
|
||||
|
||||
const escapeRe = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
|
||||
/** 构造发布组匹配正则:前界定符 - @ [ 【 & ,后界定符 结尾 @ . 空白 ] [ 】 & */
|
||||
/** 构造发布组匹配正则:前界定符 - @ [ 【 & £,后界定符 结尾 @ . 空白 ] [ 】 & £(`AC3£cXcY@FRDS` 这类多组写法) */
|
||||
export function buildGroupRegex(extra: readonly string[] = []): RegExp {
|
||||
const all = [...Object.values(RELEASE_GROUP_SEED).flat(), ...extra];
|
||||
// 长名优先,避免 CHD 抢先匹配 CHDWEB
|
||||
const uniq = [...new Set(all)].sort((a, b) => b.length - a.length).map(escapeRe);
|
||||
return new RegExp(`(?<=[-@\\[【&])(?:${uniq.join("|")})(?=$|[@.\\s\\]\\[】&])`, "giu");
|
||||
return new RegExp(`(?<=[-@\\[【&£])(?:${uniq.join("|")})(?=$|[@.\\s\\]\\[】&£])`, "giu");
|
||||
}
|
||||
|
||||
let cached: RegExp | undefined;
|
||||
|
||||
@@ -63,7 +63,7 @@ export interface ReleaseGroup {
|
||||
}
|
||||
|
||||
export interface ExplicitId {
|
||||
provider: "tmdb" | "imdb" | "douban" | "tvdb";
|
||||
provider: "tmdb" | "imdb" | "douban" | "tvdb" | "bangumi" | "anilist";
|
||||
id: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -12216,78 +12216,30 @@
|
||||
}
|
||||
],
|
||||
"deviations": {
|
||||
"R06:t03": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「2160p UHD Blu-ray HEVC」被 parseRelease 判为 BluRay 压制(isEncode=true);MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R06:t08": {
|
||||
"kind": "mp_bug",
|
||||
"note": "MP BLU 正则分支 `(UHD|4K|2160p).*(HEVC|H.265)` 在无来源标记的 2160p HEVC 上误判为原盘;我们来源未知按 !BLU 放行",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R06:t12": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「1080p Blu-ray AVC」(无 x264)被 parseRelease 判为 BluRay 压制;MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R07:t03": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「2160p UHD Blu-ray HEVC」被 parseRelease 判为 BluRay 压制(isEncode=true);MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R07:t08": {
|
||||
"kind": "mp_bug",
|
||||
"note": "MP BLU 正则分支 `(UHD|4K|2160p).*(HEVC|H.265)` 在无来源标记的 2160p HEVC 上误判为原盘;我们来源未知按 !BLU 放行",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R07:t12": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「1080p Blu-ray AVC」(无 x264)被 parseRelease 判为 BluRay 压制;MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R11:t03": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「2160p UHD Blu-ray HEVC」被 parseRelease 判为 BluRay 压制(isEncode=true);MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R11:t08": {
|
||||
"kind": "mp_bug",
|
||||
"note": "MP BLU 正则分支 `(UHD|4K|2160p).*(HEVC|H.265)` 在无来源标记的 2160p HEVC 上误判为原盘;我们来源未知按 !BLU 放行",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R11:t12": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「1080p Blu-ray AVC」(无 x264)被 parseRelease 判为 BluRay 压制;MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R13:t17": {
|
||||
"kind": "our_bug",
|
||||
"note": "副标题「CHS/ENG」:MP CNSUB 命中 chs/cht 词;parseRelease 字幕扫描只认中文关键词,未识别 CHS/CHT/GB/BIG5",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R13:t26": {
|
||||
"kind": "mp_bug",
|
||||
"note": "副标题「国语」(音轨语言)被 MP CNSUB 正则当作中文字幕;我们把国语视为音轨,不满足 requiredSubtitles",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R14:t17": {
|
||||
"kind": "our_bug",
|
||||
"note": "副标题「CHS/ENG」:MP CNSUB 命中 chs/cht 词;parseRelease 字幕扫描只认中文关键词,未识别 CHS/CHT/GB/BIG5",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R14:t26": {
|
||||
"kind": "mp_bug",
|
||||
"note": "副标题「国语」(音轨语言)被 MP CNSUB 正则当作中文字幕;我们把国语视为音轨,不满足 requiredSubtitles",
|
||||
@@ -12324,54 +12276,18 @@
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R19:t03": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「2160p UHD Blu-ray HEVC」被 parseRelease 判为 BluRay 压制(isEncode=true);MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R19:t08": {
|
||||
"kind": "mp_bug",
|
||||
"note": "MP BLU 正则分支 `(UHD|4K|2160p).*(HEVC|H.265)` 在无来源标记的 2160p HEVC 上误判为原盘;我们来源未知按 !BLU 放行",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R19:t12": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「1080p Blu-ray AVC」(无 x264)被 parseRelease 判为 BluRay 压制;MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R20:t03": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「2160p UHD Blu-ray HEVC」被 parseRelease 判为 BluRay 压制(isEncode=true);MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R20:t12": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「1080p Blu-ray AVC」(无 x264)被 parseRelease 判为 BluRay 压制;MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R21:t03": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「2160p UHD Blu-ray HEVC」被 parseRelease 判为 BluRay 压制(isEncode=true);MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R21:t08": {
|
||||
"kind": "mp_bug",
|
||||
"note": "MP BLU 正则分支 `(UHD|4K|2160p).*(HEVC|H.265)` 在无来源标记的 2160p HEVC 上误判为原盘;我们来源未知按 !BLU 放行",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R21:t12": {
|
||||
"kind": "our_bug",
|
||||
"note": "原盘命名「1080p Blu-ray AVC」(无 x264)被 parseRelease 判为 BluRay 压制;MP BLU 判为原盘。应识别为 BluRay-Disc",
|
||||
"mp": null,
|
||||
"ours": 2
|
||||
},
|
||||
"R23:t01": {
|
||||
"kind": "missing",
|
||||
"note": "MP 规则可带 tmdb 条件:媒体 original_language∈{zh,cn} 时 CNSUB 对任何种子直接放行(华语片不要求中字);Slot 无媒体上下文条件",
|
||||
@@ -12432,12 +12348,6 @@
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R23:t17": {
|
||||
"kind": "missing",
|
||||
"note": "MP 规则可带 tmdb 条件:媒体 original_language∈{zh,cn} 时 CNSUB 对任何种子直接放行(华语片不要求中字);Slot 无媒体上下文条件",
|
||||
"mp": 1,
|
||||
"ours": null
|
||||
},
|
||||
"R23:t18": {
|
||||
"kind": "missing",
|
||||
"note": "MP 规则可带 tmdb 条件:媒体 original_language∈{zh,cn} 时 CNSUB 对任何种子直接放行(华语片不要求中字);Slot 无媒体上下文条件",
|
||||
@@ -12546,6 +12456,12 @@
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R25:t17": {
|
||||
"kind": "not_expressible",
|
||||
"note": "SPECSUB(特效字幕)无对应字段,近似翻译丢失该条件",
|
||||
"mp": null,
|
||||
"ours": 1
|
||||
},
|
||||
"R25:t21": {
|
||||
"kind": "not_expressible",
|
||||
"note": "SPECSUB(特效字幕)无对应字段,近似翻译丢失该条件",
|
||||
|
||||
@@ -317,12 +317,6 @@
|
||||
"mp": null,
|
||||
"ours": "grp",
|
||||
"note": "未知发布组兜底(末段 -GROUP / 开头方括号),MP 组表未命中为 None"
|
||||
},
|
||||
"web_source": {
|
||||
"kind": "missing",
|
||||
"mp": "bbciplayer",
|
||||
"ours": null,
|
||||
"note": "流媒体平台表缺 iP(BBC iPlayer)"
|
||||
}
|
||||
},
|
||||
"T-14": {
|
||||
@@ -345,6 +339,12 @@
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"web_source": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "baha",
|
||||
"note": "MetaAnime(anitopy 路径)不产出流媒体平台;Baha 在 MP 平台表里,MetaVideo 路径同样会产出"
|
||||
}
|
||||
},
|
||||
"A-02": {
|
||||
@@ -359,6 +359,12 @@
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"web_source": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "baha",
|
||||
"note": "MetaAnime(anitopy 路径)不产出流媒体平台;Baha 在 MP 平台表里,MetaVideo 路径同样会产出"
|
||||
}
|
||||
},
|
||||
"A-03": {
|
||||
@@ -772,36 +778,6 @@
|
||||
}
|
||||
},
|
||||
"MP-01": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "thelongseason",
|
||||
"ours": "thelong",
|
||||
"note": "\"Season 2017\" 被当成第 2017 季、吞掉年份;MP 自带用例期望 en=The Long Season y=2017"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "thelongseason",
|
||||
"ours": "thelong",
|
||||
"note": "\"Season 2017\" 被当成第 2017 季、吞掉年份;MP 自带用例期望 en=The Long Season y=2017"
|
||||
},
|
||||
"year": {
|
||||
"kind": "our_bug",
|
||||
"mp": "2017",
|
||||
"ours": null,
|
||||
"note": "\"Season 2017\" 被当成第 2017 季、吞掉年份;MP 自带用例期望 en=The Long Season y=2017"
|
||||
},
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "unknown",
|
||||
"ours": "tv",
|
||||
"note": "\"Season 2017\" 被当成第 2017 季、吞掉年份;MP 自带用例期望 en=The Long Season y=2017"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "our_bug",
|
||||
"mp": null,
|
||||
"ours": "2017",
|
||||
"note": "\"Season 2017\" 被当成第 2017 季、吞掉年份;MP 自带用例期望 en=The Long Season y=2017"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -818,18 +794,6 @@
|
||||
}
|
||||
},
|
||||
"MP-03": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "欢迎来到实力至上主义的教室",
|
||||
"ours": "★7月新番欢迎来到实力至上主义的教室",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "欢迎来到实力至上主义的教室",
|
||||
"ours": "★7月新番欢迎来到实力至上主义的教室",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -838,57 +802,29 @@
|
||||
}
|
||||
},
|
||||
"MP-05": {
|
||||
"name": {
|
||||
"kind": "mp_bug",
|
||||
"mp": "akibamaidsensou",
|
||||
"ours": "秋叶原冥途战争",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "秋叶原冥途战争",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
},
|
||||
"resource_pix": {
|
||||
"kind": "missing",
|
||||
"mp": "1080p",
|
||||
"ours": null,
|
||||
"note": "方括号裸数字 [1080] 不识别为分辨率"
|
||||
},
|
||||
"resource_type": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "our_bug",
|
||||
"mp": "leagueweb",
|
||||
"ours": "秋叶原冥途战争",
|
||||
"note": "开头方括号是片名而非组名,仍被当 bracket 组;MP 按组表命中 LeagueWEB"
|
||||
}
|
||||
},
|
||||
"MP-06": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "哆啦a梦大雄的宇宙小战争2021",
|
||||
"ours": "哆啦梦大雄的宇宙小战争2021",
|
||||
"note": "哆啦A梦 的拉丁字母 A 被拆出中文名成为英文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "哆啦a梦大雄的宇宙小战争2021",
|
||||
"ours": "哆啦梦大雄的宇宙小战争2021",
|
||||
"note": "哆啦A梦 的拉丁字母 A 被拆出中文名成为英文名"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": null,
|
||||
"ours": "a",
|
||||
"note": "哆啦A梦 的拉丁字母 A 被拆出中文名成为英文名"
|
||||
}
|
||||
},
|
||||
"MP-10": {
|
||||
"web_source": {
|
||||
"kind": "missing",
|
||||
"mp": "bglobal",
|
||||
"ours": null,
|
||||
"note": "流媒体平台表缺 B-Global"
|
||||
}
|
||||
},
|
||||
"MP-12": {
|
||||
@@ -897,12 +833,6 @@
|
||||
"mp": null,
|
||||
"ours": "WEBRip",
|
||||
"note": "MP 未识别方括号内 [WEBRip]"
|
||||
},
|
||||
"audio_encode": {
|
||||
"kind": "missing",
|
||||
"mp": "51",
|
||||
"ours": null,
|
||||
"note": "孤立声道 [5.1] 不识别为音频"
|
||||
}
|
||||
},
|
||||
"MP-13": {
|
||||
@@ -918,32 +848,20 @@
|
||||
"ours": "诛仙",
|
||||
"note": "MP 丢中文名(/ 分隔或嵌套方括号)"
|
||||
},
|
||||
"resource_pix": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "2160p",
|
||||
"note": "MetaAnime 不认方括号裸数字 [2160](同一路径认 [1080]);我们按分辨率识别"
|
||||
},
|
||||
"resource_type": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "our_bug",
|
||||
"mp": "leagueweb",
|
||||
"ours": "animations(动画片)",
|
||||
"note": "开头方括号是片名而非组名,仍被当 bracket 组;MP 按组表命中 LeagueWEB"
|
||||
}
|
||||
},
|
||||
"MP-17": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "据幸存的六人所说",
|
||||
"ours": "22年日剧据幸存的六人所说",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "据幸存的六人所说",
|
||||
"ours": "22年日剧据幸存的六人所说",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -953,16 +871,16 @@
|
||||
},
|
||||
"MP-18": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "soredemoayumuwayosetekuru",
|
||||
"ours": "★7月新番即使如此依旧步步进逼",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
"ours": "即使如此依旧步步进逼",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "★7月新番即使如此依旧步步进逼",
|
||||
"note": "前缀标签混入中文名;MP 丢中文名"
|
||||
"ours": "即使如此依旧步步进逼",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
@@ -973,31 +891,19 @@
|
||||
},
|
||||
"MP-20": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "swordquest",
|
||||
"ours": "国漫寻剑",
|
||||
"note": "动漫标题前缀标签(国漫)未剥离,且 name 取中文"
|
||||
"ours": "寻剑",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "国漫寻剑",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
"ours": "寻剑",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
}
|
||||
},
|
||||
"MP-21": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "组长女儿与保姆",
|
||||
"ours": "组长女儿与照料专员组长女儿与保姆",
|
||||
"note": "\"A / B\" 两个中文名被拼接;MP 取后者"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "组长女儿与保姆",
|
||||
"ours": "组长女儿与照料专员组长女儿与保姆",
|
||||
"note": "\"A / B\" 两个中文名被拼接;MP 取后者"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -1022,56 +928,26 @@
|
||||
}
|
||||
},
|
||||
"MP-24": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "galtokyouryuu",
|
||||
"ours": "bdrip",
|
||||
"note": "[Name][02][BDRIP] 取到 BDRIP 作名称"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "galtokyouryuu",
|
||||
"ours": "bdrip",
|
||||
"note": "[Name][02][BDRIP] 取到 BDRIP 作名称"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
},
|
||||
"resource_type": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "BluRay",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "mp_bug",
|
||||
"mp": "gal to kyouryuu",
|
||||
"ours": null,
|
||||
"note": "MP 把开头的片名方括号 [Gal to Kyouryuu] 同时当成组名;我们判为片名(紧跟集号 [02])"
|
||||
}
|
||||
},
|
||||
"MP-25": {
|
||||
"name": {
|
||||
"kind": "missing",
|
||||
"mp": "逆境無頼カイジ",
|
||||
"ours": "逆境無頼カイジ13",
|
||||
"note": "#13 集号写法不识别"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "missing",
|
||||
"mp": "逆境無頼カイジ",
|
||||
"ours": "逆境無頼カイジ13",
|
||||
"note": "#13 集号写法不识别"
|
||||
},
|
||||
"type": {
|
||||
"kind": "missing",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "#13 集号写法不识别"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "missing",
|
||||
"mp": "1",
|
||||
"ours": null,
|
||||
"note": "#13 集号写法不识别"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "13",
|
||||
"ours": null,
|
||||
"note": "#13 集号写法不识别"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -1080,43 +956,37 @@
|
||||
}
|
||||
},
|
||||
"MP-27": {
|
||||
"name": {
|
||||
"kind": "mp_bug",
|
||||
"mp": "throneofseal",
|
||||
"ours": "神印王座",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "神印王座",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"resource_pix": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "2160p",
|
||||
"note": "MetaAnime 不认方括号裸数字 [2160](同一路径认 [1080]);我们按分辨率识别"
|
||||
},
|
||||
"resource_type": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "our_bug",
|
||||
"mp": "leagueweb",
|
||||
"ours": "神印王座",
|
||||
"note": "开头方括号是片名而非组名,仍被当 bracket 组;MP 按组表命中 LeagueWEB"
|
||||
}
|
||||
},
|
||||
"MP-29": {
|
||||
"name": {
|
||||
"kind": "missing",
|
||||
"mp": "西部世界",
|
||||
"ours": "西部世界12",
|
||||
"note": "\"中文名 12.mkv\" 文件名尾部裸数字不识别为集号"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "missing",
|
||||
"mp": "西部世界",
|
||||
"ours": "西部世界12",
|
||||
"note": "\"中文名 12.mkv\" 文件名尾部裸数字不识别为集号"
|
||||
},
|
||||
"type": {
|
||||
"kind": "missing",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "\"中文名 12.mkv\" 文件名尾部裸数字不识别为集号"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "12",
|
||||
"ours": null,
|
||||
"note": "\"中文名 12.mkv\" 文件名尾部裸数字不识别为集号"
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"MP-30": {
|
||||
@@ -1125,6 +995,12 @@
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"web_source": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "baha",
|
||||
"note": "MetaAnime(anitopy 路径)不产出流媒体平台;Baha 在 MP 平台表里,MetaVideo 路径同样会产出"
|
||||
}
|
||||
},
|
||||
"MP-31": {
|
||||
@@ -1143,16 +1019,16 @@
|
||||
},
|
||||
"MP-32": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "fightsbreakspherev",
|
||||
"ours": "国漫斗破苍穹",
|
||||
"note": "动漫标题前缀标签(国漫)未剥离,且 name 取中文"
|
||||
"ours": "斗破苍穹",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "国漫斗破苍穹",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
"ours": "斗破苍穹",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
}
|
||||
},
|
||||
"MP-34": {
|
||||
@@ -1215,6 +1091,12 @@
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"web_source": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "baha",
|
||||
"note": "MetaAnime(anitopy 路径)不产出流媒体平台;Baha 在 MP 平台表里,MetaVideo 路径同样会产出"
|
||||
}
|
||||
},
|
||||
"MP-41": {
|
||||
@@ -1227,10 +1109,10 @@
|
||||
},
|
||||
"MP-44": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "isekaiojisan",
|
||||
"ours": "异世界归来的舅舅",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "mp_bug",
|
||||
@@ -1238,55 +1120,31 @@
|
||||
"ours": "异世界归来的舅舅",
|
||||
"note": "MP 丢中文名"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "isekaiojisan",
|
||||
"ours": "isekaiojisan01",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "1",
|
||||
"ours": null,
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"MP-45": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "summertimerendering",
|
||||
"ours": "★04月新番★夏日重現",
|
||||
"note": "前缀标签混入中文名"
|
||||
"ours": "夏日重現",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "★04月新番★夏日重現",
|
||||
"note": "前缀标签混入中文名;MP 丢中文名"
|
||||
"ours": "夏日重現",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "summertimerendering",
|
||||
"ours": "summertimerendering15",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "15",
|
||||
"ours": null,
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"MP-46": {
|
||||
@@ -1305,56 +1163,12 @@
|
||||
"note": "未知发布组兜底(末段 -GROUP / 开头方括号),MP 组表未命中为 None"
|
||||
}
|
||||
},
|
||||
"MP-48": {
|
||||
"audio_encode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "DTSHDMA51",
|
||||
"ours": "DTSHD",
|
||||
"note": "DTS-HD MA5.1(MA 与声道粘连)只识别到 DTSHD"
|
||||
}
|
||||
},
|
||||
"MP-49": {
|
||||
"audio_encode": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "AC3",
|
||||
"note": "AC3£cXcY:MP 未切开 £ 分隔,音频丢失"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "missing",
|
||||
"mp": "cxcy@frds",
|
||||
"ours": "frds",
|
||||
"note": "£ 分隔的多组 cXcY@FRDS 只取到 FRDS"
|
||||
}
|
||||
},
|
||||
"MP-50": {
|
||||
"begin_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "13",
|
||||
"ours": null,
|
||||
"note": "S01 13-14 裸数字集区间不识别"
|
||||
},
|
||||
"end_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "14",
|
||||
"ours": null,
|
||||
"note": "S01 13-14 裸数字集区间不识别"
|
||||
}
|
||||
},
|
||||
"MP-51": {
|
||||
"end_episode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "14",
|
||||
"ours": null,
|
||||
"note": "E13-14 只取到起始集"
|
||||
}
|
||||
},
|
||||
"MP-52": {
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "unknown",
|
||||
"ours": "tv",
|
||||
"note": "开头下载日期 2022.8.2 被当成 airDate → 误判剧集"
|
||||
}
|
||||
},
|
||||
"MP-54": {
|
||||
@@ -1363,12 +1177,6 @@
|
||||
"mp": null,
|
||||
"ours": "AC3",
|
||||
"note": "AC3£cXcY:MP 未切开 £ 分隔,音频丢失"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "missing",
|
||||
"mp": "cxcy@frds",
|
||||
"ours": "frds",
|
||||
"note": "£ 分隔的多组 cXcY@FRDS 只取到 FRDS"
|
||||
}
|
||||
},
|
||||
"MP-55": {
|
||||
@@ -1385,10 +1193,10 @@
|
||||
"note": "MP 丢中文名(/ 分隔或嵌套方括号)"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "うたわれるもの",
|
||||
"ours": "utawarerumonoうたわれるもの",
|
||||
"note": "三段 / 名称(中/罗马字/日文)未拆开"
|
||||
"ours": "utawarerumono",
|
||||
"note": "MP 把 `/` 最后一段的日文假名名当英文名;我们取罗马字名,假名名只在没有英文名时兜底"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
@@ -1415,44 +1223,36 @@
|
||||
"note": "flac_ac3 我们记两种音轨,MP 只记 FLAC"
|
||||
}
|
||||
},
|
||||
"MP-56": {
|
||||
"MP-57": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "欢迎来到实力至上主义的教室",
|
||||
"ours": "7月新番欢迎来到实力至上主义的教室",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
"kind": "mp_bug",
|
||||
"mp": "jadedynasty",
|
||||
"ours": "诛仙",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "欢迎来到实力至上主义的教室",
|
||||
"ours": "7月新番欢迎来到实力至上主义的教室",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
}
|
||||
},
|
||||
"MP-57": {
|
||||
"type": {
|
||||
"kind": "missing",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "[TV 04] 集号写法不识别"
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "诛仙",
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "4",
|
||||
"ours": null,
|
||||
"note": "[TV 04] 集号写法不识别"
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
},
|
||||
"resource_pix": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "2160p",
|
||||
"note": "MetaAnime 不认方括号裸数字 [2160](同一路径认 [1080]);我们按分辨率识别"
|
||||
},
|
||||
"resource_type": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "our_bug",
|
||||
"mp": "leagueweb",
|
||||
"ours": "诛仙",
|
||||
"note": "开头方括号是片名而非组名,仍被当 bracket 组;MP 按组表命中 LeagueWEB"
|
||||
}
|
||||
},
|
||||
"MP-58": {
|
||||
@@ -1472,38 +1272,6 @@
|
||||
}
|
||||
},
|
||||
"MP-60": {
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "zhuxianjadedynasty",
|
||||
"ours": "hallofczhuxianjadedynasty",
|
||||
"note": "开头 [Hall_of_C] 组名混入英文名"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"MP-63": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "金属口红",
|
||||
"ours": "★1月新番金属口红",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "金属口红",
|
||||
"ours": "★1月新番金属口红",
|
||||
"note": "动漫标题前缀标签(★N月新番/N年日剧/国漫)未剥离,混入中文名"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "metallicrouge",
|
||||
"ours": "metallicrougegb",
|
||||
"note": "语言标记 GB 未剥离,进英文名"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -1511,33 +1279,21 @@
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "our_bug",
|
||||
"mp": "极影字幕社",
|
||||
"ours": null,
|
||||
"note": "【极影字幕社】全角方括号开头组未取到"
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "hall_of_c",
|
||||
"note": "未知发布组兜底(末段 -GROUP / 开头方括号),MP 组表未命中为 None"
|
||||
}
|
||||
},
|
||||
"MP-64": {
|
||||
"name": {
|
||||
"kind": "missing",
|
||||
"mp": "麦香",
|
||||
"ours": "maixiang",
|
||||
"note": "英文名为拼音时从副标题取中文名(MP metavideo 规则)未迁"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "missing",
|
||||
"mp": "麦香",
|
||||
"ours": null,
|
||||
"note": "英文名为拼音时从副标题取中文名(MP metavideo 规则)未迁"
|
||||
"MP-63": {
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"MP-73": {
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "unknown",
|
||||
"ours": "tv",
|
||||
"note": "父目录 Collection.20240501 的日期被当 airDate,合并后误判剧集"
|
||||
},
|
||||
"audio_encode": {
|
||||
"kind": "representation",
|
||||
"mp": "2AUDIO",
|
||||
@@ -1547,66 +1303,24 @@
|
||||
},
|
||||
"MP-74": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "intentional",
|
||||
"mp": "caligulatheultimatecut",
|
||||
"ours": "罗马帝国艳情史最终剪辑版澳大利亚版",
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": null,
|
||||
"ours": "罗马帝国艳情史最终剪辑版澳大利亚版",
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
"ours": "caligula",
|
||||
"note": "剪辑版本(Ultimate Cut 等)单独进 cut 字段,不留在名称里(REQ §6.1)"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "intentional",
|
||||
"mp": "caligulatheultimatecut",
|
||||
"ours": "diy",
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
},
|
||||
"year": {
|
||||
"kind": "our_bug",
|
||||
"mp": "2023",
|
||||
"ours": null,
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
},
|
||||
"resource_pix": {
|
||||
"kind": "our_bug",
|
||||
"mp": "2160p",
|
||||
"ours": null,
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
},
|
||||
"resource_type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "UHD BluRay",
|
||||
"ours": "UHD ?",
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
},
|
||||
"video_encode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "H.265",
|
||||
"ours": null,
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
},
|
||||
"audio_encode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "DTSHDMA51",
|
||||
"ours": null,
|
||||
"note": "[点分隔发布名][..] 形式:方括号内是完整发布名(MP BRACKET_DOT_TITLE_RE),未迁"
|
||||
"ours": "caligula",
|
||||
"note": "剪辑版本(Ultimate Cut 等)单独进 cut 字段,不留在名称里(REQ §6.1)"
|
||||
}
|
||||
},
|
||||
"MP-76": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "theshawshankredemption",
|
||||
"ours": "ytsmxtheshawshankredemption",
|
||||
"note": "[YTS.MX] 前缀未当作组名剥离"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "theshawshankredemption",
|
||||
"ours": "ytsmxtheshawshankredemption",
|
||||
"note": "[YTS.MX] 前缀未当作组名剥离"
|
||||
"resource_team": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "yts.mx",
|
||||
"note": "未知发布组兜底(末段 -GROUP / 开头方括号),MP 组表未命中为 None"
|
||||
}
|
||||
},
|
||||
"Z-02": {
|
||||
@@ -1663,6 +1377,12 @@
|
||||
"mp": null,
|
||||
"ours": "WEB-DL",
|
||||
"note": "MetaAnime(anitopy 路径)不产出来源/编码,我们产出"
|
||||
},
|
||||
"web_source": {
|
||||
"kind": "mp_bug",
|
||||
"mp": null,
|
||||
"ours": "baha",
|
||||
"note": "MetaAnime(anitopy 路径)不产出流媒体平台;Baha 在 MP 平台表里,MetaVideo 路径同样会产出"
|
||||
}
|
||||
},
|
||||
"Z-06": {
|
||||
@@ -1675,10 +1395,10 @@
|
||||
},
|
||||
"Z-07": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"kind": "mp_bug",
|
||||
"mp": "dungeonmeshi",
|
||||
"ours": "迷宫饭",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
"note": "MP 丢中文名(MetaAnime 取 `/` 后段,或把中英混排/纯中文片名块删掉),name 随之取英文名;我们保留中文名"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "mp_bug",
|
||||
@@ -1686,23 +1406,11 @@
|
||||
"ours": "迷宫饭",
|
||||
"note": "MP 丢中文名"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "dungeonmeshi",
|
||||
"ours": "dungeonmeshi13",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "13",
|
||||
"ours": null,
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"Z-08": {
|
||||
@@ -1730,18 +1438,6 @@
|
||||
}
|
||||
},
|
||||
"Z-12": {
|
||||
"name": {
|
||||
"kind": "missing",
|
||||
"mp": "指环王三部曲",
|
||||
"ours": "指环王三部曲合集",
|
||||
"note": "\"合集\" 干扰词未剥离"
|
||||
},
|
||||
"cn_name": {
|
||||
"kind": "missing",
|
||||
"mp": "指环王三部曲",
|
||||
"ours": "指环王三部曲合集",
|
||||
"note": "\"合集\" 干扰词未剥离"
|
||||
},
|
||||
"resource_team": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
@@ -1814,29 +1510,11 @@
|
||||
}
|
||||
},
|
||||
"Z-27": {
|
||||
"name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "shingekinokyojin",
|
||||
"ours": "shingekinokyojin05ma10p",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "our_bug",
|
||||
"mp": "shingekinokyojin",
|
||||
"ours": "shingekinokyojin05ma10p",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"type": {
|
||||
"kind": "our_bug",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "our_bug",
|
||||
"mp": "5",
|
||||
"ours": null,
|
||||
"note": "名称后的方括号集号 [01] 未识别,拼进英文名"
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
}
|
||||
},
|
||||
"Z-28": {
|
||||
@@ -1855,62 +1533,12 @@
|
||||
"note": "name 选择:我们有中文名就取中文,MP 仅中文名全为汉字时取中文(cn/en 一致)"
|
||||
}
|
||||
},
|
||||
"Z-31": {
|
||||
"name": {
|
||||
"kind": "missing",
|
||||
"mp": "houseofthedragon",
|
||||
"ours": "{tmdbid=94997type=tvs=1e=34}houseofthedragon",
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
},
|
||||
"en_name": {
|
||||
"kind": "missing",
|
||||
"mp": "houseofthedragon",
|
||||
"ours": "{tmdbid=94997type=tvs=1e=34}houseofthedragon",
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
},
|
||||
"type": {
|
||||
"kind": "missing",
|
||||
"mp": "tv",
|
||||
"ours": "unknown",
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
},
|
||||
"begin_season": {
|
||||
"kind": "missing",
|
||||
"mp": "1",
|
||||
"ours": null,
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
},
|
||||
"begin_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "3",
|
||||
"ours": null,
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
},
|
||||
"end_episode": {
|
||||
"kind": "missing",
|
||||
"mp": "4",
|
||||
"ours": null,
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
},
|
||||
"media_id": {
|
||||
"kind": "missing",
|
||||
"mp": "themoviedb:94997",
|
||||
"ours": null,
|
||||
"note": "{[tmdbid=..;type=tv;s=1;e=3-4]} 显式身份块未迁(find_metainfo)"
|
||||
}
|
||||
},
|
||||
"Z-32": {
|
||||
"begin_season": {
|
||||
"kind": "intentional",
|
||||
"mp": null,
|
||||
"ours": "1",
|
||||
"note": "有集号无季号推定第 1 季(seasonInferred)"
|
||||
},
|
||||
"media_id": {
|
||||
"kind": "missing",
|
||||
"mp": "bangumi:400602",
|
||||
"ours": null,
|
||||
"note": "[bangumiid=..] 未迁(我们只认 tmdb/imdb/douban/tvdb)"
|
||||
}
|
||||
},
|
||||
"Z-33": {
|
||||
|
||||
@@ -183,7 +183,14 @@ export function canonMp(m: MpMeta): Canon {
|
||||
};
|
||||
}
|
||||
|
||||
const PROVIDER: Record<string, string> = { tmdb: "themoviedb", douban: "douban", imdb: "imdb", tvdb: "tvdb" };
|
||||
const PROVIDER: Record<string, string> = {
|
||||
tmdb: "themoviedb",
|
||||
douban: "douban",
|
||||
imdb: "imdb",
|
||||
tvdb: "tvdb",
|
||||
bangumi: "bangumi",
|
||||
anilist: "anilist",
|
||||
};
|
||||
|
||||
export function oursParse(s: MetaSample): ParsedRelease {
|
||||
return s.kind === "path"
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
{
|
||||
"note": "繁→简差分已知差异:key=输入。kind 同 meta-deviations.json。",
|
||||
"deviations": {
|
||||
"咒術迴戰": { "kind": "missing", "mp": "咒术回战", "ours": "咒术迴战", "note": "字表缺 迴→回" },
|
||||
"孤獨搖滾": { "kind": "missing", "mp": "孤独摇滚", "ours": "孤独摇滾", "note": "字表缺 滾→滚" },
|
||||
"魷魚遊戲": { "kind": "missing", "mp": "鱿鱼游戏", "ours": "魷鱼游戏", "note": "字表缺 魷→鱿" },
|
||||
"瑯琊榜": { "kind": "missing", "mp": "琅琊榜", "ours": "瑯琊榜", "note": "字表缺 瑯→琅(异体)" },
|
||||
"慶餘年": {
|
||||
"kind": "mp_bug",
|
||||
"mp": "庆馀年",
|
||||
"ours": "庆余年",
|
||||
"note": "MediaWiki 词表把 餘 转成 馀,官方简体片名为 庆余年"
|
||||
},
|
||||
"臥虎藏龍": { "kind": "missing", "mp": "卧虎藏龙", "ours": "臥虎藏龙", "note": "字表缺 臥→卧" },
|
||||
"駭客任務": { "kind": "missing", "mp": "骇客任务", "ours": "駭客任务", "note": "字表缺 駭→骇" },
|
||||
"乾杯": { "kind": "missing", "mp": "干杯", "ours": "乾杯", "note": "一对多字 乾 刻意不收;MP 有词组表" },
|
||||
"瞭解": { "kind": "missing", "mp": "了解", "ours": "瞭解", "note": "一对多字 瞭 刻意不收;MP 有词组表" },
|
||||
"頭髮": { "kind": "missing", "mp": "头发", "ours": "头髮", "note": "髮→发 未收(发/發 合并字)" },
|
||||
"理髮": { "kind": "missing", "mp": "理发", "ours": "理髮", "note": "髮→发 未收" }
|
||||
"乾杯": {
|
||||
"kind": "intentional",
|
||||
"mp": "干杯",
|
||||
"ours": "乾杯",
|
||||
"note": "一对多字 乾 刻意不收;MP 有词组表(见 identity/zh-map.ts 注释)"
|
||||
},
|
||||
"瞭解": {
|
||||
"kind": "intentional",
|
||||
"mp": "了解",
|
||||
"ours": "瞭解",
|
||||
"note": "一对多字 瞭 刻意不收;MP 有词组表(见 identity/zh-map.ts 注释)"
|
||||
},
|
||||
"頭髮": {
|
||||
"kind": "intentional",
|
||||
"mp": "头发",
|
||||
"ours": "头髮",
|
||||
"note": "一对多字 髮 刻意不收;MP 有词组表(见 identity/zh-map.ts 注释)"
|
||||
},
|
||||
"理髮": {
|
||||
"kind": "intentional",
|
||||
"mp": "理发",
|
||||
"ours": "理髮",
|
||||
"note": "一对多字 髮 刻意不收;MP 有词组表(见 identity/zh-map.ts 注释)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,8 +56,9 @@ const TITLES: Sample[] = [
|
||||
title: "奥本海默",
|
||||
titleCn: "奥本海默",
|
||||
titleEn: "Oppenheimer",
|
||||
source: "BluRay",
|
||||
isEncode: true,
|
||||
// Blu-ray + HEVC 且没有 x265/H.265 → 原盘(对照 MP 内置规则 BLU)
|
||||
source: "BluRay-Disc",
|
||||
isEncode: false,
|
||||
uhd: true,
|
||||
hdr: ["DV"],
|
||||
group: "MTeam",
|
||||
@@ -446,6 +447,180 @@ const TITLES: Sample[] = [
|
||||
{ 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);
|
||||
|
||||
Reference in new issue
Block a user