feat: custom controls option for embedded players
This commit is contained in:
parent
fa653a8859
commit
776b0c4036
@ -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',
|
||||||
},
|
},
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user