From 8f1ad745200d16aea1f61670f47103d147b511c2 Mon Sep 17 00:00:00 2001 From: Onni Hakala Date: Mon, 11 Nov 2024 21:48:54 +0200 Subject: [PATCH] Add support for high quality and responsive youtube preview images --- .../src/components/lite-youtube-embed.tsx | 75 ++++++++++++++++--- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/packages/react-notion-x/src/components/lite-youtube-embed.tsx b/packages/react-notion-x/src/components/lite-youtube-embed.tsx index 151d72aa8..3f40c85fd 100644 --- a/packages/react-notion-x/src/components/lite-youtube-embed.tsx +++ b/packages/react-notion-x/src/components/lite-youtube-embed.tsx @@ -10,6 +10,44 @@ const qs = (params: Record) => { .join('&') } +type ImageType = 'jpg' | 'webp'; +// Define a type for video resolutions +type VideoResolution = 120 | 320 | 480 | 640 | 1280; + +const resolutions: VideoResolution[] = [120, 320, 480, 640, 1280]; + +const resolutionMap: Record = { + 120: 'default', + 320: 'mqdefault', + 480: 'hqdefault', + 640: 'sddefault', + 1280: 'maxresdefault' + // 2k, 4k, 8k images don't seem to be available + // Source: https://longzero.com/articles/youtube-thumbnail-sizes-url/ +}; + +// Function to get the poster URL based on the resolution type +function getPosterUrl(id: string, resolution: VideoResolution = 480, type: ImageType = 'jpg'): string { + // Return the appropriate URL based on the image type + if (type === 'webp') { + return `https://i.ytimg.com/vi_webp/${id}/${resolutionMap[resolution]}.webp`; + } + // Default to jpg + return `https://i.ytimg.com/vi/${id}/${resolutionMap[resolution]}.jpg`; +} + +function generateSrcSet(id: string, type: ImageType = 'jpg'): string { + return resolutions + .map((resolution) => `${getPosterUrl(id, resolution, type)} ${resolution}w`) + .join(', '); +} + +function generateSizes(): string { + return resolutions + .map((resolution) => `(max-width: ${resolution}px) ${resolution}px`) + .join(', '); +} + export function LiteYouTubeEmbed({ id, defaultPlay = false, @@ -38,10 +76,7 @@ export function LiteYouTubeEmbed({ () => qs({ autoplay: '1', mute: muteParam, ...params }), [muteParam, params] ) - // const mobileResolution = 'hqdefault' - // const desktopResolution = 'maxresdefault' - const resolution = 'hqdefault' - const posterUrl = `https://i.ytimg.com/vi/${id}/${resolution}.jpg` + const ytUrl = 'https://www.youtube-nocookie.com' const iframeSrc = `${ytUrl}/embed/${id}?${queryString}` @@ -65,7 +100,11 @@ export function LiteYouTubeEmbed({ return ( <> - + {/* + 'it seems pretty unlikely for a browser to support preloading but not WebP images' + Source: https://blog.laurenashpole.com/post/658079409151016960 + */} + {isPreconnected && ( <> @@ -96,12 +135,26 @@ export function LiteYouTubeEmbed({ )} style={style} > - {alt} + + {/* + Browsers which don't support srcSet will most likely not support webp too + These browsers will then just get the default 480 size jpg + */} + {resolutions.map((resolution) => ( + + ))} + {alt} +