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
+25 -5
View File
@@ -92,10 +92,27 @@ 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, {
headers: source.headers,
redirect: 'follow', redirect: 'follow',
cf: { cf: {
cacheEverything: true, cacheEverything: true,
@@ -103,9 +120,9 @@ async function handleWebsiteIcon(host: string): Promise<Response> {
}, },
} 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,
@@ -114,6 +131,9 @@ async function handleWebsiteIcon(host: string): Promise<Response> {
'Cache-Control': `public, max-age=${LIMITS.cache.iconTtlSeconds}`, 'Cache-Control': `public, max-age=${LIMITS.cache.iconTtlSeconds}`,
}, },
}); });
}
return handleNwFavicon();
} catch { } catch {
return handleNwFavicon(); return handleNwFavicon();
} }