docs(plan): on-demand site detail page parsing (HHClub details.php)

Co-Authored-By: Claude Fable 5.1 <[email protected]>
This commit is contained in:
rootandClaude Fable 5.1 committed 2026-09-29 15:13:35 +08:00
1 parent 94fd48bff2
commit ac478673bc
39 files changed
+2446 -339

No files matched your search

@@ -476,25 +476,43 @@ export function registerLibraryRoutes(app: ModuleApp, d: AoDeps) {
response: MediaServerInventory,
},
async (_c, { query }) => {
const e = await db()
.selectFrom("media_entity")
.select(["id", "kind", "title", "year"])
.where("id", "=", query.mediaEntityId)
.executeTakeFirst();
if (!e) notFound("作品");
const idents = await db()
.selectFrom("external_identity")
.select(["provider", "entity_type", "external_id"])
.where("media_entity_id", "=", e!.id)
.where("status", "=", "accepted")
.execute();
// 按 TMDB 条目查时:本地已建档(接受了该身份,合并跟到最终作品)就按作品查,否则只用这一个 TMDB ID
let entityId = query.mediaEntityId ?? null;
if (!entityId && query.tmdbType && query.tmdbId) {
const hit = await db()
.selectFrom("external_identity as i")
.innerJoin("media_entity as m", "m.id", "i.media_entity_id")
.select(["m.id", "m.status", "m.merged_into_id"])
.where("i.provider", "=", "tmdb")
.where("i.entity_type", "=", query.tmdbType)
.where("i.external_id", "=", query.tmdbId)
.where("i.status", "=", "accepted")
.executeTakeFirst();
entityId = hit ? (hit.status === "merged" && hit.merged_into_id ? hit.merged_into_id : hit.id) : null;
}
const e = entityId
? await db()
.selectFrom("media_entity")
.select(["id", "kind", "title", "year"])
.where("id", "=", entityId)
.executeTakeFirst()
: null;
if (entityId && !e) notFound("作品");
const idents = e
? await db()
.selectFrom("external_identity")
.select(["provider", "entity_type", "external_id"])
.where("media_entity_id", "=", e.id)
.where("status", "=", "accepted")
.execute()
: [{ provider: "tmdb", entity_type: query.tmdbType!, external_id: query.tmdbId! }];
const insts = await db()
.selectFrom("media_server_instance")
.selectAll()
.where("enabled", "=", true)
.orderBy("name")
.execute();
const type = e!.kind === "movie" ? "Movie" : "Series";
const type = (e ? e.kind === "movie" : query.tmdbType === "movie") ? "Movie" : "Series";
const usable = idents.filter((i) => MS_PROVIDER_KEY[i.provider]);
// 按实例并行(allSettled):单个 Emby 慢/挂只让自己 unknown,不拖住其它实例;每实例内部限并发 + 总超时
const settled = await Promise.allSettled(
@@ -514,7 +532,7 @@ export function registerLibraryRoutes(app: ModuleApp, d: AoDeps) {
);
// partial:至少一个实例因查询失败/超时为 unknown(no_external_id 不算失败)
const partial = instances.some((x) => x.status === "unknown" && x.reason !== "no_external_id");
return { mediaEntityId: e!.id, instances, partial } satisfies MediaServerInventory;
return { mediaEntityId: e?.id ?? null, instances, partial } satisfies MediaServerInventory;
},
{ tag: TAG },
);