diff options
Diffstat (limited to 'src/js')
-rw-r--r-- | src/js/config/defaults.js | 6 | ||||
-rw-r--r-- | src/js/html5.js | 4 | ||||
-rw-r--r-- | src/js/listeners.js | 8 | ||||
-rw-r--r-- | src/js/plugins/previewThumbnails.js | 11 | ||||
-rw-r--r-- | src/js/plugins/vimeo.js | 2 | ||||
-rw-r--r-- | src/js/plugins/youtube.js | 9 | ||||
-rw-r--r-- | src/js/plyr.js | 41 | ||||
-rw-r--r-- | src/js/utils/style.js | 67 |
8 files changed, 116 insertions, 32 deletions
diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index 82809511..c45131bc 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -42,8 +42,9 @@ const defaults = { // Clicking the currentTime inverts it's value to show time left rather than elapsed toggleInvert: true, - // Aspect ratio (for embeds) - ratio: '16:9', + // Force an aspect ratio + // The format must be `'w:h'` (e.g. `'16:9'`) + ratio: null, // Click video container to play/pause clickToPlay: true, @@ -330,6 +331,7 @@ const defaults = { provider: 'plyr--{0}', video: 'plyr__video-wrapper', embed: 'plyr__video-embed', + videoFixedRatio: 'plyr__video-wrapper--fixed-ratio', embedContainer: 'plyr__video-embed__container', poster: 'plyr__poster', posterEnabled: 'plyr__poster-enabled', diff --git a/src/js/html5.js b/src/js/html5.js index 3266a58e..34f0c391 100644 --- a/src/js/html5.js +++ b/src/js/html5.js @@ -6,6 +6,7 @@ import support from './support'; import { removeElement } from './utils/elements'; import { triggerEvent } from './utils/events'; import is from './utils/is'; +import { setAspectRatio } from './utils/style'; const html5 = { getSources() { @@ -43,6 +44,9 @@ const html5 = { const player = this; + // Set aspect ratio if set + setAspectRatio.call(player); + // Quality Object.defineProperty(player.media, 'quality', { get() { diff --git a/src/js/listeners.js b/src/js/listeners.js index 3c65b824..5a593b10 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -9,7 +9,7 @@ import browser from './utils/browser'; import { getElement, getElements, matches, toggleClass, toggleHidden } from './utils/elements'; import { off, on, once, toggleListener, triggerEvent } from './utils/events'; import is from './utils/is'; -import { setAspectRatio } from './utils/style'; +import { getAspectRatio, setAspectRatio } from './utils/style'; class Listeners { constructor(player) { @@ -317,10 +317,10 @@ class Listeners { } const target = player.elements.wrapper.firstChild; - const [, height] = ratio.split(':').map(Number); - const [videoWidth, videoHeight] = player.embed.ratio.split(':').map(Number); + const [, y] = ratio; + const [videoX, videoY] = getAspectRatio.call(this); - target.style.maxWidth = toggle ? `${(height / videoHeight) * videoWidth}px` : null; + target.style.maxWidth = toggle ? `${(y / videoY) * videoX}px` : null; target.style.margin = toggle ? '0 auto' : null; }; diff --git a/src/js/plugins/previewThumbnails.js b/src/js/plugins/previewThumbnails.js index bd7a6bbd..813bc47e 100644 --- a/src/js/plugins/previewThumbnails.js +++ b/src/js/plugins/previewThumbnails.js @@ -17,17 +17,17 @@ const parseVtt = vttDataString => { if (!is.number(result.startTime)) { // The line with start and end times on it is the first line of interest const matchTimes = line.match( - /([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{2,3})( ?--> ?)([0-9]{2}):([0-9]{2}):([0-9]{2}).([0-9]{2,3})/, + /([0-9]{2})?:?([0-9]{2}):([0-9]{2}).([0-9]{2,3})( ?--> ?)([0-9]{2})?:?([0-9]{2}):([0-9]{2}).([0-9]{2,3})/, ); // Note that this currently ignores caption formatting directives that are optionally on the end of this line - fine for non-captions VTT if (matchTimes) { result.startTime = - Number(matchTimes[1]) * 60 * 60 + + Number(matchTimes[1] || 0) * 60 * 60 + Number(matchTimes[2]) * 60 + Number(matchTimes[3]) + Number(`0.${matchTimes[4]}`); result.endTime = - Number(matchTimes[6]) * 60 * 60 + + Number(matchTimes[6] || 0) * 60 * 60 + Number(matchTimes[7]) * 60 + Number(matchTimes[8]) + Number(`0.${matchTimes[9]}`); @@ -148,7 +148,10 @@ class PreviewThumbnails { // If the URLs don't start with '/', then we need to set their relative path to be the location of the VTT file // If the URLs do start with '/', then they obviously don't need a prefix, so it will remain blank - if (!thumbnail.frames[0].text.startsWith('/')) { + // If the thumbnail URLs start with with none of '/', 'http://' or 'https://', then we need to set their relative path to be the location of the VTT file + if (!thumbnail.frames[0].text.startsWith('/') && + !thumbnail.frames[0].text.startsWith('http://') && + !thumbnail.frames[0].text.startsWith('https://')) { thumbnail.urlPrefix = url.substring(0, url.lastIndexOf('/') + 1); } diff --git a/src/js/plugins/vimeo.js b/src/js/plugins/vimeo.js index a7664e73..9d6c1665 100644 --- a/src/js/plugins/vimeo.js +++ b/src/js/plugins/vimeo.js @@ -282,7 +282,7 @@ const vimeo = { Promise.all([player.embed.getVideoWidth(), player.embed.getVideoHeight()]).then(dimensions => { const [width, height] = dimensions; player.embed.ratio = `${width}:${height}`; - setAspectRatio.call(this, player.embed.ratio); + setAspectRatio.call(this); }); // Set autopause diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js index 9c447f7d..d862e4dd 100644 --- a/src/js/plugins/youtube.js +++ b/src/js/plugins/youtube.js @@ -39,7 +39,12 @@ function getHost(config) { return 'https://www.youtube-nocookie.com'; } - return `${window.location.protocol}//www.youtube.com`; + if (window.location.protocol === 'http:') { + return 'http://www.youtube.com'; + } + + // Use YouTube's default + return undefined; } const youtube = { @@ -394,7 +399,7 @@ const youtube = { case 1: // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet) - if (player.media.paused && !player.embed.hasPlayed) { + if (!player.config.autoplay && player.media.paused && !player.embed.hasPlayed) { player.media.pause(); } else { assurePlaybackState.call(player, true); diff --git a/src/js/plyr.js b/src/js/plyr.js index 0d3d1674..1dd3ecb9 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -26,6 +26,7 @@ import { off, on, once, triggerEvent, unbindListeners } from './utils/events'; import is from './utils/is'; import loadSprite from './utils/loadSprite'; import { cloneDeep, extend } from './utils/objects'; +import { getAspectRatio, reduceAspectRatio, setAspectRatio, validateRatio } from './utils/style'; import { parseUrl } from './utils/urls'; // Private properties @@ -301,8 +302,8 @@ class Plyr { } // Autoplay if required - if (this.config.autoplay) { - this.play(); + if (this.isHTML5 && this.config.autoplay) { + setTimeout(() => this.play(), 10); } // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek @@ -847,6 +848,34 @@ class Plyr { } /** + * Get the current aspect ratio in use + */ + get ratio() { + const ratio = reduceAspectRatio(getAspectRatio.call(this)); + + return is.array(ratio) ? ratio.join(':') : ratio; + } + + /** + * Set video aspect ratio + */ + set ratio(input) { + if (!this.isVideo) { + this.debug.warn('Aspect ratio can only be set for video'); + return; + } + + if (!is.string(input) || !validateRatio(input)) { + this.debug.error(`Invalid aspect ratio specified (${input})`); + return; + } + + this.config.ratio = input; + + setAspectRatio.call(this); + } + + /** * Set the autoplay state * @param {Boolean} input - Whether to autoplay or not */ @@ -1088,11 +1117,13 @@ class Plyr { // Stop playback this.stop(); + // Clear timeouts + clearTimeout(this.timers.loading); + clearTimeout(this.timers.controls); + clearTimeout(this.timers.resized); + // Provider specific stuff if (this.isHTML5) { - // Clear timeout - clearTimeout(this.timers.loading); - // Restore native video controls ui.toggleNativeControls.call(this, true); diff --git a/src/js/utils/style.js b/src/js/utils/style.js index a8eb393b..191e6461 100644 --- a/src/js/utils/style.js +++ b/src/js/utils/style.js @@ -4,26 +4,63 @@ import is from './is'; -/* function reduceAspectRatio(width, height) { - const getRatio = (w, h) => (h === 0 ? w : getRatio(h, w % h)); - const ratio = getRatio(width, height); - return `${width / ratio}:${height / ratio}`; -} */ +export function validateRatio(input) { + if (!is.array(input) && (!is.string(input) || !input.includes(':'))) { + return false; + } -// Set aspect ratio for responsive container -export function setAspectRatio(input) { - let ratio = input; + const ratio = is.array(input) ? input : input.split(':'); + + return ratio.map(Number).every(is.number); +} + +export function reduceAspectRatio(ratio) { + if (!is.array(ratio) || !ratio.every(is.number)) { + return null; + } + + const [width, height] = ratio; + const getDivider = (w, h) => (h === 0 ? w : getDivider(h, w % h)); + const divider = getDivider(width, height); + + return [width / divider, height / divider]; +} - if (!is.string(ratio) && !is.nullOrUndefined(this.embed)) { - ({ ratio } = this.embed); +export function getAspectRatio(input) { + const parse = ratio => { + if (!validateRatio(ratio)) { + return null; + } + + return ratio.split(':').map(Number); + }; + + // Provided ratio + let ratio = parse(input); + + // Get from config + if (ratio === null) { + ratio = parse(this.config.ratio); + } + + // Get from embed + if (ratio === null && !is.empty(this.embed) && is.string(this.embed.ratio)) { + ratio = parse(this.embed.ratio); } - if (!is.string(ratio)) { - ({ ratio } = this.config); + return ratio; +} + +// Set aspect ratio for responsive container +export function setAspectRatio(input) { + if (!this.isVideo) { + return {}; } - const [x, y] = ratio.split(':').map(Number); - const padding = (100 / x) * y; + const ratio = getAspectRatio.call(this, input); + + const [w, h] = is.array(ratio) ? ratio : [0, 0]; + const padding = (100 / w) * h; this.elements.wrapper.style.paddingBottom = `${padding}%`; @@ -32,6 +69,8 @@ export function setAspectRatio(input) { const height = 240; const offset = (height - padding) / (height / 50); this.media.style.transform = `translateY(-${offset}%)`; + } else if (this.isHTML5) { + this.elements.wrapper.classList.toggle(this.config.classNames.videoFixedRatio, ratio !== null); } return { padding, ratio }; |