import type { ManualAcquisitionResult, SearchRelease } from "@umt/contracts"; import { Bot, Download } from "lucide-react"; import { useState } from "react"; import { Link } from "react-router"; import { toast } from "sonner"; import { usePlanFromSearch } from "~/api/search.ts"; import { useSlots } from "~/api/slots.ts"; import { openAgentDrawer } from "~/components/agent/agent-store.ts"; import { FilterSelect } from "~/components/console/filter-bar.tsx"; import { SLOT_STATUS } from "~/components/library/labels.ts"; import { Button } from "~/components/ui/button.tsx"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "~/components/ui/dialog.tsx"; import { errorMessage } from "~/lib/api.ts"; import { formatBytes } from "~/lib/utils.ts"; // 与站点工作台同一套下载说明;请求走 POST /search/releases/{siteId}/{siteReleaseId}/plan(同 /acquisition-plans 流程) const STEPS = [ "生成下载计划,预留收录版本和预算;每个收录版本同时只有一个在途计划", "已有相同资源或相同 hash 的任务时直接接管,不重复提交", "缓存卷超过硬阈值或读不到磁盘状态时无法提交", "提交前复核免费、做种等易变字段", ]; /** 委托 Agent:和工作台一样带上资源、作品、站点 */ export function delegateToAgent(r: SearchRelease) { openAgentDrawer({ label: `资源:${r.title}`, releaseId: r.sourceReleaseId ?? undefined, entityId: r.entity?.id, siteId: r.siteId, goal: r.sourceReleaseId ? "判断这个资源是否值得下载;合适就按正常流程提交" : `判断站点 ${r.siteName} 的资源「${r.title}」是否值得下载;合适就按正常流程提交`, }); } export function SearchDownloadDialog({ release, open, onOpenChange, }: { release: SearchRelease; open: boolean; onOpenChange: (o: boolean) => void; }) { const plan = usePlanFromSearch(); const entityId = release.entity?.id; const slots = useSlots({ mediaEntityId: entityId }, open && !!entityId); const slotList = slots.data?.items ?? []; const [slotId, setSlotId] = useState(""); const [rejected, setRejected] = useState(null); const [done, setDone] = useState(null); const slotName = (id: string | null) => slotList.find((s) => s.id === id)?.name ?? null; const go = () => plan.mutate( { siteId: release.siteId, siteReleaseId: release.siteReleaseId, ...(slotId ? { slotId } : entityId ? { entityId } : {}), }, { onSuccess: (r) => { if (r.submitted && r.plan) { setRejected(null); setDone(r.plan.id); toast.success(`已提交${slotName(r.slotId) ? `(${slotName(r.slotId)})` : ""},进度见「下载队列」`); } else { setRejected(r.rejected); toast.warning("没有生成下载计划"); } }, onError: (e) => toast.error(errorMessage(e)), }, ); return ( { if (!o) { setRejected(null); setDone(null); } onOpenChange(o); }} > 下载这个资源 {release.siteName} · {release.title} {release.sizeBytes !== null ? ` · ${formatBytes(release.sizeBytes, 1)}` : ""}
    {STEPS.map((s) => (
  1. {s}
  2. ))}
{!entityId ? (

资源未关联本地作品。先在「身份与元数据」指定。

) : slots.isPending ? (

正在读取收录版本…

) : slotList.length ? (
({ value: s.id, label: `${s.name}(${SLOT_STATUS[s.status]?.label ?? s.status})`, }))} />
) : (

这个作品没有收录版本。先在订阅里新建。

)} {release.entityMatch === "alias" ? (

作品关联来自标题别名,尚未确认。

) : null} {rejected ? (

没有生成下载计划:

    {rejected.map((r, i) => (
  • {slotName(r.slotId) ? `${slotName(r.slotId)}:` : ""} {r.message}
  • ))}
) : null} {done ? (

计划已生成。 查看

) : null}
); }