Respect call order and prioritize public API calls for setting poster, in order to avoid race conditions
This commit is contained in:
parent
2af60c5c0d
commit
115f352ade
@ -140,7 +140,7 @@ const vimeo = {
|
|||||||
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);
|
ui.setPoster.call(player, url.href).catch(() => {});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Setup instance
|
// Setup instance
|
||||||
|
@ -166,7 +166,7 @@ const youtube = {
|
|||||||
const container = createElement('div', { id, poster });
|
const container = createElement('div', { id, poster });
|
||||||
player.media = replaceElement(container, player.media);
|
player.media = replaceElement(container, player.media);
|
||||||
|
|
||||||
// Set poster image
|
// Id to poster wrapper
|
||||||
const posterSrc = format => `https://img.youtube.com/vi/${videoId}/${format}default.jpg`;
|
const posterSrc = format => `https://img.youtube.com/vi/${videoId}/${format}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)
|
||||||
@ -179,7 +179,8 @@ const youtube = {
|
|||||||
if (!posterSrc.includes('maxres')) {
|
if (!posterSrc.includes('maxres')) {
|
||||||
player.elements.poster.style.backgroundSize = 'cover';
|
player.elements.poster.style.backgroundSize = 'cover';
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
|
||||||
// Setup instance
|
// Setup instance
|
||||||
// https://developers.google.com/youtube/iframe_api_reference
|
// https://developers.google.com/youtube/iframe_api_reference
|
||||||
|
@ -790,7 +790,7 @@ class Plyr {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.setPoster.call(this, input);
|
ui.setPoster.call(this, input, false).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
49
src/js/ui.js
49
src/js/ui.js
@ -8,7 +8,7 @@ import i18n from './i18n';
|
|||||||
import support from './support';
|
import support from './support';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { getElement, toggleClass, toggleState } from './utils/elements';
|
import { getElement, toggleClass, toggleState } from './utils/elements';
|
||||||
import { triggerEvent } from './utils/events';
|
import { ready, triggerEvent } from './utils/events';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import loadImage from './utils/loadImage';
|
import loadImage from './utils/loadImage';
|
||||||
|
|
||||||
@ -109,8 +109,8 @@ const ui = {
|
|||||||
ui.setTitle.call(this);
|
ui.setTitle.call(this);
|
||||||
|
|
||||||
// Assure the poster image is set, if the property was added before the element was created
|
// Assure the poster image is set, if the property was added before the element was created
|
||||||
if (this.poster && this.elements.poster && !this.elements.poster.style.backgroundImage) {
|
if (this.poster) {
|
||||||
ui.setPoster.call(this, this.poster);
|
ui.setPoster.call(this, this.poster, false).catch(() => {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manually set the duration if user has overridden it.
|
// Manually set the duration if user has overridden it.
|
||||||
@ -163,18 +163,35 @@ const ui = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Set the poster image (async)
|
// Set the poster image (async)
|
||||||
setPoster(poster) {
|
// Used internally for the poster setter, with the passive option forced to false
|
||||||
// Set property regardless of validity
|
setPoster(poster, passive = true) {
|
||||||
this.media.setAttribute('poster', poster);
|
// Don't override if call is passive
|
||||||
|
if (passive && this.poster) {
|
||||||
// Bail if element is missing
|
return Promise.reject(new Error('Poster already set'));
|
||||||
if (!is.element(this.elements.poster)) {
|
|
||||||
return Promise.reject();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the image, and set poster if successful
|
// Set property synchronously to respect the call order
|
||||||
const loadPromise = loadImage(poster).then(() => {
|
this.media.setAttribute('poster', poster);
|
||||||
this.elements.poster.style.backgroundImage = `url('${poster}')`;
|
|
||||||
|
// Wait until ui is ready
|
||||||
|
return ready.call(this)
|
||||||
|
// Load image
|
||||||
|
.then(() => loadImage(poster))
|
||||||
|
.catch(err => {
|
||||||
|
// Hide poster on error unless it's been set by another call
|
||||||
|
if (poster === this.poster) {
|
||||||
|
ui.togglePoster.call(this, false);
|
||||||
|
}
|
||||||
|
// Rethrow
|
||||||
|
throw err;
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
// Prevent race conditions
|
||||||
|
if (poster !== this.poster) {
|
||||||
|
throw new Error('setPoster cancelled by later call to setPoster');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
Object.assign(this.elements.poster.style, {
|
Object.assign(this.elements.poster.style, {
|
||||||
backgroundImage: `url('${poster}')`,
|
backgroundImage: `url('${poster}')`,
|
||||||
// Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube)
|
// Reset backgroundSize as well (since it can be set to "cover" for padded thumbnails for youtube)
|
||||||
@ -183,12 +200,6 @@ const ui = {
|
|||||||
ui.togglePoster.call(this, true);
|
ui.togglePoster.call(this, true);
|
||||||
return poster;
|
return poster;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Hide the element if the poster can't be loaded (otherwise it will just be a black element covering the video)
|
|
||||||
loadPromise.catch(() => ui.togglePoster.call(this, false));
|
|
||||||
|
|
||||||
// Return the promise so the caller can use it as well
|
|
||||||
return loadPromise;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Check playing state
|
// Check playing state
|
||||||
|
Loading…
x
Reference in New Issue
Block a user