perf(web-player): serve YouTube artwork through a caching proxy
The browser used to pull every cover straight from Google, so a search grid plus infinite scroll fired dozens of cross-origin image requests and started coming back as 429. Covers now go through /api/youtube/thumbnail, which resizes the upstream URL, caches the bytes in memory, collapses duplicate in-flight fetches, caps the concurrency against Google and backs off when it answers 429. Responses are immutable for a month and revalidate with an ETag, and serving them same-origin also lets the accent extractor read the pixels.
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
import type { RequestHandler } from './$types';
|
||||
import { error } from '@sveltejs/kit';
|
||||
import { loadThumbnail, parseThumbnailUrl } from '$lib/server/thumbnails';
|
||||
import { thumbnailConfig } from '$lib/server/config';
|
||||
import { THUMBNAIL_SIZES } from '$lib/thumbnails';
|
||||
|
||||
export const GET: RequestHandler = async ({ url, request, setHeaders }) => {
|
||||
const source = parseThumbnailUrl(url.searchParams.get('u') ?? '');
|
||||
if (!source) error(400, 'Miniatura no permitida.');
|
||||
|
||||
const requested = Number(url.searchParams.get('size'));
|
||||
const size =
|
||||
Number.isInteger(requested) && requested > 0
|
||||
? Math.min(requested, thumbnailConfig.maxSize)
|
||||
: THUMBNAIL_SIZES.large;
|
||||
|
||||
const image = await loadThumbnail(source, size);
|
||||
if (!image) error(404, 'Miniatura no disponible.');
|
||||
|
||||
setHeaders({
|
||||
'Cache-Control': `public, max-age=${thumbnailConfig.maxAgeSeconds}, immutable`,
|
||||
'Content-Type': image.contentType,
|
||||
ETag: image.etag
|
||||
});
|
||||
|
||||
if (request.headers.get('if-none-match') === image.etag) {
|
||||
return new Response(null, { status: 304 });
|
||||
}
|
||||
|
||||
return new Response(image.body);
|
||||
};
|
||||
Reference in New Issue
Block a user