@@ -10,6 +10,44 @@ const qs = (params: Record<string, string>) => {
10
10
. join ( '&' )
11
11
}
12
12
13
+ type ImageType = 'jpg' | 'webp' ;
14
+ // Define a type for video resolutions
15
+ type VideoResolution = 120 | 320 | 480 | 640 | 1280 ;
16
+
17
+ const resolutions : VideoResolution [ ] = [ 120 , 320 , 480 , 640 , 1280 ] ;
18
+
19
+ const resolutionMap : Record < VideoResolution , string > = {
20
+ 120 : 'default' ,
21
+ 320 : 'mqdefault' ,
22
+ 480 : 'hqdefault' ,
23
+ 640 : 'sddefault' ,
24
+ 1280 : 'maxresdefault'
25
+ // 2k, 4k, 8k images don't seem to be available
26
+ // Source: https://longzero.com/articles/youtube-thumbnail-sizes-url/
27
+ } ;
28
+
29
+ // Function to get the poster URL based on the resolution type
30
+ function getPosterUrl ( id : string , resolution : VideoResolution = 480 , type : ImageType = 'jpg' ) : string {
31
+ // Return the appropriate URL based on the image type
32
+ if ( type === 'webp' ) {
33
+ return `https://i.ytimg.com/vi_webp/${ id } /${ resolutionMap [ resolution ] } .webp` ;
34
+ }
35
+ // Default to jpg
36
+ return `https://i.ytimg.com/vi/${ id } /${ resolutionMap [ resolution ] } .jpg` ;
37
+ }
38
+
39
+ function generateSrcSet ( id : string , type : ImageType = 'jpg' ) : string {
40
+ return resolutions
41
+ . map ( ( resolution ) => `${ getPosterUrl ( id , resolution , type ) } ${ resolution } w` )
42
+ . join ( ', ' ) ;
43
+ }
44
+
45
+ function generateSizes ( ) : string {
46
+ return resolutions
47
+ . map ( ( resolution ) => `(max-width: ${ resolution } px) ${ resolution } px` )
48
+ . join ( ', ' ) ;
49
+ }
50
+
13
51
export function LiteYouTubeEmbed ( {
14
52
id,
15
53
defaultPlay = false ,
@@ -38,10 +76,7 @@ export function LiteYouTubeEmbed({
38
76
( ) => qs ( { autoplay : '1' , mute : muteParam , ...params } ) ,
39
77
[ muteParam , params ]
40
78
)
41
- // const mobileResolution = 'hqdefault'
42
- // const desktopResolution = 'maxresdefault'
43
- const resolution = 'hqdefault'
44
- const posterUrl = `https://i.ytimg.com/vi/${ id } /${ resolution } .jpg`
79
+
45
80
const ytUrl = 'https://www.youtube-nocookie.com'
46
81
const iframeSrc = `${ ytUrl } /embed/${ id } ?${ queryString } `
47
82
@@ -65,7 +100,11 @@ export function LiteYouTubeEmbed({
65
100
66
101
return (
67
102
< >
68
- < link rel = 'preload' href = { posterUrl } as = 'image' />
103
+ { /*
104
+ 'it seems pretty unlikely for a browser to support preloading but not WebP images'
105
+ Source: https://blog.laurenashpole.com/post/658079409151016960
106
+ */ }
107
+ < link rel = 'preload' as = 'image' href = { getPosterUrl ( id ) } imageSrcSet = { generateSrcSet ( id , 'webp' ) } imageSizes = { generateSizes ( ) } />
69
108
70
109
{ isPreconnected && (
71
110
< >
@@ -96,12 +135,26 @@ export function LiteYouTubeEmbed({
96
135
) }
97
136
style = { style }
98
137
>
99
- < img
100
- src = { posterUrl }
101
- className = 'notion-yt-thumbnail'
102
- loading = { lazyImage ? 'lazy' : undefined }
103
- alt = { alt }
104
- />
138
+ < picture >
139
+ { /*
140
+ Browsers which don't support srcSet will most likely not support webp too
141
+ These browsers will then just get the default 480 size jpg
142
+ */ }
143
+ { resolutions . map ( ( resolution ) => (
144
+ < source
145
+ key = { resolution }
146
+ srcSet = { `${ getPosterUrl ( id , resolution , 'webp' ) } ${ resolution } w` }
147
+ media = { `(max-width: ${ resolution } px)` }
148
+ type = 'image/webp'
149
+ />
150
+ ) ) }
151
+ < img
152
+ src = { getPosterUrl ( id ) }
153
+ className = 'notion-yt-thumbnail'
154
+ loading = { lazyImage ? 'lazy' : undefined }
155
+ alt = { alt }
156
+ />
157
+ </ picture >
105
158
106
159
< div className = 'notion-yt-playbtn' />
107
160
0 commit comments