feat: d1 local cache

This commit is contained in:
shinya
2025-07-14 22:09:53 +08:00
parent 7e6f4bcadc
commit b61430856a
6 changed files with 992 additions and 121 deletions

View File

@@ -4,7 +4,11 @@
import { useEffect, useState } from 'react';
import type { PlayRecord } from '@/lib/db.client';
import { clearAllPlayRecords, getAllPlayRecords } from '@/lib/db.client';
import {
clearAllPlayRecords,
getAllPlayRecords,
subscribeToDataUpdates,
} from '@/lib/db.client';
import ScrollableRow from '@/components/ScrollableRow';
import VideoCard from '@/components/VideoCard';
@@ -19,28 +23,30 @@ export default function ContinueWatching({ className }: ContinueWatchingProps) {
>([]);
const [loading, setLoading] = useState(true);
// 处理播放记录数据更新的函数
const updatePlayRecords = (allRecords: Record<string, PlayRecord>) => {
// 将记录转换为数组并根据 save_time 由近到远排序
const recordsArray = Object.entries(allRecords).map(([key, record]) => ({
...record,
key,
}));
// 按 save_time 降序排序(最新的在前面)
const sortedRecords = recordsArray.sort(
(a, b) => b.save_time - a.save_time
);
setPlayRecords(sortedRecords);
};
useEffect(() => {
const fetchPlayRecords = async () => {
try {
setLoading(true);
// 从 localStorage 获取所有播放记录
// 从缓存或API获取所有播放记录
const allRecords = await getAllPlayRecords();
// 将记录转换为数组并根据 save_time 由近到远排序
const recordsArray = Object.entries(allRecords).map(
([key, record]) => ({
...record,
key,
})
);
// 按 save_time 降序排序(最新的在前面)
const sortedRecords = recordsArray.sort(
(a, b) => b.save_time - a.save_time
);
setPlayRecords(sortedRecords);
updatePlayRecords(allRecords);
} catch (error) {
console.error('获取播放记录失败:', error);
setPlayRecords([]);
@@ -50,6 +56,16 @@ export default function ContinueWatching({ className }: ContinueWatchingProps) {
};
fetchPlayRecords();
// 监听播放记录更新事件
const unsubscribe = subscribeToDataUpdates(
'playRecordsUpdated',
(newRecords: Record<string, PlayRecord>) => {
updatePlayRecords(newRecords);
}
);
return unsubscribe;
}, []);
// 如果没有播放记录,则不渲染组件

View File

@@ -1,9 +1,17 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { CheckCircle, Heart, Link, PlayCircleIcon } from 'lucide-react';
import Image from 'next/image';
import { useRouter } from 'next/navigation';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { deletePlayRecord, isFavorited, toggleFavorite } from '@/lib/db.client';
import {
deletePlayRecord,
generateStorageKey,
isFavorited,
subscribeToDataUpdates,
toggleFavorite,
} from '@/lib/db.client';
import { SearchResult } from '@/lib/types';
import { ImagePlaceholder } from '@/components/ImagePlaceholder';
@@ -103,6 +111,7 @@ export default function VideoCard({
// 获取收藏状态
useEffect(() => {
if (from === 'douban' || !actualSource || !actualId) return;
const fetchFavoriteStatus = async () => {
try {
const fav = await isFavorited(actualSource, actualId);
@@ -111,7 +120,21 @@ export default function VideoCard({
throw new Error('检查收藏状态失败');
}
};
fetchFavoriteStatus();
// 监听收藏状态更新事件
const storageKey = generateStorageKey(actualSource, actualId);
const unsubscribe = subscribeToDataUpdates(
'favoritesUpdated',
(newFavorites: Record<string, any>) => {
// 检查当前项目是否在新的收藏列表中
const isNowFavorited = !!newFavorites[storageKey];
setFavorited(isNowFavorited);
}
);
return unsubscribe;
}, [from, actualSource, actualId]);
const handleToggleFavorite = useCallback(