feat: custom controls option for embedded players

This commit is contained in:
Sam Potts 2020-10-19 22:26:33 +11:00
parent fa653a8859
commit 776b0c4036
4 changed files with 62 additions and 46 deletions

View File

@ -59,9 +59,11 @@ import toggleClass from './toggle-class';
}, },
previewThumbnails: { previewThumbnails: {
enabled: true, enabled: true,
customControls: true,
src: ['https://cdn.plyr.io/static/demo/thumbs/100p.vtt', 'https://cdn.plyr.io/static/demo/thumbs/240p.vtt'], src: ['https://cdn.plyr.io/static/demo/thumbs/100p.vtt', 'https://cdn.plyr.io/static/demo/thumbs/240p.vtt'],
}, },
vimeo: { vimeo: {
customControls: true,
// Prevent Vimeo blocking plyr.io demo site // Prevent Vimeo blocking plyr.io demo site
referrerPolicy: 'no-referrer', referrerPolicy: 'no-referrer',
}, },

View File

@ -422,20 +422,23 @@ const defaults = {
title: false, title: false,
speed: true, speed: true,
transparent: false, transparent: false,
// Custom settings from Plyr
customControls: false,
referrerPolicy: null, // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
// Whether the owner of the video has a Pro or Business account // Whether the owner of the video has a Pro or Business account
// (which allows us to properly hide controls without CSS hacks, etc) // (which allows us to properly hide controls without CSS hacks, etc)
premium: false, premium: false,
// Custom settings from Plyr
referrerPolicy: null, // https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement/referrerPolicy
}, },
// YouTube plugin // YouTube plugin
youtube: { youtube: {
noCookie: false, // Whether to use an alternative version of YouTube without cookies
rel: 0, // No related vids rel: 0, // No related vids
showinfo: 0, // Hide info showinfo: 0, // Hide info
iv_load_policy: 3, // Hide annotations iv_load_policy: 3, // Hide annotations
modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused) modestbranding: 1, // Hide logos as much as possible (they still show one in the corner when paused)
// Custom settings from Plyr
customControls: false,
noCookie: false, // Whether to use an alternative version of YouTube without cookies
}, },
}; };

View File

@ -112,31 +112,35 @@ const vimeo = {
} }
// Inject the package // Inject the package
const { poster } = player; if (premium || !config.customControls) {
if (premium) { iframe.setAttribute('data-poster', player.poster);
iframe.setAttribute('data-poster', poster);
player.media = replaceElement(iframe, player.media); player.media = replaceElement(iframe, player.media);
} else { } else {
const wrapper = createElement('div', { class: player.config.classNames.embedContainer, 'data-poster': poster }); const wrapper = createElement('div', {
class: player.config.classNames.embedContainer,
'data-poster': player.poster,
});
wrapper.appendChild(iframe); wrapper.appendChild(iframe);
player.media = replaceElement(wrapper, player.media); player.media = replaceElement(wrapper, player.media);
} }
// Get poster image // Get poster image
fetch(format(player.config.urls.vimeo.api, id), 'json').then((response) => { if (!config.customControls) {
if (is.empty(response)) { fetch(format(player.config.urls.vimeo.api, id), 'json').then((response) => {
return; if (is.empty(response)) {
} return;
}
// Get the URL for thumbnail // Get the URL for thumbnail
const url = new URL(response[0].thumbnail_large); const url = new URL(response[0].thumbnail_large);
// Get original image // Get original image
url.pathname = `${url.pathname.split('_')[0]}.jpg`; url.pathname = `${url.pathname.split('_')[0]}.jpg`;
// Set and show poster // Set and show poster
ui.setPoster.call(player, url.href).catch(() => {}); ui.setPoster.call(player, url.href).catch(() => {});
}); });
}
// Setup instance // Setup instance
// https://github.com/vimeo/player.js // https://github.com/vimeo/player.js
@ -407,7 +411,9 @@ const vimeo = {
}); });
// Rebuild UI // Rebuild UI
setTimeout(() => ui.build.call(player), 0); if (config.customControls) {
setTimeout(() => ui.build.call(player), 0);
}
}, },
}; };

View File

