diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index cacf05a..71a836f 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -30,12 +30,11 @@ import { convertDanmakuFormat, getDanmakuById, getEpisodes, - loadDanmakuMemory, loadDanmakuSettings, - saveDanmakuMemory, saveDanmakuSettings, searchAnime, initDanmakuModule, + getDanmakuFromCache, } from '@/lib/danmaku/api'; import type { DanmakuAnime, DanmakuSelection, DanmakuSettings } from '@/lib/danmaku/types'; import { SearchResult, DanmakuFilterConfig, EpisodeFilterConfig } from '@/lib/types'; @@ -509,37 +508,193 @@ function PlayPageClient() { }, [currentEpisodeIndex]); // 监听剧集切换,自动加载对应的弹幕 - const lastLoadedEpisodeIdRef = useRef(null); + const lastLoadedEpisodeIndexForDanmakuRef = useRef(null); useEffect(() => { - // 只有在有弹幕选择且有剧集列表时才自动切换 - if ( - currentDanmakuSelection && - danmakuEpisodesList.length > 0 && - currentEpisodeIndex < danmakuEpisodesList.length - ) { - const episode = danmakuEpisodesList[currentEpisodeIndex]; - if (episode && episode.episodeId !== currentDanmakuSelection.episodeId) { - // 避免重复加载同一集的弹幕 - if (lastLoadedEpisodeIdRef.current === episode.episodeId) { - console.log(`跳过重复加载弹幕: episodeId=${episode.episodeId}`); - return; - } - - // 自动加载新集数的弹幕 - const newSelection: DanmakuSelection = { - animeId: currentDanmakuSelection.animeId, - episodeId: episode.episodeId, - animeTitle: currentDanmakuSelection.animeTitle, - episodeTitle: episode.episodeTitle, - }; - setCurrentDanmakuSelection(newSelection); - lastLoadedEpisodeIdRef.current = episode.episodeId; - loadDanmaku(episode.episodeId); - console.log(`自动切换弹幕到第 ${currentEpisodeIndex + 1} 集`); - } + // 检查集数是否有效且是否已改变 + if (currentEpisodeIndex < 0 || !videoTitle) { + return; } - }, [currentEpisodeIndex]); + + // 如果集数已经加载过,跳过 + if (lastLoadedEpisodeIndexForDanmakuRef.current === currentEpisodeIndex) { + return; + } + + // 标记当前集数已加载 + lastLoadedEpisodeIndexForDanmakuRef.current = currentEpisodeIndex; + + console.log(`[弹幕] 剧集切换到第 ${currentEpisodeIndex + 1} 集,自动加载弹幕`); + + // 自动加载弹幕的逻辑 + const loadDanmakuForCurrentEpisode = async () => { + const title = videoTitleRef.current; + if (!title) { + console.warn('[弹幕] 视频标题为空,无法加载弹幕'); + return; + } + + const episodeIndex = currentEpisodeIndexRef.current; + console.log(`[弹幕] 开始加载第 ${episodeIndex + 1} 集弹幕`); + + // 先尝试从 IndexedDB 缓存加载 + try { + const cachedComments = await getDanmakuFromCache(title, episodeIndex); + if (cachedComments && cachedComments.length > 0 && danmakuPluginRef.current) { + console.log(`[弹幕] 使用缓存: title="${title}", episodeIndex=${episodeIndex}, 数量=${cachedComments.length}`); + + setDanmakuLoading(true); + + // 转换弹幕格式 + let danmakuData = convertDanmakuFormat(cachedComments); + + // 手动应用过滤规则 + const filterConfig = danmakuFilterConfigRef.current; + if (filterConfig && filterConfig.rules.length > 0) { + const originalCount = danmakuData.length; + danmakuData = danmakuData.filter((danmu) => { + for (const rule of filterConfig.rules) { + if (!rule.enabled) continue; + try { + if (rule.type === 'normal') { + if (danmu.text.includes(rule.keyword)) { + return false; + } + } else if (rule.type === 'regex') { + if (new RegExp(rule.keyword).test(danmu.text)) { + return false; + } + } + } catch (e) { + console.error('弹幕过滤规则错误:', e); + } + } + return true; + }); + const filteredCount = originalCount - danmakuData.length; + if (filteredCount > 0) { + console.log(`弹幕过滤: 原始 ${originalCount} 条,过滤 ${filteredCount} 条,剩余 ${danmakuData.length} 条`); + } + } + + // 加载弹幕到插件 + const currentSettings = danmakuSettingsRef.current; + danmakuPluginRef.current.config({ + danmuku: danmakuData, + speed: currentSettings.speed, + opacity: currentSettings.opacity, + fontSize: currentSettings.fontSize, + margin: [currentSettings.marginTop, currentSettings.marginBottom], + synchronousPlayback: currentSettings.synchronousPlayback, + }); + danmakuPluginRef.current.load(); + + // 根据设置显示或隐藏弹幕 + if (currentSettings.enabled) { + danmakuPluginRef.current.show(); + } else { + danmakuPluginRef.current.hide(); + } + + setDanmakuCount(danmakuData.length); + console.log(`[弹幕] 缓存加载成功,共 ${danmakuData.length} 条`); + + await new Promise((resolve) => setTimeout(resolve, 1500)); + setDanmakuLoading(false); + + return; // 使用缓存成功,直接返回 + } + } catch (error) { + console.error('[弹幕] 读取缓存失败:', error); + } + + // 没有缓存,执行自动搜索弹幕 + console.log(`[弹幕] 第 ${episodeIndex + 1} 集缓存未命中,开始搜索`); + setDanmakuLoading(true); + + try { + const searchResult = await searchAnime(title); + + if (searchResult.success && searchResult.animes.length > 0) { + // 应用智能过滤:优先匹配年份和标题 + const videoYear = detailRef.current?.year; + const filteredAnimes = filterDanmakuSources( + searchResult.animes, + title, + videoYear + ); + + // 如果有多个匹配结果,让用户选择 + if (filteredAnimes.length > 1) { + console.log(`找到 ${filteredAnimes.length} 个弹幕源,等待用户选择`); + setDanmakuMatches(filteredAnimes); + setCurrentSearchKeyword(title); + setShowDanmakuSourceSelector(true); + setDanmakuLoading(false); + if (artPlayerRef.current) { + artPlayerRef.current.notice.show = `找到 ${filteredAnimes.length} 个弹幕源,请选择`; + } + return; + } + + // 只有一个结果,直接使用 + const anime = filteredAnimes[0]; + + // 获取剧集列表 + const episodesResult = await getEpisodes(anime.animeId); + + if ( + episodesResult.success && + episodesResult.bangumi.episodes.length > 0 + ) { + // 根据当前集数选择对应的弹幕 + const currentEp = currentEpisodeIndexRef.current; + const videoEpTitle = detailRef.current?.episodes_titles?.[currentEp]; + const episode = matchDanmakuEpisode(currentEp, episodesResult.bangumi.episodes, videoEpTitle); + + if (episode) { + const selection: DanmakuSelection = { + animeId: anime.animeId, + episodeId: episode.episodeId, + animeTitle: anime.animeTitle, + episodeTitle: episode.episodeTitle, + }; + + // 设置选择记录 + setCurrentDanmakuSelection(selection); + + // 加载弹幕 + await loadDanmaku(episode.episodeId); + + // 设置剧集列表 + setDanmakuEpisodesList(episodesResult.bangumi.episodes); + + console.log('自动搜索弹幕成功:', selection); + } + } else { + console.warn('未找到剧集信息'); + if (artPlayerRef.current) { + artPlayerRef.current.notice.show = '弹幕加载失败:未找到剧集信息'; + } + } + } else { + console.warn('未找到匹配的弹幕'); + if (artPlayerRef.current) { + artPlayerRef.current.notice.show = '未找到匹配的弹幕,可在弹幕选项卡手动搜索'; + } + } + } catch (error) { + console.error('自动搜索弹幕失败:', error); + if (artPlayerRef.current) { + artPlayerRef.current.notice.show = '弹幕加载失败,请检查网络或稍后重试'; + } + } finally { + setDanmakuLoading(false); + } + }; + + loadDanmakuForCurrentEpisode(); + }, [currentEpisodeIndex, videoTitle]); // 获取豆瓣评分数据 useEffect(() => { @@ -2613,8 +2768,13 @@ function PlayPageClient() { }); danmakuPluginRef.current.load(); - // 获取弹幕数据 - const comments = await getDanmakuById(episodeId); + // 获取弹幕数据(使用 title + episodeIndex 缓存) + const title = videoTitleRef.current; + const episodeIndex = currentEpisodeIndex; + + console.log(`[弹幕加载] episodeId=${episodeId}, title="${title}", episodeIndex=${episodeIndex}`); + + const comments = await getDanmakuById(episodeId, title, episodeIndex); if (comments.length === 0) { console.warn('未获取到弹幕数据'); @@ -2705,16 +2865,6 @@ function PlayPageClient() { const handleDanmakuSelect = async (selection: DanmakuSelection) => { setCurrentDanmakuSelection(selection); - // 保存选择记忆(包含搜索关键词) - saveDanmakuMemory( - videoTitleRef.current, - selection.animeId, - selection.episodeId, - selection.animeTitle, - selection.episodeTitle, - selection.searchKeyword // 保存用户使用的搜索关键词 - ); - // 获取该动漫的所有剧集列表 try { const episodesResult = await getEpisodes(selection.animeId); @@ -2745,9 +2895,6 @@ function PlayPageClient() { episodesResult.success && episodesResult.bangumi.episodes.length > 0 ) { - // 保存剧集列表 - setDanmakuEpisodesList(episodesResult.bangumi.episodes); - // 根据当前集数选择对应的弹幕 const currentEp = currentEpisodeIndexRef.current; const videoEpTitle = detailRef.current?.episodes_titles?.[currentEp]; @@ -2761,21 +2908,15 @@ function PlayPageClient() { episodeTitle: episode.episodeTitle, }; + // 先设置选择记录 setCurrentDanmakuSelection(selection); - // 保存选择记忆(使用当前搜索关键词) - saveDanmakuMemory( - title, - selection.animeId, - selection.episodeId, - selection.animeTitle, - selection.episodeTitle, - currentSearchKeyword || undefined // 使用保存的搜索关键词 - ); - // 加载弹幕 await loadDanmaku(episode.episodeId); + // 设置剧集列表 + setDanmakuEpisodesList(episodesResult.bangumi.episodes); + console.log('用户选择弹幕源:', selection); } } else { @@ -2845,99 +2986,92 @@ function PlayPageClient() { return; } - console.log('[弹幕] 开始自动搜索 - 视频标题:', title); + const currentEpisodeIndex = currentEpisodeIndexRef.current; + console.log('[弹幕] 开始加载弹幕 - 视频标题:', title, '集数:', currentEpisodeIndex); - // 检查是否有记忆 - const memory = loadDanmakuMemory(title); - if (memory) { - console.log('[弹幕] 找到缓存 - 视频:', title, '→ 弹幕源:', memory.animeTitle); + // 先尝试从 IndexedDB 缓存加载 + try { + const cachedComments = await getDanmakuFromCache(title, currentEpisodeIndex); + if (cachedComments && cachedComments.length > 0) { + console.log(`[弹幕] 使用缓存: title="${title}", episodeIndex=${currentEpisodeIndex}, 数量=${cachedComments.length}`); - // 获取该动漫的所有剧集列表 - try { - const episodesResult = await getEpisodes(memory.animeId); - if (episodesResult.success && episodesResult.bangumi.episodes.length > 0) { - setDanmakuEpisodesList(episodesResult.bangumi.episodes); + // 直接加载缓存的弹幕,不需要调用 API + if (!danmakuPluginRef.current) { + console.warn('弹幕插件未初始化'); + return; + } - // 根据当前集数选择对应的弹幕 - const currentEp = currentEpisodeIndexRef.current; - const videoEpTitle = detailRef.current?.episodes_titles?.[currentEp]; - const episode = matchDanmakuEpisode(currentEp, episodesResult.bangumi.episodes, videoEpTitle); + setDanmakuLoading(true); - if (episode) { - const selection: DanmakuSelection = { - animeId: memory.animeId, - episodeId: episode.episodeId, - animeTitle: memory.animeTitle, - episodeTitle: episode.episodeTitle, - }; + // 转换弹幕格式 + let danmakuData = convertDanmakuFormat(cachedComments); - setCurrentDanmakuSelection(selection); - - // 更新选择记忆(保留原搜索词) - saveDanmakuMemory( - title, - selection.animeId, - selection.episodeId, - selection.animeTitle, - selection.episodeTitle, - memory.searchKeyword // 保留原有的搜索关键词 - ); - - console.log('[弹幕] 使用缓存成功,跳过搜索'); - lastLoadedEpisodeIdRef.current = episode.episodeId; - await loadDanmaku(episode.episodeId); - return; // 成功使用缓存,直接返回 - } else { - console.warn('[弹幕] 缓存中没有找到匹配的剧集'); + // 手动应用过滤规则 + const filterConfig = danmakuFilterConfigRef.current; + if (filterConfig && filterConfig.rules.length > 0) { + const originalCount = danmakuData.length; + danmakuData = danmakuData.filter((danmu) => { + for (const rule of filterConfig.rules) { + if (!rule.enabled) continue; + try { + if (rule.type === 'normal') { + if (danmu.text.includes(rule.keyword)) { + return false; + } + } else if (rule.type === 'regex') { + if (new RegExp(rule.keyword).test(danmu.text)) { + return false; + } + } + } catch (e) { + console.error('弹幕过滤规则错误:', e); + } + } + return true; + }); + const filteredCount = originalCount - danmakuData.length; + if (filteredCount > 0) { + console.log(`弹幕过滤: 原始 ${originalCount} 条,过滤 ${filteredCount} 条,剩余 ${danmakuData.length} 条`); } + } + + // 加载弹幕到插件 + const currentSettings = danmakuSettingsRef.current; + danmakuPluginRef.current.config({ + danmuku: danmakuData, + speed: currentSettings.speed, + opacity: currentSettings.opacity, + fontSize: currentSettings.fontSize, + margin: [currentSettings.marginTop, currentSettings.marginBottom], + synchronousPlayback: currentSettings.synchronousPlayback, + }); + danmakuPluginRef.current.load(); + + // 根据设置显示或隐藏弹幕 + if (currentSettings.enabled) { + danmakuPluginRef.current.show(); } else { - console.warn('[弹幕] 获取剧集列表失败或列表为空'); + danmakuPluginRef.current.hide(); } - // 如果使用记忆加载失败(没有找到对应的剧集),清除该记忆 - console.warn('[弹幕] 缓存失效,清除缓存'); - if (typeof window !== 'undefined') { - try { - const memoriesJson = localStorage.getItem('danmaku_memories'); - if (memoriesJson) { - const memories = JSON.parse(memoriesJson); - delete memories[title]; - localStorage.setItem('danmaku_memories', JSON.stringify(memories)); - console.log('[弹幕] 已清除失效的缓存'); - } - } catch (e) { - console.error('[弹幕] 清除缓存失败:', e); - } - } - } catch (error) { - console.error('[弹幕] 使用缓存加载失败:', error); - // 清除失效的记忆 - if (typeof window !== 'undefined') { - try { - const memoriesJson = localStorage.getItem('danmaku_memories'); - if (memoriesJson) { - const memories = JSON.parse(memoriesJson); - delete memories[title]; - localStorage.setItem('danmaku_memories', JSON.stringify(memories)); - console.log('[弹幕] 已清除失效的缓存'); - } - } catch (e) { - console.error('[弹幕] 清除缓存失败:', e); - } - } + setDanmakuCount(danmakuData.length); + console.log(`[弹幕] 缓存加载成功,共 ${danmakuData.length} 条`); + + // 延迟一下让用户看到弹幕数量 + await new Promise((resolve) => setTimeout(resolve, 1500)); + setDanmakuLoading(false); + + return; // 使用缓存成功,直接返回 } - // 缓存失效,降级到搜索流程 - console.log('[弹幕] 缓存已失效,降级到搜索流程'); - if (artPlayerRef.current) { - artPlayerRef.current.notice.show = '缓存的弹幕源失效,正在重新搜索...'; - } - // 注意:这里故意不return,继续执行下面的搜索流程 + } catch (error) { + console.error('[弹幕] 读取缓存失败:', error); } - // 没有缓存或缓存失效,执行自动搜索弹幕 + // 没有缓存,执行自动搜索弹幕 + console.log('[弹幕] 缓存未命中,开始搜索'); setDanmakuLoading(true); - // 使用视频标题作为搜索关键词(缓存失效或不存在时) + // 使用视频标题作为搜索关键词 const searchKeyword = title; console.log('[弹幕] 搜索关键词:', searchKeyword, '(使用视频标题)'); @@ -2976,9 +3110,6 @@ function PlayPageClient() { episodesResult.success && episodesResult.bangumi.episodes.length > 0 ) { - // 保存剧集列表 - setDanmakuEpisodesList(episodesResult.bangumi.episodes); - // 根据当前集数选择对应的弹幕 const currentEp = currentEpisodeIndexRef.current; const videoEpTitle = detailRef.current?.episodes_titles?.[currentEp]; @@ -2992,22 +3123,15 @@ function PlayPageClient() { episodeTitle: episode.episodeTitle, }; + // 先设置选择记录 setCurrentDanmakuSelection(selection); - // 保存选择记忆(保存搜索关键词) - saveDanmakuMemory( - title, - selection.animeId, - selection.episodeId, - selection.animeTitle, - selection.episodeTitle, - searchKeyword // 保存实际使用的搜索关键词 - ); - // 加载弹幕 - lastLoadedEpisodeIdRef.current = episode.episodeId; await loadDanmaku(episode.episodeId); + // 设置剧集列表 + setDanmakuEpisodesList(episodesResult.bangumi.episodes); + console.log('自动搜索弹幕成功:', selection); } } else { diff --git a/src/lib/danmaku/api.ts b/src/lib/danmaku/api.ts index cf5ae17..fb22ed3 100644 --- a/src/lib/danmaku/api.ts +++ b/src/lib/danmaku/api.ts @@ -17,6 +17,7 @@ import { clearAllDanmakuCache, clearDanmakuCache, getDanmakuCacheStats, + generateCacheKey, } from './cache'; // 初始化弹幕模块(清理过期缓存) @@ -46,6 +47,8 @@ export { clearDanmakuCache, clearExpiredDanmakuCache, getDanmakuCacheStats, + generateCacheKey, + getDanmakuFromCache, }; // 搜索动漫 @@ -138,18 +141,24 @@ export async function getEpisodes( // 通过剧集 ID 获取弹幕(优先从缓存读取) export async function getDanmakuById( - episodeId: number + episodeId: number, + title?: string, + episodeIndex?: number ): Promise { try { - // 1. 先尝试从缓存读取 - const cachedComments = await getDanmakuFromCache(episodeId); - if (cachedComments) { - console.log(`[弹幕缓存] 使用缓存: episodeId=${episodeId}, 数量=${cachedComments.length}`); - return cachedComments; + // 1. 如果提供了 title 和 episodeIndex,先尝试从缓存读取 + if (title && episodeIndex !== undefined) { + const cachedComments = await getDanmakuFromCache(title, episodeIndex); + if (cachedComments) { + console.log(`[弹幕缓存] 使用缓存: title=${title}, episodeIndex=${episodeIndex}, 数量=${cachedComments.length}`); + return cachedComments; + } + console.log(`[弹幕缓存] 缓存未命中,从 API 获取: title=${title}, episodeIndex=${episodeIndex}`); + } else { + console.log(`[弹幕缓存] 未提供 title/episodeIndex,跳过缓存: episodeId=${episodeId}`); } // 2. 缓存未命中,从 API 获取 - console.log(`[弹幕缓存] 缓存未命中,从 API 获取: episodeId=${episodeId}`); const url = `/api/danmaku/comment?episodeId=${episodeId}`; const response = await fetch(url); @@ -160,15 +169,18 @@ export async function getDanmakuById( const data = (await response.json()) as DanmakuCommentsResponse; const comments = data.comments || []; - // 3. 保存到缓存 - if (comments.length > 0) { + // 3. 如果提供了 title 和 episodeIndex,保存到缓存 + if (comments.length > 0 && title && title.trim() !== '' && episodeIndex !== undefined && episodeIndex >= 0) { try { - await saveDanmakuToCache(episodeId, comments); - console.log(`[弹幕缓存] 已缓存: episodeId=${episodeId}, 数量=${comments.length}`); + console.log(`[弹幕缓存] 尝试保存缓存: title="${title}", episodeIndex=${episodeIndex}, 数量=${comments.length}`); + await saveDanmakuToCache(title, episodeIndex, comments); + console.log(`[弹幕缓存] 已缓存: title=${title}, episodeIndex=${episodeIndex}, 数量=${comments.length}`); } catch (cacheError) { console.error('[弹幕缓存] 保存缓存失败:', cacheError); // 缓存失败不影响返回结果 } + } else { + console.log(`[弹幕缓存] 不满足缓存条件: title="${title}", episodeIndex=${episodeIndex}, comments.length=${comments.length}`); } return comments; diff --git a/src/lib/danmaku/cache.ts b/src/lib/danmaku/cache.ts index 034ea17..3100e9b 100644 --- a/src/lib/danmaku/cache.ts +++ b/src/lib/danmaku/cache.ts @@ -3,15 +3,23 @@ import type { DanmakuComment } from './types'; // IndexedDB 数据库名称和版本 -const DB_NAME = 'moontvplus_danmaku_cache'; +const DB_NAME = 'moontvplus_danmaku_cache_v2'; const DB_VERSION = 1; const STORE_NAME = 'danmaku'; // 缓存数据结构 export interface DanmakuCacheData { - episodeId: number; + cacheKey: string; // title + episodeIndex 组合键 comments: DanmakuComment[]; timestamp: number; // 缓存时间戳 + title?: string; // 可选:视频标题 + episodeIndex?: number; // 可选:集数索引 +} + +// 生成缓存键(title + episodeIndex) +export function generateCacheKey(title: string, episodeIndex: number): string { + // 使用 | 分隔符连接 title 和 episodeIndex + return `${title}|${episodeIndex}`; } // 获取弹幕缓存失效时间(毫秒) @@ -53,7 +61,7 @@ async function openDB(): Promise { // 创建对象存储(如果不存在) if (!db.objectStoreNames.contains(STORE_NAME)) { - const objectStore = db.createObjectStore(STORE_NAME, { keyPath: 'episodeId' }); + const objectStore = db.createObjectStore(STORE_NAME, { keyPath: 'cacheKey' }); objectStore.createIndex('timestamp', 'timestamp', { unique: false }); console.log('IndexedDB 对象存储已创建:', STORE_NAME); } @@ -63,9 +71,20 @@ async function openDB(): Promise { // 保存弹幕到缓存 export async function saveDanmakuToCache( - episodeId: number, + title: string, + episodeIndex: number, comments: DanmakuComment[] ): Promise { + // 验证参数 + if (!title || title.trim() === '') { + console.warn('弹幕缓存: title 为空,跳过保存'); + return; + } + if (episodeIndex === undefined || episodeIndex === null || episodeIndex < 0) { + console.warn('弹幕缓存: episodeIndex 无效,跳过保存'); + return; + } + // 如果缓存时间设置为 0,不保存缓存 const expireTime = getDanmakuCacheExpireTime(); if (expireTime === 0) { @@ -78,21 +97,33 @@ export async function saveDanmakuToCache( const transaction = db.transaction([STORE_NAME], 'readwrite'); const objectStore = transaction.objectStore(STORE_NAME); + const cacheKey = generateCacheKey(title, episodeIndex); const cacheData: DanmakuCacheData = { - episodeId, + cacheKey, comments, timestamp: Date.now(), + title, + episodeIndex, }; + // 添加调试日志 + console.log(`[弹幕缓存] 准备保存: cacheKey="${cacheKey}", title="${title}", episodeIndex=${episodeIndex}`); + return new Promise((resolve, reject) => { const request = objectStore.put(cacheData); request.onsuccess = () => { - console.log(`弹幕已缓存: episodeId=${episodeId}, 数量=${comments.length}`); + console.log(`弹幕已缓存: title=${title}, episodeIndex=${episodeIndex}, 数量=${comments.length}`); resolve(); }; - request.onerror = () => { + request.onerror = (event) => { + console.error('保存弹幕缓存失败,详细信息:', { + error: (event.target as IDBRequest).error, + cacheKey, + title, + episodeIndex, + }); reject(new Error('保存弹幕缓存失败')); }; @@ -108,7 +139,8 @@ export async function saveDanmakuToCache( // 从缓存获取弹幕 export async function getDanmakuFromCache( - episodeId: number + title: string, + episodeIndex: number ): Promise { // 如果缓存时间设置为 0,不使用缓存 const expireTime = getDanmakuCacheExpireTime(); @@ -122,14 +154,16 @@ export async function getDanmakuFromCache( const transaction = db.transaction([STORE_NAME], 'readonly'); const objectStore = transaction.objectStore(STORE_NAME); + const cacheKey = generateCacheKey(title, episodeIndex); + return new Promise((resolve, reject) => { - const request = objectStore.get(episodeId); + const request = objectStore.get(cacheKey); request.onsuccess = () => { const result = request.result as DanmakuCacheData | undefined; if (!result) { - console.log(`弹幕缓存未找到: episodeId=${episodeId}`); + console.log(`弹幕缓存未找到: title=${title}, episodeIndex=${episodeIndex}`); resolve(null); return; } @@ -142,7 +176,7 @@ export async function getDanmakuFromCache( if (age > expireTime) { const ageMinutes = Math.floor(age / 1000 / 60); console.log( - `弹幕缓存已过期: episodeId=${episodeId}, 年龄=${ageMinutes}分钟` + `弹幕缓存已过期: title=${title}, episodeIndex=${episodeIndex}, 年龄=${ageMinutes}分钟` ); resolve(null); return; @@ -150,7 +184,7 @@ export async function getDanmakuFromCache( const ageMinutes = Math.floor(age / 1000 / 60); console.log( - `从缓存获取弹幕: episodeId=${episodeId}, 数量=${result.comments.length}, 年龄=${ageMinutes}分钟` + `从缓存获取弹幕: title=${title}, episodeIndex=${episodeIndex}, 数量=${result.comments.length}, 年龄=${ageMinutes}分钟` ); resolve(result.comments); }; @@ -170,17 +204,19 @@ export async function getDanmakuFromCache( } // 清除指定弹幕缓存 -export async function clearDanmakuCache(episodeId: number): Promise { +export async function clearDanmakuCache(title: string, episodeIndex: number): Promise { try { const db = await openDB(); const transaction = db.transaction([STORE_NAME], 'readwrite'); const objectStore = transaction.objectStore(STORE_NAME); + const cacheKey = generateCacheKey(title, episodeIndex); + return new Promise((resolve, reject) => { - const request = objectStore.delete(episodeId); + const request = objectStore.delete(cacheKey); request.onsuccess = () => { - console.log(`弹幕缓存已清除: episodeId=${episodeId}`); + console.log(`弹幕缓存已清除: title=${title}, episodeIndex=${episodeIndex}`); resolve(); };