Files
UHD_Media_Tool/apps/web/app/components/browser/resource-download.tsx
T
rootandClaude Opus 5.5 6e645bce8f feat(下载对话框): 学 MoviePilot 重做手动下载对话框
- 标题区:海报、作品名 (年份)、站点;资源行显示原始标题、促销、H&R、做种 / 下载、大小、发布时间
- 下载器与保存目录并排下拉,缺省「自动」,下方写明「将保存到」的实际路径;保留「自定义路径」
- 作品身份折叠区:类型 + TMDB 编号(可搜索作品),未识别时默认展开,指定后随下载绑定
- 已有版本先显示一行摘要,选一次性洗版才展开勾选列表
- 搜索、工作台、原站视图三处调用方补传资源字段

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Cxwgnn2pbzQ7rXv3rq7fei
2026-10-06 12:10:03 +08:00

86 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { BrowserResourceResult, BrowserSessionView } from "@umt/contracts";
import { Download, Settings2 } from "lucide-react";
import { useState } from "react";
import { Link } from "react-router";
import { toast } from "sonner";
import { useSubmitRelease } from "~/api/releases.ts";
import { ManualDownloadDialog } from "~/components/downloads/manual-download-dialog.tsx";
import { Button } from "~/components/ui/button.tsx";
import { workbenchResource } from "~/components/workbench/download-dialog.tsx";
import { apiData, errorMessage } from "~/lib/api.ts";
/** 控件位于 iframe/截图外;直接解析当前详情页并交给共同手动下载入口。 */
export function ResourceDownload({ session }: { session: BrowserSessionView }) {
const [busy, setBusy] = useState(false);
const [resource, setResource] = useState<BrowserResourceResult | null>(null);
const [open, setOpen] = useState(false);
const [unrecognized, setUnrecognized] = useState(false);
const [planId, setPlanId] = useState<string | null>(null);
const submit = useSubmitRelease();
const prepare = async (options: boolean) => {
setBusy(true);
try {
const r = await apiData<BrowserResourceResult>("/browser/sessions/{id}/resource", {
method: "POST",
pathParams: { id: session.id },
body: {},
});
setResource(r);
setUnrecognized(false);
if (options) setOpen(true);
else {
const result = await submit.mutateAsync({
sourceReleaseId: r.release.id,
importMode: "normal",
replacementAssetIds: [],
});
if (result.requiresConfirmation) {
setUnrecognized(true);
setOpen(true);
} else if (result.submitted) {
setPlanId(result.plan?.id ?? null);
toast.success("已提交下载");
} else toast.warning(result.rejected.map((v) => v.message).join(";") || "没有提交下载");
}
} catch (e) {
toast.error(errorMessage(e));
} finally {
setBusy(false);
}
};
return (
<>
<div className="flex flex-wrap items-center gap-2">
<Button size="sm" disabled={busy || session.controller === "closed"} onClick={() => void prepare(false)}>
<Download />
{busy ? "正在处理…" : "下载当前资源"}
</Button>
<Button
size="sm"
variant="outline"
disabled={busy || session.controller === "closed"}
onClick={() => void prepare(true)}
>
<Settings2 />
下载选项
</Button>
{planId ? (
<Link className="text-caption underline" to={`/console/downloads?plan=${planId}`}>
查看下载任务
</Link>
) : null}
</div>
{resource ? (
<ManualDownloadDialog
key={resource.release.id}
resource={workbenchResource(resource.release)}
open={open}
onOpenChange={setOpen}
initialUnrecognized={unrecognized}
submit={(options) => submit.mutateAsync({ ...options, sourceReleaseId: resource.release.id })}
/>
) : null}
</>
);
}