mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-02-26 22:24:42 +08:00
feat: d1 local cache
This commit is contained in:
@@ -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<string, any>) => {
|
||||
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<string, any>) => {
|
||||
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) => {
|
||||
|
||||
@@ -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<string, any>) => {
|
||||
const key = generateStorageKey(currentSource, currentId);
|
||||
const isFav = !!favorites[key];
|
||||
setFavorited(isFav);
|
||||
}
|
||||
);
|
||||
|
||||
return unsubscribe;
|
||||
}, [currentSource, currentId]);
|
||||
|
||||
// 切换收藏
|
||||
const handleToggleFavorite = async () => {
|
||||
if (
|
||||
|
||||
@@ -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 && (
|
||||
<button
|
||||
onClick={async () => {
|
||||
await clearSearchHistory();
|
||||
setSearchHistory([]);
|
||||
onClick={() => {
|
||||
clearSearchHistory(); // 事件监听会自动更新界面
|
||||
}}
|
||||
className='ml-3 text-sm text-gray-500 hover:text-red-500 transition-colors dark:text-gray-400 dark:hover:text-red-500'
|
||||
>
|
||||
@@ -303,12 +309,10 @@ function SearchPageClient() {
|
||||
{/* 删除按钮 */}
|
||||
<button
|
||||
aria-label='删除搜索历史'
|
||||
onClick={async (e) => {
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
await deleteSearchHistory(item);
|
||||
const history = await getSearchHistory();
|
||||
setSearchHistory(history);
|
||||
deleteSearchHistory(item); // 事件监听会自动更新界面
|
||||
}}
|
||||
className='absolute -top-1 -right-1 w-4 h-4 opacity-0 group-hover:opacity-100 bg-gray-400 hover:bg-red-500 text-white rounded-full flex items-center justify-center text-[10px] transition-colors'
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user