fix(identity): 改 TMDB 映射删旧作品的 tmdb 别名;合并作品时内容单元迁到目标作品(M3)
改映射:没锁的 tmdb 来源作品别名删除,人工 / 站点别名保留,刷新后按新详情重新登记。 合并:被合并作品的单元改归目标作品(单元级别名一并改),与目标同季同集的按重复单元合并、 所有引用改指向保留的那条;目标是电影时源单元退役。 Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
1 parent
1959e62f3f
commit
92bce3b601
1 file changed
+40
-1
@@ -33,6 +33,7 @@ import { clearTmdbMetadata } from "./metadata.ts";
|
||||
import { metadataLanguages, metadataTextOptions } from "./metadata-rich.ts";
|
||||
import { recordAttempt } from "./resolve.ts";
|
||||
import { backfillRecognizeCache } from "./tmdb-recognize-cache.ts";
|
||||
import { mergeDuplicateUnits } from "./unit-merge.ts";
|
||||
|
||||
// 人工纠错:指定来源资源身份(加锁)、改作品外部映射(新增修订、旧映射退役)、合并作品(旧 ID 跳转)。
|
||||
// 所有变更留 identity_revision / resolution_attempt / audit_event,不直接覆盖历史。
|
||||
@@ -314,6 +315,15 @@ export async function setEntityIdentity(rt: SourcesRuntime, entityId: string, in
|
||||
.execute();
|
||||
for (const o of derived) await retireIdentity(trx, o, actor, "tmdb_mapping_changed");
|
||||
await clearTmdbMetadata(trx, id, rt.now());
|
||||
// 旧 TMDB 条目带来的别名(没锁的)删除:留着会让旧作品的同名资源继续本地召回到这里;人工 / 站点别名保留,
|
||||
// 刷新后按新详情重新登记 tmdb 别名
|
||||
await trx
|
||||
.deleteFrom("title_alias")
|
||||
.where("media_entity_id", "=", id)
|
||||
.where("content_unit_id", "is", null)
|
||||
.where("source", "=", "tmdb")
|
||||
.where("locked", "=", false)
|
||||
.execute();
|
||||
}
|
||||
await audit(
|
||||
trx,
|
||||
@@ -414,7 +424,7 @@ export async function updateExternalIdentity(
|
||||
|
||||
/**
|
||||
* 合并重复作品:from → into。旧 ID 保留(status=merged + merged_into_id)并写 identity_redirect;
|
||||
* 本模块的引用(来源资源、别名、待识别池、外部身份)迁到目标;其它模块的表按 merged_into_id 跳转解析。
|
||||
* 本模块的引用(来源资源、别名、待识别池、外部身份、内容单元)迁到目标;其它模块的表按 merged_into_id 跳转解析。
|
||||
*/
|
||||
export async function mergeEntities(
|
||||
rt: SourcesRuntime,
|
||||
@@ -483,6 +493,35 @@ export async function mergeEntities(
|
||||
select ${intoResolved}, null, alias, normalized, language, kind, source, locked from title_alias
|
||||
where media_entity_id = ${fromId} and content_unit_id is null
|
||||
on conflict (media_entity_id, content_unit_id, normalized, kind) do nothing`.execute(trx);
|
||||
// 内容单元随作品迁到目标(M3):单元改归目标作品;与目标已有单元同季同集的
|
||||
// 按重复单元合并(所有引用改指向保留的那条,见 unit-merge.ts)。目标是电影时源作品的单元退役
|
||||
const into = await trx
|
||||
.selectFrom("media_entity")
|
||||
.select(["kind"])
|
||||
.where("id", "=", intoResolved)
|
||||
.executeTakeFirstOrThrow();
|
||||
if (into.kind === "movie") {
|
||||
await trx.updateTable("content_unit").set({ status: "retired" }).where("media_entity_id", "=", fromId).execute();
|
||||
} else {
|
||||
const moved = (
|
||||
await trx
|
||||
.updateTable("content_unit")
|
||||
.set({ media_entity_id: intoResolved })
|
||||
.where("media_entity_id", "=", fromId)
|
||||
.returning(["id"])
|
||||
.execute()
|
||||
).map((u) => u.id);
|
||||
if (moved.length) {
|
||||
// 单元级元数据 / 覆盖只挂 content_unit_id,随单元走;单元级别名还带作品 ID,一并改
|
||||
await trx
|
||||
.updateTable("title_alias")
|
||||
.set({ media_entity_id: intoResolved })
|
||||
.where("media_entity_id", "=", fromId)
|
||||
.where("content_unit_id", "in", moved)
|
||||
.execute();
|
||||
await mergeDuplicateUnits(trx, intoResolved);
|
||||
}
|
||||
}
|
||||
await trx
|
||||
.updateTable("source_release")
|
||||
.set({ media_entity_id: intoResolved })
|
||||
|
||||
Reference in new issue
Block a user