merge: ui/j-download-dialog

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-06 12:22:37 +08:00
commit 1360120e75
14 files changed
+1272 -123

No files matched your search

+8
View File
@@ -64,6 +64,14 @@ export const executionApi = {
body: execution.ManualAcquisitionRequest,
response: execution.ManualAcquisitionResult,
}),
savePaths: ep({
method: "get",
path: "/download-save-paths",
scope: "read",
summary: "手动下载可选的下载器与保存目录(默认保存目录 + 路径映射),以及「自动」会用哪个下载器",
query: execution.DownloadSavePathQuery,
response: execution.DownloadSavePaths,
}),
why: ep({
method: "get",
path: "/acquisition-plans/{id}/why",
+38
View File
@@ -1,5 +1,6 @@
import { z } from "zod";
import { EntityBase, Id, JsonObject, NonNegInt, SERVER_MANAGED, Timestamp } from "./common.ts";
import { ExternalRef } from "./identity.ts";
import { AcquisitionPriority } from "./policy.ts";
// 执行域:业务任务、下载计划、下载任务、操作账本(REQ §8.4、§11;ADR-002)
@@ -146,6 +147,13 @@ export const ManualAcquisitionRequest = z.object({
allowUnrecognized: z.boolean().optional(),
importMode: z.enum(["normal", "replace"]).default("normal"),
replacementAssetIds: z.array(Id).default([]),
/**
* 下载前指定作品:本地作品或外部身份(未登记的按 TMDB 详情加入媒体库),
* 与 POST /source-releases/{id}/identity 同一实现,绑定到资源并加人工锁;给了就不再用 entityId。
*/
identity: z
.union([z.object({ mediaEntityId: Id }).strict(), z.object({ external: ExternalRef }).strict()])
.optional(),
});
export type ManualAcquisitionRequest = z.infer<typeof ManualAcquisitionRequest>;
@@ -161,6 +169,36 @@ export const ManualAcquisitionResult = z.object({
rejected: z.array(z.object({ slotId: Id.nullable(), code: z.string(), message: z.string() })),
});
export type ManualAcquisitionResult = z.infer<typeof ManualAcquisitionResult>;
/** 手动下载可选的保存目录:按下载器列出默认保存目录与路径映射的下载器侧目录 */
export const DownloadSavePathQuery = z.object({
/** 资源所在站点;站点指定了下载器时「自动」按它解析 */
siteId: Id.optional(),
});
export type DownloadSavePathQuery = z.infer<typeof DownloadSavePathQuery>;
export const DownloadSaveDir = z.object({
/** 下载器视角的路径(提交给下载器的保存路径) */
path: z.string(),
/** 本机视角的路径;配置了映射但对不上时为 null */
hostPath: z.string().nullable(),
/** 下载器设置里的默认保存目录(「自动」用它) */
isDefault: z.boolean(),
});
export type DownloadSaveDir = z.infer<typeof DownloadSaveDir>;
export const DownloadSaveTarget = z.object({
instanceId: Id,
name: z.string(),
isDefault: z.boolean(),
/** 第一个是默认保存目录 */
dirs: z.array(DownloadSaveDir),
});
export type DownloadSaveTarget = z.infer<typeof DownloadSaveTarget>;
export const DownloadSavePaths = z.object({
/** 不指定下载器时会用的那个(站点指定 > 默认下载器 > 第一个有保存目录的);没有可用下载器为 null */
autoInstanceId: Id.nullable(),
instances: z.array(DownloadSaveTarget),
});
export type DownloadSavePaths = z.infer<typeof DownloadSavePaths>;
export const AcquisitionPlanUpdate = AcquisitionPlan.pick({ status: true, taskId: true, statusReason: true }).partial();
export type AcquisitionPlanUpdate = z.infer<typeof AcquisitionPlanUpdate>;