mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-09 07:03:25 +00:00
97 lines
2.8 KiB
TypeScript
97 lines
2.8 KiB
TypeScript
import { NextApiRequest, NextApiResponse } from 'next';
|
|
import { createReadStream } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import {
|
|
downloadImageFromUrl,
|
|
getFavicon,
|
|
makeRequestWithUserAgent,
|
|
} from 'lib/request';
|
|
import { Favicon } from 'types/types';
|
|
import { buildFaviconUrl, findFaviconPath } from 'lib/url';
|
|
import { convertBase64ToBuffer, isBase64Image, isImage } from 'lib/image';
|
|
|
|
export default async function handler(
|
|
req: NextApiRequest,
|
|
res: NextApiResponse,
|
|
) {
|
|
const urlParam = (req.query?.urlParam as string) || '';
|
|
if (!urlParam) {
|
|
throw new Error('URL is missing');
|
|
}
|
|
|
|
const faviconRequestUrl = buildFaviconUrl(urlParam, '/favicon.ico');
|
|
try {
|
|
return sendImage(res, await getFavicon(faviconRequestUrl));
|
|
} catch (error) {
|
|
console.error(
|
|
'[Favicon]',
|
|
`[first: ${faviconRequestUrl}]`,
|
|
'Unable to retrieve favicon from favicon.ico url',
|
|
);
|
|
}
|
|
|
|
const requestDocument = await makeRequestWithUserAgent(urlParam);
|
|
const documentAsText = await requestDocument.text();
|
|
|
|
const faviconPath = findFaviconPath(documentAsText);
|
|
if (!faviconPath) {
|
|
console.error(
|
|
'[Favicon]',
|
|
`[first: ${faviconRequestUrl}]`,
|
|
'No link/href attribute found',
|
|
);
|
|
return sendDefaultImage(res);
|
|
}
|
|
|
|
const finalUrl = buildFaviconUrl(requestDocument.url, faviconPath);
|
|
try {
|
|
if (!faviconPath) {
|
|
throw new Error('Unable to find favicon path');
|
|
}
|
|
|
|
if (isBase64Image(faviconPath)) {
|
|
console.log(
|
|
'[Favicon]',
|
|
`[second: ${faviconRequestUrl}]`,
|
|
'info: base64, convert it to buffer',
|
|
);
|
|
const buffer = convertBase64ToBuffer(faviconPath);
|
|
return sendImage(res, {
|
|
buffer,
|
|
type: 'image/x-icon',
|
|
size: buffer.length,
|
|
url: faviconPath,
|
|
});
|
|
}
|
|
|
|
const finalUrl = faviconPath.startsWith('http')
|
|
? faviconPath
|
|
: buildFaviconUrl(requestDocument.url, faviconPath);
|
|
const favicon = await downloadImageFromUrl(finalUrl);
|
|
if (!isImage(favicon.type)) {
|
|
throw new Error('Favicon path does not return an image');
|
|
}
|
|
|
|
console.log('[Favicon]', `[second: ${finalUrl}]`, 'success: image found');
|
|
return sendImage(res, favicon);
|
|
} catch (error) {
|
|
const errorMessage = error?.message || 'Unable to retrieve favicon';
|
|
console.log('[Favicon]', `[second: ${finalUrl}], error:`, errorMessage);
|
|
return sendDefaultImage(res);
|
|
}
|
|
}
|
|
|
|
function sendImage(res: NextApiResponse, { buffer, type, size }: Favicon) {
|
|
res.setHeader('Content-Type', type);
|
|
res.setHeader('Content-Length', size);
|
|
res.send(buffer);
|
|
}
|
|
|
|
function sendDefaultImage(res: NextApiResponse) {
|
|
const readStream = createReadStream(
|
|
resolve(process.cwd(), './public/empty-image.png'),
|
|
);
|
|
res.writeHead(206);
|
|
readStream.pipe(res);
|
|
}
|