mirror of
https://github.com/MoonTechLab/LunaTV.git
synced 2026-02-21 17:24:41 +08:00
feat: unify local cache
This commit is contained in:
@@ -9,13 +9,14 @@ import { useRouter, useSearchParams } from 'next/navigation';
|
||||
import { Suspense, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
deleteFavorite,
|
||||
deletePlayRecord,
|
||||
generateStorageKey,
|
||||
getAllPlayRecords,
|
||||
isFavorited,
|
||||
saveFavorite,
|
||||
savePlayRecord,
|
||||
subscribeToDataUpdates,
|
||||
toggleFavorite,
|
||||
} from '@/lib/db.client';
|
||||
import { SearchResult } from '@/lib/types';
|
||||
import { getVideoResolutionFromM3u8, processImageUrl } from '@/lib/utils';
|
||||
@@ -944,10 +945,13 @@ function PlayPageClient() {
|
||||
return;
|
||||
|
||||
try {
|
||||
const newState = await toggleFavorite(
|
||||
currentSourceRef.current,
|
||||
currentIdRef.current,
|
||||
{
|
||||
if (favorited) {
|
||||
// 如果已收藏,删除收藏
|
||||
await deleteFavorite(currentSourceRef.current, currentIdRef.current);
|
||||
setFavorited(false);
|
||||
} else {
|
||||
// 如果未收藏,添加收藏
|
||||
await saveFavorite(currentSourceRef.current, currentIdRef.current, {
|
||||
title: videoTitleRef.current,
|
||||
source_name: detailRef.current?.source_name || '',
|
||||
year: detailRef.current?.year,
|
||||
@@ -955,9 +959,9 @@ function PlayPageClient() {
|
||||
total_episodes: detailRef.current?.episodes.length || 1,
|
||||
save_time: Date.now(),
|
||||
search_title: searchTitle,
|
||||
}
|
||||
);
|
||||
setFavorited(newState);
|
||||
});
|
||||
setFavorited(true);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error('切换收藏失败:', err);
|
||||
}
|
||||
|
||||
@@ -6,11 +6,12 @@ import { useRouter } from 'next/navigation';
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
|
||||
import {
|
||||
deleteFavorite,
|
||||
deletePlayRecord,
|
||||
generateStorageKey,
|
||||
isFavorited,
|
||||
saveFavorite,
|
||||
subscribeToDataUpdates,
|
||||
toggleFavorite,
|
||||
} from '@/lib/db.client';
|
||||
import { SearchResult } from '@/lib/types';
|
||||
import { processImageUrl } from '@/lib/utils';
|
||||
@@ -144,15 +145,22 @@ export default function VideoCard({
|
||||
e.stopPropagation();
|
||||
if (from === 'douban' || !actualSource || !actualId) return;
|
||||
try {
|
||||
const newState = await toggleFavorite(actualSource, actualId, {
|
||||
title: actualTitle,
|
||||
source_name: source_name || '',
|
||||
year: actualYear || '',
|
||||
cover: actualPoster,
|
||||
total_episodes: actualEpisodes ?? 1,
|
||||
save_time: Date.now(),
|
||||
});
|
||||
setFavorited(newState);
|
||||
if (favorited) {
|
||||
// 如果已收藏,删除收藏
|
||||
await deleteFavorite(actualSource, actualId);
|
||||
setFavorited(false);
|
||||
} else {
|
||||
// 如果未收藏,添加收藏
|
||||
await saveFavorite(actualSource, actualId, {
|
||||
title: actualTitle,
|
||||
source_name: source_name || '',
|
||||
year: actualYear || '',
|
||||
cover: actualPoster,
|
||||
total_episodes: actualEpisodes ?? 1,
|
||||
save_time: Date.now(),
|
||||
});
|
||||
setFavorited(true);
|
||||
}
|
||||
} catch (err) {
|
||||
throw new Error('切换收藏状态失败');
|
||||
}
|
||||
@@ -166,6 +174,7 @@ export default function VideoCard({
|
||||
actualYear,
|
||||
actualPoster,
|
||||
actualEpisodes,
|
||||
favorited,
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -380,7 +380,7 @@ export async function getAllPlayRecords(): Promise<Record<string, PlayRecord>> {
|
||||
}
|
||||
|
||||
// D1 存储模式:使用混合缓存策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 优先从缓存获取数据
|
||||
const cachedData = cacheManager.getCachedPlayRecords();
|
||||
|
||||
@@ -419,11 +419,6 @@ export async function getAllPlayRecords(): Promise<Record<string, PlayRecord>> {
|
||||
}
|
||||
}
|
||||
|
||||
// 其他数据库存储模式:直接从 API 获取
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
return fetchFromApi<Record<string, PlayRecord>>(`/api/playrecords`);
|
||||
}
|
||||
|
||||
// localstorage 模式
|
||||
try {
|
||||
const raw = localStorage.getItem(PLAY_RECORDS_KEY);
|
||||
@@ -447,7 +442,7 @@ export async function savePlayRecord(
|
||||
const key = generateStorageKey(source, id);
|
||||
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
const cachedRecords = cacheManager.getCachedPlayRecords() || {};
|
||||
cachedRecords[key] = record;
|
||||
@@ -480,24 +475,6 @@ export async function savePlayRecord(
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式:直接通过 API 保存
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
const res = await fetch('/api/playrecords', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ key, record }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`保存播放记录失败: ${res.status}`);
|
||||
} catch (err) {
|
||||
console.error('保存播放记录到数据库失败:', err);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localstorage 模式
|
||||
if (typeof window === 'undefined') {
|
||||
console.warn('无法在服务端保存播放记录到 localStorage');
|
||||
@@ -508,6 +485,11 @@ export async function savePlayRecord(
|
||||
const allRecords = await getAllPlayRecords();
|
||||
allRecords[key] = record;
|
||||
localStorage.setItem(PLAY_RECORDS_KEY, JSON.stringify(allRecords));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('playRecordsUpdated', {
|
||||
detail: allRecords,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('保存播放记录失败:', err);
|
||||
throw err;
|
||||
@@ -525,7 +507,7 @@ export async function deletePlayRecord(
|
||||
const key = generateStorageKey(source, id);
|
||||
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
const cachedRecords = cacheManager.getCachedPlayRecords() || {};
|
||||
delete cachedRecords[key];
|
||||
@@ -554,23 +536,6 @@ export async function deletePlayRecord(
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式:直接通过 API 删除
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`/api/playrecords?key=${encodeURIComponent(key)}`,
|
||||
{
|
||||
method: 'DELETE',
|
||||
}
|
||||
);
|
||||
if (!res.ok) throw new Error(`删除播放记录失败: ${res.status}`);
|
||||
} catch (err) {
|
||||
console.error('删除播放记录到数据库失败:', err);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localstorage 模式
|
||||
if (typeof window === 'undefined') {
|
||||
console.warn('无法在服务端删除播放记录到 localStorage');
|
||||
@@ -581,7 +546,11 @@ export async function deletePlayRecord(
|
||||
const allRecords = await getAllPlayRecords();
|
||||
delete allRecords[key];
|
||||
localStorage.setItem(PLAY_RECORDS_KEY, JSON.stringify(allRecords));
|
||||
console.log('播放记录已删除:', key);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('playRecordsUpdated', {
|
||||
detail: allRecords,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('删除播放记录失败:', err);
|
||||
throw err;
|
||||
@@ -601,7 +570,7 @@ export async function getSearchHistory(): Promise<string[]> {
|
||||
}
|
||||
|
||||
// D1 存储模式:使用混合缓存策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 优先从缓存获取数据
|
||||
const cachedData = cacheManager.getCachedSearchHistory();
|
||||
|
||||
@@ -638,16 +607,6 @@ export async function getSearchHistory(): Promise<string[]> {
|
||||
}
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
return fetchFromApi<string[]>(`/api/searchhistory`);
|
||||
} catch (err) {
|
||||
console.error('获取搜索历史失败:', err);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
try {
|
||||
const raw = localStorage.getItem(SEARCH_HISTORY_KEY);
|
||||
@@ -670,7 +629,7 @@ export async function addSearchHistory(keyword: string): Promise<void> {
|
||||
if (!trimmed) return;
|
||||
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
const cachedHistory = cacheManager.getCachedSearchHistory() || [];
|
||||
const newHistory = [trimmed, ...cachedHistory.filter((k) => k !== trimmed)];
|
||||
@@ -703,22 +662,6 @@ export async function addSearchHistory(keyword: string): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
await fetch('/api/searchhistory', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ keyword: trimmed }),
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('保存搜索历史失败:', err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
@@ -730,6 +673,11 @@ export async function addSearchHistory(keyword: string): Promise<void> {
|
||||
newHistory.length = SEARCH_HISTORY_LIMIT;
|
||||
}
|
||||
localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(newHistory));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('searchHistoryUpdated', {
|
||||
detail: newHistory,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('保存搜索历史失败:', err);
|
||||
}
|
||||
@@ -741,7 +689,7 @@ export async function addSearchHistory(keyword: string): Promise<void> {
|
||||
*/
|
||||
export async function clearSearchHistory(): Promise<void> {
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
cacheManager.cacheSearchHistory([]);
|
||||
|
||||
@@ -764,21 +712,14 @@ export async function clearSearchHistory(): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
await fetch(`/api/searchhistory`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('清空搜索历史失败:', err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.removeItem(SEARCH_HISTORY_KEY);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('searchHistoryUpdated', {
|
||||
detail: [],
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -790,7 +731,7 @@ export async function deleteSearchHistory(keyword: string): Promise<void> {
|
||||
if (!trimmed) return;
|
||||
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
const cachedHistory = cacheManager.getCachedSearchHistory() || [];
|
||||
const newHistory = cachedHistory.filter((k) => k !== trimmed);
|
||||
@@ -818,18 +759,6 @@ export async function deleteSearchHistory(keyword: string): Promise<void> {
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
await fetch(`/api/searchhistory?keyword=${encodeURIComponent(trimmed)}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('删除搜索历史失败:', err);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
|
||||
@@ -837,6 +766,11 @@ export async function deleteSearchHistory(keyword: string): Promise<void> {
|
||||
const history = await getSearchHistory();
|
||||
const newHistory = history.filter((k) => k !== trimmed);
|
||||
localStorage.setItem(SEARCH_HISTORY_KEY, JSON.stringify(newHistory));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('searchHistoryUpdated', {
|
||||
detail: newHistory,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('删除搜索历史失败:', err);
|
||||
}
|
||||
@@ -855,7 +789,7 @@ export async function getAllFavorites(): Promise<Record<string, Favorite>> {
|
||||
}
|
||||
|
||||
// D1 存储模式:使用混合缓存策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 优先从缓存获取数据
|
||||
const cachedData = cacheManager.getCachedFavorites();
|
||||
|
||||
@@ -894,11 +828,6 @@ export async function getAllFavorites(): Promise<Record<string, Favorite>> {
|
||||
}
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
return fetchFromApi<Record<string, Favorite>>(`/api/favorites`);
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
try {
|
||||
const raw = localStorage.getItem(FAVORITES_KEY);
|
||||
@@ -922,7 +851,7 @@ export async function saveFavorite(
|
||||
const key = generateStorageKey(source, id);
|
||||
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
const cachedFavorites = cacheManager.getCachedFavorites() || {};
|
||||
cachedFavorites[key] = favorite;
|
||||
@@ -952,24 +881,6 @@ export async function saveFavorite(
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
const res = await fetch('/api/favorites', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ key, favorite }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`保存收藏失败: ${res.status}`);
|
||||
} catch (err) {
|
||||
console.error('保存收藏到数据库失败:', err);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') {
|
||||
console.warn('无法在服务端保存收藏到 localStorage');
|
||||
@@ -980,6 +891,11 @@ export async function saveFavorite(
|
||||
const allFavorites = await getAllFavorites();
|
||||
allFavorites[key] = favorite;
|
||||
localStorage.setItem(FAVORITES_KEY, JSON.stringify(allFavorites));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('favoritesUpdated', {
|
||||
detail: allFavorites,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('保存收藏失败:', err);
|
||||
throw err;
|
||||
@@ -997,7 +913,7 @@ export async function deleteFavorite(
|
||||
const key = generateStorageKey(source, id);
|
||||
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
const cachedFavorites = cacheManager.getCachedFavorites() || {};
|
||||
delete cachedFavorites[key];
|
||||
@@ -1023,20 +939,6 @@ export async function deleteFavorite(
|
||||
return;
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
const res = await fetch(`/api/favorites?key=${encodeURIComponent(key)}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
if (!res.ok) throw new Error(`删除收藏失败: ${res.status}`);
|
||||
} catch (err) {
|
||||
console.error('删除收藏到数据库失败:', err);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') {
|
||||
console.warn('无法在服务端删除收藏到 localStorage');
|
||||
@@ -1047,6 +949,11 @@ export async function deleteFavorite(
|
||||
const allFavorites = await getAllFavorites();
|
||||
delete allFavorites[key];
|
||||
localStorage.setItem(FAVORITES_KEY, JSON.stringify(allFavorites));
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('favoritesUpdated', {
|
||||
detail: allFavorites,
|
||||
})
|
||||
);
|
||||
} catch (err) {
|
||||
console.error('删除收藏失败:', err);
|
||||
throw err;
|
||||
@@ -1055,7 +962,7 @@ export async function deleteFavorite(
|
||||
|
||||
/**
|
||||
* 判断是否已收藏。
|
||||
* D1 存储模式下优先使用缓存数据。
|
||||
* D1 存储模式下使用混合缓存策略:优先返回缓存数据,后台异步同步最新数据。
|
||||
*/
|
||||
export async function isFavorited(
|
||||
source: string,
|
||||
@@ -1063,35 +970,42 @@ export async function isFavorited(
|
||||
): Promise<boolean> {
|
||||
const key = generateStorageKey(source, id);
|
||||
|
||||
// D1 存储模式:优先使用缓存
|
||||
if (STORAGE_TYPE === 'd1') {
|
||||
const cachedFavorites = cacheManager.getCachedFavorites();
|
||||
if (cachedFavorites) {
|
||||
return !!cachedFavorites[key];
|
||||
}
|
||||
|
||||
// 缓存为空时从 API 获取
|
||||
try {
|
||||
const res = await fetch(`/api/favorites?key=${encodeURIComponent(key)}`);
|
||||
if (!res.ok) return false;
|
||||
const data = await res.json();
|
||||
return !!data;
|
||||
} catch (err) {
|
||||
console.error('检查收藏状态失败:', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 其他数据库存储模式
|
||||
// D1 存储模式:使用混合缓存策略
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
try {
|
||||
const res = await fetch(`/api/favorites?key=${encodeURIComponent(key)}`);
|
||||
if (!res.ok) return false;
|
||||
const data = await res.json();
|
||||
return !!data;
|
||||
} catch (err) {
|
||||
console.error('检查收藏状态失败:', err);
|
||||
return false;
|
||||
const cachedFavorites = cacheManager.getCachedFavorites();
|
||||
|
||||
if (cachedFavorites) {
|
||||
// 返回缓存数据,同时后台异步更新
|
||||
fetchFromApi<Record<string, Favorite>>(`/api/favorites`)
|
||||
.then((freshData) => {
|
||||
// 只有数据真正不同时才更新缓存
|
||||
if (JSON.stringify(cachedFavorites) !== JSON.stringify(freshData)) {
|
||||
cacheManager.cacheFavorites(freshData);
|
||||
// 触发数据更新事件
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('favoritesUpdated', {
|
||||
detail: freshData,
|
||||
})
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.warn('后台同步收藏失败:', err);
|
||||
});
|
||||
|
||||
return !!cachedFavorites[key];
|
||||
} else {
|
||||
// 缓存为空,直接从 API 获取并缓存
|
||||
try {
|
||||
const freshData = await fetchFromApi<Record<string, Favorite>>(
|
||||
`/api/favorites`
|
||||
);
|
||||
cacheManager.cacheFavorites(freshData);
|
||||
return !!freshData[key];
|
||||
} catch (err) {
|
||||
console.error('检查收藏状态失败:', err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1100,43 +1014,33 @@ export async function isFavorited(
|
||||
return !!allFavorites[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* 切换收藏状态
|
||||
* 返回切换后的状态(true = 已收藏)
|
||||
*/
|
||||
export async function toggleFavorite(
|
||||
source: string,
|
||||
id: string,
|
||||
favoriteData?: Favorite
|
||||
): Promise<boolean> {
|
||||
const already = await isFavorited(source, id);
|
||||
|
||||
if (already) {
|
||||
await deleteFavorite(source, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!favoriteData) {
|
||||
throw new Error('收藏数据缺失');
|
||||
}
|
||||
|
||||
await saveFavorite(source, id, favoriteData);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空全部播放记录
|
||||
* D1 存储模式下使用乐观更新:先更新缓存,再异步同步到数据库。
|
||||
*/
|
||||
export async function clearAllPlayRecords(): Promise<void> {
|
||||
// 数据库模式
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
cacheManager.cachePlayRecords({});
|
||||
|
||||
// 触发立即更新事件
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('playRecordsUpdated', {
|
||||
detail: {},
|
||||
})
|
||||
);
|
||||
|
||||
// 异步同步到数据库
|
||||
try {
|
||||
await fetch(`/api/playrecords`, {
|
||||
const res = await fetch(`/api/playrecords`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
if (!res.ok) throw new Error(`清空播放记录失败: ${res.status}`);
|
||||
} catch (err) {
|
||||
console.error('清空播放记录失败:', err);
|
||||
await handleDatabaseOperationFailure('playRecords', err);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1144,21 +1048,40 @@ export async function clearAllPlayRecords(): Promise<void> {
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.removeItem(PLAY_RECORDS_KEY);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('playRecordsUpdated', {
|
||||
detail: {},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空全部收藏
|
||||
* D1 存储模式下使用乐观更新:先更新缓存,再异步同步到数据库。
|
||||
*/
|
||||
export async function clearAllFavorites(): Promise<void> {
|
||||
// 数据库模式
|
||||
// D1 存储模式:乐观更新策略
|
||||
if (STORAGE_TYPE !== 'localstorage') {
|
||||
// 立即更新缓存
|
||||
cacheManager.cacheFavorites({});
|
||||
|
||||
// 触发立即更新事件
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('favoritesUpdated', {
|
||||
detail: {},
|
||||
})
|
||||
);
|
||||
|
||||
// 异步同步到数据库
|
||||
try {
|
||||
await fetch(`/api/favorites`, {
|
||||
const res = await fetch(`/api/favorites`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
if (!res.ok) throw new Error(`清空收藏失败: ${res.status}`);
|
||||
} catch (err) {
|
||||
console.error('清空收藏失败:', err);
|
||||
await handleDatabaseOperationFailure('favorites', err);
|
||||
throw err;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -1166,6 +1089,11 @@ export async function clearAllFavorites(): Promise<void> {
|
||||
// localStorage 模式
|
||||
if (typeof window === 'undefined') return;
|
||||
localStorage.removeItem(FAVORITES_KEY);
|
||||
window.dispatchEvent(
|
||||
new CustomEvent('favoritesUpdated', {
|
||||
detail: {},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// ---------------- 混合缓存辅助函数 ----------------
|
||||
|
||||
@@ -129,27 +129,6 @@ export class DbManager {
|
||||
return favorite !== null;
|
||||
}
|
||||
|
||||
async toggleFavorite(
|
||||
userName: string,
|
||||
source: string,
|
||||
id: string,
|
||||
favoriteData?: Favorite
|
||||
): Promise<boolean> {
|
||||
const isFav = await this.isFavorited(userName, source, id);
|
||||
|
||||
if (isFav) {
|
||||
await this.deleteFavorite(userName, source, id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (favoriteData) {
|
||||
await this.saveFavorite(userName, source, id, favoriteData);
|
||||
return true;
|
||||
}
|
||||
|
||||
throw new Error('Favorite data is required when adding to favorites');
|
||||
}
|
||||
|
||||
// ---------- 用户相关 ----------
|
||||
async registerUser(userName: string, password: string): Promise<void> {
|
||||
await this.storage.registerUser(userName, password);
|
||||
|
||||
Reference in New Issue
Block a user