搜索增加部分缓存快速启动机制

This commit is contained in:
mtvpls
2026-05-16 09:56:40 +08:00
parent 09fc63c116
commit 4f0a0db0fd
3 changed files with 137 additions and 88 deletions
+88 -82
View File
@@ -109,6 +109,13 @@ interface PlayFallbackRecommendation {
doubanId?: number;
}
interface SearchCachePayload {
status: 'complete' | 'partial';
results: SearchResult[];
query: string;
updatedAt: number;
}
function PlayPageClient() {
const LOCAL_TRANSCODER_BASE_URL = 'http://localhost:19080';
const router = useRouter();
@@ -3764,53 +3771,88 @@ function PlayPageClient() {
.slice(0, 12);
};
const readSearchCache = (query: string): SearchCachePayload | null => {
if (typeof window === 'undefined' || !query.trim()) {
return null;
}
try {
const cacheKey = `search_cache_${query.trim()}`;
const cached = sessionStorage.getItem(cacheKey);
if (!cached) return null;
const parsed = JSON.parse(cached) as SearchCachePayload;
if (
(parsed?.status === 'complete' || parsed?.status === 'partial') &&
Array.isArray(parsed.results)
) {
return parsed;
}
} catch (error) {
console.error('[Play] 读取缓存失败:', error);
}
return null;
};
const writeCompleteSearchCache = (query: string, results: SearchResult[]) => {
if (typeof window === 'undefined' || !query.trim()) return;
try {
const cacheKey = `search_cache_${query.trim()}`;
const payload: SearchCachePayload = {
status: 'complete',
results,
query: query.trim(),
updatedAt: Date.now(),
};
sessionStorage.setItem(cacheKey, JSON.stringify(payload));
} catch (error) {
console.error('[Play] 写入缓存失败:', error);
}
};
const filterSourcesForCurrentVideo = (items: SearchResult[]): SearchResult[] => {
return items.filter(
(result: SearchResult) =>
normalizeTitle(result.title).toLowerCase() ===
normalizeTitle(videoTitleRef.current).toLowerCase() &&
(videoYearRef.current
? result.year.toLowerCase() === videoYearRef.current.toLowerCase() ||
!result.year ||
result.year.trim() === '' ||
result.year === 'unknown' ||
!/^\d{4}$/.test(result.year)
: true) &&
(searchType
? getType(result) === searchType
: true)
);
};
const fetchSourcesData = async (query: string): Promise<SearchResult[]> => {
// 根据搜索词获取全部源信息
setHasCompletedSearchRequest(false);
setFallbackRecommendations([]);
let fallbackCachedResults: SearchResult[] = [];
try {
// 先检查 sessionStorage 中是否有缓存
const cacheKey = `search_cache_${query.trim()}`;
let results: SearchResult[] = [];
const cachedPayload = readSearchCache(query);
if (cachedPayload) {
console.log(`[Play] 使用 sessionStorage ${cachedPayload.status === 'partial' ? '临时' : '完整'}缓存的搜索结果`);
setFallbackRecommendations(buildFallbackRecommendations(cachedPayload.results, query));
if (typeof window !== 'undefined') {
try {
const cached = sessionStorage.getItem(cacheKey);
if (cached) {
console.log('[Play] 使用 sessionStorage 缓存的搜索结果');
const cachedData = JSON.parse(cached) as SearchResult[];
const cachedResults = filterSourcesForCurrentVideo(cachedPayload.results);
fallbackCachedResults = cachedResults;
setAvailableSources(applyCorrectionsToSources(cachedResults));
setHasCompletedSearchRequest(true);
setFallbackRecommendations(buildFallbackRecommendations(cachedData, query));
// 处理缓存的搜索结果,根据规则过滤
results = cachedData.filter(
(result: SearchResult) =>
normalizeTitle(result.title).toLowerCase() ===
normalizeTitle(videoTitleRef.current).toLowerCase() &&
(videoYearRef.current
? result.year.toLowerCase() === videoYearRef.current.toLowerCase() ||
!result.year ||
result.year.trim() === '' ||
result.year === 'unknown' ||
!/^\d{4}$/.test(result.year)
: true) &&
(searchType
? getType(result) === searchType
: true)
);
setAvailableSources(applyCorrectionsToSources(results));
return results;
}
} catch (error) {
console.error('[Play] 读取缓存失败:', error);
// 继续执行 API 调用
if (cachedPayload.status === 'complete') {
setHasCompletedSearchRequest(true);
return cachedResults;
}
}
// 如果没有缓存,调用 API
// 没有缓存或只有 partial 缓存时,重新请求完整搜索结果
const response = await fetch(
`/api/search?q=${encodeURIComponent(query.trim())}`
);
@@ -3820,29 +3862,18 @@ function PlayPageClient() {
const data = await response.json();
const allResults = (data.results || []) as SearchResult[];
writeCompleteSearchCache(query, allResults);
setHasCompletedSearchRequest(true);
setFallbackRecommendations(buildFallbackRecommendations(allResults, query));
// 处理搜索结果,根据规则过滤
results = allResults.filter(
(result: SearchResult) =>
normalizeTitle(result.title).toLowerCase() ===
normalizeTitle(videoTitleRef.current).toLowerCase() &&
(videoYearRef.current
? result.year.toLowerCase() === videoYearRef.current.toLowerCase() ||
!result.year ||
result.year.trim() === '' ||
result.year === 'unknown' ||
!/^\d{4}$/.test(result.year)
: true) &&
(searchType
? getType(result) === searchType
: true)
);
const results = filterSourcesForCurrentVideo(allResults);
setAvailableSources(applyCorrectionsToSources(results));
return results;
} catch (err) {
setSourceSearchError(err instanceof Error ? err.message : '搜索失败');
if (fallbackCachedResults.length > 0) {
return fallbackCachedResults;
}
setAvailableSources([]);
return [];
} finally {
@@ -3851,39 +3882,14 @@ function PlayPageClient() {
};
const getCachedSourcesData = (query: string): SearchResult[] => {
if (typeof window === 'undefined' || !query.trim()) {
const cachedPayload = readSearchCache(query);
if (!cachedPayload) {
return [];
}
try {
const cacheKey = `search_cache_${query.trim()}`;
const cached = sessionStorage.getItem(cacheKey);
if (!cached) {
return [];
}
const cachedData = JSON.parse(cached);
const results = cachedData.filter(
(result: SearchResult) =>
normalizeTitle(result.title).toLowerCase() ===
normalizeTitle(videoTitleRef.current).toLowerCase() &&
(videoYearRef.current
? result.year.toLowerCase() === videoYearRef.current.toLowerCase() ||
!result.year ||
result.year.trim() === '' ||
result.year === 'unknown' ||
!/^\d{4}$/.test(result.year)
: true) &&
(searchType
? getType(result) === searchType
: true)
);
return applyCorrectionsToSources(results);
} catch (error) {
console.error('[Play] 读取缓存失败:', error);
return [];
}
return applyCorrectionsToSources(
filterSourcesForCurrentVideo(cachedPayload.results)
);
};
const initAll = async () => {