From fe32a9afe42aa3d295ce449d38825166f11e577a Mon Sep 17 00:00:00 2001 From: mtvpls Date: Wed, 29 Apr 2026 16:28:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E9=AB=98=E7=94=B5=E5=AD=90=E4=B9=A6?= =?UTF-8?q?=E6=BA=90=E6=8E=A2=E6=B5=8B=E7=A8=B3=E5=AE=9A=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib/opds.client.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/lib/opds.client.ts b/src/lib/opds.client.ts index 9370497..121f286 100644 --- a/src/lib/opds.client.ts +++ b/src/lib/opds.client.ts @@ -50,6 +50,8 @@ interface ParsedFeed { const DEFAULT_TIMEOUT_MS = Number(process.env.OPDS_TIMEOUT_MS || 20000); const feedCache = new Map(); const sourceCapabilityCache = new Map(); +const SOURCE_CAPABILITY_SUCCESS_TTL_MS = 6 * 60 * 60 * 1000; +const SOURCE_CAPABILITY_FAILURE_TTL_MS = 30 * 1000; function asArray(value: T | T[] | undefined | null): T[] { if (!value) return []; @@ -291,8 +293,8 @@ async function getSourceById(sourceId: string): Promise { async function detectCapabilities(source: BookSource): Promise { const cached = sourceCapabilityCache.get(source.id); - const { cacheTTL } = await resolveOPDSConfig(); - if (cached && cached.expiresAt > Date.now()) return cached.data; + const now = Date.now(); + if (cached && cached.expiresAt > now) return cached.data; try { const feed = await getFeed(source); @@ -311,23 +313,29 @@ async function detectCapabilities(source: BookSource): Promise 0 ? 'navigation' : entryCount > 0 ? 'flat' : 'disabled', acquisitionTypes, - lastCheckedAt: Date.now(), + lastCheckedAt: now, }; - sourceCapabilityCache.set(source.id, { data, expiresAt: Date.now() + cacheTTL }); + sourceCapabilityCache.set(source.id, { data, expiresAt: now + SOURCE_CAPABILITY_SUCCESS_TTL_MS }); return data; } catch (error) { - const data: BookSourceCapabilities = { + const failureData: BookSourceCapabilities = { searchSupported: !!source.searchTemplate, catalogSupported: false, searchMode: source.searchTemplate ? 'template' : 'disabled', catalogMode: 'disabled', acquisitionTypes: [], - lastCheckedAt: Date.now(), + lastCheckedAt: now, lastError: (error as Error).message, }; - sourceCapabilityCache.set(source.id, { data, expiresAt: Date.now() + cacheTTL / 2 }); - return data; + + if (cached?.data && !cached.data.lastError) { + sourceCapabilityCache.set(source.id, { data: cached.data, expiresAt: now + SOURCE_CAPABILITY_FAILURE_TTL_MS }); + return cached.data; + } + + sourceCapabilityCache.set(source.id, { data: failureData, expiresAt: now + SOURCE_CAPABILITY_FAILURE_TTL_MS }); + return failureData; } }