diff --git a/src/lang/en/home.json b/src/lang/en/home.json index 104cc2e83..509e893e7 100644 --- a/src/lang/en/home.json +++ b/src/lang/en/home.json @@ -135,6 +135,7 @@ "delete_policy": { "delete_on_upload_succeed": "Delete on upload succeed", "delete_on_upload_failed": "Delete on upload failed", + "delete_after_seeding": "Delete after seeding ends", "delete_never": "Never delete", "delete_always": "Always delete", "upload_download_stream": "Download stream direct upload" diff --git a/src/pages/home/toolbar/OfflineDownload.tsx b/src/pages/home/toolbar/OfflineDownload.tsx index 7eaa6793e..ab95148c7 100644 --- a/src/pages/home/toolbar/OfflineDownload.tsx +++ b/src/pages/home/toolbar/OfflineDownload.tsx @@ -17,12 +17,29 @@ const deletePolicies = [ "upload_download_stream", "delete_on_upload_succeed", "delete_on_upload_failed", + "delete_after_seeding", "delete_never", "delete_always", ] as const type DeletePolicy = (typeof deletePolicies)[number] +const defaultDeletePolicy: DeletePolicy = "upload_download_stream" +const fallbackDeletePolicy: DeletePolicy = "delete_on_upload_succeed" + +const supportsDeleteAfterSeeding = (tool: string) => + tool === "qBittorrent" || tool === "Transmission" + +const supportsDeletePolicy = (policy: DeletePolicy, tool: string) => { + if (policy === "upload_download_stream") { + return tool === "SimpleHttp" + } + if (policy === "delete_after_seeding") { + return supportsDeleteAfterSeeding(tool) + } + return true +} + function utf8Decode(data: Uint8Array): string { return crypto.enc.Utf8.stringify(crypto.lib.WordArray.create(data)) } @@ -58,14 +75,19 @@ export const OfflineDownload = () => { return r.get("/public/offline_download_tools") }) const [tool, setTool] = createSignal("") - const [deletePolicy, setDeletePolicy] = createSignal( - "upload_download_stream", - ) + const [deletePolicy, setDeletePolicy] = + createSignal(defaultDeletePolicy) + const updateTool = (nextTool: string) => { + if (!supportsDeletePolicy(deletePolicy(), nextTool)) { + setDeletePolicy(fallbackDeletePolicy) + } + setTool(nextTool) + } onMount(async () => { const resp = await reqTool() handleResp(resp, (data) => { setTools(data) - setTool(data[0]) + updateTool(data[0]) }) }) @@ -120,13 +142,7 @@ export const OfflineDownload = () => { { - if ( - v !== "SimpleHttp" && - deletePolicy() === "upload_download_stream" - ) { - setDeletePolicy("delete_on_upload_succeed") - } - setTool(v) + updateTool(v) }} options={tools().map((tool) => { return { value: tool, label: tool } @@ -140,11 +156,7 @@ export const OfflineDownload = () => { value={deletePolicy()} onChange={(v) => setDeletePolicy(v as DeletePolicy)} options={deletePolicies - .filter((policy) => - policy == "upload_download_stream" - ? tool() === "SimpleHttp" - : true, - ) + .filter((policy) => supportsDeletePolicy(policy, tool())) .map((policy) => { return { value: policy, diff --git a/src/pages/home/toolbar/OfflineDownloadEnhanced.tsx b/src/pages/home/toolbar/OfflineDownloadEnhanced.tsx index 888d62736..f55c1f927 100644 --- a/src/pages/home/toolbar/OfflineDownloadEnhanced.tsx +++ b/src/pages/home/toolbar/OfflineDownloadEnhanced.tsx @@ -45,12 +45,29 @@ const deletePolicies = [ "upload_download_stream", "delete_on_upload_succeed", "delete_on_upload_failed", + "delete_after_seeding", "delete_never", "delete_always", ] as const type DeletePolicy = (typeof deletePolicies)[number] +const defaultDeletePolicy: DeletePolicy = "upload_download_stream" +const fallbackDeletePolicy: DeletePolicy = "delete_on_upload_succeed" + +const supportsDeleteAfterSeeding = (tool: string) => + tool === "qBittorrent" || tool === "Transmission" + +const supportsDeletePolicy = (policy: DeletePolicy, tool: string) => { + if (policy === "upload_download_stream") { + return tool === "SimpleHttp" + } + if (policy === "delete_after_seeding") { + return supportsDeleteAfterSeeding(tool) + } + return true +} + // Tab 类型 type TabType = "link" | "bt" @@ -105,9 +122,15 @@ export const OfflineDownloadEnhanced = () => { return r.get("/public/offline_download_tools") }) const [tool, setTool] = createSignal("") - const [deletePolicy, setDeletePolicy] = createSignal( - "upload_download_stream", - ) + const [deletePolicy, setDeletePolicy] = + createSignal(defaultDeletePolicy) + + const updateTool = (nextTool: string) => { + if (!supportsDeletePolicy(deletePolicy(), nextTool)) { + setDeletePolicy(fallbackDeletePolicy) + } + setTool(nextTool) + } // 对话框状态 const { isOpen, onOpen, onClose } = createDisclosure() @@ -236,7 +259,7 @@ export const OfflineDownloadEnhanced = () => { if (shouldDisableSimpleHttp() && tool() === "SimpleHttp") { const available = availableTools() if (available.length > 0) { - setTool(available[0]) + updateTool(available[0]) } } }) @@ -245,7 +268,7 @@ export const OfflineDownloadEnhanced = () => { const resp = await reqTool() handleResp(resp, (data) => { setTools(data) - setTool(data[0]) + updateTool(data[0]) }) }) @@ -494,7 +517,22 @@ export const OfflineDownloadEnhanced = () => { return } - // 正常离线下载:将 torrent 转为磁力链提交 + // qBittorrent 直接提交原始 torrent 文件,避免 PT 私种转磁力后卡在获取元信息 + if (tool() === "qBittorrent") { + const resp = await offlineDownload( + savePath(), + [], + tool(), + deletePolicy(), + [torrentData()], + ) + handleRespWithNotifySuccess(resp, () => { + handleClose() + }) + return + } + + // 其它工具保持原行为:将 torrent 转为磁力链提交 const buffer = Uint8Array.from(atob(torrentData()), (c) => c.charCodeAt(0), ) @@ -689,13 +727,7 @@ export const OfflineDownloadEnhanced = () => { : tool() } onChange={(v) => { - if ( - v !== "SimpleHttp" && - deletePolicy() === "upload_download_stream" - ) { - setDeletePolicy("delete_on_upload_succeed") - } - setTool(v) + updateTool(v) }} options={availableTools().map((t) => ({ value: t, @@ -724,11 +756,7 @@ export const OfflineDownloadEnhanced = () => { value={deletePolicy()} onChange={(v) => setDeletePolicy(v as DeletePolicy)} options={deletePolicies - .filter((policy) => - policy === "upload_download_stream" - ? tool() === "SimpleHttp" - : true, - ) + .filter((policy) => supportsDeletePolicy(policy, tool())) .map((policy) => ({ value: policy, label: t(`home.toolbar.delete_policy.${policy}`), diff --git a/src/utils/api.ts b/src/utils/api.ts index 39f6463ba..b171dec9e 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -220,8 +220,15 @@ export const offlineDownload = ( urls: string[], tool: string, delete_policy: string, + torrent_data: string[] = [], ): PEmptyResp => { - return r.post(`/fs/add_offline_download`, { path, urls, tool, delete_policy }) + return r.post(`/fs/add_offline_download`, { + path, + urls, + tool, + delete_policy, + ...(torrent_data.length ? { torrent_data } : {}), + }) } export const fetchText = async (