diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx
index 850294f..3754903 100644
--- a/src/app/play/page.tsx
+++ b/src/app/play/page.tsx
@@ -40,6 +40,7 @@ import { SearchResult, DanmakuFilterConfig } from '@/lib/types';
import { getVideoResolutionFromM3u8, processImageUrl } from '@/lib/utils';
import EpisodeSelector from '@/components/EpisodeSelector';
+import DownloadEpisodeSelector from '@/components/DownloadEpisodeSelector';
import PageLayout from '@/components/PageLayout';
import DoubanComments from '@/components/DoubanComments';
import DanmakuFilterSettings from '@/components/DanmakuFilterSettings';
@@ -500,6 +501,9 @@ function PlayPageClient() {
const [isEpisodeSelectorCollapsed, setIsEpisodeSelectorCollapsed] =
useState(false);
+ // 下载选集面板显示状态
+ const [showDownloadSelector, setShowDownloadSelector] = useState(false);
+
// 换源加载状态
const [isVideoLoading, setIsVideoLoading] = useState(true);
const [videoLoadingStage, setVideoLoadingStage] = useState<
@@ -754,6 +758,76 @@ function PlayPageClient() {
}
};
+ // 处理下载指定集数(支持批量下载)
+ const handleDownloadEpisode = async (episodeIndexes: number[]) => {
+ if (!detail || !detail.episodes || episodeIndexes.length === 0) {
+ if (artPlayerRef.current) {
+ artPlayerRef.current.notice.show = '无法获取视频地址';
+ }
+ return;
+ }
+
+ const tokenParam = proxyToken ? `&token=${encodeURIComponent(proxyToken)}` : '';
+ const origin = `${window.location.protocol}//${window.location.host}`;
+
+ let successCount = 0;
+ let failCount = 0;
+
+ // 批量处理下载
+ for (const episodeIndex of episodeIndexes) {
+ if (episodeIndex >= detail.episodes.length) {
+ failCount++;
+ continue;
+ }
+
+ const episodeUrl = detail.episodes[episodeIndex];
+ const proxyUrl = externalPlayerAdBlock
+ ? `${origin}/api/proxy-m3u8?url=${encodeURIComponent(episodeUrl)}&source=${encodeURIComponent(currentSource)}${tokenParam}`
+ : episodeUrl;
+ const isM3u8 = episodeUrl.toLowerCase().includes('.m3u8') || episodeUrl.toLowerCase().includes('/m3u8/');
+
+ if (isM3u8) {
+ // M3U8格式 - 使用新的下载器,TS 格式
+ try {
+ const downloadTitle = `${videoTitle}_第${episodeIndex + 1}集`;
+ await addDownloadTask(proxyUrl, downloadTitle, 'TS');
+ successCount++;
+ } catch (error) {
+ console.error(`添加下载任务失败 (第${episodeIndex + 1}集):`, error);
+ failCount++;
+ }
+ } else {
+ // 普通视频格式 - 直接下载
+ try {
+ const a = document.createElement('a');
+ a.href = proxyUrl;
+ a.download = `${videoTitle}_第${episodeIndex + 1}集.mp4`;
+ a.target = '_blank';
+ document.body.appendChild(a);
+ a.click();
+ document.body.removeChild(a);
+ successCount++;
+ // 添加延迟避免浏览器阻止多个下载
+ await new Promise(resolve => setTimeout(resolve, 300));
+ } catch (error) {
+ console.error(`下载失败 (第${episodeIndex + 1}集):`, error);
+ failCount++;
+ }
+ }
+ }
+
+ // 显示结果通知
+ if (artPlayerRef.current) {
+ if (failCount === 0) {
+ artPlayerRef.current.notice.show = `已添加 ${successCount} 个下载任务!`;
+ } else if (successCount === 0) {
+ artPlayerRef.current.notice.show = '下载失败,请重试';
+ } else {
+ artPlayerRef.current.notice.show = `成功 ${successCount} 个,失败 ${failCount} 个`;
+ }
+ }
+ };
+
const ensureVideoSource = (video: HTMLVideoElement | null, url: string) => {
if (!video || !url) return;
const sources = Array.from(video.getElementsByTagName('source'));
@@ -3646,47 +3720,9 @@ function PlayPageClient() {
{/* 下载按钮 */}