Files
UHD_Media_Tool/packages/domain/src/identity/sequel.ts
T
rootandClaude Opus 5.5 f6ec993b5f 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]>
2026-09-29 17:41:22 +08:00

61 lines
1.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 续作 / 章节 / 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];
}