feat: update icon fetching logic to support multiple upstream sources

This commit is contained in:
shuaiplus
2026-03-18 22:37:37 +08:00
parent bb3fe41330
commit 8bc43b8f0c
2 changed files with 40 additions and 20 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v5
with: with:
fetch-depth: 0 fetch-depth: 0
+39 -19
View File
@@ -92,28 +92,48 @@ async function handleWebsiteIcon(host: string): Promise<Response> {
const normalizedHost = normalizeIconHost(host); const normalizedHost = normalizeIconHost(host);
if (!normalizedHost) return handleNwFavicon(); if (!normalizedHost) return handleNwFavicon();
const upstream = `https://favicon.im/${encodeURIComponent(normalizedHost)}`; const encodedHost = encodeURIComponent(normalizedHost);
const requestHeaders = { 'User-Agent': 'NodeWarden/1.0' };
const upstreamSources: Array<{ url: string; headers?: HeadersInit }> = [
{
url: `https://icons.bitwarden.net/${encodedHost}/icon.png`,
headers: requestHeaders,
},
{
url: `https://favicon.im/${encodedHost}`,
headers: requestHeaders,
},
{
url: `https://icons.duckduckgo.com/ip3/${encodedHost}.ico`,
headers: requestHeaders,
},
];
try { try {
const resp = await fetch(upstream, { for (const source of upstreamSources) {
headers: { 'User-Agent': 'NodeWarden/1.0' }, const resp = await fetch(source.url, {
redirect: 'follow', headers: source.headers,
cf: { redirect: 'follow',
cacheEverything: true, cf: {
cacheTtl: LIMITS.cache.iconTtlSeconds, cacheEverything: true,
}, cacheTtl: LIMITS.cache.iconTtlSeconds,
} as RequestInit & { cf: { cacheEverything: boolean; cacheTtl: number } }); },
} as RequestInit & { cf: { cacheEverything: boolean; cacheTtl: number } });
if (!resp.ok) return handleNwFavicon(); if (!resp.ok) continue;
const contentType = String(resp.headers.get('Content-Type') || '').toLowerCase(); const contentType = String(resp.headers.get('Content-Type') || '').toLowerCase();
if (!contentType.startsWith('image/')) return handleNwFavicon(); if (!contentType.startsWith('image/')) continue;
return new Response(resp.body, { return new Response(resp.body, {
status: 200, status: 200,
headers: { headers: {
'Content-Type': resp.headers.get('Content-Type') || 'image/png', 'Content-Type': resp.headers.get('Content-Type') || 'image/png',
'Cache-Control': `public, max-age=${LIMITS.cache.iconTtlSeconds}`, 'Cache-Control': `public, max-age=${LIMITS.cache.iconTtlSeconds}`,
}, },
}); });
}
return handleNwFavicon();
} catch { } catch {
return handleNwFavicon(); return handleNwFavicon();
} }