feat: 批量下载弹窗增加开始下载按钮
CI / lint-and-build (push) Has been cancelled

- 通过创建隐藏 a 标签并点击触发浏览器下载

- 多个下载任务间隔 300ms 触发,降低被浏览器拦截的概率

- 保留复制链接功能作为备选
This commit is contained in:
2026-06-29 18:18:04 +06:00
parent 962cbc8df3
commit a90fd3cf84
+63 -22
View File
@@ -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<VideoItem[]>([]);
@@ -115,40 +125,40 @@ export default function VideosPage() {
}
};
const [downloadResults, setDownloadResults] = useState<DownloadResult[]>([]);
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: (
<div style={{ maxHeight: 400, overflow: 'auto' }}>
{results.map((item) => (
<div key={item.videoId} style={{ marginBottom: 12 }}>
<Text strong>{item.title || item.videoId}</Text>
<ul style={{ margin: 4, paddingLeft: 20 }}>
{item.urls.map((url, idx) => (
<li key={idx}>
<Text copyable>{url.url}</Text>
<Tag style={{ marginLeft: 8 }}>{url.definition}</Tag>
</li>
))}
</ul>
</div>
))}
</div>
),
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() {
}}
/>
<Modal
title="批量下载地址"
open={downloadModalOpen}
width={800}
onCancel={() => setDownloadModalOpen(false)}
footer={[
<Button key="download" type="primary" onClick={startDownloads}>
</Button>,
<Button key="close" onClick={() => setDownloadModalOpen(false)}>
</Button>,
]}
>
<div style={{ maxHeight: 400, overflow: 'auto' }}>
{downloadResults.map((item) => (
<div key={item.videoId} style={{ marginBottom: 12 }}>
<Text strong>{item.title || item.videoId}</Text>
<ul style={{ margin: 4, paddingLeft: 20 }}>
{item.urls.map((url, idx) => (
<li key={idx}>
<Text copyable>{url.url}</Text>
<Tag style={{ marginLeft: 8 }}>{url.definition}</Tag>
</li>
))}
</ul>
</div>
))}
</div>
</Modal>
<Drawer
title="视频详情"
width={560}