feat(identity): 识别接入集数解析——映射规则表、规范季集写回解析结果、待确认不建单元并开待处理、规则失效停用、按作品重算
迁移 0066_episode_mapping。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
7b9939e0a0
commit
691671a1d2
20 files changed
+1181
-17
No files matched your search
@@ -93,14 +93,40 @@ const PRIORITY: Record<ReturnType<typeof priorityOf>, AcquisitionPriority> = {
|
||||
|
||||
const BUSY: readonly string[] = ["reserved", "downloading", "verifying"];
|
||||
|
||||
/** source_release → ParsedRelease(解析版本过期时按原标题重解析;站点体积覆盖解析体积) */
|
||||
interface StoredEpisodeResolution {
|
||||
method?: string;
|
||||
special?: string;
|
||||
canonical?: { season: number; episodes: { start: number; end: number } } | null;
|
||||
}
|
||||
|
||||
const episodeResolutionOf = (r: Pick<SourceReleaseRow, "episode_resolution">): StoredEpisodeResolution | null =>
|
||||
r.episode_resolution && typeof r.episode_resolution === "object"
|
||||
? (r.episode_resolution as StoredEpisodeResolution)
|
||||
: null;
|
||||
|
||||
/**
|
||||
* source_release → ParsedRelease(解析版本过期时按原标题重解析;站点体积覆盖解析体积)。
|
||||
* 重解析时把集数解析的规范季集叠加回去(parsed 列本来就是规范值,重解析不能丢映射)。
|
||||
*/
|
||||
export function parsedOf(r: SourceReleaseRow): ParsedRelease {
|
||||
const p =
|
||||
fromParsedColumns({ parsed: (r.parsed ?? {}) as Record<string, unknown>, parserVersion: r.parser_version }) ??
|
||||
parseRelease(r.title, r.subtitle ? { subtitle: r.subtitle } : {});
|
||||
let p = fromParsedColumns({ parsed: (r.parsed ?? {}) as Record<string, unknown>, parserVersion: r.parser_version });
|
||||
if (!p) {
|
||||
p = parseRelease(r.title, r.subtitle ? { subtitle: r.subtitle } : {});
|
||||
const c = episodeResolutionOf(r)?.canonical;
|
||||
if (c) {
|
||||
const { seasonEnd: _drop, ...rest } = p;
|
||||
p = { ...rest, season: c.season, episodes: { ...c.episodes }, seasonInferred: false };
|
||||
}
|
||||
}
|
||||
return r.size_bytes !== null ? { ...p, sizeBytes: r.size_bytes } : p;
|
||||
}
|
||||
|
||||
/** 集数待确认(无法换算 / 规则失效)或映射为特别篇 / 花絮 / 忽略:不参与订阅评估 */
|
||||
export function episodeUnresolved(r: Pick<SourceReleaseRow, "episode_resolution">): boolean {
|
||||
const res = episodeResolutionOf(r);
|
||||
return !!res && (res.method === "unresolved" || !!res.special);
|
||||
}
|
||||
|
||||
/** 当前资产的交付特征:入库时记在 media_info._umt.quality */
|
||||
export async function currentFacts(exec: Exec, assetId: string | null): Promise<QualityFacts | null> {
|
||||
if (!assetId) return null;
|
||||
@@ -338,6 +364,7 @@ async function evaluateRelease(c: Ctx, rel: SourceReleaseRow, eventUnits: readon
|
||||
if (rel.availability !== "active") return skip(`release_${rel.availability}`);
|
||||
const entity = await resolveEntity(db, rel.media_entity_id);
|
||||
if (!entity || entity.status === "archived") return skip("entity_unavailable");
|
||||
if (entity.kind !== "movie" && episodeUnresolved(rel)) return skip("episode_unresolved");
|
||||
const parsed = parsedOf(rel);
|
||||
const units = await releaseUnits(
|
||||
db,
|
||||
|
||||
Reference in new issue
Block a user