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.
20 lines
458 B
TypeScript
20 lines
458 B
TypeScript
export const THUMBNAIL_SIZES = {
|
|
small: 96,
|
|
medium: 160,
|
|
large: 320
|
|
} as const;
|
|
|
|
export type ThumbnailSize = keyof typeof THUMBNAIL_SIZES;
|
|
|
|
const PROXY_PATH = '/api/youtube/thumbnail';
|
|
|
|
export function thumbnailSrc(
|
|
url: string | undefined,
|
|
size: ThumbnailSize = 'large'
|
|
): string | undefined {
|
|
if (!url) return undefined;
|
|
if (!url.startsWith('http')) return url;
|
|
|
|
return `${PROXY_PATH}?u=${encodeURIComponent(url)}&size=${THUMBNAIL_SIZES[size]}`;
|
|
}
|