feat(metadata): one-shot metadata.backfill_languages maintenance job (FIX-5)

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 19:37:11 +08:00
1 parent a51dc1590f
commit 2c9e5a1d00
7 files changed
+281 -8

No files matched your search

@@ -79,6 +79,38 @@ export class SourcesRuntime {
if (this.tmdbClient === undefined) this.tmdbClient = this.overrides.tmdb();
return this.tmdbClient;
}
const { sig, cfg } = await this.tmdbConfig();
if (this.tmdbClient !== undefined && this.tmdbSig === sig) return this.tmdbClient;
this.tmdbSig = sig;
this.tmdbClient = cfg ? createTmdbClient(cfg) : null;
return this.tmdbClient;
}
/**
* 批量任务用的独立 TMDB 客户端(FIX-5 元数据回刷):串行、网络请求间隔 ≥ minIntervalMs(缓存命中不占额度),
* 同样走 PG 请求缓存;requests() 返回实际发出的网络请求数。测试注入的客户端原样返回(requests 为 null)。
*/
async tmdbForBatch(opts: {
minIntervalMs: number;
}): Promise<{ client: TmdbClient; requests: () => number | null } | null> {
if (this.overrides.tmdb) {
const client = await this.tmdb();
return client ? { client, requests: () => null } : null;
}
const { cfg } = await this.tmdbConfig();
if (!cfg) return null;
let n = 0;
const base = cfg.fetch ?? globalThis.fetch;
const counted: typeof fetch = (input, init) => {
n++;
return base(input, init);
};
const client = createTmdbClient({ ...cfg, fetch: counted, maxConcurrent: 1, minIntervalMs: opts.minIntervalMs });
return { client, requests: () => n };
}
/** TMDB 客户端配置(未配置凭证时 cfg 为 null)与签名(设置变化时重建客户端) */
private async tmdbConfig(): Promise<{ sig: string; cfg: Parameters<typeof createTmdbClient>[0] | null }> {
const meta = await this.ctx.settings.get("metadata").catch(() => null);
const policy = await tmdbCachePolicy(this.ctx);
const env = (k: string) => Deno.env.get(k);
@@ -90,7 +122,6 @@ export class SourcesRuntime {
policy,
ref ? null : [!!env("TMDB_API_KEY"), !!env("TMDB_ACCESS_TOKEN")],
]);
if (this.tmdbClient !== undefined && this.tmdbSig === sig) return this.tmdbClient;
let apiKey: string | undefined;
let accessToken: string | undefined;
if (ref) {
@@ -106,10 +137,9 @@ export class SourcesRuntime {
apiKey = env("TMDB_API_KEY");
accessToken = env("TMDB_ACCESS_TOKEN");
}
this.tmdbSig = sig;
this.tmdbClient =
const cfg =
apiKey || accessToken
? createTmdbClient({
? {
...(apiKey ? { apiKey } : {}),
...(accessToken ? { accessToken } : {}),
...(baseUrl ? { baseUrl } : {}),
@@ -121,9 +151,9 @@ export class SourcesRuntime {
emptyTtlMs: policy.emptyTtl * 1000,
},
sharedCache: tmdbSharedCache(this.ctx, policy),
})
}
: null;
return this.tmdbClient;
return { sig, cfg };
}
/** 站点默认(settings.sites),读库并刷新缓存;读失败用上次值 */