From 07838eee04f07095795df9298c43f05296bd8f32 Mon Sep 17 00:00:00 2001 From: "Graham F. Scott" Date: Sun, 10 Mar 2024 12:46:27 -0400 Subject: [PATCH 1/5] Add option to opt in to WebP thumbnail format --- packages/youtube/lib/defaults.js | 11 +++- packages/youtube/lib/embed.js | 24 +++++++- packages/youtube/test/embed.lite.test.js | 77 +++++++++++++++++++----- 3 files changed, 92 insertions(+), 20 deletions(-) diff --git a/packages/youtube/lib/defaults.js b/packages/youtube/lib/defaults.js index 97be233..247743e 100644 --- a/packages/youtube/lib/defaults.js +++ b/packages/youtube/lib/defaults.js @@ -35,10 +35,14 @@ const defaults = { * @typedef {Object} Thumbnails * @property {string[]} validSizes - An array of valid sizes. * @property {string} defaultSize - The default size. + * @property {string[]} validFormats - An array of valid formats. + * @property {string} defaultFormat - The default format. */ const thumbnails = { validSizes: ["default", "hqdefault", "mqdefault", "sddefault", "maxresdefault"], - defaultSize: "hqdefault" + defaultSize: "hqdefault", + validFormats: ["jpg", "webp"], + defaultFormat: "jpg", } /** @@ -58,15 +62,16 @@ const liteDefaults = { css: { enabled: true, inline: false, - path: 'https://cdn.jsdelivr.net/gh/paulirish/lite-youtube-embed@0.3.0/src/lite-yt-embed.min.css' + path: 'https://cdn.jsdelivr.net/gh/paulirish/lite-youtube-embed@0.3.2/src/lite-yt-embed.min.css' }, js: { enabled: true, inline: false, - path: 'https://cdn.jsdelivr.net/gh/paulirish/lite-youtube-embed@0.3.0/src/lite-yt-embed.min.js' + path: 'https://cdn.jsdelivr.net/gh/paulirish/lite-youtube-embed@0.3.2/src/lite-yt-embed.min.js' }, responsive: false, thumbnailQuality: thumbnails.defaultSize, + thumbnailFormat: thumbnails.defaultFormat, }; module.exports.thumbnails = thumbnails; diff --git a/packages/youtube/lib/embed.js b/packages/youtube/lib/embed.js index dec4da5..b84906d 100644 --- a/packages/youtube/lib/embed.js +++ b/packages/youtube/lib/embed.js @@ -73,8 +73,15 @@ function liteEmbed({id, url}, options, index) { options = merge(options, getInputUrlParams(url)) const liteOpt = liteConfig(options); liteOpt.thumbnailQuality = validateThumbnailSize(liteOpt.thumbnailQuality); + liteOpt.thumbnailFormat = validateThumbnailFormat(liteOpt.thumbnailFormat); const params = stringifyUrlParams(options); + const thumbnailUrl = () => { + const fileTypePath = liteOpt.thumbnailFormat === 'webp' ? 'vi_webp' : 'vi'; + const fileName = `${liteOpt.thumbnailQuality}.${liteOpt.thumbnailFormat}`; + return `https://i.ytimg.com/${fileTypePath}/${id}/${fileName}`; + } + // Access the file system to read the lite embed CSS and JS const fs = require('fs'); const path = require('path'); @@ -96,7 +103,7 @@ function liteEmbed({id, url}, options, index) { out += index === 0 && liteOpt.responsive ? `\n` : ''; out += `
`; - out += ``; + out += ``; out += '
'; return out; } @@ -198,5 +205,20 @@ async function getYouTubeTitleViaOembed(id, options) { } } +/** + * Validates the thumbnail format and returns the format if it is valid, otherwise returns the default format. + * + * @param {string} format - The thumbnail format to validate. + * @param {object} options - The options object containing the valid thumbnail formats. + * @returns {string} - The validated thumbnail format. + */ +function validateThumbnailFormat(format) { + if ( !thumbnails.validFormats.includes(format) ) { + return thumbnails.defaultFormat + } + return format; +} + module.exports.validateThumbnailSize = validateThumbnailSize; +module.exports.validateThumbnailFormat = validateThumbnailFormat; module.exports.getYouTubeTitleViaOembed = getYouTubeTitleViaOembed; \ No newline at end of file diff --git a/packages/youtube/test/embed.lite.test.js b/packages/youtube/test/embed.lite.test.js index e10662d..6fc0ba0 100644 --- a/packages/youtube/test/embed.lite.test.js +++ b/packages/youtube/test/embed.lite.test.js @@ -3,7 +3,7 @@ const merge = require('deepmerge'); const pattern = require('../lib/pattern.js'); const embed = require('../lib/embed.js'); const {defaults} = require('../lib/defaults.js'); -const { validateThumbnailSize } = require('../lib/embed.js'); +const { validateThumbnailSize, validateThumbnailFormat } = require('../lib/embed.js'); const fs = require('fs'); const path = require('path'); @@ -38,47 +38,57 @@ const override = (obj) => merge(defaults, obj); */ test(`Build embed lite mode, zero index, lite defaults`, t => { t.is(embed(extract(testString), override({lite: true}), 0), - `\n\n
` + `\n\n
` + ); +}); +test(`Build embed lite mode, zero index, valid thumbnail format override`, t => { + t.is(embed(extract(testString), override({lite: {thumbnailFormat: 'webp'}}), 0), + `\n\n
` + ); +}); +test(`Build embed lite mode, zero index, invalid thumbnail format override`, t => { + t.is(embed(extract(testString), override({lite: {thumbnailFormat: 'no'}}), 0), + `\n\n
` ); }); test(`Build embed lite mode, zero index, valid thumbnail quality override`, t => { t.is(embed(extract(testString), override({lite: { thumbnailQuality: 'maxresdefault'}}), 0), - `\n\n
` + `\n\n
` ); }); test(`Build embed lite mode, zero index, invalid thumbnail quality override`, t => { t.is(embed(extract(testString), override({lite: { thumbnailQuality: 'nope'}}), 0), - `\n\n
` + `\n\n
` ); }); test(`Build embed lite mode, zero index, lite defaults with URL start time param`, t => { t.is(embed(extract('

https://www.youtube.com/watch?v=hIs5StN8J-0&t=30s

'), override({lite: true}), 0), - `\n\n
` + `\n\n
` ); }); test(`Build embed lite mode, zero index, css disabled`, t => { t.is(embed(extract(testString), override({lite:{css:{enabled: false}}}), 0), - `\n
` + `\n
` ); }); test(`Build embed lite mode, zero index, css inline`, t => { t.is(embed(extract(testString), override({lite:{css:{inline: true}}}), 0), - `\n\n
` + `\n\n
` ); }); test(`Build embed lite mode, zero index, css path override`, t => { t.is(embed(extract(testString), override({lite:{css:{path: 'foo'}}}), 0), - `\n\n
` + `\n\n
` ); }); test(`Build embed lite mode, zero index, js disabled`, t => { t.is(embed(extract(testString), override({lite:{js:{enabled: false}}}), 0), - `\n
` + `\n
` ); }); test(`Build embed lite mode, zero index, js inline`, t => { t.is(embed(extract(testString), override({lite:{js:{inline: true}}}), 0), - `\n\n
` + `\n\n
` ); }); test(`Build embed lite mode, zero index, css AND js disabled`, t => { @@ -98,7 +108,7 @@ test(`Build embed lite mode, zero index, css AND js inline`, t => { }); test(`Build embed lite mode, zero index, responsive true`, t => { t.is(embed(extract(testString), override({lite: { responsive: true }}), 0), - `\n\n\n
` + `\n\n\n
` ); }); @@ -111,6 +121,26 @@ test(`Build embed lite mode, 1+ index, lite defaults`, t => { `
` ); }); +test(`Build embed lite mode, 1+ index, valid thumbnail quality override`, t => { + t.is(embed(extract(testString), override({lite: { thumbnailQuality: 'maxresdefault'}}), 1), + `
` + ); +}); +test(`Build embed lite mode, 1+ index, invalid thumbnail quality override`, t => { + t.is(embed(extract(testString), override({lite: { thumbnailQuality: 'nope'}}), 1), + `
` + ); +}); +test(`Build embed lite mode, 1+ index, valid thumbnail format override`, t => { + t.is(embed(extract(testString), override({lite: {thumbnailFormat: 'webp'}}), 1), + `
` + ); +}); +test(`Build embed lite mode, 1+ index, invalid thumbnail format override`, t => { + t.is(embed(extract(testString), override({lite: {thumbnailFormat: 'foo'}}), 1), + `
` + ); +}); test(`Build embed lite mode, 1+ index, lite defaults with URL start time param`, t => { t.is(embed(extract('

https://www.youtube.com/watch?v=hIs5StN8J-0&t=30s

'), override({lite: true}), 1), `
` @@ -148,22 +178,37 @@ test(`Build embed lite mode, 1+ index, responsive true`, t => { }); /** - * In lite mode, test that the thumbnail size validator returns the expected values. + * In lite mode, test that the thumbnail validators return the expected values. */ -test(`Thumbnail validator returns default value in response to empty parameter`, t => { +test(`Thumbnail size validator returns default value in response to empty parameter`, t => { t.is(validateThumbnailSize(), 'hqdefault'); }); -test(`Thumbnail validator returns default value in response to incorrect parameter types`, t => { +test(`Thumbnail size validator returns default value in response to incorrect parameter types`, t => { t.is(validateThumbnailSize(1), 'hqdefault'); t.is(validateThumbnailSize(true), 'hqdefault'); }); -test(`Thumbnail validator returns default value in response to invalid string`, t => { +test(`Thumbnail size validator returns default value in response to invalid string`, t => { t.is(validateThumbnailSize('foo'), 'hqdefault'); }); -test(`Thumbnail validator returns expected strings when passed expected strings`, t => { +test(`Thumbnail size validator returns expected strings when passed expected strings`, t => { t.is(validateThumbnailSize('default'), 'default'); t.is(validateThumbnailSize('hqdefault'), 'hqdefault'); t.is(validateThumbnailSize('mqdefault'), 'mqdefault'); t.is(validateThumbnailSize('sddefault'), 'sddefault'); t.is(validateThumbnailSize('maxresdefault'), 'maxresdefault'); +}); + +test(`Thumbnail format validator returns default value in response to empty parameter`, t => { + t.is(validateThumbnailFormat(), 'jpg'); +}) +test(`Thumbnail format validator returns default value in response to incorrect parameter types`, t => { + t.is(validateThumbnailFormat(1), 'jpg'); + t.is(validateThumbnailFormat(true), 'jpg'); +}); +test(`Thumbnail format validator returns default value in response to invalid string`, t => { + t.is(validateThumbnailFormat('avif'), 'jpg'); +}); +test(`Thumbnail format validator returns expected strings when passed expected strings`, t => { + t.is(validateThumbnailFormat('jpg'), 'jpg'); + t.is(validateThumbnailFormat('webp'), 'webp'); }); \ No newline at end of file From e9dc0c7a38e965f9f29f7251afb552d922d9cb2e Mon Sep 17 00:00:00 2001 From: "Graham F. Scott" Date: Sun, 10 Mar 2024 12:57:52 -0400 Subject: [PATCH 2/5] Add option to enable JS API option in lite mode --- packages/youtube/lib/defaults.js | 2 ++ packages/youtube/lib/embed.js | 2 +- packages/youtube/test/embed.lite.test.js | 10 ++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/youtube/lib/defaults.js b/packages/youtube/lib/defaults.js index 247743e..74816fa 100644 --- a/packages/youtube/lib/defaults.js +++ b/packages/youtube/lib/defaults.js @@ -55,6 +55,7 @@ const thumbnails = { * @property {boolean} [js.enabled] - Whether JS is enabled. * @property {boolean} [js.inline] - Whether JS is inline. * @property {string} [js.path] - The path to the JS file. + * * @property {boolean} [responsive] - Whether the layout is responsive. * @property {string} [thumbnailQuality] - The quality of the thumbnail. */ @@ -69,6 +70,7 @@ const liteDefaults = { inline: false, path: 'https://cdn.jsdelivr.net/gh/paulirish/lite-youtube-embed@0.3.2/src/lite-yt-embed.min.js' }, + jsApi: false, responsive: false, thumbnailQuality: thumbnails.defaultSize, thumbnailFormat: thumbnails.defaultFormat, diff --git a/packages/youtube/lib/embed.js b/packages/youtube/lib/embed.js index b84906d..4e759aa 100644 --- a/packages/youtube/lib/embed.js +++ b/packages/youtube/lib/embed.js @@ -103,7 +103,7 @@ function liteEmbed({id, url}, options, index) { out += index === 0 && liteOpt.responsive ? `\n` : ''; out += `
`; - out += ``; + out += ``; out += '
'; return out; } diff --git a/packages/youtube/test/embed.lite.test.js b/packages/youtube/test/embed.lite.test.js index 6fc0ba0..df39185 100644 --- a/packages/youtube/test/embed.lite.test.js +++ b/packages/youtube/test/embed.lite.test.js @@ -41,6 +41,11 @@ test(`Build embed lite mode, zero index, lite defaults`, t => { `\n\n
` ); }); +test(`Build embed lite mode, zero index, JS API enabled`, t => { + t.is(embed(extract(testString), override({lite: {jsApi: true}}), 0), + `\n\n
` + ); +}); test(`Build embed lite mode, zero index, valid thumbnail format override`, t => { t.is(embed(extract(testString), override({lite: {thumbnailFormat: 'webp'}}), 0), `\n\n
` @@ -121,6 +126,11 @@ test(`Build embed lite mode, 1+ index, lite defaults`, t => { `
` ); }); +test(`Build embed lite mode, 1+ index, JS API enabled`, t => { + t.is(embed(extract(testString), override({lite: {jsApi: true}}), 1), + `
` + ); +}); test(`Build embed lite mode, 1+ index, valid thumbnail quality override`, t => { t.is(embed(extract(testString), override({lite: { thumbnailQuality: 'maxresdefault'}}), 1), `
` From c0389e47befc11ffc87a4fc09f7ec1a59bdbd552 Mon Sep 17 00:00:00 2001 From: "Graham F. Scott" Date: Sun, 10 Mar 2024 12:59:58 -0400 Subject: [PATCH 3/5] Changeset --- .changeset/old-dragons-float.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/old-dragons-float.md diff --git a/.changeset/old-dragons-float.md b/.changeset/old-dragons-float.md new file mode 100644 index 0000000..f65fde9 --- /dev/null +++ b/.changeset/old-dragons-float.md @@ -0,0 +1,5 @@ +--- +"eleventy-plugin-youtube-embed": minor +--- + +Add lite-mode options for thumbnail format and YouTube JS API access From 6ae4f9029a114430e282c85fcfa6713abcd0df67 Mon Sep 17 00:00:00 2001 From: "Graham F. Scott" Date: Sun, 10 Mar 2024 13:19:38 -0400 Subject: [PATCH 4/5] Update readme --- packages/youtube/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/youtube/README.md b/packages/youtube/README.md index 78e9c38..1bdc46a 100644 --- a/packages/youtube/README.md +++ b/packages/youtube/README.md @@ -256,6 +256,12 @@ eleventyConfig.addPlugin(embedYouTube, { false If you change this to true, then the plugin adds a CSS rule to override the default max-width of <lite-youtube> elements, which are hard coded to a maximum of 720 pixels. + + lite.thumbnailFormat
New in v1.11.0! + String + jpg + If you change this to webp, then the plugin will load the YouTube thumbnail image in WebP format instead of JPEG. + lite.thumbnailQuality String From 5dd5a8eeaf60d598a2556abc4a4b3a201b787b5e Mon Sep 17 00:00:00 2001 From: "Graham F. Scott" Date: Sun, 10 Mar 2024 13:27:57 -0400 Subject: [PATCH 5/5] Update Readme --- packages/youtube/README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/youtube/README.md b/packages/youtube/README.md index 1bdc46a..2fb1144 100644 --- a/packages/youtube/README.md +++ b/packages/youtube/README.md @@ -250,6 +250,12 @@ eleventyConfig.addPlugin(embedYouTube, { https://cdn.jsdelivr.net/gh/paulirish/lite-youtube-embed@0.3.0/src/lite-yt-embed.min.js Pass a custom URL to load the necessary JavaScript from the source of your choice. + + lite.jsApi
New in v1.11.0! + Boolean + false + If you change this to true, then the plugin adds a `js-api` parameter to the custom element that enables access to YouTube's IFrame Player API. See usage example and demo. + lite.responsive
New in v1.10.0! Boolean