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
@@ -147,6 +147,8 @@ export const DecisionKind = z.enum([
|
||||
"other",
|
||||
/** 待识别资源没有可选候选(no_match / 复查耗尽的查询失败):手动指定 TMDB id、选本地作品或忽略 */
|
||||
"identity_unresolved",
|
||||
/** 资源已绑定作品但集数待确认(无法换算 / 映射规则失效):按作品 + 来源季 + 发布组合并,附建议规则 */
|
||||
"episode_mapping",
|
||||
]);
|
||||
export type DecisionKind = z.infer<typeof DecisionKind>;
|
||||
export const DecisionStatus = z.enum(["open", "investigating", "awaiting_user", "resolved", "dismissed", "expired"]);
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import { z } from "zod";
|
||||
import { ActorType, EntityBase, Id, JsonObject } from "./common.ts";
|
||||
import { EvidenceLevel } from "./identity.ts";
|
||||
|
||||
// 集数映射规则(docs/plan/episode-resolution.md):作品 + 来源季(可空)+ 发布组(可空)的作用域,
|
||||
// 同一作用域同时只有一条 active。取值与 0066 迁移的 CHECK 一致(db-sync.test.ts 会查)。
|
||||
|
||||
export const EpisodeMappingRuleKind = z.enum(["expression", "table", "special"]);
|
||||
export type EpisodeMappingRuleKind = z.infer<typeof EpisodeMappingRuleKind>;
|
||||
export const EpisodeSpecialKind = z.enum(["special", "extra", "ignore"]);
|
||||
export type EpisodeSpecialKind = z.infer<typeof EpisodeSpecialKind>;
|
||||
export const EpisodeMappingRuleStatus = z.enum(["active", "disabled"]);
|
||||
export type EpisodeMappingRuleStatus = z.infer<typeof EpisodeMappingRuleStatus>;
|
||||
|
||||
const EpisodeRangeSchema = z.object({ start: z.number().int(), end: z.number().int() });
|
||||
|
||||
/** 表格规则的一条:来源集号区间 → 目标的一集 */
|
||||
export const EpisodeMappingTableEntry = z.object({
|
||||
from: EpisodeRangeSchema,
|
||||
to: z.object({ season: z.number().int(), episode: z.number().int() }),
|
||||
});
|
||||
export type EpisodeMappingTableEntry = z.infer<typeof EpisodeMappingTableEntry>;
|
||||
|
||||
export const EpisodeMappingRuleRow = EntityBase.extend({
|
||||
mediaEntityId: Id,
|
||||
/** 来源季;null = 任意季 */
|
||||
season: z.number().int().nullable(),
|
||||
/** 发布组;null = 任意发布组,比较忽略大小写 */
|
||||
releaseGroup: z.string().nullable(),
|
||||
kind: EpisodeMappingRuleKind,
|
||||
/** expression 规则的偏移表达式(如 `EP-12`) */
|
||||
expression: z.string().nullable(),
|
||||
targetSeason: z.number().int().nullable(),
|
||||
tableEntries: z.array(EpisodeMappingTableEntry).nullable(),
|
||||
special: EpisodeSpecialKind.nullable(),
|
||||
status: EpisodeMappingRuleStatus,
|
||||
evidenceLevel: EvidenceLevel,
|
||||
evidence: JsonObject,
|
||||
/** 规则失效被停用时的证据 */
|
||||
disabledReason: z.string().nullable(),
|
||||
createdByType: ActorType,
|
||||
createdById: z.string().nullable(),
|
||||
});
|
||||
export type EpisodeMappingRuleRow = z.infer<typeof EpisodeMappingRuleRow>;
|
||||
@@ -11,6 +11,7 @@ export * from "./classification.ts";
|
||||
export * from "./common.ts";
|
||||
export * from "./content.ts";
|
||||
export * from "./download-board.ts";
|
||||
export * from "./episode-mapping.ts";
|
||||
export * from "./events.ts";
|
||||
export * from "./execution.ts";
|
||||
export * from "./identity.ts";
|
||||
|
||||
@@ -17,6 +17,8 @@ const REASONS: Record<string, ReasonText> = {
|
||||
identity_unknown: { text: "没识别出作品", action: "指定作品后重新整理" },
|
||||
identity_ambiguous: { text: "没识别出作品", action: "指定作品" },
|
||||
identity_unresolved: { text: "没识别出作品", action: "指定作品" },
|
||||
episode_mapping: { text: "集数对不上作品的季集", action: "确认集数映射" },
|
||||
episode_unresolved: { text: "集数对不上作品的季集", action: "确认集数映射" },
|
||||
target_exists: { text: "媒体库里已有同名文件", action: "在待处理里选择替换或跳过" },
|
||||
duplicate_target: { text: "改名后与其他文件同名", action: "改命名模板或排除其中一个" },
|
||||
replace_requires_grant: { text: "替换已有文件需要你批准", action: "在待处理里批准" },
|
||||
|
||||
@@ -592,6 +592,8 @@ export const SourceRelease = EntityBase.extend({
|
||||
raw: JsonObject,
|
||||
/** 人工确认的身份关联:自动识别/复查不得改写 mediaEntityId/contentUnitId */
|
||||
resolutionLocked: z.boolean(),
|
||||
/** 集数解析结果(原始季集、规范季集、方式、规则、证据);未解析过为 null */
|
||||
episodeResolution: JsonObject.nullable(),
|
||||
});
|
||||
export type SourceRelease = z.infer<typeof SourceRelease>;
|
||||
/** 由适配器/任务写入(按 siteId+siteReleaseId upsert) */
|
||||
@@ -621,6 +623,7 @@ export const SourceReleaseCreate = SourceRelease.omit({
|
||||
resolutionEvidence: true,
|
||||
availability: true,
|
||||
raw: true,
|
||||
episodeResolution: true,
|
||||
resolutionLocked: true,
|
||||
});
|
||||
export type SourceReleaseCreate = z.infer<typeof SourceReleaseCreate>;
|
||||
|
||||
Reference in new issue
Block a user