fix: favicons
This commit is contained in:
@@ -71,7 +71,7 @@ async function fetchImage(
|
||||
url: URL,
|
||||
): Promise<{ buffer: Buffer; contentType: string; status: number }> {
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 10000); // 10s timeout
|
||||
const timeout = setTimeout(() => controller.abort(), 1000); // 10s timeout
|
||||
|
||||
try {
|
||||
const response = await fetch(url.toString(), {
|
||||
@@ -175,20 +175,10 @@ async function processImage(
|
||||
bufferSize: buffer.length,
|
||||
});
|
||||
|
||||
// If Sharp fails, try to create a simple fallback image
|
||||
return createFallbackImage();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Create a simple transparent fallback image when Sharp can't process the original
|
||||
function createFallbackImage(): Buffer {
|
||||
// 1x1 transparent PNG
|
||||
return Buffer.from(
|
||||
'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=',
|
||||
'base64',
|
||||
);
|
||||
}
|
||||
|
||||
// Process OG image with Sharp (resize to 300px width)
|
||||
async function processOgImage(
|
||||
buffer: Buffer,
|
||||
@@ -220,8 +210,7 @@ async function processOgImage(
|
||||
bufferSize: buffer.length,
|
||||
});
|
||||
|
||||
// If Sharp fails, try to create a simple fallback image
|
||||
return createFallbackImage();
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,11 +230,15 @@ export async function getFavicon(
|
||||
reply: FastifyReply,
|
||||
) {
|
||||
try {
|
||||
logger.info('getFavicon', {
|
||||
url: request.query.url,
|
||||
});
|
||||
const url = validateUrl(request.query.url);
|
||||
if (!url) {
|
||||
reply.header('Content-Type', 'image/png');
|
||||
reply.header('Cache-Control', 'public, max-age=3600');
|
||||
return reply.send(createFallbackImage());
|
||||
return reply
|
||||
.status(404)
|
||||
.header('Content-Type', 'text/plain')
|
||||
.send('Not found');
|
||||
}
|
||||
|
||||
const cacheKey = createCacheKey(url.toString());
|
||||
@@ -259,11 +252,13 @@ export async function getFavicon(
|
||||
}
|
||||
|
||||
let imageUrl: URL;
|
||||
|
||||
// If it's a direct image URL, use it directly
|
||||
if (isDirectImage(url)) {
|
||||
imageUrl = url;
|
||||
} else {
|
||||
logger.info('before parseUrlMeta', {
|
||||
url: url.toString(),
|
||||
});
|
||||
// For website URLs, extract favicon from HTML
|
||||
const meta = await parseUrlMeta(url.toString());
|
||||
logger.info('parseUrlMeta result', {
|
||||
@@ -323,9 +318,10 @@ export async function getFavicon(
|
||||
|
||||
// Accept any response as long as we have valid image data
|
||||
if (buffer.length === 0) {
|
||||
reply.header('Content-Type', 'image/png');
|
||||
reply.header('Cache-Control', 'public, max-age=3600');
|
||||
return reply.send(createFallbackImage());
|
||||
return reply
|
||||
.status(404)
|
||||
.header('Content-Type', 'text/plain')
|
||||
.send('Not found');
|
||||
}
|
||||
|
||||
// Process the image (resize to 30x30 PNG, or serve ICO as-is)
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
process.env.TZ = 'UTC';
|
||||
|
||||
import compress from '@fastify/compress';
|
||||
import cookie from '@fastify/cookie';
|
||||
import cors, { type FastifyCorsOptions } from '@fastify/cors';
|
||||
@@ -12,7 +14,7 @@ import {
|
||||
type IServiceClientWithProject,
|
||||
runWithAlsSession,
|
||||
} from '@openpanel/db';
|
||||
import { getCache, getRedisPub } from '@openpanel/redis';
|
||||
import { getRedisPub } from '@openpanel/redis';
|
||||
import type { AppRouter } from '@openpanel/trpc';
|
||||
import { appRouter, createContext } from '@openpanel/trpc';
|
||||
|
||||
@@ -50,8 +52,6 @@ import { logger } from './utils/logger';
|
||||
|
||||
sourceMapSupport.install();
|
||||
|
||||
process.env.TZ = 'UTC';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyRequest {
|
||||
client: IServiceClientWithProject | null;
|
||||
|
||||
@@ -72,7 +72,9 @@ interface UrlMetaData {
|
||||
|
||||
export async function parseUrlMeta(url: string) {
|
||||
try {
|
||||
const metadata = (await urlMetadata(url)) as UrlMetaData;
|
||||
const metadata = (await urlMetadata(url, {
|
||||
timeout: 500,
|
||||
})) as UrlMetaData;
|
||||
const data = transform(metadata, url);
|
||||
return data;
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user