import type { FilesEntityFromCandidateResult, FilesExternalCandidate } from "@umt/contracts"; import type { Principal } from "../../http/auth.ts"; import { CandidateError, createEntityFromTmdbCandidate } from "../sources-identity/service/entity-from-candidate.ts"; import { actorOfP, FilesError, type FmDeps } from "./common.ts"; import { audit } from "./ledger.ts"; // G1:整理向导选中"仅 TMDB 候选"作品 → 就地建本地作品 + 外部映射(accepted/manual)+ 季集单元,返回 entityId。 // 幂等(同 TMDB id 已有映射即复用);/files/organize 的 external 项与独立端点共用。 const actorOf = (p: Principal | undefined) => ({ type: p?.kind === "api_key" ? ("api_key" as const) : ("user" as const), id: actorOfP(p), }); export async function entityFromCandidate( d: FmDeps, principal: Principal | undefined, ref: FilesExternalCandidate, ): Promise { try { const r = await createEntityFromTmdbCandidate(d.ctx.db, d.tmdb, ref, actorOf(principal)); if (r.created) await audit(d, principal, "entity_from_candidate", { ...ref, mediaEntityId: r.mediaEntityId }); return r; } catch (e) { if (e instanceof CandidateError) throw new FilesError( e.reason === "not_found" ? "not_found" : e.reason === "upstream" ? "upstream" : "bad_request", e.message, ); throw e; } } export const externalKey = (x: FilesExternalCandidate) => `${x.provider}:${x.kind}:${x.externalId}`;