2022-10-09 04:48:00 +02:00
|
|
|
import fetch from 'node-fetch';
|
|
|
|
|
import { parse } from 'node-html-parser';
|
2022-10-09 18:23:30 +02:00
|
|
|
import { TimeoutController } from 'timeout-abort-controller';
|
2022-10-09 04:48:00 +02:00
|
|
|
|
|
|
|
|
const filterLinks = links => {
|
|
|
|
|
const attrs = ['rel', 'href', 'sizes'];
|
|
|
|
|
const filterAttrs = link =>
|
|
|
|
|
attrs.reduce((total, attr) => ({ ...total, [attr]: link.getAttribute(attr) }), {});
|
|
|
|
|
return [...links]
|
|
|
|
|
.filter(link => link.getAttribute('href') && link.getAttribute('rel').includes('icon'))
|
|
|
|
|
.map(filterAttrs);
|
|
|
|
|
};
|
|
|
|
|
|
2022-10-09 18:23:30 +02:00
|
|
|
const formatValues = (url, icons) => {
|
2022-10-09 04:48:00 +02:00
|
|
|
const getOrigin = url => new URL(url).origin;
|
|
|
|
|
return icons.map(({ sizes, href, rel }) => ({
|
|
|
|
|
size: parseInt(sizes?.split('x')[0]) || undefined,
|
|
|
|
|
href: href[0] === '/' ? `${getOrigin(url)}${href}` : href,
|
|
|
|
|
rel,
|
|
|
|
|
}));
|
|
|
|
|
};
|
|
|
|
|
|
2022-10-09 18:23:30 +02:00
|
|
|
const fetchLinks = async url => {
|
|
|
|
|
// Time out the favicon request if it doesn't respond in a reasonable time.
|
|
|
|
|
const tc = new TimeoutController(3000);
|
|
|
|
|
|
|
|
|
|
let links = [];
|
2022-10-09 04:48:00 +02:00
|
|
|
|
|
|
|
|
try {
|
2022-10-09 18:23:30 +02:00
|
|
|
const html = await (await fetch(url, { signal: tc.signal })).text();
|
|
|
|
|
links = parse(html).querySelectorAll('head link');
|
2022-10-09 04:48:00 +02:00
|
|
|
} catch (e) {
|
|
|
|
|
// eslint-disable-next-line no-console
|
|
|
|
|
console.log(`Could not fetch favicon for url ${url}`, e);
|
|
|
|
|
} finally {
|
2022-10-09 18:23:30 +02:00
|
|
|
tc.clear();
|
2022-10-09 04:48:00 +02:00
|
|
|
}
|
2022-10-09 18:23:30 +02:00
|
|
|
|
|
|
|
|
return links;
|
2022-10-09 04:48:00 +02:00
|
|
|
};
|
|
|
|
|
|
2022-10-09 18:23:30 +02:00
|
|
|
const getIcons = async url => {
|
|
|
|
|
const links = await fetchLinks(url);
|
|
|
|
|
const icons = filterLinks(links);
|
|
|
|
|
return formatValues(url, icons);
|
|
|
|
|
};
|
2022-10-09 04:48:00 +02:00
|
|
|
|
|
|
|
|
export default async domain => {
|
|
|
|
|
const icons = await getIcons(`https://${domain}`);
|
|
|
|
|
|
|
|
|
|
if (icons.length && icons.length > 0) {
|
|
|
|
|
return icons[0]?.href;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
};
|