feat: user control fluid search

This commit is contained in:
shinya
2025-08-17 17:32:42 +08:00
parent 714c4e0e9c
commit 98835391b5
20 changed files with 312 additions and 246 deletions

View File

@@ -15,6 +15,7 @@ export interface AdminConfig {
DoubanImageProxyType: string;
DoubanImageProxy: string;
DisableYellowFilter: boolean;
FluidSearch: boolean;
};
UserConfig: {
AllowRegister: boolean;

View File

@@ -168,6 +168,8 @@ async function getInitConfig(configFile: string, subConfig: {
DoubanImageProxy: process.env.NEXT_PUBLIC_DOUBAN_IMAGE_PROXY || '',
DisableYellowFilter:
process.env.NEXT_PUBLIC_DISABLE_YELLOW_FILTER === 'true',
FluidSearch:
process.env.NEXT_PUBLIC_FLUID_SEARCH !== 'false',
},
UserConfig: {
AllowRegister: process.env.NEXT_PUBLIC_ENABLE_REGISTER === 'true',

View File

@@ -1,7 +1,9 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import { API_CONFIG, ApiSite, getConfig } from '@/lib/config';
import { getCachedSearchPage, setCachedSearchPage } from '@/lib/search-cache';
import { SearchResult } from '@/lib/types';
import { cleanHtmlTags } from '@/lib/utils';
import { getCachedSearchPage, setCachedSearchPage } from '@/lib/search-cache';
interface ApiSearchItem {
vod_id: string;
@@ -24,17 +26,14 @@ async function searchWithCache(
query: string,
page: number,
url: string,
timeoutMs: number = 5000
timeoutMs = 5000
): Promise<{ results: SearchResult[]; pageCount?: number }> {
// 先查缓存
const cached = getCachedSearchPage(apiSite.key, query, page);
if (cached) {
if (cached.status === 'ok') {
console.log(`🎯 缓存命中 [${apiSite.key}] query="${query}" page=${page} status=ok results=${cached.data.length}`);
return { results: cached.data, pageCount: cached.pageCount };
} else {
console.log(`🚫 缓存命中 [${apiSite.key}] query="${query}" page=${page} status=${cached.status} - 返回空结果`);
// timeout / forbidden 命中缓存,直接返回空
return { results: [] };
}
}
@@ -144,7 +143,7 @@ export async function searchFromApi(
// 使用新的缓存搜索函数处理第一页
const firstPageResult = await searchWithCache(apiSite, query, 1, apiUrl, 5000);
let results = firstPageResult.results;
const results = firstPageResult.results;
const pageCountFromFirst = firstPageResult.pageCount;
const config = await getConfig();

View File

@@ -66,10 +66,7 @@ export function setCachedSearchPage(
// 惰性清理:每次写入时检查是否需要清理
const now = Date.now();
if (now - lastCleanupTime > CACHE_CLEANUP_INTERVAL_MS) {
const stats = performCacheCleanup();
if (stats.expired > 0 || stats.sizeLimited > 0) {
console.log(`🧹 惰性缓存清理: 删除过期${stats.expired}项,删除超限${stats.sizeLimited}项,剩余${stats.total}`);
}
performCacheCleanup();
}
const key = makeSearchCacheKey(sourceKey, query, page);
@@ -87,7 +84,6 @@ export function setCachedSearchPage(
function ensureAutoCleanupStarted(): void {
if (!cleanupTimer) {
startAutoCleanup();
console.log(`🚀 启动自动缓存清理,间隔${CACHE_CLEANUP_INTERVAL_MS / 1000}秒,最大缓存${MAX_CACHE_SIZE}`);
}
}
@@ -138,10 +134,7 @@ function startAutoCleanup(): void {
if (cleanupTimer) return; // 避免重复启动
cleanupTimer = setInterval(() => {
const stats = performCacheCleanup();
if (stats.expired > 0 || stats.sizeLimited > 0) {
console.log(`🧹 自动缓存清理: 删除过期${stats.expired}项,删除超限${stats.sizeLimited}项,剩余${stats.total}`);
}
performCacheCleanup();
}, CACHE_CLEANUP_INTERVAL_MS);
// 在 Node.js 环境中避免阻止程序退出