From a90fd3cf849ec706d1eae5f25348f4907b075c0a Mon Sep 17 00:00:00 2001 From: William Date: Mon, 29 Jun 2026 18:18:04 +0600 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=89=B9=E9=87=8F=E4=B8=8B=E8=BD=BD?= =?UTF-8?q?=E5=BC=B9=E7=AA=97=E5=A2=9E=E5=8A=A0=E5=BC=80=E5=A7=8B=E4=B8=8B?= =?UTF-8?q?=E8=BD=BD=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 通过创建隐藏 a 标签并点击触发浏览器下载 - 多个下载任务间隔 300ms 触发,降低被浏览器拦截的概率 - 保留复制链接功能作为备选 --- apps/web/src/pages/Videos.tsx | 85 ++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 22 deletions(-) diff --git a/apps/web/src/pages/Videos.tsx b/apps/web/src/pages/Videos.tsx index 09478d6..31f3918 100644 --- a/apps/web/src/pages/Videos.tsx +++ b/apps/web/src/pages/Videos.tsx @@ -41,6 +41,16 @@ const formatSize = (bytes?: number) => { return `${size.toFixed(2)} ${units[i]}`; }; +const getExtFromUrl = (url: string): string => { + try { + const pathname = new URL(url).pathname; + const ext = pathname.split('.').pop(); + return ext && ext.length <= 5 ? ext : 'mp4'; + } catch { + return 'mp4'; + } +}; + export default function VideosPage() { const user = useAuthStore((state) => state.user); const [videos, setVideos] = useState([]); @@ -115,40 +125,40 @@ export default function VideosPage() { } }; + const [downloadResults, setDownloadResults] = useState([]); + const [downloadModalOpen, setDownloadModalOpen] = useState(false); + const handleBatchDownload = async () => { const ids = selectedRows.map((v) => v.videoId); try { const results = await batchDownload(ids); const valid = results.filter((r) => r.urls.length > 0); - showDownloadResults(valid); + setDownloadResults(valid); + setDownloadModalOpen(true); setSelectedRows([]); } catch (error) { message.error('获取下载地址失败'); } }; - const showDownloadResults = (results: DownloadResult[]) => { - Modal.info({ - title: '批量下载地址', - width: 800, - content: ( -
- {results.map((item) => ( -
- {item.title || item.videoId} -
    - {item.urls.map((url, idx) => ( -
  • - {url.url} - {url.definition} -
  • - ))} -
-
- ))} -
- ), + const startDownloads = () => { + let count = 0; + downloadResults.forEach((item) => { + item.urls.forEach((urlInfo) => { + const link = document.createElement('a'); + link.href = urlInfo.url; + link.target = '_blank'; + link.rel = 'noreferrer'; + link.download = `${item.title || item.videoId}_${urlInfo.definition}.${getExtFromUrl(urlInfo.url)}`; + document.body.appendChild(link); + setTimeout(() => { + link.click(); + document.body.removeChild(link); + }, count * 300); + count++; + }); }); + message.success(`已尝试触发 ${count} 个下载任务`); }; const handleRowClick = (record: VideoItem) => { @@ -284,6 +294,37 @@ export default function VideosPage() { }} /> + setDownloadModalOpen(false)} + footer={[ + , + , + ]} + > +
+ {downloadResults.map((item) => ( +
+ {item.title || item.videoId} +
    + {item.urls.map((url, idx) => ( +
  • + {url.url} + {url.definition} +
  • + ))} +
+
+ ))} +
+
+