diff --git a/apps/server/src/modules/acquisition-organize/services/organize-records.ts b/apps/server/src/modules/acquisition-organize/services/organize-records.ts index 4f9658f8..3cfb0f77 100644 --- a/apps/server/src/modules/acquisition-organize/services/organize-records.ts +++ b/apps/server/src/modules/acquisition-organize/services/organize-records.ts @@ -70,6 +70,10 @@ export async function loadRecordsPublic(exec: Exec, rows: OrganizationRecordRow[ const v = (metadata as { posterPath?: { value?: unknown } } | null)?.posterPath?.value; return typeof v === "string" && v ? v : null; }; + const categoryOf = (plan: unknown) => { + const v = (plan as { classification?: { category?: unknown } } | null)?.classification?.category; + return typeof v === "string" && v ? v : null; + }; // blocked:* 的说明在 error.conflicts[].detail(中文),有就用它,不把内部串直接给人看 const conflictText = (err: unknown) => ((err as { conflicts?: { detail?: string }[] } | null)?.conflicts ?? []) @@ -119,6 +123,7 @@ export async function loadRecordsPublic(exec: Exec, rows: OrganizationRecordRow[ externalId: i.external_id, })), posterPath: posterOf(e.metadata), + category: categoryOf(r.plan), } : null, trigger: r.trigger, diff --git a/apps/server/test/acquisition-organize/records-filter.test.ts b/apps/server/test/acquisition-organize/records-filter.test.ts index 07172472..f0ee3fa6 100644 --- a/apps/server/test/acquisition-organize/records-filter.test.ts +++ b/apps/server/test/acquisition-organize/records-filter.test.ts @@ -44,6 +44,10 @@ describe.skipIf(skip)("整理记录筛选与统计", () => { media_entity_id: r.entity, download_task_id: "task" in r ? r.task : null, source_path: r.src, + // 冻结计划里的二级分类(列表带出 media.category) + ...(r.k === "film" + ? { plan: JSON.stringify({ classification: { category: "欧美电影", matchedFields: [], fallback: false } }) } + : {}), action: r.action, status: r.status, ...("at" in r ? { created_at: r.at } : {}), @@ -135,13 +139,15 @@ describe.skipIf(skip)("整理记录筛选与统计", () => { } }); - it("列表项带海报、大小、下载器名称与 hash", async () => { + it("列表项带海报、分类、大小、下载器名称与 hash", async () => { const [film] = await list("q=Arrival.2016"); expect(film).toMatchObject({ - media: { title: "Arrival", posterPath: "/arrival.jpg" }, + media: { title: "Arrival", posterPath: "/arrival.jpg", category: "欧美电影" }, sizeBytes: 1000, download: { name: "Arrival.2016", hash: "abcdef0123456789abcdef0123456789abcdef01", downloaderName: "家里的 qB" }, }); + const [show] = await list("q=Severance"); + expect(show).toMatchObject({ media: { title: "Severance", category: null } }); const [unknown] = await list("kind=none"); expect(unknown).toMatchObject({ media: null, download: null, sizeBytes: 1000 }); }); diff --git a/packages/contracts/src/organization.ts b/packages/contracts/src/organization.ts index c90a4989..470cf93d 100644 --- a/packages/contracts/src/organization.ts +++ b/packages/contracts/src/organization.ts @@ -232,6 +232,8 @@ export const PublicOrganizationRecord = z.object({ externalIds: z.array(z.object({ provider: z.string(), entityType: z.string(), externalId: z.string() })), /** HIS-1:作品海报(TMDB poster_path,如 /abc.jpg);没有为 null */ posterPath: z.string().nullable().optional(), + /** 整理时按二级分类策略得到的分类(如「纪录片」「欧美电影」,取自冻结计划);没有为 null */ + category: z.string().nullable().optional(), }) .nullable(), trigger: OrganizationTrigger,