aboutsummaryrefslogtreecommitdiffstats
path: root/src/js/plyr.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/plyr.js')
-rw-r--r--src/js/plyr.js202
1 files changed, 138 insertions, 64 deletions
diff --git a/src/js/plyr.js b/src/js/plyr.js
index 90bf00c8..f30d334a 100644
--- a/src/js/plyr.js
+++ b/src/js/plyr.js
@@ -1,6 +1,6 @@
// ==========================================================================
// Plyr
-// plyr.js v3.5.0-beta.5
+// plyr.js v3.5.6
// https://github.com/sampotts/plyr
// License: The MIT License (MIT)
// ==========================================================================
@@ -15,7 +15,7 @@ import Fullscreen from './fullscreen';
import Listeners from './listeners';
import media from './media';
import Ads from './plugins/ads';
-import PreviewThumbnails from './plugins/previewThumbnails';
+import PreviewThumbnails from './plugins/preview-thumbnails';
import source from './source';
import Storage from './storage';
import support from './support';
@@ -24,8 +24,10 @@ import { closest } from './utils/arrays';
import { createElement, hasClass, removeElement, replaceElement, toggleClass, wrap } from './utils/elements';
import { off, on, once, triggerEvent, unbindListeners } from './utils/events';
import is from './utils/is';
-import loadSprite from './utils/loadSprite';
+import loadSprite from './utils/load-sprite';
+import { clamp } from './utils/numbers';
import { cloneDeep, extend } from './utils/objects';
+import { getAspectRatio, reduceAspectRatio, setAspectRatio, validateRatio } from './utils/style';
import { parseUrl } from './utils/urls';
// Private properties
@@ -149,7 +151,6 @@ class Plyr {
// Set media type based on tag or data attribute
// Supported: video, audio, vimeo, youtube
const type = this.media.tagName.toLowerCase();
-
// Embed properties
let iframe = null;
let url = null;
@@ -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
@@ -322,27 +323,27 @@ class Plyr {
* Types and provider helpers
*/
get isHTML5() {
- return Boolean(this.provider === providers.html5);
+ return this.provider === providers.html5;
}
get isEmbed() {
- return Boolean(this.isYouTube || this.isVimeo);
+ return this.isYouTube || this.isVimeo;
}
get isYouTube() {
- return Boolean(this.provider === providers.youtube);
+ return this.provider === providers.youtube;
}
get isVimeo() {
- return Boolean(this.provider === providers.vimeo);
+ return this.provider === providers.vimeo;
}
get isVideo() {
- return Boolean(this.type === types.video);
+ return this.type === types.video;
}
get isAudio() {
- return Boolean(this.type === types.audio);
+ return this.type === types.audio;
}
/**
@@ -403,7 +404,7 @@ class Plyr {
/**
* Toggle playback based on current status
- * @param {boolean} input
+ * @param {Boolean} input
*/
togglePlay(input) {
// Toggle based on current state if nothing passed
@@ -437,7 +438,7 @@ class Plyr {
/**
* Rewind
- * @param {number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime
+ * @param {Number} seekTime - how far to rewind in seconds. Defaults to the config.seekTime
*/
rewind(seekTime) {
this.currentTime = this.currentTime - (is.number(seekTime) ? seekTime : this.config.seekTime);
@@ -445,7 +446,7 @@ class Plyr {
/**
* Fast forward
- * @param {number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime
+ * @param {Number} seekTime - how far to fast forward in seconds. Defaults to the config.seekTime
*/
forward(seekTime) {
this.currentTime = this.currentTime + (is.number(seekTime) ? seekTime : this.config.seekTime);
@@ -453,7 +454,7 @@ class Plyr {
/**
* Seek to a time
- * @param {number} input - where to seek to in seconds. Defaults to 0 (the start)
+ * @param {Number} input - where to seek to in seconds. Defaults to 0 (the start)
*/
set currentTime(input) {
// Bail if media duration isn't available yet
@@ -512,7 +513,6 @@ class Plyr {
get duration() {
// Faux duration set via config
const fauxDuration = parseFloat(this.config.duration);
-
// Media duration can be NaN or Infinity before the media has loaded
const realDuration = (this.media || {}).duration;
const duration = !is.number(realDuration) || realDuration === Infinity ? 0 : realDuration;
@@ -523,7 +523,7 @@ class Plyr {
/**
* Set the player volume
- * @param {number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage
+ * @param {Number} value - must be between 0 and 1. Defaults to the value from local storage and config.volume if not set in storage
*/
set volume(value) {
let volume = value;
@@ -574,7 +574,7 @@ class Plyr {
/**
* Increase volume
- * @param {boolean} step - How much to decrease by (between 0 and 1)
+ * @param {Boolean} step - How much to decrease by (between 0 and 1)
*/
increaseVolume(step) {
const volume = this.media.muted ? 0 : this.volume;
@@ -583,7 +583,7 @@ class Plyr {
/**
* Decrease volume
- * @param {boolean} step - How much to decrease by (between 0 and 1)
+ * @param {Boolean} step - How much to decrease by (between 0 and 1)
*/
decreaseVolume(step) {
this.increaseVolume(-step);
@@ -591,7 +591,7 @@ class Plyr {
/**
* Set muted state
- * @param {boolean} mute
+ * @param {Boolean} mute
*/
set muted(mute) {
let toggle = mute;
@@ -643,7 +643,7 @@ class Plyr {
/**
* Set playback speed
- * @param {number} speed - the speed of playback (0.5-2.0)
+ * @param {Number} speed - the speed of playback (0.5-2.0)
*/
set speed(input) {
let speed = null;
@@ -660,24 +660,17 @@ class Plyr {
speed = this.config.speed.selected;
}
- // Set min/max
- if (speed < 0.1) {
- speed = 0.1;
- }
- if (speed > 2.0) {
- speed = 2.0;
- }
-
- if (!this.config.speed.options.includes(speed)) {
- this.debug.warn(`Unsupported speed (${speed})`);
- return;
- }
+ // Clamp to min/max
+ const { minimumSpeed: min, maximumSpeed: max } = this;
+ speed = clamp(speed, min, max);
// Update config
this.config.speed.selected = speed;
// Set media speed
- this.media.playbackRate = speed;
+ setTimeout(() => {
+ this.media.playbackRate = speed;
+ }, 0);
}
/**
@@ -688,9 +681,45 @@ class Plyr {
}
/**
+ * Get the minimum allowed speed
+ */
+ get minimumSpeed() {
+ if (this.isYouTube) {
+ // https://developers.google.com/youtube/iframe_api_reference#setPlaybackRate
+ return Math.min(...this.options.speed);
+ }
+
+ if (this.isVimeo) {
+ // https://github.com/vimeo/player.js/#setplaybackrateplaybackrate-number-promisenumber-rangeerrorerror
+ return 0.5;
+ }
+
+ // https://stackoverflow.com/a/32320020/1191319
+ return 0.0625;
+ }
+
+ /**
+ * Get the maximum allowed speed
+ */
+ get maximumSpeed() {
+ if (this.isYouTube) {
+ // https://developers.google.com/youtube/iframe_api_reference#setPlaybackRate
+ return Math.max(...this.options.speed);
+ }
+
+ if (this.isVimeo) {
+ // https://github.com/vimeo/player.js/#setplaybackrateplaybackrate-number-promisenumber-rangeerrorerror
+ return 2;
+ }
+
+ // https://stackoverflow.com/a/32320020/1191319
+ return 16;
+ }
+
+ /**
* Set playback quality
* Currently HTML5 & YouTube only
- * @param {number} input - Quality level
+ * @param {Number} input - Quality level
*/
set quality(input) {
const config = this.config.quality;
@@ -740,7 +769,7 @@ class Plyr {
/**
* Toggle loop
* TODO: Finish fancy new logic. Set the indicator on load as user may pass loop as config
- * @param {boolean} input - Whether to loop or not
+ * @param {Boolean} input - Whether to loop or not
*/
set loop(input) {
const toggle = is.boolean(input) ? input : this.config.loop.active;
@@ -800,7 +829,7 @@ class Plyr {
/**
* Set new media source
- * @param {object} input - The new source object (see docs)
+ * @param {Object} input - The new source object (see docs)
*/
set source(input) {
source.change.call(this, input);
@@ -823,8 +852,21 @@ class Plyr {
}
/**
+ * Set the download URL
+ */
+ set download(input) {
+ if (!is.url(input)) {
+ return;
+ }
+
+ this.config.urls.download = input;
+
+ controls.setDownloadUrl.call(this);
+ }
+
+ /**
* Set the poster image for a video
- * @param {input} - the URL for the new poster image
+ * @param {String} input - the URL for the new poster image
*/
set poster(input) {
if (!this.isVideo) {
@@ -847,8 +889,40 @@ class Plyr {
}
/**
+ * Get the current aspect ratio in use
+ */
+ get ratio() {
+ if (!this.isVideo) {
+ return null;
+ }
+
+ 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
+ * @param {Boolean} input - Whether to autoplay or not
*/
set autoplay(input) {
const toggle = is.boolean(input) ? input : this.config.autoplay;
@@ -864,7 +938,7 @@ class Plyr {
/**
* Toggle captions
- * @param {boolean} input - Whether to enable captions
+ * @param {Boolean} input - Whether to enable captions
*/
toggleCaptions(input) {
captions.toggle.call(this, input, false);
@@ -872,7 +946,7 @@ class Plyr {
/**
* Set the caption track by index
- * @param {number} - Caption index
+ * @param {Number} - Caption index
*/
set currentTrack(input) {
captions.set.call(this, input, false);
@@ -889,7 +963,7 @@ class Plyr {
/**
* Set the wanted language for captions
* Since tracks can be added later it won't update the actual caption track until there is a matching track
- * @param {string} - Two character ISO language code (e.g. EN, FR, PT, etc)
+ * @param {String} - Two character ISO language code (e.g. EN, FR, PT, etc)
*/
set language(input) {
captions.setLanguage.call(this, input, false);
@@ -962,17 +1036,15 @@ class Plyr {
/**
* Toggle the player controls
- * @param {boolean} [toggle] - Whether to show the controls
+ * @param {Boolean} [toggle] - Whether to show the controls
*/
toggleControls(toggle) {
// Don't toggle if missing UI support or if it's audio
if (this.supported.ui && !this.isAudio) {
// Get state before change
const isHidden = hasClass(this.elements.container, this.config.classNames.hideControls);
-
// Negate the argument if not undefined since adding the class to hides the controls
const force = typeof toggle === 'undefined' ? undefined : !toggle;
-
// Apply and get updated state
const hiding = toggleClass(this.elements.container, this.config.classNames.hideControls, force);
@@ -995,8 +1067,8 @@ class Plyr {
/**
* Add event listeners
- * @param {string} event - Event type
- * @param {function} callback - Callback for when event occurs
+ * @param {String} event - Event type
+ * @param {Function} callback - Callback for when event occurs
*/
on(event, callback) {
on.call(this, this.elements.container, event, callback);
@@ -1004,8 +1076,8 @@ class Plyr {
/**
* Add event listeners once
- * @param {string} event - Event type
- * @param {function} callback - Callback for when event occurs
+ * @param {String} event - Event type
+ * @param {Function} callback - Callback for when event occurs
*/
once(event, callback) {
once.call(this, this.elements.container, event, callback);
@@ -1013,8 +1085,8 @@ class Plyr {
/**
* Remove event listeners
- * @param {string} event - Event type
- * @param {function} callback - Callback for when event occurs
+ * @param {String} event - Event type
+ * @param {Function} callback - Callback for when event occurs
*/
off(event, callback) {
off(this.elements.container, event, callback);
@@ -1024,8 +1096,8 @@ class Plyr {
* Destroy an instance
* Event listeners are removed when elements are removed
* http://stackoverflow.com/questions/12528049/if-a-dom-element-is-removed-are-its-listeners-also-removed-from-memory
- * @param {function} callback - Callback for when destroy is complete
- * @param {boolean} soft - Whether it's a soft destroy (for source changes etc)
+ * @param {Function} callback - Callback for when destroy is complete
+ * @param {Boolean} soft - Whether it's a soft destroy (for source changes etc)
*/
destroy(callback, soft = false) {
if (!this.ready) {
@@ -1088,11 +1160,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);
@@ -1124,7 +1198,7 @@ class Plyr {
/**
* Check for support for a mime type (HTML5 only)
- * @param {string} type - Mime type
+ * @param {String} type - Mime type
*/
supports(type) {
return support.mime.call(this, type);
@@ -1132,9 +1206,9 @@ class Plyr {
/**
* Check for support
- * @param {string} type - Player type (audio/video)
- * @param {string} provider - Provider (html5/youtube/vimeo)
- * @param {bool} inline - Where player has `playsinline` sttribute
+ * @param {String} type - Player type (audio/video)
+ * @param {String} provider - Provider (html5/youtube/vimeo)
+ * @param {Boolean} inline - Where player has `playsinline` sttribute
*/
static supported(type, provider, inline) {
return support.check(type, provider, inline);
@@ -1142,8 +1216,8 @@ class Plyr {
/**
* Load an SVG sprite into the page
- * @param {string} url - URL for the SVG sprite
- * @param {string} [id] - Unique ID
+ * @param {String} url - URL for the SVG sprite
+ * @param {String} [id] - Unique ID
*/
static loadSprite(url, id) {
return loadSprite(url, id);
@@ -1152,7 +1226,7 @@ class Plyr {
/**
* Setup multiple instances
* @param {*} selector
- * @param {object} options
+ * @param {Object} options
*/
static setup(selector, options = {}) {
let targets = null;