@ -104,6 +104,7 @@ const youtube = {
// API ready // API ready
ready() { ready() {
const player = this; const player = this;
const config = player.config.youtube;
// Ignore already setup (race condition) // Ignore already setup (race condition)
const currentId = player.media && player.media.getAttribute('id'); const currentId = player.media && player.media.getAttribute('id');
if (!is.empty(currentId) && currentId.startsWith('youtube-')) { if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
@ -121,29 +122,26 @@ const youtube = {
// Replace the <iframe> with a <div> due to YouTube API issues // Replace the <iframe> with a <div> due to YouTube API issues
const videoId = parseId(source); const videoId = parseId(source);
const id = generateId(player.provider); const id = generateId(player.provider);
// Get poster, if already set
const { poster } = player;
// Replace media element // Replace media element
const container = createElement('div', { id, 'data-poster': poster }); const container = createElement('div', { id, 'data-poster': config.customControls ? player.poster : undefined });
player.media = replaceElement(container, player.media); player.media = replaceElement(container, player.media);
// Id to poster wrapper if (config.customControls) {
const posterSrc = (s) => `https://i.ytimg.com/vi/${videoId}/${s}default.jpg`; const posterSrc = (s) => `https://i.ytimg.com/vi/${videoId}/${s}default.jpg`;
// Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide) // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
.catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3 .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
.catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
.then((image) => ui.setPoster.call(player, image.src)) .then((image) => ui.setPoster.call(player, image.src))
.then((src) => { .then((src) => {
// If the image is padded, use background-size "cover" instead (like youtube does too with their posters) // If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
if (!src.includes('maxres')) { if (!src.includes('maxres')) {
player.elements.poster.style.backgroundSize = 'cover'; player.elements.poster.style.backgroundSize = 'cover';
} }
}) })
.catch(() => {}); .catch(() => {});
}
const config = player.config.youtube;
// Setup instance // Setup instance
// https://developers.google.com/youtube/iframe_api_reference // https://developers.google.com/youtube/iframe_api_reference
@ -153,11 +151,16 @@ const youtube = {
playerVars: extend( playerVars: extend(
{}, {},
{ {
autoplay: player.config.autoplay ? 1 : 0, // Autoplay // Autoplay
hl: player.config.hl, // iframe interface language autoplay: player.config.autoplay ? 1 : 0,
controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported // iframe interface language
disablekb: 1, // Disable keyboard as we handle it hl: player.config.hl,
playsinline: !player.config.fullscreen.iosNative ? 1 : 0, // Allow iOS inline playback // Only show controls if not fully supported or opted out
controls: player.supported.ui && config.customControls ? 0 : 1,
// Disable keyboard as we handle it
disablekb: 1,
// Allow iOS inline playback
playsinline: !player.config.fullscreen.iosNative ? 1 : 0,
// Captions are flaky on YouTube // Captions are flaky on YouTube
cc_load_policy: player.captions.active ? 1 : 0, cc_load_policy: player.captions.active ? 1 : 0,
cc_lang_pref: player.config.captions.language, cc_lang_pref: player.config.captions.language,
@ -302,7 +305,7 @@ const youtube = {
player.options.speed = speeds.filter((s) => player.config.speed.options.includes(s)); player.options.speed = speeds.filter((s) => player.config.speed.options.includes(s));
// Set the tabindex to avoid focus entering iframe // Set the tabindex to avoid focus entering iframe
if (player.supported.ui) { if (player.supported.ui && config.customControls) {
player.media.setAttribute('tabindex', -1); player.media.setAttribute('tabindex', -1);
} }
@ -335,7 +338,9 @@ const youtube = {
}, 200); }, 200);
// Rebuild UI // Rebuild UI
setTimeout(() => ui.build.call(player), 50); if (config.customControls) {
setTimeout(() => ui.build.call(player), 50);
}
}, },
onStateChange(event) { onStateChange(event) {
// Get the instance // Get the instance
@ -386,7 +391,7 @@ const youtube = {
case 1: case 1:
// Restore paused state (YouTube starts playing on seek if the video hasn't been played yet) // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) { if (config.customControls && !player.config.autoplay && player.media.paused && !player.embed.hasPlayed) {
player.media.pause(); player.media.pause();
} else { } else {
assurePlaybackState.call(player, true); assurePlaybackState.call(player, true);