fix(episode): 半转正的临时季也进季表;迁移 0091 补做 DH-1 前漏掉的季集转正

兰香缘等 26 部:季单元是资源懒建的临时单元,TMDB 集已挂在下面成了正式单元,
季单元没转正,季表丢掉整季,资源全成「元数据未覆盖」。

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-10-08 12:36:32 +08:00
1 parent 8ff1817845
commit 4866e735c8
3 files changed
+87 -1

No files matched your search

@@ -71,9 +71,17 @@ export async function loadSeasonTable(exec: Exec, entityId: string): Promise<Sea
.orderBy("created_at")
.execute();
const seasons = new Map<number, SeasonInfo>();
// 季单元还是临时、但下面已有元数据建的正式集(DH-1 之前的旧数据,季单元没跟着转正)也算元数据覆盖,
// 否则整季从季表里消失,资源一律成了「元数据未覆盖」
const covered = new Set(
units
.filter((u) => u.kind === "episode" && u.status === "confirmed" && (u.source === "tmdb" || u.source === "user"))
.map((u) => u.season_number),
);
for (const u of units) {
if (u.kind !== "season" || u.season_number === null || u.season_number < 0) continue;
if (u.status !== "confirmed" && u.source !== "tmdb" && u.source !== "user") continue;
if (u.status !== "confirmed" && u.source !== "tmdb" && u.source !== "user" && !covered.has(u.season_number))
continue;
const cur = seasons.get(u.season_number);
// 重复季单元(并发懒建遗留)取已知的较大总集数
const total = u.episode_total ?? null;
@@ -284,6 +284,47 @@ describe.skipIf(!pg)("识别准确度与失败可见性", () => {
expect(table.latestSeason).toBe(2);
});
it("季表:临时季下已有 TMDB 正式集(DH-1 前的半转正数据)也进季表", async () => {
const e = await h.db
.insertInto("media_entity")
.values({ kind: "series", title: "半转正季表" })
.returning("id")
.executeTakeFirstOrThrow();
const s1 = await h.db
.insertInto("content_unit")
.values({ media_entity_id: e.id, kind: "season", season_number: 1, episode_total: 47, status: "provisional" })
.returning("id")
.executeTakeFirstOrThrow();
await h.db
.insertInto("content_unit")
.values([
{
media_entity_id: e.id,
parent_unit_id: s1.id,
kind: "episode",
season_number: 1,
episode_number: 1,
status: "confirmed",
source: "tmdb",
air_date: "2026-09-11",
},
// 只有资源懒建的临时集:不算覆盖
{ media_entity_id: e.id, kind: "season", season_number: 3, status: "provisional", source: "release" },
{
media_entity_id: e.id,
kind: "episode",
season_number: 3,
episode_number: 1,
status: "provisional",
source: "release",
},
])
.execute();
const table = await loadSeasonTable(h.db, e.id);
expect(table.seasons.map((s) => [s.season, s.total])).toEqual([[1, 47]]);
expect(table.latestSeason).toBe(1);
});
it("快照连续失败 N 次开站点不可达事项(按站点去重),恢复后自动关闭", async () => {
// 用有站点定义(支持列表抓取)的 key,适配器换成会失败的假实现
const { site } = await seedSite(h, { key: "hhanclub", baseUrl: "https://hhanclub.example/" });