From 3af1d7fb24985ae856a23ad96a5a301236417cbe Mon Sep 17 00:00:00 2001 From: mtvpls Date: Tue, 2 Dec 2025 17:22:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=BC=B9=E5=B9=95=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/play/page.tsx | 262 +++++++++++++++++++++++++++++++++++++++++- start.sh | 4 +- 2 files changed, 260 insertions(+), 6 deletions(-) diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index b1b8a94..1bf928d 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -34,7 +34,7 @@ import { saveDanmakuSettings, searchAnime, } from '@/lib/danmaku/api'; -import type { DanmakuSelection, DanmakuSettings } from '@/lib/danmaku/types'; +import type { DanmakuAnime, DanmakuSelection, DanmakuSettings } from '@/lib/danmaku/types'; import { SearchResult } from '@/lib/types'; import { getVideoResolutionFromM3u8, processImageUrl } from '@/lib/utils'; @@ -179,6 +179,10 @@ function PlayPageClient() { const danmakuPluginRef = useRef(null); const danmakuSettingsRef = useRef(danmakuSettings); + // 多条弹幕匹配结果 + const [danmakuMatches, setDanmakuMatches] = useState([]); + const [showDanmakuSourceSelector, setShowDanmakuSourceSelector] = useState(false); + useEffect(() => { danmakuSettingsRef.current = danmakuSettings; }, [danmakuSettings]); @@ -1406,6 +1410,106 @@ function PlayPageClient() { await loadDanmaku(selection.episodeId); }; + // 处理用户选择弹幕源 + const handleDanmakuSourceSelect = async (selectedAnime: DanmakuAnime) => { + setShowDanmakuSourceSelector(false); + setDanmakuLoading(true); + + try { + const title = videoTitleRef.current; + console.log('[弹幕] 用户选择弹幕源 - 视频:', title, '弹幕源:', selectedAnime.animeTitle); + + // 获取剧集列表 + const episodesResult = await getEpisodes(selectedAnime.animeId); + + if ( + episodesResult.success && + episodesResult.bangumi.episodes.length > 0 + ) { + // 保存剧集列表 + setDanmakuEpisodesList(episodesResult.bangumi.episodes); + + // 根据当前集数选择对应的弹幕 + const currentEp = currentEpisodeIndexRef.current; + const episode = + episodesResult.bangumi.episodes[ + Math.min(currentEp, episodesResult.bangumi.episodes.length - 1) + ]; + + if (episode) { + const selection: DanmakuSelection = { + animeId: selectedAnime.animeId, + episodeId: episode.episodeId, + animeTitle: selectedAnime.animeTitle, + episodeTitle: episode.episodeTitle, + }; + + setCurrentDanmakuSelection(selection); + + // 保存选择记忆 + saveDanmakuMemory( + title, + selection.animeId, + selection.episodeId, + selection.animeTitle, + selection.episodeTitle + ); + + // 加载弹幕 + await loadDanmaku(episode.episodeId); + + console.log('用户选择弹幕源:', selection); + } + } else { + console.warn('未找到剧集信息'); + } + } catch (error) { + console.error('加载弹幕失败:', error); + } finally { + setDanmakuLoading(false); + } + }; + + // 手动重新选择弹幕源(忽略记忆) + const handleReselectDanmakuSource = async () => { + const title = videoTitleRef.current; + if (!title) { + console.warn('视频标题为空,无法搜索弹幕'); + return; + } + + console.log('[弹幕] 用户手动重新选择弹幕源 - 视频:', title); + setDanmakuLoading(true); + + try { + const searchResult = await searchAnime(title); + + if (searchResult.success && searchResult.animes.length > 0) { + // 如果有多个匹配结果,让用户选择 + if (searchResult.animes.length > 1) { + console.log(`[弹幕] 找到 ${searchResult.animes.length} 个弹幕源`); + setDanmakuMatches(searchResult.animes); + setShowDanmakuSourceSelector(true); + setDanmakuLoading(false); + return; + } + + // 只有一个结果,直接使用 + const anime = searchResult.animes[0]; + await handleDanmakuSourceSelect(anime); + } else { + console.warn('[弹幕] 未找到匹配的弹幕'); + if (artPlayerRef.current) { + artPlayerRef.current.notice.show = '未找到匹配的弹幕源'; + } + setDanmakuLoading(false); + } + } catch (error) { + console.error('[弹幕] 搜索失败:', error); + setDanmakuLoading(false); + } + }; + // 自动搜索并加载弹幕 const autoSearchDanmaku = async () => { const title = videoTitleRef.current; @@ -1414,10 +1518,12 @@ function PlayPageClient() { return; } + console.log('[弹幕] 开始自动搜索 - 视频标题:', title); + // 检查是否有记忆 const memory = loadDanmakuMemory(title); if (memory) { - console.log('使用记忆的弹幕动漫:', memory.animeTitle); + console.log('[弹幕] 找到记忆 - 视频:', title, '→ 弹幕源:', memory.animeTitle); // 获取该动漫的所有剧集列表 try { @@ -1467,7 +1573,16 @@ function PlayPageClient() { const searchResult = await searchAnime(title); if (searchResult.success && searchResult.animes.length > 0) { - // 使用第一个搜索结果 + // 如果有多个匹配结果,让用户选择 + if (searchResult.animes.length > 1) { + console.log(`找到 ${searchResult.animes.length} 个弹幕源,等待用户选择`); + setDanmakuMatches(searchResult.animes); + setShowDanmakuSourceSelector(true); + setDanmakuLoading(false); + return; + } + + // 只有一个结果,直接使用 const anime = searchResult.animes[0]; // 获取剧集列表 @@ -2615,6 +2730,117 @@ function PlayPageClient() { return ( + {/* 弹幕源选择对话框 */} + {showDanmakuSourceSelector && danmakuMatches.length > 0 && ( +
+
+ {/* 标题栏 */} +
+

+ + + + 选择弹幕源 +

+

+ 找到 {danmakuMatches.length} 个匹配的弹幕源,请选择一个 +

+
+ + {/* 列表区域 */} +
+
+ {danmakuMatches.map((anime) => ( + + ))} +
+
+ + {/* 底部操作栏 */} +
+ +
+
+
+ )} +
{/* 第一行:影片标题 */}
@@ -2763,6 +2989,36 @@ function PlayPageClient() { )}
)} + + {/* 弹幕源切换按钮 - 当有弹幕加载完成且不在加载中时显示 */} + {!danmakuLoading && currentDanmakuSelection && ( +
+ +
+ )}
{/* 第三方应用打开按钮 */} diff --git a/start.sh b/start.sh index 01fef33..8dbad0e 100755 --- a/start.sh +++ b/start.sh @@ -1,5 +1,3 @@ #!/bin/bash -set +a -source .env -set -a +./.env pnpm dev \ No newline at end of file