diff --git a/apps/server/src/modules/sources-identity/service/lifecycle-events.ts b/apps/server/src/modules/sources-identity/service/lifecycle-events.ts index 5964d907..ccb50fc9 100644 --- a/apps/server/src/modules/sources-identity/service/lifecycle-events.ts +++ b/apps/server/src/modules/sources-identity/service/lifecycle-events.ts @@ -26,7 +26,7 @@ export async function emitMediaWatched( ); } -/** 作品元数据刷新完成(刷新任务的调用方发;按任务 run 去重) */ +/** 作品元数据刷新完成(refreshMetadata 内发;runId 传本次刷新时间,按次去重) */ export async function emitMetadataRefreshed( ctx: Pick, exec: Exec, diff --git a/apps/server/src/modules/sources-identity/service/metadata.ts b/apps/server/src/modules/sources-identity/service/metadata.ts index f37931c0..8bb1fa54 100644 --- a/apps/server/src/modules/sources-identity/service/metadata.ts +++ b/apps/server/src/modules/sources-identity/service/metadata.ts @@ -27,6 +27,7 @@ import { type Actor, audit, type Exec } from "./common.ts"; import { resolveEntityId, seedAliases } from "./entities.ts"; import { reresolveEntityEpisodes } from "./episode-resolution.ts"; import { entityEpisodeGroup, groupLayout, type Layout, relayoutUnits } from "./episode-structure.ts"; +import { emitMetadataRefreshed } from "./lifecycle-events.ts"; import { applySeasonMetadata, metadataIncludeSpecials, @@ -423,6 +424,13 @@ export async function refreshMetadata( await trx.updateTable("media_entity").set({ last_metadata_refresh_at: now }).where("id", "=", id).execute(); // 季总集数 / 播出日期 / 完结状态更新后重算待确认与滞后放行的资源(raw / 换算过的资源不受只升的总集数影响) if (ident.entity_type === "tv") await reresolveEntityEpisodes(ctx, trx, id, { onlyPending: true }); + // 生命周期广播(ADR-006):元数据已刷新——所有刷新入口(刷新任务、语言回刷、剧集组切换)统一在这里发,与刷新同事务 + await emitMetadataRefreshed(ctx, trx, { + mediaEntityId: id, + full: !!opts.full, + changedFields: r.changedFields, + runId: now.toISOString(), + }); const promoted = episodes.reduce((n, x) => n + x.promoted, 0); return { status: "refreshed" as const, diff --git a/apps/server/src/modules/sources-identity/tasks.ts b/apps/server/src/modules/sources-identity/tasks.ts index d9a1943d..1053cdc5 100644 --- a/apps/server/src/modules/sources-identity/tasks.ts +++ b/apps/server/src/modules/sources-identity/tasks.ts @@ -5,7 +5,6 @@ import type { SourcesRuntime } from "./runtime.ts"; import { refreshSiteAccount } from "./service/account.ts"; import { AUTO_ENRICH_TASK, runAutoEnrich } from "./service/enrich.ts"; import { ingestFeed } from "./service/feeds.ts"; -import { emitMetadataRefreshed } from "./service/lifecycle-events.ts"; import { refreshMetadata } from "./service/metadata.ts"; import { prewarmMetadata } from "./service/metadata-prewarm.ts"; import { resolveRelease } from "./service/resolve.ts"; @@ -78,16 +77,8 @@ export function registerSourcesTasks(registry: TaskRegistry, rt: () => SourcesRu retryPolicy: NETWORK_RETRY, handler: (t) => t.step.run("refresh", async () => { - const r = await refreshMetadata(rt(), t.input.mediaEntityId, { full: !!t.input.full }); - // 生命周期广播(ADR-006):元数据已刷新(在调用方发,刷新本身在 metadata.ts) - if (r.status === "refreshed") - await emitMetadataRefreshed(rt().ctx, rt().ctx.db, { - mediaEntityId: t.input.mediaEntityId, - full: !!t.input.full, - changedFields: r.changedFields, - runId: t.runId, - }); - return r; + // 「元数据已刷新」生命周期事件在 refreshMetadata 内与刷新同事务发出 + return await refreshMetadata(rt(), t.input.mediaEntityId, { full: !!t.input.full }); }), }), // 关注作品预热(统一元数据缓存):详情 / 各季 / 剧集组 / 图片先进缓存;网络道,走 TMDB 客户端限流 diff --git a/docs/plan/README.md b/docs/plan/README.md index 8d427893..a82205e1 100644 --- a/docs/plan/README.md +++ b/docs/plan/README.md @@ -31,9 +31,6 @@ ### 进行中 -- 下一轮(界面第二轮合并后): - - 统一元数据缓存:TMDB / 豆瓣 / Bangumi 共用「来源 × 资源类型」TTL 策略;进程内存一级 + PG `kv_cache` 二级,LISTEN/NOTIFY 跨进程失效;过期先用旧值后台刷新;关注中作品续期不淘汰、进入关注时预热(各季、剧集组、图片);同请求合并;按 region 统计命中率。刮削顺带接 TMDB `logos` 写 `clearlogo.png`。fanart.tv 暂不接(用户 2026-10-06 定)。 - - 生命周期事件与功能模块约定:广播事件 + 链式钩子(参考 MoviePilot EventType / ChainEventType),功能清单给智能体,前端插槽默认显示、不做开关;补字幕迁为样板。 - 系统梳理后的待办:[system-review.md](system-review.md),T0~T6 按优先级。 - 补字幕:[subtitles.md](subtitles.md),第 1、2 步已完成;待办:以后接进整理 / 订阅工作流。 - 沙箱第二批:站点网页、RSS、网页抓取的 HTML / XML 解析迁入常驻子进程池(ADR-005)。