feat(domain): pure business logic for parsing, identity, slots, acquisition, paths, organize, download state (W1-2)
- release-parser: title/file/dir parsing with MP parity + deviations (airDate/issue, cut, release group suffix fallback, dir+file merge, safe episode offset) - identity: title normalization (NFKC, trad->simp map, season suffix) and evidence-level candidate ranking (year tolerance ±1, no probabilities) - slot: hard/soft/upgrade evaluation (missing vs unmet fields), state machine, movie/unit completion (season pack must be covered by actual file list) - acquisition: new_title/catch_up/upgrade modes, priority order, budget, cache volume hard threshold with resume watermark (no double counting) - path: immutable path bindings, restricted naming templates, sanitize, conflict detection, downloader<->host path mapping - organize: planOrganize with sidecar pairing, sample exclusion, existing target policy, crossDevice marking, H&R -> conflict for move - download-state: qB state mapping, completion, no-progress evidence 230 tests, ~97% statement coverage. Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
1 parent
a6d049db81
commit
7ba712ea55
40 files changed
+5885
-2
No files matched your search
@@ -0,0 +1,37 @@
|
||||
import { CN_NUM } from "../release-parser/cn-number";
|
||||
import { toSimplified } from "./zh-map";
|
||||
|
||||
const SEASON_SUFFIX = [
|
||||
new RegExp(`\\s*第\\s*${CN_NUM}\\s*[季部]\\s*$`, "u"),
|
||||
/\s*[::-]?\s*(?:season|series)\s*\d+\s*$/iu,
|
||||
/\s+S\d{1,2}\s*$/iu,
|
||||
/\s*[((]\s*(?:19|20)\d{2}\s*[))]\s*$/u,
|
||||
];
|
||||
|
||||
/** 去掉标题末尾的季号/年份后缀("庆余年 第二季"、"Show Season 2"、"Title (2019)") */
|
||||
export function stripSeasonSuffix(s: string): string {
|
||||
let out = s.trim();
|
||||
for (let changed = true; changed; ) {
|
||||
changed = false;
|
||||
for (const re of SEASON_SUFFIX) {
|
||||
const next = out.replace(re, "");
|
||||
if (next !== out && next.trim().length > 0) {
|
||||
out = next.trim();
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 标题归一化(用于比较,不用于展示):
|
||||
* 全角→半角(NFKC)、繁→简、小写、& → and、去季号后缀、去标点与空白。
|
||||
*/
|
||||
export function normalizeTitle(s: string): string {
|
||||
const base = stripSeasonSuffix(toSimplified(s.normalize("NFKC")));
|
||||
return base
|
||||
.toLowerCase()
|
||||
.replace(/&/g, "and")
|
||||
.replace(/[^\p{L}\p{N}]+/gu, "");
|
||||
}
|
||||
Reference in new issue
Block a user