diff --git a/src/app/page.tsx b/src/app/page.tsx index 70b7cbf..7b0eb24 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any, react-hooks/exhaustive-deps */ + 'use client'; import { ChevronRight } from 'lucide-react'; @@ -9,6 +11,7 @@ import { clearAllFavorites, getAllFavorites, getAllPlayRecords, + subscribeToDataUpdates, } from '@/lib/db.client'; import { DoubanItem, DoubanResult } from '@/lib/types'; @@ -82,42 +85,57 @@ function HomeClient() { fetchDoubanData(); }, []); + // 处理收藏数据更新的函数 + const updateFavoriteItems = async (allFavorites: Record) => { + const allPlayRecords = await getAllPlayRecords(); + + // 根据保存时间排序(从近到远) + const sorted = Object.entries(allFavorites) + .sort(([, a], [, b]) => b.save_time - a.save_time) + .map(([key, fav]) => { + const plusIndex = key.indexOf('+'); + const source = key.slice(0, plusIndex); + const id = key.slice(plusIndex + 1); + + // 查找对应的播放记录,获取当前集数 + const playRecord = allPlayRecords[key]; + const currentEpisode = playRecord?.index; + + return { + id, + source, + title: fav.title, + year: fav.year, + poster: fav.cover, + episodes: fav.total_episodes, + source_name: fav.source_name, + currentEpisode, + search_title: fav?.search_title, + } as FavoriteItem; + }); + setFavoriteItems(sorted); + }; + // 当切换到收藏夹时加载收藏数据 useEffect(() => { if (activeTab !== 'favorites') return; - (async () => { - const [allFavorites, allPlayRecords] = await Promise.all([ - getAllFavorites(), - getAllPlayRecords(), - ]); + const loadFavorites = async () => { + const allFavorites = await getAllFavorites(); + await updateFavoriteItems(allFavorites); + }; - // 根据保存时间排序(从近到远) - const sorted = Object.entries(allFavorites) - .sort(([, a], [, b]) => b.save_time - a.save_time) - .map(([key, fav]) => { - const plusIndex = key.indexOf('+'); - const source = key.slice(0, plusIndex); - const id = key.slice(plusIndex + 1); + loadFavorites(); - // 查找对应的播放记录,获取当前集数 - const playRecord = allPlayRecords[key]; - const currentEpisode = playRecord?.index; + // 监听收藏更新事件 + const unsubscribe = subscribeToDataUpdates( + 'favoritesUpdated', + (newFavorites: Record) => { + updateFavoriteItems(newFavorites); + } + ); - return { - id, - source, - title: fav.title, - year: fav.year, - poster: fav.cover, - episodes: fav.total_episodes, - source_name: fav.source_name, - currentEpisode, - search_title: fav?.search_title, - } as FavoriteItem; - }); - setFavoriteItems(sorted); - })(); + return unsubscribe; }, [activeTab]); const handleCloseAnnouncement = (announcement: string) => { diff --git a/src/app/play/page.tsx b/src/app/play/page.tsx index fc2e858..9c66a6a 100644 --- a/src/app/play/page.tsx +++ b/src/app/play/page.tsx @@ -14,6 +14,7 @@ import { getAllPlayRecords, isFavorited, savePlayRecord, + subscribeToDataUpdates, toggleFavorite, } from '@/lib/db.client'; import { SearchResult } from '@/lib/types'; @@ -916,6 +917,22 @@ function PlayPageClient() { })(); }, [currentSource, currentId]); + // 监听收藏数据更新事件 + useEffect(() => { + if (!currentSource || !currentId) return; + + const unsubscribe = subscribeToDataUpdates( + 'favoritesUpdated', + (favorites: Record) => { + const key = generateStorageKey(currentSource, currentId); + const isFav = !!favorites[key]; + setFavorited(isFav); + } + ); + + return unsubscribe; + }, [currentSource, currentId]); + // 切换收藏 const handleToggleFavorite = async () => { if ( diff --git a/src/app/search/page.tsx b/src/app/search/page.tsx index 87d84a0..c547195 100644 --- a/src/app/search/page.tsx +++ b/src/app/search/page.tsx @@ -10,6 +10,7 @@ import { clearSearchHistory, deleteSearchHistory, getSearchHistory, + subscribeToDataUpdates, } from '@/lib/db.client'; import { SearchResult } from '@/lib/types'; @@ -85,7 +86,19 @@ function SearchPageClient() { useEffect(() => { // 无搜索参数时聚焦搜索框 !searchParams.get('q') && document.getElementById('searchInput')?.focus(); + + // 初始加载搜索历史 getSearchHistory().then(setSearchHistory); + + // 监听搜索历史更新事件 + const unsubscribe = subscribeToDataUpdates( + 'searchHistoryUpdated', + (newHistory: string[]) => { + setSearchHistory(newHistory); + } + ); + + return unsubscribe; }, []); useEffect(() => { @@ -95,11 +108,8 @@ function SearchPageClient() { setSearchQuery(query); fetchSearchResults(query); - // 保存到搜索历史 - addSearchHistory(query).then(async () => { - const history = await getSearchHistory(); - setSearchHistory(history); - }); + // 保存到搜索历史 (事件监听会自动更新界面) + addSearchHistory(query); } else { setShowResults(false); } @@ -161,11 +171,8 @@ function SearchPageClient() { // 直接发请求 fetchSearchResults(trimmed); - // 保存到搜索历史 - addSearchHistory(trimmed).then(async () => { - const history = await getSearchHistory(); - setSearchHistory(history); - }); + // 保存到搜索历史 (事件监听会自动更新界面) + addSearchHistory(trimmed); }; return ( @@ -276,9 +283,8 @@ function SearchPageClient() { 搜索历史 {searchHistory.length > 0 && (