Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
333619f1e3 | |||
17dcb63c26 | |||
e04b90c9c0 | |||
f62e1da01a | |||
2fe949629f | |||
20f2ddc11d | |||
004528a65c | |||
39c7bd40c2 | |||
43879e08f4 | |||
5ed7aa6620 | |||
47750b6aad | |||
de7832eb8b | |||
52ea5bd0ab | |||
457d112df7 | |||
22cdec9d38 | |||
d72e502107 | |||
94055f0772 | |||
ede9323524 | |||
c45f428f61 | |||
b61ba02f3d | |||
ea4d91d2a0 | |||
22d524ac9d | |||
8584f6a1db |
27
changelog.md
27
changelog.md
@ -1,3 +1,30 @@
|
||||
# v3.3.19
|
||||
|
||||
- Remove `pointer-events: none` on embed `<iframe>` to comply with YouTube ToS
|
||||
|
||||
# 3.3.18
|
||||
|
||||
- Ads are now only supported on HTML5 videos as it violates terms of service for YouTube and Vimeo 😢
|
||||
- Fix i18n defaults path on README (thanks @meyt!)
|
||||
- Minor increaseVolume and decreaseVolume changes (thanks @friday!)
|
||||
|
||||
# v3.3.17
|
||||
|
||||
- Fix YouTube muting after seeking with the progress slider (thanks @friday!)
|
||||
- Respect preload="none" when setting quality if the media hasn't been loaded some other way (thanks @friday!)
|
||||
|
||||
# v3.3.16
|
||||
|
||||
- Fixed regression relating the play button status (fixes #1048)
|
||||
|
||||
# v3.3.15
|
||||
|
||||
- Fix for error relating to play buttons when switching source
|
||||
|
||||
# v3.3.14
|
||||
|
||||
- Fix sprite loading regression
|
||||
|
||||
# v3.3.13
|
||||
|
||||
You guessed it, a load of awesome changes from contributors:
|
||||
|
2
demo/dist/demo.css
vendored
2
demo/dist/demo.css
vendored
File diff suppressed because one or more lines are too long
11
demo/dist/demo.js
vendored
11
demo/dist/demo.js
vendored
@ -1874,7 +1874,7 @@ typeof navigator === "object" && (function () {
|
||||
// webpack (using a build step causes webpack #1617). Grunt verifies that
|
||||
// this value matches package.json during build.
|
||||
// See: https://github.com/getsentry/raven-js/issues/465
|
||||
VERSION: '3.26.2',
|
||||
VERSION: '3.26.3',
|
||||
|
||||
debug: false,
|
||||
|
||||
@ -2351,7 +2351,9 @@ typeof navigator === "object" && (function () {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._globalOptions.stacktrace || (options && options.stacktrace)) {
|
||||
// Always attempt to get stacktrace if message is empty.
|
||||
// It's the only way to provide any helpful information to the user.
|
||||
if (this._globalOptions.stacktrace || options.stacktrace || data.message === '') {
|
||||
// fingerprint on msg, not stack trace (legacy behavior, could be revisited)
|
||||
data.fingerprint = data.fingerprint == null ? msg : data.fingerprint;
|
||||
|
||||
@ -3508,6 +3510,11 @@ typeof navigator === "object" && (function () {
|
||||
options
|
||||
);
|
||||
|
||||
var ex = data.exception.values[0];
|
||||
if (ex.type == null && ex.value === '') {
|
||||
ex.value = 'Unrecoverable error caught';
|
||||
}
|
||||
|
||||
// Move mechanism from options to exception interface
|
||||
// We do this, as requiring user to pass `{exception:{mechanism:{ ... }}}` would be
|
||||
// too much
|
||||
|
2
demo/dist/demo.js.map
vendored
2
demo/dist/demo.js.map
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js
vendored
2
demo/dist/demo.min.js
vendored
File diff suppressed because one or more lines are too long
2
demo/dist/demo.min.js.map
vendored
2
demo/dist/demo.min.js.map
vendored
File diff suppressed because one or more lines are too long
@ -96,7 +96,7 @@
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" type="video/mp4" size="576">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4" type="video/mp4" size="720">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4" type="video/mp4" size="1080">
|
||||
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4" type="video/mp4" size="1440">
|
||||
<!-- <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4" type="video/mp4" size="1440"> -->
|
||||
|
||||
<!-- Caption files -->
|
||||
<track kind="captions" label="English" srclang="en" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt"
|
||||
|
@ -143,7 +143,11 @@ import Raven from 'raven-js';
|
||||
// Set a new source
|
||||
function newSource(type, init) {
|
||||
// Bail if new type isn't known, it's the current type, or current type is empty (video is default) and new type is video
|
||||
if (!(type in types) || (!init && type === currentType) || (!currentType.length && type === types.video)) {
|
||||
if (
|
||||
!(type in types) ||
|
||||
(!init && type === currentType) ||
|
||||
(!currentType.length && type === types.video)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -215,10 +219,12 @@ import Raven from 'raven-js';
|
||||
case types.youtube:
|
||||
player.source = {
|
||||
type: 'video',
|
||||
sources: [{
|
||||
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
||||
provider: 'youtube',
|
||||
}],
|
||||
sources: [
|
||||
{
|
||||
src: 'https://youtube.com/watch?v=bTqVqk7FSmY',
|
||||
provider: 'youtube',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
break;
|
||||
@ -226,10 +232,12 @@ import Raven from 'raven-js';
|
||||
case types.vimeo:
|
||||
player.source = {
|
||||
type: 'video',
|
||||
sources: [{
|
||||
src: 'https://vimeo.com/76979871',
|
||||
provider: 'vimeo',
|
||||
}],
|
||||
sources: [
|
||||
{
|
||||
src: 'https://vimeo.com/76979871',
|
||||
provider: 'vimeo',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
break;
|
||||
|
2
dist/plyr.css
vendored
2
dist/plyr.css
vendored
File diff suppressed because one or more lines are too long
330
dist/plyr.js
vendored
330
dist/plyr.js
vendored
@ -11,60 +11,92 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
var getConstructor = function getConstructor(input) {
|
||||
return input !== null && typeof input !== 'undefined' ? input.constructor : null;
|
||||
};
|
||||
|
||||
var instanceOf = function instanceOf(input, constructor) {
|
||||
return Boolean(input && constructor && input instanceof constructor);
|
||||
};
|
||||
var isNullOrUndefined = function isNullOrUndefined(input) {
|
||||
return input === null || typeof input === 'undefined';
|
||||
};
|
||||
var isObject = function isObject(input) {
|
||||
return getConstructor(input) === Object;
|
||||
};
|
||||
var isNumber = function isNumber(input) {
|
||||
return getConstructor(input) === Number && !Number.isNaN(input);
|
||||
};
|
||||
var isString = function isString(input) {
|
||||
return getConstructor(input) === String;
|
||||
};
|
||||
var isBoolean = function isBoolean(input) {
|
||||
return getConstructor(input) === Boolean;
|
||||
};
|
||||
var isFunction = function isFunction(input) {
|
||||
return getConstructor(input) === Function;
|
||||
};
|
||||
var isArray = function isArray(input) {
|
||||
return Array.isArray(input);
|
||||
};
|
||||
var isWeakMap = function isWeakMap(input) {
|
||||
return instanceOf(input, WeakMap);
|
||||
};
|
||||
var isNodeList = function isNodeList(input) {
|
||||
return instanceOf(input, NodeList);
|
||||
};
|
||||
var isElement = function isElement(input) {
|
||||
return instanceOf(input, Element);
|
||||
};
|
||||
var isTextNode = function isTextNode(input) {
|
||||
return getConstructor(input) === Text;
|
||||
};
|
||||
var isEvent = function isEvent(input) {
|
||||
return instanceOf(input, Event);
|
||||
};
|
||||
var isCue = function isCue(input) {
|
||||
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||
};
|
||||
var isTrack = function isTrack(input) {
|
||||
return instanceOf(input, TextTrack) || !isNullOrUndefined(input) && isString(input.kind);
|
||||
};
|
||||
|
||||
var isEmpty = function isEmpty(input) {
|
||||
return isNullOrUndefined(input) || (isString(input) || isArray(input) || isNodeList(input)) && !input.length || isObject(input) && !Object.keys(input).length;
|
||||
};
|
||||
|
||||
var isUrl = function isUrl(input) {
|
||||
// Accept a URL object
|
||||
if (instanceOf(input, window.URL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add the protocol if required
|
||||
var string = input;
|
||||
if (!input.startsWith('http://') || !input.startsWith('https://')) {
|
||||
string = 'http://' + input;
|
||||
}
|
||||
|
||||
try {
|
||||
return !isEmpty(new URL(string).hostname);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var is = {
|
||||
object: function object(input) {
|
||||
return getConstructor(input) === Object;
|
||||
},
|
||||
number: function number(input) {
|
||||
return getConstructor(input) === Number && !Number.isNaN(input);
|
||||
},
|
||||
string: function string(input) {
|
||||
return getConstructor(input) === String;
|
||||
},
|
||||
boolean: function boolean(input) {
|
||||
return getConstructor(input) === Boolean;
|
||||
},
|
||||
function: function _function(input) {
|
||||
return getConstructor(input) === Function;
|
||||
},
|
||||
array: function array(input) {
|
||||
return !is.nullOrUndefined(input) && Array.isArray(input);
|
||||
},
|
||||
weakMap: function weakMap(input) {
|
||||
return instanceOf(input, WeakMap);
|
||||
},
|
||||
nodeList: function nodeList(input) {
|
||||
return instanceOf(input, NodeList);
|
||||
},
|
||||
element: function element(input) {
|
||||
return instanceOf(input, Element);
|
||||
},
|
||||
textNode: function textNode(input) {
|
||||
return getConstructor(input) === Text;
|
||||
},
|
||||
event: function event(input) {
|
||||
return instanceOf(input, Event);
|
||||
},
|
||||
cue: function cue(input) {
|
||||
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||
},
|
||||
track: function track(input) {
|
||||
return instanceOf(input, TextTrack) || !is.nullOrUndefined(input) && is.string(input.kind);
|
||||
},
|
||||
url: function url(input) {
|
||||
return !is.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input);
|
||||
},
|
||||
nullOrUndefined: function nullOrUndefined(input) {
|
||||
return input === null || typeof input === 'undefined';
|
||||
},
|
||||
empty: function empty(input) {
|
||||
return is.nullOrUndefined(input) || (is.string(input) || is.array(input) || is.nodeList(input)) && !input.length || is.object(input) && !Object.keys(input).length;
|
||||
}
|
||||
nullOrUndefined: isNullOrUndefined,
|
||||
object: isObject,
|
||||
number: isNumber,
|
||||
string: isString,
|
||||
boolean: isBoolean,
|
||||
function: isFunction,
|
||||
array: isArray,
|
||||
weakMap: isWeakMap,
|
||||
nodeList: isNodeList,
|
||||
element: isElement,
|
||||
textNode: isTextNode,
|
||||
event: isEvent,
|
||||
cue: isCue,
|
||||
track: isTrack,
|
||||
url: isUrl,
|
||||
empty: isEmpty
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
@ -769,22 +801,17 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
|
||||
// Quality
|
||||
Object.defineProperty(player.media, 'quality', {
|
||||
get: function get$$1() {
|
||||
get: function get() {
|
||||
// Get sources
|
||||
var sources = html5.getSources.call(player);
|
||||
|
||||
var _sources$filter = sources.filter(function (source) {
|
||||
var source = sources.find(function (source) {
|
||||
return source.getAttribute('src') === player.source;
|
||||
}),
|
||||
_sources$filter2 = slicedToArray(_sources$filter, 1),
|
||||
source = _sources$filter2[0];
|
||||
});
|
||||
|
||||
// Return size, if match is found
|
||||
|
||||
|
||||
return source && Number(source.getAttribute('size'));
|
||||
},
|
||||
set: function set$$1(input) {
|
||||
set: function set(input) {
|
||||
// Get sources
|
||||
var sources = html5.getSources.call(player);
|
||||
|
||||
@ -799,25 +826,30 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}
|
||||
|
||||
// Get current state
|
||||
var currentTime = player.currentTime,
|
||||
playing = player.playing;
|
||||
var _player$media = player.media,
|
||||
currentTime = _player$media.currentTime,
|
||||
paused = _player$media.paused,
|
||||
preload = _player$media.preload,
|
||||
readyState = _player$media.readyState;
|
||||
|
||||
// Set new source
|
||||
|
||||
player.media.src = source.getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
var onLoadedMetaData = function onLoadedMetaData() {
|
||||
player.currentTime = currentTime;
|
||||
};
|
||||
player.once('loadedmetadata', onLoadedMetaData);
|
||||
// Prevent loading if preload="none" and the current source isn't loaded (#1044)
|
||||
if (preload !== 'none' || readyState) {
|
||||
// Restore time
|
||||
player.once('loadedmetadata', function () {
|
||||
player.currentTime = currentTime;
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
// Resume playing
|
||||
if (!paused) {
|
||||
player.play();
|
||||
}
|
||||
});
|
||||
|
||||
// Resume playing
|
||||
if (playing) {
|
||||
player.play();
|
||||
// Load new source
|
||||
player.media.load();
|
||||
}
|
||||
|
||||
// Trigger change event
|
||||
@ -1137,6 +1169,51 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
return Storage;
|
||||
}();
|
||||
|
||||
// ==========================================================================
|
||||
// Fetch wrapper
|
||||
// Using XHR to avoid issues with older browsers
|
||||
// ==========================================================================
|
||||
|
||||
function fetch(url) {
|
||||
var responseType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
// Check for CORS support
|
||||
if (!('withCredentials' in request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request.addEventListener('load', function () {
|
||||
if (responseType === 'text') {
|
||||
try {
|
||||
resolve(JSON.parse(request.responseText));
|
||||
} catch (e) {
|
||||
resolve(request.responseText);
|
||||
}
|
||||
} else {
|
||||
resolve(request.response);
|
||||
}
|
||||
});
|
||||
|
||||
request.addEventListener('error', function () {
|
||||
throw new Error(request.status);
|
||||
});
|
||||
|
||||
request.open('GET', url, true);
|
||||
|
||||
// Set the required response type
|
||||
request.responseType = responseType;
|
||||
|
||||
request.send();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
// Load an external SVG sprite
|
||||
@ -2709,51 +2786,6 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
// Fetch wrapper
|
||||
// Using XHR to avoid issues with older browsers
|
||||
// ==========================================================================
|
||||
|
||||
function fetch$1(url) {
|
||||
var responseType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
// Check for CORS support
|
||||
if (!('withCredentials' in request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request.addEventListener('load', function () {
|
||||
if (responseType === 'text') {
|
||||
try {
|
||||
resolve(JSON.parse(request.responseText));
|
||||
} catch (e) {
|
||||
resolve(request.responseText);
|
||||
}
|
||||
} else {
|
||||
resolve(request.response);
|
||||
}
|
||||
});
|
||||
|
||||
request.addEventListener('error', function () {
|
||||
throw new Error(request.statusText);
|
||||
});
|
||||
|
||||
request.open('GET', url, true);
|
||||
|
||||
// Set the required response type
|
||||
request.responseType = responseType;
|
||||
|
||||
request.send();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
@ -2833,7 +2865,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
var url = parseUrl(src);
|
||||
|
||||
if (url !== null && url.hostname !== window.location.href.hostname && ['http:', 'https:'].includes(url.protocol)) {
|
||||
fetch$1(src, 'blob').then(function (blob) {
|
||||
fetch(src, 'blob').then(function (blob) {
|
||||
track.setAttribute('src', window.URL.createObjectURL(blob));
|
||||
}).catch(function () {
|
||||
removeElement(track);
|
||||
@ -3997,11 +4029,9 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}
|
||||
|
||||
// If there's a play button, set label
|
||||
if (is.nodeList(this.elements.buttons.play)) {
|
||||
Array.from(this.elements.buttons.play).forEach(function (button) {
|
||||
button.setAttribute('aria-label', label);
|
||||
});
|
||||
}
|
||||
Array.from(this.elements.buttons.play || []).forEach(function (button) {
|
||||
button.setAttribute('aria-label', label);
|
||||
});
|
||||
|
||||
// Set iframe title
|
||||
// https://github.com/sampotts/plyr/issues/124
|
||||
@ -4081,7 +4111,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
|
||||
|
||||
// Set state
|
||||
Array.from(this.elements.buttons.play).forEach(function (target) {
|
||||
Array.from(this.elements.buttons.play || []).forEach(function (target) {
|
||||
target.pressed = _this3.playing;
|
||||
});
|
||||
|
||||
@ -4779,33 +4809,28 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
// Detect "natural" scroll - suppored on OS X Safari only
|
||||
// Other browsers on OS X will be inverted until support improves
|
||||
var inverted = event.webkitDirectionInvertedFromDevice;
|
||||
var step = 1 / 50;
|
||||
var direction = 0;
|
||||
|
||||
// Scroll down (or up on natural) to decrease
|
||||
if (event.deltaY < 0 || event.deltaX > 0) {
|
||||
if (inverted) {
|
||||
_this4.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
} else {
|
||||
_this4.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
}
|
||||
}
|
||||
// Get delta from event. Invert if `inverted` is true
|
||||
|
||||
// Scroll up (or down on natural) to increase
|
||||
if (event.deltaY > 0 || event.deltaX < 0) {
|
||||
if (inverted) {
|
||||
_this4.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
} else {
|
||||
_this4.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
}
|
||||
}
|
||||
var _map = [event.deltaX, -event.deltaY].map(function (value) {
|
||||
return inverted ? -value : value;
|
||||
}),
|
||||
_map2 = slicedToArray(_map, 2),
|
||||
x = _map2[0],
|
||||
y = _map2[1];
|
||||
|
||||
// Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)
|
||||
|
||||
|
||||
var direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);
|
||||
|
||||
// Change the volume by 2%
|
||||
_this4.player.increaseVolume(direction / 50);
|
||||
|
||||
// Don't break page scrolling at max and min
|
||||
if (direction === 1 && _this4.player.media.volume < 1 || direction === -1 && _this4.player.media.volume > 0) {
|
||||
var volume = _this4.player.media.volume;
|
||||
|
||||
if (direction === 1 && volume < 1 || direction === -1 && volume > 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}, 'volume', false);
|
||||
@ -5253,7 +5278,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
|
||||
// Get poster image
|
||||
fetch$1(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is.empty(response)) {
|
||||
return;
|
||||
}
|
||||
@ -5668,7 +5693,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
if (is.string(key) && !is.empty(key)) {
|
||||
var url = format(this.config.urls.youtube.api, videoId, key);
|
||||
|
||||
fetch$1(url).then(function (result) {
|
||||
fetch(url).then(function (result) {
|
||||
if (is.object(result)) {
|
||||
_this2.config.title = result.items[0].snippet.title;
|
||||
ui.setTitle.call(_this2);
|
||||
@ -5824,8 +5849,8 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
return Number(instance.getCurrentTime());
|
||||
},
|
||||
set: function set(time) {
|
||||
// If paused, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused) {
|
||||
// If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused && !player.embed.hasPlayed) {
|
||||
player.embed.mute();
|
||||
}
|
||||
|
||||
@ -6744,7 +6769,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}, {
|
||||
key: 'enabled',
|
||||
get: function get$$1() {
|
||||
return this.player.isVideo && this.player.config.ads.enabled && !is.empty(this.publisherId);
|
||||
return this.player.isHTML5 && this.player.isVideo && this.player.config.ads.enabled && !is.empty(this.publisherId);
|
||||
}
|
||||
}, {
|
||||
key: 'tagUrl',
|
||||
@ -7301,7 +7326,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
*/
|
||||
value: function increaseVolume(step) {
|
||||
var volume = this.media.muted ? 0 : this.volume;
|
||||
this.volume = volume + (is.number(step) ? step : 1);
|
||||
this.volume = volume + (is.number(step) ? step : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7312,8 +7337,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}, {
|
||||
key: 'decreaseVolume',
|
||||
value: function decreaseVolume(step) {
|
||||
var volume = this.media.muted ? 0 : this.volume;
|
||||
this.volume = volume - (is.number(step) ? step : 1);
|
||||
this.increaseVolume(-step);
|
||||
}
|
||||
|
||||
/**
|
||||
|
2
dist/plyr.js.map
vendored
2
dist/plyr.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js
vendored
2
dist/plyr.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.min.js.map
vendored
2
dist/plyr.min.js.map
vendored
File diff suppressed because one or more lines are too long
326
dist/plyr.polyfilled.js
vendored
326
dist/plyr.polyfilled.js
vendored
@ -5397,60 +5397,92 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
var getConstructor = function getConstructor(input) {
|
||||
return input !== null && typeof input !== 'undefined' ? input.constructor : null;
|
||||
};
|
||||
|
||||
var instanceOf = function instanceOf(input, constructor) {
|
||||
return Boolean(input && constructor && input instanceof constructor);
|
||||
};
|
||||
var isNullOrUndefined = function isNullOrUndefined(input) {
|
||||
return input === null || typeof input === 'undefined';
|
||||
};
|
||||
var isObject = function isObject(input) {
|
||||
return getConstructor(input) === Object;
|
||||
};
|
||||
var isNumber = function isNumber(input) {
|
||||
return getConstructor(input) === Number && !Number.isNaN(input);
|
||||
};
|
||||
var isString = function isString(input) {
|
||||
return getConstructor(input) === String;
|
||||
};
|
||||
var isBoolean = function isBoolean(input) {
|
||||
return getConstructor(input) === Boolean;
|
||||
};
|
||||
var isFunction = function isFunction(input) {
|
||||
return getConstructor(input) === Function;
|
||||
};
|
||||
var isArray = function isArray(input) {
|
||||
return Array.isArray(input);
|
||||
};
|
||||
var isWeakMap = function isWeakMap(input) {
|
||||
return instanceOf(input, WeakMap);
|
||||
};
|
||||
var isNodeList = function isNodeList(input) {
|
||||
return instanceOf(input, NodeList);
|
||||
};
|
||||
var isElement = function isElement(input) {
|
||||
return instanceOf(input, Element);
|
||||
};
|
||||
var isTextNode = function isTextNode(input) {
|
||||
return getConstructor(input) === Text;
|
||||
};
|
||||
var isEvent = function isEvent(input) {
|
||||
return instanceOf(input, Event);
|
||||
};
|
||||
var isCue = function isCue(input) {
|
||||
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||
};
|
||||
var isTrack = function isTrack(input) {
|
||||
return instanceOf(input, TextTrack) || !isNullOrUndefined(input) && isString(input.kind);
|
||||
};
|
||||
|
||||
var isEmpty = function isEmpty(input) {
|
||||
return isNullOrUndefined(input) || (isString(input) || isArray(input) || isNodeList(input)) && !input.length || isObject(input) && !Object.keys(input).length;
|
||||
};
|
||||
|
||||
var isUrl = function isUrl(input) {
|
||||
// Accept a URL object
|
||||
if (instanceOf(input, window.URL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add the protocol if required
|
||||
var string = input;
|
||||
if (!input.startsWith('http://') || !input.startsWith('https://')) {
|
||||
string = 'http://' + input;
|
||||
}
|
||||
|
||||
try {
|
||||
return !isEmpty(new URL(string).hostname);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var is$1 = {
|
||||
object: function object(input) {
|
||||
return getConstructor(input) === Object;
|
||||
},
|
||||
number: function number(input) {
|
||||
return getConstructor(input) === Number && !Number.isNaN(input);
|
||||
},
|
||||
string: function string(input) {
|
||||
return getConstructor(input) === String;
|
||||
},
|
||||
boolean: function boolean(input) {
|
||||
return getConstructor(input) === Boolean;
|
||||
},
|
||||
function: function _function(input) {
|
||||
return getConstructor(input) === Function;
|
||||
},
|
||||
array: function array(input) {
|
||||
return !is$1.nullOrUndefined(input) && Array.isArray(input);
|
||||
},
|
||||
weakMap: function weakMap(input) {
|
||||
return instanceOf(input, WeakMap);
|
||||
},
|
||||
nodeList: function nodeList(input) {
|
||||
return instanceOf(input, NodeList);
|
||||
},
|
||||
element: function element(input) {
|
||||
return instanceOf(input, Element);
|
||||
},
|
||||
textNode: function textNode(input) {
|
||||
return getConstructor(input) === Text;
|
||||
},
|
||||
event: function event(input) {
|
||||
return instanceOf(input, Event);
|
||||
},
|
||||
cue: function cue(input) {
|
||||
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||
},
|
||||
track: function track(input) {
|
||||
return instanceOf(input, TextTrack) || !is$1.nullOrUndefined(input) && is$1.string(input.kind);
|
||||
},
|
||||
url: function url(input) {
|
||||
return !is$1.nullOrUndefined(input) && /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input);
|
||||
},
|
||||
nullOrUndefined: function nullOrUndefined(input) {
|
||||
return input === null || typeof input === 'undefined';
|
||||
},
|
||||
empty: function empty(input) {
|
||||
return is$1.nullOrUndefined(input) || (is$1.string(input) || is$1.array(input) || is$1.nodeList(input)) && !input.length || is$1.object(input) && !Object.keys(input).length;
|
||||
}
|
||||
nullOrUndefined: isNullOrUndefined,
|
||||
object: isObject,
|
||||
number: isNumber,
|
||||
string: isString,
|
||||
boolean: isBoolean,
|
||||
function: isFunction,
|
||||
array: isArray,
|
||||
weakMap: isWeakMap,
|
||||
nodeList: isNodeList,
|
||||
element: isElement,
|
||||
textNode: isTextNode,
|
||||
event: isEvent,
|
||||
cue: isCue,
|
||||
track: isTrack,
|
||||
url: isUrl,
|
||||
empty: isEmpty
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
@ -6158,16 +6190,11 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
get: function get() {
|
||||
// Get sources
|
||||
var sources = html5.getSources.call(player);
|
||||
|
||||
var _sources$filter = sources.filter(function (source) {
|
||||
var source = sources.find(function (source) {
|
||||
return source.getAttribute('src') === player.source;
|
||||
}),
|
||||
_sources$filter2 = slicedToArray(_sources$filter, 1),
|
||||
source = _sources$filter2[0];
|
||||
});
|
||||
|
||||
// Return size, if match is found
|
||||
|
||||
|
||||
return source && Number(source.getAttribute('size'));
|
||||
},
|
||||
set: function set(input) {
|
||||
@ -6185,25 +6212,30 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}
|
||||
|
||||
// Get current state
|
||||
var currentTime = player.currentTime,
|
||||
playing = player.playing;
|
||||
var _player$media = player.media,
|
||||
currentTime = _player$media.currentTime,
|
||||
paused = _player$media.paused,
|
||||
preload = _player$media.preload,
|
||||
readyState = _player$media.readyState;
|
||||
|
||||
// Set new source
|
||||
|
||||
player.media.src = source.getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
var onLoadedMetaData = function onLoadedMetaData() {
|
||||
player.currentTime = currentTime;
|
||||
};
|
||||
player.once('loadedmetadata', onLoadedMetaData);
|
||||
// Prevent loading if preload="none" and the current source isn't loaded (#1044)
|
||||
if (preload !== 'none' || readyState) {
|
||||
// Restore time
|
||||
player.once('loadedmetadata', function () {
|
||||
player.currentTime = currentTime;
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
// Resume playing
|
||||
if (!paused) {
|
||||
player.play();
|
||||
}
|
||||
});
|
||||
|
||||
// Resume playing
|
||||
if (playing) {
|
||||
player.play();
|
||||
// Load new source
|
||||
player.media.load();
|
||||
}
|
||||
|
||||
// Trigger change event
|
||||
@ -6523,6 +6555,51 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
return Storage;
|
||||
}();
|
||||
|
||||
// ==========================================================================
|
||||
// Fetch wrapper
|
||||
// Using XHR to avoid issues with older browsers
|
||||
// ==========================================================================
|
||||
|
||||
function fetch(url) {
|
||||
var responseType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
// Check for CORS support
|
||||
if (!('withCredentials' in request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request.addEventListener('load', function () {
|
||||
if (responseType === 'text') {
|
||||
try {
|
||||
resolve(JSON.parse(request.responseText));
|
||||
} catch (e) {
|
||||
resolve(request.responseText);
|
||||
}
|
||||
} else {
|
||||
resolve(request.response);
|
||||
}
|
||||
});
|
||||
|
||||
request.addEventListener('error', function () {
|
||||
throw new Error(request.status);
|
||||
});
|
||||
|
||||
request.open('GET', url, true);
|
||||
|
||||
// Set the required response type
|
||||
request.responseType = responseType;
|
||||
|
||||
request.send();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
// Load an external SVG sprite
|
||||
@ -8095,51 +8172,6 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}
|
||||
};
|
||||
|
||||
// ==========================================================================
|
||||
// Fetch wrapper
|
||||
// Using XHR to avoid issues with older browsers
|
||||
// ==========================================================================
|
||||
|
||||
function fetch$1(url) {
|
||||
var responseType = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'text';
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var request = new XMLHttpRequest();
|
||||
|
||||
// Check for CORS support
|
||||
if (!('withCredentials' in request)) {
|
||||
return;
|
||||
}
|
||||
|
||||
request.addEventListener('load', function () {
|
||||
if (responseType === 'text') {
|
||||
try {
|
||||
resolve(JSON.parse(request.responseText));
|
||||
} catch (e) {
|
||||
resolve(request.responseText);
|
||||
}
|
||||
} else {
|
||||
resolve(request.response);
|
||||
}
|
||||
});
|
||||
|
||||
request.addEventListener('error', function () {
|
||||
throw new Error(request.statusText);
|
||||
});
|
||||
|
||||
request.open('GET', url, true);
|
||||
|
||||
// Set the required response type
|
||||
request.responseType = responseType;
|
||||
|
||||
request.send();
|
||||
} catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ==========================================================================
|
||||
|
||||
/**
|
||||
@ -8219,7 +8251,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
var url = parseUrl(src);
|
||||
|
||||
if (url !== null && url.hostname !== window.location.href.hostname && ['http:', 'https:'].includes(url.protocol)) {
|
||||
fetch$1(src, 'blob').then(function (blob) {
|
||||
fetch(src, 'blob').then(function (blob) {
|
||||
track.setAttribute('src', window.URL.createObjectURL(blob));
|
||||
}).catch(function () {
|
||||
removeElement(track);
|
||||
@ -9383,11 +9415,9 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}
|
||||
|
||||
// If there's a play button, set label
|
||||
if (is$1.nodeList(this.elements.buttons.play)) {
|
||||
Array.from(this.elements.buttons.play).forEach(function (button) {
|
||||
button.setAttribute('aria-label', label);
|
||||
});
|
||||
}
|
||||
Array.from(this.elements.buttons.play || []).forEach(function (button) {
|
||||
button.setAttribute('aria-label', label);
|
||||
});
|
||||
|
||||
// Set iframe title
|
||||
// https://github.com/sampotts/plyr/issues/124
|
||||
@ -9467,7 +9497,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
|
||||
|
||||
// Set state
|
||||
Array.from(this.elements.buttons.play).forEach(function (target) {
|
||||
Array.from(this.elements.buttons.play || []).forEach(function (target) {
|
||||
target.pressed = _this3.playing;
|
||||
});
|
||||
|
||||
@ -10165,33 +10195,28 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
// Detect "natural" scroll - suppored on OS X Safari only
|
||||
// Other browsers on OS X will be inverted until support improves
|
||||
var inverted = event.webkitDirectionInvertedFromDevice;
|
||||
var step = 1 / 50;
|
||||
var direction = 0;
|
||||
|
||||
// Scroll down (or up on natural) to decrease
|
||||
if (event.deltaY < 0 || event.deltaX > 0) {
|
||||
if (inverted) {
|
||||
_this4.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
} else {
|
||||
_this4.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
}
|
||||
}
|
||||
// Get delta from event. Invert if `inverted` is true
|
||||
|
||||
// Scroll up (or down on natural) to increase
|
||||
if (event.deltaY > 0 || event.deltaX < 0) {
|
||||
if (inverted) {
|
||||
_this4.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
} else {
|
||||
_this4.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
}
|
||||
}
|
||||
var _map = [event.deltaX, -event.deltaY].map(function (value) {
|
||||
return inverted ? -value : value;
|
||||
}),
|
||||
_map2 = slicedToArray(_map, 2),
|
||||
x = _map2[0],
|
||||
y = _map2[1];
|
||||
|
||||
// Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)
|
||||
|
||||
|
||||
var direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);
|
||||
|
||||
// Change the volume by 2%
|
||||
_this4.player.increaseVolume(direction / 50);
|
||||
|
||||
// Don't break page scrolling at max and min
|
||||
if (direction === 1 && _this4.player.media.volume < 1 || direction === -1 && _this4.player.media.volume > 0) {
|
||||
var volume = _this4.player.media.volume;
|
||||
|
||||
if (direction === 1 && volume < 1 || direction === -1 && volume > 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}, 'volume', false);
|
||||
@ -10633,7 +10658,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
player.media = replaceElement(wrapper, player.media);
|
||||
|
||||
// Get poster image
|
||||
fetch$1(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
fetch(format(player.config.urls.vimeo.api, id), 'json').then(function (response) {
|
||||
if (is$1.empty(response)) {
|
||||
return;
|
||||
}
|
||||
@ -11048,7 +11073,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
if (is$1.string(key) && !is$1.empty(key)) {
|
||||
var url = format(this.config.urls.youtube.api, videoId, key);
|
||||
|
||||
fetch$1(url).then(function (result) {
|
||||
fetch(url).then(function (result) {
|
||||
if (is$1.object(result)) {
|
||||
_this2.config.title = result.items[0].snippet.title;
|
||||
ui.setTitle.call(_this2);
|
||||
@ -11204,8 +11229,8 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
return Number(instance.getCurrentTime());
|
||||
},
|
||||
set: function set(time) {
|
||||
// If paused, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused) {
|
||||
// If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused && !player.embed.hasPlayed) {
|
||||
player.embed.mute();
|
||||
}
|
||||
|
||||
@ -12124,7 +12149,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}, {
|
||||
key: 'enabled',
|
||||
get: function get() {
|
||||
return this.player.isVideo && this.player.config.ads.enabled && !is$1.empty(this.publisherId);
|
||||
return this.player.isHTML5 && this.player.isVideo && this.player.config.ads.enabled && !is$1.empty(this.publisherId);
|
||||
}
|
||||
}, {
|
||||
key: 'tagUrl',
|
||||
@ -12681,7 +12706,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
*/
|
||||
value: function increaseVolume(step) {
|
||||
var volume = this.media.muted ? 0 : this.volume;
|
||||
this.volume = volume + (is$1.number(step) ? step : 1);
|
||||
this.volume = volume + (is$1.number(step) ? step : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -12692,8 +12717,7 @@ typeof navigator === "object" && (function (global, factory) {
|
||||
}, {
|
||||
key: 'decreaseVolume',
|
||||
value: function decreaseVolume(step) {
|
||||
var volume = this.media.muted ? 0 : this.volume;
|
||||
this.volume = volume - (is$1.number(step) ? step : 1);
|
||||
this.increaseVolume(-step);
|
||||
}
|
||||
|
||||
/**
|
||||
|
2
dist/plyr.polyfilled.js.map
vendored
2
dist/plyr.polyfilled.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js
vendored
2
dist/plyr.polyfilled.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/plyr.polyfilled.min.js.map
vendored
2
dist/plyr.polyfilled.min.js.map
vendored
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "plyr",
|
||||
"version": "3.3.13",
|
||||
"version": "3.3.19",
|
||||
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||
"homepage": "https://plyr.io",
|
||||
"main": "./dist/plyr.js",
|
||||
@ -45,11 +45,11 @@
|
||||
"rollup-plugin-node-resolve": "^3.3.0",
|
||||
"run-sequence": "^2.2.1",
|
||||
"stylelint": "^9.3.0",
|
||||
"stylelint-config-prettier": "^3.2.0",
|
||||
"stylelint-config-prettier": "^3.3.0",
|
||||
"stylelint-config-recommended": "^2.1.0",
|
||||
"stylelint-config-sass-guidelines": "^5.0.0",
|
||||
"stylelint-order": "^0.8.1",
|
||||
"stylelint-scss": "^3.1.2",
|
||||
"stylelint-scss": "^3.1.3",
|
||||
"stylelint-selector-bem-pattern": "^2.0.0"
|
||||
},
|
||||
"keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],
|
||||
@ -74,7 +74,7 @@
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"custom-event-polyfill": "^0.3.0",
|
||||
"loadjs": "^3.5.4",
|
||||
"raven-js": "^3.26.2",
|
||||
"raven-js": "^3.26.3",
|
||||
"url-polyfill": "^1.0.13"
|
||||
}
|
||||
}
|
||||
|
10
readme.md
10
readme.md
@ -132,13 +132,13 @@ See [initialising](#initialising) for more information on advanced setups.
|
||||
You can use our CDN (provided by [Fastly](https://www.fastly.com/)) for the JavaScript. There's 2 versions; one with and one without [polyfills](#polyfills). My recommendation would be to manage polyfills seperately as part of your application but to make life easier you can use the polyfilled build.
|
||||
|
||||
```html
|
||||
<script src="https://cdn.plyr.io/3.3.13/plyr.js"></script>
|
||||
<script src="https://cdn.plyr.io/3.3.19/plyr.js"></script>
|
||||
```
|
||||
|
||||
...or...
|
||||
|
||||
```html
|
||||
<script src="https://cdn.plyr.io/3.3.13/plyr.polyfilled.js"></script>
|
||||
<script src="https://cdn.plyr.io/3.3.19/plyr.polyfilled.js"></script>
|
||||
```
|
||||
|
||||
### CSS
|
||||
@ -152,13 +152,13 @@ Include the `plyr.css` stylsheet into your `<head>`
|
||||
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
||||
|
||||
```html
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.3.13/plyr.css">
|
||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.3.19/plyr.css">
|
||||
```
|
||||
|
||||
### SVG Sprite
|
||||
|
||||
The SVG sprite is loaded automatically from our CDN (provided by [Fastly](https://www.fastly.com/)). To change this, see the [options](#options) below. For
|
||||
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.3.13/plyr.svg`.
|
||||
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.3.19/plyr.svg`.
|
||||
|
||||
## Ads
|
||||
|
||||
@ -286,7 +286,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
|
||||
| `debug` | Boolean | `false` | Display debugging information in the console |
|
||||
| `controls` | Array, Function or Element | `['play-large', 'play', 'progress', 'current-time', 'mute', 'volume', 'captions', 'settings', 'pip', 'airplay', 'fullscreen']` | If a function is passed, it is assumed your method will return either an element or HTML string for the controls. Three arguments will be passed to your function; `id` (the unique id for the player), `seektime` (the seektime step in seconds), and `title` (the media title). See [controls.md](controls.md) for more info on how the html needs to be structured. |
|
||||
| `settings` | Array | `['captions', 'quality', 'speed', 'loop']` | If you're using the default controls are used then you can specify which settings to show in the menu |
|
||||
| `i18n` | Object | See [defaults.js](/src/js/defaults.js) | Used for internationalization (i18n) of the text within the UI. |
|
||||
| `i18n` | Object | See [defaults.js](/src/js/config/defaults.js) | Used for internationalization (i18n) of the text within the UI. |
|
||||
| `loadSprite` | Boolean | `true` | Load the SVG sprite specified as the `iconUrl` option (if a URL). If `false`, it is assumed you are handling sprite loading yourself. |
|
||||
| `iconUrl` | String | `null` | Specify a URL or path to the SVG sprite. See the [SVG section](#svg) for more info. |
|
||||
| `iconPrefix` | String | `plyr` | Specify the id prefix for the icons used in the default controls (e.g. "plyr-play" would be "plyr"). This is to prevent clashes if you're using your own SVG sprite but with the default controls. Most people can ignore this option. |
|
||||
|
@ -39,7 +39,7 @@ const html5 = {
|
||||
get() {
|
||||
// Get sources
|
||||
const sources = html5.getSources.call(player);
|
||||
const [source] = sources.filter(source => source.getAttribute('src') === player.source);
|
||||
const source = sources.find(source => source.getAttribute('src') === player.source);
|
||||
|
||||
// Return size, if match is found
|
||||
return source && Number(source.getAttribute('size'));
|
||||
@ -57,23 +57,25 @@ const html5 = {
|
||||
}
|
||||
|
||||
// Get current state
|
||||
const { currentTime, playing } = player;
|
||||
const { currentTime, paused, preload, readyState } = player.media;
|
||||
|
||||
// Set new source
|
||||
player.media.src = source.getAttribute('src');
|
||||
|
||||
// Restore time
|
||||
const onLoadedMetaData = () => {
|
||||
player.currentTime = currentTime;
|
||||
};
|
||||
player.once('loadedmetadata', onLoadedMetaData);
|
||||
// Prevent loading if preload="none" and the current source isn't loaded (#1044)
|
||||
if (preload !== 'none' || readyState) {
|
||||
// Restore time
|
||||
player.once('loadedmetadata', () => {
|
||||
player.currentTime = currentTime;
|
||||
|
||||
// Load new source
|
||||
player.media.load();
|
||||
// Resume playing
|
||||
if (!paused) {
|
||||
player.play();
|
||||
}
|
||||
});
|
||||
|
||||
// Resume playing
|
||||
if (playing) {
|
||||
player.play();
|
||||
// Load new source
|
||||
player.media.load();
|
||||
}
|
||||
|
||||
// Trigger change event
|
||||
|
@ -665,36 +665,20 @@ class Listeners {
|
||||
// Detect "natural" scroll - suppored on OS X Safari only
|
||||
// Other browsers on OS X will be inverted until support improves
|
||||
const inverted = event.webkitDirectionInvertedFromDevice;
|
||||
const step = 1 / 50;
|
||||
let direction = 0;
|
||||
|
||||
// Scroll down (or up on natural) to decrease
|
||||
if (event.deltaY < 0 || event.deltaX > 0) {
|
||||
if (inverted) {
|
||||
this.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
} else {
|
||||
this.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
}
|
||||
}
|
||||
// Get delta from event. Invert if `inverted` is true
|
||||
const [x, y] = [event.deltaX, -event.deltaY]
|
||||
.map(value => inverted ? -value : value);
|
||||
|
||||
// Scroll up (or down on natural) to increase
|
||||
if (event.deltaY > 0 || event.deltaX < 0) {
|
||||
if (inverted) {
|
||||
this.player.increaseVolume(step);
|
||||
direction = 1;
|
||||
} else {
|
||||
this.player.decreaseVolume(step);
|
||||
direction = -1;
|
||||
}
|
||||
}
|
||||
// Using the biggest delta, normalize to 1 or -1 (or 0 if no delta)
|
||||
const direction = Math.sign(Math.abs(x) > Math.abs(y) ? x : y);
|
||||
|
||||
// Change the volume by 2%
|
||||
this.player.increaseVolume(direction / 50);
|
||||
|
||||
// Don't break page scrolling at max and min
|
||||
if (
|
||||
(direction === 1 && this.player.media.volume < 1) ||
|
||||
(direction === -1 && this.player.media.volume > 0)
|
||||
) {
|
||||
const { volume } = this.player.media;
|
||||
if ((direction === 1 && volume < 1) || (direction === -1 && volume > 0)) {
|
||||
event.preventDefault();
|
||||
}
|
||||
},
|
||||
|
@ -49,7 +49,9 @@ class Ads {
|
||||
}
|
||||
|
||||
get enabled() {
|
||||
return this.player.isVideo && this.player.config.ads.enabled && !is.empty(this.publisherId);
|
||||
return (
|
||||
this.player.isHTML5 && this.player.isVideo && this.player.config.ads.enabled && !is.empty(this.publisherId)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -270,8 +270,8 @@ const youtube = {
|
||||
return Number(instance.getCurrentTime());
|
||||
},
|
||||
set(time) {
|
||||
// If paused, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused) {
|
||||
// If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
|
||||
if (player.paused && !player.embed.hasPlayed) {
|
||||
player.embed.mute();
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
// ==========================================================================
|
||||
// Plyr
|
||||
// plyr.js v3.3.13
|
||||
// plyr.js v3.3.19
|
||||
// https://github.com/sampotts/plyr
|
||||
// License: The MIT License (MIT)
|
||||
// ==========================================================================
|
||||
@ -553,7 +553,7 @@ class Plyr {
|
||||
*/
|
||||
increaseVolume(step) {
|
||||
const volume = this.media.muted ? 0 : this.volume;
|
||||
this.volume = volume + (is.number(step) ? step : 1);
|
||||
this.volume = volume + (is.number(step) ? step : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -561,8 +561,7 @@ class Plyr {
|
||||
* @param {boolean} step - How much to decrease by (between 0 and 1)
|
||||
*/
|
||||
decreaseVolume(step) {
|
||||
const volume = this.media.muted ? 0 : this.volume;
|
||||
this.volume = volume - (is.number(step) ? step : 1);
|
||||
this.increaseVolume(-step);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
// ==========================================================================
|
||||
// Plyr Polyfilled Build
|
||||
// plyr.js v3.3.13
|
||||
// plyr.js v3.3.19
|
||||
// https://github.com/sampotts/plyr
|
||||
// License: The MIT License (MIT)
|
||||
// ==========================================================================
|
||||
|
10
src/js/ui.js
10
src/js/ui.js
@ -135,11 +135,9 @@ const ui = {
|
||||
}
|
||||
|
||||
// If there's a play button, set label
|
||||
if (is.nodeList(this.elements.buttons.play)) {
|
||||
Array.from(this.elements.buttons.play).forEach(button => {
|
||||
button.setAttribute('aria-label', label);
|
||||
});
|
||||
}
|
||||
Array.from(this.elements.buttons.play || []).forEach(button => {
|
||||
button.setAttribute('aria-label', label);
|
||||
});
|
||||
|
||||
// Set iframe title
|
||||
// https://github.com/sampotts/plyr/issues/124
|
||||
@ -214,7 +212,7 @@ const ui = {
|
||||
toggleClass(this.elements.container, this.config.classNames.stopped, this.stopped);
|
||||
|
||||
// Set state
|
||||
Array.from(this.elements.buttons.play).forEach(target => {
|
||||
Array.from(this.elements.buttons.play || []).forEach(target => {
|
||||
target.pressed = this.playing;
|
||||
});
|
||||
|
||||
|
@ -26,7 +26,7 @@ export default function fetch(url, responseType = 'text') {
|
||||
});
|
||||
|
||||
request.addEventListener('error', () => {
|
||||
throw new Error(request.statusText);
|
||||
throw new Error(request.status);
|
||||
});
|
||||
|
||||
request.open('GET', url, true);
|
||||
|
@ -3,65 +3,61 @@
|
||||
// ==========================================================================
|
||||
|
||||
const getConstructor = input => (input !== null && typeof input !== 'undefined' ? input.constructor : null);
|
||||
|
||||
const instanceOf = (input, constructor) => Boolean(input && constructor && input instanceof constructor);
|
||||
const isNullOrUndefined = input => input === null || typeof input === 'undefined';
|
||||
const isObject = input => getConstructor(input) === Object;
|
||||
const isNumber = input => getConstructor(input) === Number && !Number.isNaN(input);
|
||||
const isString = input => getConstructor(input) === String;
|
||||
const isBoolean = input => getConstructor(input) === Boolean;
|
||||
const isFunction = input => getConstructor(input) === Function;
|
||||
const isArray = input => Array.isArray(input);
|
||||
const isWeakMap = input => instanceOf(input, WeakMap);
|
||||
const isNodeList = input => instanceOf(input, NodeList);
|
||||
const isElement = input => instanceOf(input, Element);
|
||||
const isTextNode = input => getConstructor(input) === Text;
|
||||
const isEvent = input => instanceOf(input, Event);
|
||||
const isCue = input => instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||
const isTrack = input => instanceOf(input, TextTrack) || (!isNullOrUndefined(input) && isString(input.kind));
|
||||
|
||||
const is = {
|
||||
object(input) {
|
||||
return getConstructor(input) === Object;
|
||||
},
|
||||
number(input) {
|
||||
return getConstructor(input) === Number && !Number.isNaN(input);
|
||||
},
|
||||
string(input) {
|
||||
return getConstructor(input) === String;
|
||||
},
|
||||
boolean(input) {
|
||||
return getConstructor(input) === Boolean;
|
||||
},
|
||||
function(input) {
|
||||
return getConstructor(input) === Function;
|
||||
},
|
||||
array(input) {
|
||||
return !is.nullOrUndefined(input) && Array.isArray(input);
|
||||
},
|
||||
weakMap(input) {
|
||||
return instanceOf(input, WeakMap);
|
||||
},
|
||||
nodeList(input) {
|
||||
return instanceOf(input, NodeList);
|
||||
},
|
||||
element(input) {
|
||||
return instanceOf(input, Element);
|
||||
},
|
||||
textNode(input) {
|
||||
return getConstructor(input) === Text;
|
||||
},
|
||||
event(input) {
|
||||
return instanceOf(input, Event);
|
||||
},
|
||||
cue(input) {
|
||||
return instanceOf(input, window.TextTrackCue) || instanceOf(input, window.VTTCue);
|
||||
},
|
||||
track(input) {
|
||||
return instanceOf(input, TextTrack) || (!is.nullOrUndefined(input) && is.string(input.kind));
|
||||
},
|
||||
url(input) {
|
||||
return (
|
||||
!is.nullOrUndefined(input) &&
|
||||
/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-/]))?/.test(input)
|
||||
);
|
||||
},
|
||||
nullOrUndefined(input) {
|
||||
return input === null || typeof input === 'undefined';
|
||||
},
|
||||
empty(input) {
|
||||
return (
|
||||
is.nullOrUndefined(input) ||
|
||||
((is.string(input) || is.array(input) || is.nodeList(input)) && !input.length) ||
|
||||
(is.object(input) && !Object.keys(input).length)
|
||||
);
|
||||
},
|
||||
const isEmpty = input =>
|
||||
isNullOrUndefined(input) ||
|
||||
((isString(input) || isArray(input) || isNodeList(input)) && !input.length) ||
|
||||
(isObject(input) && !Object.keys(input).length);
|
||||
|
||||
const isUrl = input => {
|
||||
// Accept a URL object
|
||||
if (instanceOf(input, window.URL)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add the protocol if required
|
||||
let string = input;
|
||||
if (!input.startsWith('http://') || !input.startsWith('https://')) {
|
||||
string = `http://${input}`;
|
||||
}
|
||||
|
||||
try {
|
||||
return !isEmpty(new URL(string).hostname);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export default is;
|
||||
export default {
|
||||
nullOrUndefined: isNullOrUndefined,
|
||||
object: isObject,
|
||||
number: isNumber,
|
||||
string: isString,
|
||||
boolean: isBoolean,
|
||||
function: isFunction,
|
||||
array: isArray,
|
||||
weakMap: isWeakMap,
|
||||
nodeList: isNodeList,
|
||||
element: isElement,
|
||||
textNode: isTextNode,
|
||||
event: isEvent,
|
||||
cue: isCue,
|
||||
track: isTrack,
|
||||
url: isUrl,
|
||||
empty: isEmpty,
|
||||
};
|
||||
|
@ -3,6 +3,7 @@
|
||||
// ==========================================================================
|
||||
|
||||
import Storage from './../storage';
|
||||
import fetch from './fetch';
|
||||
import is from './is';
|
||||
|
||||
// Load an external SVG sprite
|
||||
|
@ -27,11 +27,6 @@ $embed-padding: ((100 / 16) * 9);
|
||||
$height: 240;
|
||||
$offset: to-percentage(($height - $embed-padding) / ($height / 50));
|
||||
|
||||
// To allow mouse events to be captured if full support
|
||||
iframe {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
// Only used for Vimeo
|
||||
> .plyr__video-embed__container {
|
||||
padding-bottom: to-percentage($height);
|
||||
|
18
yarn.lock
18
yarn.lock
@ -5000,9 +5000,9 @@ randomatic@^1.1.3:
|
||||
is-number "^3.0.0"
|
||||
kind-of "^4.0.0"
|
||||
|
||||
raven-js@^3.26.2:
|
||||
version "3.26.2"
|
||||
resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.26.2.tgz#9153af2416e96ccf4e0b9cbc6c90c34dda0d7e88"
|
||||
raven-js@^3.26.3:
|
||||
version "3.26.3"
|
||||
resolved "https://registry.yarnpkg.com/raven-js/-/raven-js-3.26.3.tgz#0efb49969b5b11ab965f7b0d6da4ca102b763cb0"
|
||||
|
||||
rc@^1.0.1, rc@^1.1.6:
|
||||
version "1.2.6"
|
||||
@ -5903,9 +5903,9 @@ style-search@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902"
|
||||
|
||||
stylelint-config-prettier@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-3.2.0.tgz#af32b7845adeeddbf0a0bd642ace4ca1e68958e2"
|
||||
stylelint-config-prettier@^3.3.0:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-config-prettier/-/stylelint-config-prettier-3.3.0.tgz#cc22a4b5310c1919cee77131d6e220c60a62a480"
|
||||
dependencies:
|
||||
stylelint "^9.1.1"
|
||||
|
||||
@ -5938,9 +5938,9 @@ stylelint-scss@^2.0.0:
|
||||
postcss-selector-parser "^3.1.1"
|
||||
postcss-value-parser "^3.3.0"
|
||||
|
||||
stylelint-scss@^3.1.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.1.2.tgz#3257c0600d197fe7642f3698944b47c91567f379"
|
||||
stylelint-scss@^3.1.3:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.1.3.tgz#28f881ae298c3f5db667b10b6cf94a1a219001d6"
|
||||
dependencies:
|
||||
lodash "^4.17.10"
|
||||
postcss-media-query-parser "^0.2.3"
|
||||
|
Reference in New Issue
Block a user