mirror of
https://gitlab.com/soapbox-pub/ditto.git
synced 2025-12-06 03:19:46 +00:00
44 lines
1.3 KiB
TypeScript
44 lines
1.3 KiB
TypeScript
import { DOMParser } from '@b-fuze/deno-dom';
|
|
import Debug from '@soapbox/stickynotes/debug';
|
|
import tldts from 'tldts';
|
|
|
|
import { Conf } from '@/config.ts';
|
|
import { cachedFaviconsSizeGauge } from '@/metrics.ts';
|
|
import { SimpleLRU } from '@/utils/SimpleLRU.ts';
|
|
import { fetchWorker } from '@/workers/fetch.ts';
|
|
|
|
const debug = Debug('ditto:favicon');
|
|
|
|
const faviconCache = new SimpleLRU<string, URL>(
|
|
async (key, { signal }) => {
|
|
debug(`Fetching favicon ${key}`);
|
|
const tld = tldts.parse(key);
|
|
|
|
if (!tld.isIcann || tld.isIp || tld.isPrivate) {
|
|
throw new Error(`Invalid favicon domain: ${key}`);
|
|
}
|
|
|
|
const rootUrl = new URL('/', `https://${key}/`);
|
|
const response = await fetchWorker(rootUrl, { signal });
|
|
const html = await response.text();
|
|
|
|
const doc = new DOMParser().parseFromString(html, 'text/html');
|
|
const link = doc.querySelector('link[rel="icon"], link[rel="shortcut icon"]');
|
|
|
|
if (link) {
|
|
const href = link.getAttribute('href');
|
|
if (href) {
|
|
try {
|
|
return new URL(href);
|
|
} catch {
|
|
return new URL(href, rootUrl);
|
|
}
|
|
}
|
|
}
|
|
|
|
throw new Error(`Favicon not found: ${key}`);
|
|
},
|
|
{ ...Conf.caches.favicon, gauge: cachedFaviconsSizeGauge },
|
|
);
|
|
|
|
export { faviconCache };
|