feat(identity): weighted evidence table, sequel numbers, generic-name guard (ID-2)

Configurable DEFAULT_MATCH_WEIGHTS; Chinese/English names both count and
corroborate; Chapter/Part/第N章 sequel conflicts reject; missing season
penalised; category words and single-word aliases colliding in the pool
cannot confirm alone; alias-only hits need year or second-script support;
same-level ties broken by exact year then matched name scripts.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 17:41:22 +08:00
1 parent 51e0032d14
commit f6ec993b5f
5 files changed
+527 -34

No files matched your search

+60
View File
@@ -0,0 +1,60 @@
/**
* 续作 / 章节 / Part 序号(ID-2):`Chapter III`、`Part Two`、`Vol. 2`、`第3章`、`第三章`、`Ⅲ`。
* 只认显式关键词或罗马数字符号,不把片名末尾的普通数字当序号(`Blade Runner 2049`、`Apollo 13`)。
* 季号不在这里(季由解析器单独给出)。
*/
import { cnToInt } from "../release-parser/cn-number.ts";
const WORD_NUM: Record<string, number> = {
one: 1,
two: 2,
three: 3,
four: 4,
five: 5,
six: 6,
seven: 7,
eight: 8,
nine: 9,
ten: 10,
first: 1,
second: 2,
third: 3,
fourth: 4,
final: -1,
};
const ROMAN: Record<string, number> = { i: 1, ii: 2, iii: 3, iv: 4, v: 5, vi: 6, vii: 7, viii: 8, ix: 9, x: 10 };
const ROMAN_CHAR: Record<string, number> = {
Ⅰ: 1,
Ⅱ: 2,
Ⅲ: 3,
Ⅳ: 4,
Ⅴ: 5,
Ⅵ: 6,
Ⅶ: 7,
Ⅷ: 8,
Ⅸ: 9,
Ⅹ: 10,
};
function toNum(tok: string): number | undefined {
const t = tok.toLowerCase();
if (/^\d{1,2}$/.test(t)) return Number(t);
if (t in ROMAN) return ROMAN[t];
if (t in WORD_NUM) return WORD_NUM[t]! > 0 ? WORD_NUM[t] : undefined;
return undefined;
}
export function sequelNumbers(title: string): number[] {
if (!title) return [];
const out = new Set<number>();
const s = title.replace(/[ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩ]/g, (c) => ` ${ROMAN_CHAR[c]} `);
for (const m of s.matchAll(/\b(?:chapter|part|vol(?:ume)?)\b\.?\s*[::-]?\s*([0-9]{1,2}|[ivx]{1,4}|[a-z]+)\b/giu)) {
const n = toNum(m[1]!);
if (n !== undefined) out.add(n);
}
for (const m of s.matchAll(/第\s*([0-9]{1,2}|[一二三四五六七八九十]{1,3})\s*章/gu)) {
const n = /^\d+$/.test(m[1]!) ? Number(m[1]) : cnToInt(m[1]!);
if (n !== undefined) out.add(n);
}
return [...out];
}