搜索增加部分缓存快速启动机制
This commit is contained in:
+88
-82
@@ -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 () => {
|
||||
|
||||
Reference in New Issue
Block a user