Compare commits
26 Commits
v3.4.0-beta.2
...
v3.4.2
| Author | SHA1 | Date | |
|---|---|---|---|
| eaeccd66ae | |||
| 7a43649c13 | |||
| 525bbf313e | |||
| cfaebe9bf2 | |||
| b57b7b2153 | |||
| 48bf368316 | |||
| 8f94ce86a0 | |||
| 10a9cf08f1 | |||
| 286d0d1794 | |||
| 95f6fa2731 | |||
| 1aeef81288 | |||
| 211ad6c8f5 | |||
| 468b20d227 | |||
| f6bc42c2bc | |||
| 2c01b8ba76 | |||
| 4e1df8677f | |||
| 6953a12e2a | |||
| 1d0db89194 | |||
| 297f297d18 | |||
| 059205c378 | |||
| f94e53ffb1 | |||
| a4f1fdec5d | |||
| 75374eb154 | |||
| dbf768b1bd | |||
| a8f8486cf4 | |||
| a343e58e53 |
@@ -1,8 +1,21 @@
|
|||||||
|
# v3.4.2
|
||||||
|
|
||||||
|
- Fix play/pause button state
|
||||||
|
|
||||||
|
# v3.4.1
|
||||||
|
|
||||||
|
- Bug fix for custom controls (fixes #1161)
|
||||||
|
|
||||||
# v3.4.0
|
# v3.4.0
|
||||||
|
|
||||||
- Accessibility improvements (see #905)
|
- Accessibility improvements (see #905)
|
||||||
- Improvements to the way the controls work on iOS
|
- Improvements to the way the controls work on iOS
|
||||||
- Demo code clean up
|
- Demo code clean up
|
||||||
|
- YouTube quality selection removed due to their poor support for it. As a result, the `qualityrequested` event has been removed
|
||||||
|
- Controls spacing improvements
|
||||||
|
- Fix for pressed property missing with custom controls (Fixes #1062)
|
||||||
|
- Fix #1153: Captions language fallback (thanks @friday)
|
||||||
|
- Fix for setting pressed property of undefined (Fixes #1102)
|
||||||
|
|
||||||
# v3.3.23
|
# v3.3.23
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+3
-2
@@ -4118,9 +4118,10 @@ typeof navigator === "object" && (function () {
|
|||||||
|
|
||||||
// Remove class on blur
|
// Remove class on blur
|
||||||
document.addEventListener('focusout', function (event) {
|
document.addEventListener('focusout', function (event) {
|
||||||
if (container.contains(event.target)) {
|
if (!event.target.classList || container.contains(event.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.target.classList.remove(tabClassName);
|
event.target.classList.remove(tabClassName);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -4135,7 +4136,7 @@ typeof navigator === "object" && (function () {
|
|||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
var focused = document.activeElement;
|
var focused = document.activeElement;
|
||||||
|
|
||||||
if (!focused || container.contains(focused)) {
|
if (!focused || !focused.classList || container.contains(focused)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+3
-2
@@ -31,9 +31,10 @@ import Raven from 'raven-js';
|
|||||||
|
|
||||||
// Remove class on blur
|
// Remove class on blur
|
||||||
document.addEventListener('focusout', event => {
|
document.addEventListener('focusout', event => {
|
||||||
if (container.contains(event.target)) {
|
if (!event.target.classList || container.contains(event.target)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.target.classList.remove(tabClassName);
|
event.target.classList.remove(tabClassName);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,7 +49,7 @@ import Raven from 'raven-js';
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const focused = document.activeElement;
|
const focused = document.activeElement;
|
||||||
|
|
||||||
if (!focused || container.contains(focused)) {
|
if (!focused || !focused.classList || container.contains(focused)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+74
-119
@@ -886,6 +886,9 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
||||||
quality: input
|
quality: input
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save to storage
|
||||||
|
player.storage.set({ quality: input });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -918,6 +921,30 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
// Remove duplicates in an array
|
||||||
|
function dedupe(array) {
|
||||||
|
if (!is.array(array)) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.filter(function (item, index) {
|
||||||
|
return array.indexOf(item) === index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the closest value in an array
|
||||||
|
function closest(array, value) {
|
||||||
|
if (!is.array(array) || !array.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.reduce(function (prev, curr) {
|
||||||
|
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
// Clone nested objects
|
// Clone nested objects
|
||||||
function cloneDeep(object) {
|
function cloneDeep(object) {
|
||||||
return JSON.parse(JSON.stringify(object));
|
return JSON.parse(JSON.stringify(object));
|
||||||
@@ -1096,30 +1123,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
// Remove duplicates in an array
|
|
||||||
function dedupe(array) {
|
|
||||||
if (!is.array(array)) {
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array.filter(function (item, index) {
|
|
||||||
return array.indexOf(item) === index;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the closest value in an array
|
|
||||||
function closest(array, value) {
|
|
||||||
if (!is.array(array) || !array.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array.reduce(function (prev, curr) {
|
|
||||||
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
var Storage = function () {
|
var Storage = function () {
|
||||||
function Storage(player) {
|
function Storage(player) {
|
||||||
classCallCheck(this, Storage);
|
classCallCheck(this, Storage);
|
||||||
@@ -1604,20 +1607,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
this.elements.buttons[type] = button;
|
this.elements.buttons[type] = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle classname when pressed property is set
|
|
||||||
var className = this.config.classNames.controlPressed;
|
|
||||||
Object.defineProperty(button, 'pressed', {
|
|
||||||
enumerable: true,
|
|
||||||
get: function get$$1() {
|
|
||||||
return hasClass(button, className);
|
|
||||||
},
|
|
||||||
set: function set$$1() {
|
|
||||||
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
||||||
|
|
||||||
toggleClass(button, className, pressed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -2490,9 +2479,8 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// Focus the first item if key interaction
|
// Focus the first item if key interaction
|
||||||
if (show && is.keyboardEvent(input)) {
|
if (show && is.keyboardEvent(input)) {
|
||||||
controls.focusFirstMenuItem.call(this, null, true);
|
controls.focusFirstMenuItem.call(this, null, true);
|
||||||
}
|
} else if (!show && !hidden) {
|
||||||
// If closing, re-focus the button
|
// If closing, re-focus the button
|
||||||
else if (!show && !hidden) {
|
|
||||||
setFocus.call(this, button, is.keyboardEvent(input));
|
setFocus.call(this, button, is.keyboardEvent(input));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2651,17 +2639,19 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
container.appendChild(controls.createTime.call(this, 'duration'));
|
container.appendChild(controls.createTime.call(this, 'duration'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle mute button
|
// Volume controls
|
||||||
if (this.config.controls.includes('mute')) {
|
if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {
|
||||||
container.appendChild(controls.createButton.call(this, 'mute'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Volume range control
|
|
||||||
if (this.config.controls.includes('volume')) {
|
|
||||||
var volume = createElement('div', {
|
var volume = createElement('div', {
|
||||||
class: 'plyr__volume'
|
class: 'plyr__volume'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Toggle mute button
|
||||||
|
if (this.config.controls.includes('mute')) {
|
||||||
|
volume.appendChild(controls.createButton.call(this, 'mute'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume range control
|
||||||
|
if (this.config.controls.includes('volume')) {
|
||||||
// Set the attributes
|
// Set the attributes
|
||||||
var attributes = {
|
var attributes = {
|
||||||
max: 1,
|
max: 1,
|
||||||
@@ -2675,6 +2665,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
})));
|
})));
|
||||||
|
|
||||||
this.elements.volume = volume;
|
this.elements.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
container.appendChild(volume);
|
container.appendChild(volume);
|
||||||
}
|
}
|
||||||
@@ -2836,6 +2827,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
this.elements.controls = container;
|
this.elements.controls = container;
|
||||||
|
|
||||||
|
// Set available quality levels
|
||||||
if (this.isHTML5) {
|
if (this.isHTML5) {
|
||||||
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
|
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
|
||||||
}
|
}
|
||||||
@@ -2948,6 +2940,33 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
controls.findElements.call(this);
|
controls.findElements.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add pressed property to buttons
|
||||||
|
if (!is.empty(this.elements.buttons)) {
|
||||||
|
var addProperty = function addProperty(button) {
|
||||||
|
var className = _this10.config.classNames.controlPressed;
|
||||||
|
Object.defineProperty(button, 'pressed', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get$$1() {
|
||||||
|
return hasClass(button, className);
|
||||||
|
},
|
||||||
|
set: function set$$1() {
|
||||||
|
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
||||||
|
|
||||||
|
toggleClass(button, className, pressed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle classname when pressed property is set
|
||||||
|
Object.values(this.elements.buttons).filter(Boolean).forEach(function (button) {
|
||||||
|
if (is.array(button)) {
|
||||||
|
button.filter(Boolean).forEach(addProperty);
|
||||||
|
} else {
|
||||||
|
addProperty(button);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Edge sometimes doesn't finish the paint so force a redraw
|
// Edge sometimes doesn't finish the paint so force a redraw
|
||||||
if (window.navigator.userAgent.includes('Edge')) {
|
if (window.navigator.userAgent.includes('Edge')) {
|
||||||
repaint(target);
|
repaint(target);
|
||||||
@@ -3065,7 +3084,8 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// * active: The state preferred by user settings or config
|
// * active: The state preferred by user settings or config
|
||||||
// * toggled: The real captions state
|
// * toggled: The real captions state
|
||||||
|
|
||||||
var languages = dedupe(Array.from(navigator.languages || navigator.language || navigator.userLanguage).map(function (language) {
|
var browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
|
||||||
|
var languages = dedupe(browserLanguages.map(function (language) {
|
||||||
return language.split('-')[0];
|
return language.split('-')[0];
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -3488,7 +3508,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// Quality default
|
// Quality default
|
||||||
quality: {
|
quality: {
|
||||||
default: 576,
|
default: 576,
|
||||||
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240, 'default']
|
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Set loops
|
// Set loops
|
||||||
@@ -3638,7 +3658,10 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',
|
'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',
|
||||||
|
|
||||||
// YouTube
|
// YouTube
|
||||||
'statechange', 'qualitychange', 'qualityrequested',
|
'statechange',
|
||||||
|
|
||||||
|
// Quality
|
||||||
|
'qualitychange',
|
||||||
|
|
||||||
// Ads
|
// Ads
|
||||||
'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
|
'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
|
||||||
@@ -3947,9 +3970,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// iOS native fullscreen doesn't need the request step
|
// iOS native fullscreen doesn't need the request step
|
||||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||||
if (this.player.playing) {
|
|
||||||
this.target.webkitEnterFullscreen();
|
this.target.webkitEnterFullscreen();
|
||||||
}
|
|
||||||
} else if (!Fullscreen.native) {
|
} else if (!Fullscreen.native) {
|
||||||
toggleFallback.call(this, true);
|
toggleFallback.call(this, true);
|
||||||
} else if (!this.prefix) {
|
} else if (!this.prefix) {
|
||||||
@@ -4636,7 +4657,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// Remove button states for fullscreen
|
// Remove button states for fullscreen
|
||||||
|
|
||||||
if (event.type === 'enterfullscreen') {
|
if (controls$$1 && event.type === 'enterfullscreen') {
|
||||||
controls$$1.pressed = false;
|
controls$$1.pressed = false;
|
||||||
controls$$1.hover = false;
|
controls$$1.hover = false;
|
||||||
}
|
}
|
||||||
@@ -4794,12 +4815,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
player.storage.set({ speed: player.speed });
|
player.storage.set({ speed: player.speed });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality request
|
|
||||||
on.call(player, player.media, 'qualityrequested', function (event) {
|
|
||||||
// Save to storage
|
|
||||||
player.storage.set({ quality: event.detail.quality });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Quality change
|
// Quality change
|
||||||
on.call(player, player.media, 'qualitychange', function (event) {
|
on.call(player, player.media, 'qualitychange', function (event) {
|
||||||
// Update UI
|
// Update UI
|
||||||
@@ -5879,43 +5894,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
return url.match(regex) ? RegExp.$2 : url;
|
return url.match(regex) ? RegExp.$2 : url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standardise YouTube quality unit
|
|
||||||
function mapQualityUnit(input) {
|
|
||||||
var qualities = {
|
|
||||||
hd2160: 2160,
|
|
||||||
hd1440: 1440,
|
|
||||||
hd1080: 1080,
|
|
||||||
hd720: 720,
|
|
||||||
large: 480,
|
|
||||||
medium: 360,
|
|
||||||
small: 240,
|
|
||||||
tiny: 144
|
|
||||||
};
|
|
||||||
|
|
||||||
var entry = Object.entries(qualities).find(function (entry) {
|
|
||||||
return entry.includes(input);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
// Get the match corresponding to the input
|
|
||||||
return entry.find(function (value) {
|
|
||||||
return value !== input;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'default';
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapQualityUnits(levels) {
|
|
||||||
if (is.empty(levels)) {
|
|
||||||
return levels;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dedupe(levels.map(function (level) {
|
|
||||||
return mapQualityUnit(level);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set playback state and trigger change (only on actual change)
|
// Set playback state and trigger change (only on actual change)
|
||||||
function assurePlaybackState$1(play) {
|
function assurePlaybackState$1(play) {
|
||||||
if (play && !this.embed.hasPlayed) {
|
if (play && !this.embed.hasPlayed) {
|
||||||
@@ -6099,11 +6077,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
triggerEvent.call(player, player.media, 'error');
|
triggerEvent.call(player, player.media, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPlaybackQualityChange: function onPlaybackQualityChange() {
|
|
||||||
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
|
||||||
quality: player.media.quality
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onPlaybackRateChange: function onPlaybackRateChange(event) {
|
onPlaybackRateChange: function onPlaybackRateChange(event) {
|
||||||
// Get the instance
|
// Get the instance
|
||||||
var instance = event.target;
|
var instance = event.target;
|
||||||
@@ -6173,16 +6146,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality
|
|
||||||
Object.defineProperty(player.media, 'quality', {
|
|
||||||
get: function get() {
|
|
||||||
return mapQualityUnit(instance.getPlaybackQuality());
|
|
||||||
},
|
|
||||||
set: function set(input) {
|
|
||||||
instance.setPlaybackQuality(mapQualityUnit(input));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Volume
|
// Volume
|
||||||
var volume = player.config.volume;
|
var volume = player.config.volume;
|
||||||
|
|
||||||
@@ -6335,9 +6298,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
player.media.duration = instance.getDuration();
|
player.media.duration = instance.getDuration();
|
||||||
triggerEvent.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get quality
|
|
||||||
controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -8203,11 +8163,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
quality = value;
|
quality = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger request event
|
|
||||||
triggerEvent.call(this, this.media, 'qualityrequested', false, {
|
|
||||||
quality: quality
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update config
|
// Update config
|
||||||
config.selected = quality;
|
config.selected = quality;
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+131
-146
@@ -20,7 +20,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
var _core = createCommonjsModule(function (module) {
|
var _core = createCommonjsModule(function (module) {
|
||||||
var core = module.exports = { version: '2.5.3' };
|
var core = module.exports = { version: '2.5.7' };
|
||||||
if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
|
if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef
|
||||||
});
|
});
|
||||||
var _core_1 = _core.version;
|
var _core_1 = _core.version;
|
||||||
@@ -333,11 +333,18 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var _shared = createCommonjsModule(function (module) {
|
||||||
var SHARED = '__core-js_shared__';
|
var SHARED = '__core-js_shared__';
|
||||||
var store = _global[SHARED] || (_global[SHARED] = {});
|
var store = _global[SHARED] || (_global[SHARED] = {});
|
||||||
var _shared = function (key) {
|
|
||||||
return store[key] || (store[key] = {});
|
(module.exports = function (key, value) {
|
||||||
};
|
return store[key] || (store[key] = value !== undefined ? value : {});
|
||||||
|
})('versions', []).push({
|
||||||
|
version: _core.version,
|
||||||
|
mode: 'global',
|
||||||
|
copyright: '© 2018 Denis Pushkarev (zloirock.ru)'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
var shared = _shared('keys');
|
var shared = _shared('keys');
|
||||||
|
|
||||||
@@ -741,12 +748,12 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
if ($slice !== undefined && end === undefined) return $slice.call(_anObject(this), start); // FF fix
|
if ($slice !== undefined && end === undefined) return $slice.call(_anObject(this), start); // FF fix
|
||||||
var len = _anObject(this).byteLength;
|
var len = _anObject(this).byteLength;
|
||||||
var first = _toAbsoluteIndex(start, len);
|
var first = _toAbsoluteIndex(start, len);
|
||||||
var final = _toAbsoluteIndex(end === undefined ? len : end, len);
|
var fin = _toAbsoluteIndex(end === undefined ? len : end, len);
|
||||||
var result = new (_speciesConstructor(this, $ArrayBuffer))(_toLength(final - first));
|
var result = new (_speciesConstructor(this, $ArrayBuffer))(_toLength(fin - first));
|
||||||
var viewS = new $DataView(this);
|
var viewS = new $DataView(this);
|
||||||
var viewT = new $DataView(result);
|
var viewT = new $DataView(result);
|
||||||
var index = 0;
|
var index = 0;
|
||||||
while (first < final) {
|
while (first < fin) {
|
||||||
viewT.setUint8(index++, viewS.getUint8(first++));
|
viewT.setUint8(index++, viewS.getUint8(first++));
|
||||||
} return result;
|
} return result;
|
||||||
}
|
}
|
||||||
@@ -991,7 +998,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
var VALUES_BUG = false;
|
var VALUES_BUG = false;
|
||||||
var proto = Base.prototype;
|
var proto = Base.prototype;
|
||||||
var $native = proto[ITERATOR$2] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
|
var $native = proto[ITERATOR$2] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT];
|
||||||
var $default = (!BUGGY && $native) || getMethod(DEFAULT);
|
var $default = $native || getMethod(DEFAULT);
|
||||||
var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
|
var $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined;
|
||||||
var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
|
var $anyNative = NAME == 'Array' ? proto.entries || $native : $native;
|
||||||
var methods, key, IteratorPrototype;
|
var methods, key, IteratorPrototype;
|
||||||
@@ -1002,7 +1009,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// Set @@toStringTag to native iterators
|
// Set @@toStringTag to native iterators
|
||||||
_setToStringTag(IteratorPrototype, TAG, true);
|
_setToStringTag(IteratorPrototype, TAG, true);
|
||||||
// fix for some old engines
|
// fix for some old engines
|
||||||
if (!_has(IteratorPrototype, ITERATOR$2)) _hide(IteratorPrototype, ITERATOR$2, returnThis);
|
if (typeof IteratorPrototype[ITERATOR$2] != 'function') _hide(IteratorPrototype, ITERATOR$2, returnThis);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// fix Array#{values, @@iterator}.name in V8 / FF
|
// fix Array#{values, @@iterator}.name in V8 / FF
|
||||||
@@ -2495,9 +2502,11 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
}
|
}
|
||||||
if (_has(ownDesc, 'value')) {
|
if (_has(ownDesc, 'value')) {
|
||||||
if (ownDesc.writable === false || !_isObject(receiver)) return false;
|
if (ownDesc.writable === false || !_isObject(receiver)) return false;
|
||||||
existingDescriptor = _objectGopd.f(receiver, propertyKey) || _propertyDesc(0);
|
if (existingDescriptor = _objectGopd.f(receiver, propertyKey)) {
|
||||||
|
if (existingDescriptor.get || existingDescriptor.set || existingDescriptor.writable === false) return false;
|
||||||
existingDescriptor.value = V;
|
existingDescriptor.value = V;
|
||||||
_objectDp.f(receiver, propertyKey, existingDescriptor);
|
_objectDp.f(receiver, propertyKey, existingDescriptor);
|
||||||
|
} else _objectDp.f(receiver, propertyKey, _propertyDesc(0, V));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true);
|
return ownDesc.set === undefined ? false : (ownDesc.set.call(receiver, V), true);
|
||||||
@@ -2642,7 +2651,8 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
};
|
};
|
||||||
// environments with maybe non-completely correct, but existent Promise
|
// environments with maybe non-completely correct, but existent Promise
|
||||||
} else if (Promise$1 && Promise$1.resolve) {
|
} else if (Promise$1 && Promise$1.resolve) {
|
||||||
var promise = Promise$1.resolve();
|
// Promise.resolve without an argument throws an error in LG WebOS 2
|
||||||
|
var promise = Promise$1.resolve(undefined);
|
||||||
notify = function () {
|
notify = function () {
|
||||||
promise.then(flush);
|
promise.then(flush);
|
||||||
};
|
};
|
||||||
@@ -2699,6 +2709,10 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var navigator$1 = _global.navigator;
|
||||||
|
|
||||||
|
var _userAgent = navigator$1 && navigator$1.userAgent || '';
|
||||||
|
|
||||||
var _promiseResolve = function (C, x) {
|
var _promiseResolve = function (C, x) {
|
||||||
_anObject(C);
|
_anObject(C);
|
||||||
if (_isObject(x) && x.constructor === C) return x;
|
if (_isObject(x) && x.constructor === C) return x;
|
||||||
@@ -2713,9 +2727,12 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var PROMISE = 'Promise';
|
var PROMISE = 'Promise';
|
||||||
var TypeError$1 = _global.TypeError;
|
var TypeError$1 = _global.TypeError;
|
||||||
var process$2 = _global.process;
|
var process$2 = _global.process;
|
||||||
|
var versions = process$2 && process$2.versions;
|
||||||
|
var v8 = versions && versions.v8 || '';
|
||||||
var $Promise = _global[PROMISE];
|
var $Promise = _global[PROMISE];
|
||||||
var isNode$1 = _classof(process$2) == 'process';
|
var isNode$1 = _classof(process$2) == 'process';
|
||||||
var empty = function () { /* empty */ };
|
var empty = function () { /* empty */ };
|
||||||
@@ -2730,7 +2747,13 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
exec(empty, empty);
|
exec(empty, empty);
|
||||||
};
|
};
|
||||||
// unhandled rejections tracking support, NodeJS Promise without it fails @@species test
|
// unhandled rejections tracking support, NodeJS Promise without it fails @@species test
|
||||||
return (isNode$1 || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise;
|
return (isNode$1 || typeof PromiseRejectionEvent == 'function')
|
||||||
|
&& promise.then(empty) instanceof FakePromise
|
||||||
|
// v8 6.6 (Node 10 and Chrome 66) have a bug with resolving custom thenables
|
||||||
|
// https://bugs.chromium.org/p/chromium/issues/detail?id=830565
|
||||||
|
// we can't detect it synchronously, so just check versions
|
||||||
|
&& v8.indexOf('6.6') !== 0
|
||||||
|
&& _userAgent.indexOf('Chrome/66') === -1;
|
||||||
} catch (e) { /* empty */ }
|
} catch (e) { /* empty */ }
|
||||||
}();
|
}();
|
||||||
|
|
||||||
@@ -2752,7 +2775,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
var resolve = reaction.resolve;
|
var resolve = reaction.resolve;
|
||||||
var reject = reaction.reject;
|
var reject = reaction.reject;
|
||||||
var domain = reaction.domain;
|
var domain = reaction.domain;
|
||||||
var result, then;
|
var result, then, exited;
|
||||||
try {
|
try {
|
||||||
if (handler) {
|
if (handler) {
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -2762,8 +2785,11 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
if (handler === true) result = value;
|
if (handler === true) result = value;
|
||||||
else {
|
else {
|
||||||
if (domain) domain.enter();
|
if (domain) domain.enter();
|
||||||
result = handler(value);
|
result = handler(value); // may throw
|
||||||
if (domain) domain.exit();
|
if (domain) {
|
||||||
|
domain.exit();
|
||||||
|
exited = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (result === reaction.promise) {
|
if (result === reaction.promise) {
|
||||||
reject(TypeError$1('Promise-chain cycle'));
|
reject(TypeError$1('Promise-chain cycle'));
|
||||||
@@ -2772,6 +2798,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
} else resolve(result);
|
} else resolve(result);
|
||||||
} else reject(value);
|
} else reject(value);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
if (domain && !exited) domain.exit();
|
||||||
reject(e);
|
reject(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -4154,10 +4181,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
return left ? stringFiller + S : S + stringFiller;
|
return left ? stringFiller + S : S + stringFiller;
|
||||||
};
|
};
|
||||||
|
|
||||||
var navigator$1 = _global.navigator;
|
|
||||||
|
|
||||||
var _userAgent = navigator$1 && navigator$1.userAgent || '';
|
|
||||||
|
|
||||||
// https://github.com/tc39/proposal-string-pad-start-end
|
// https://github.com/tc39/proposal-string-pad-start-end
|
||||||
|
|
||||||
|
|
||||||
@@ -5190,12 +5213,11 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proto.toString = function() {
|
proto.toString = function() {
|
||||||
var searchString = '';
|
var searchArray = [];
|
||||||
this.forEach(function(value, name) {
|
this.forEach(function(value, name) {
|
||||||
if(searchString.length > 0) searchString+= '&';
|
searchArray.push(serializeParam(name) + '=' + serializeParam(value));
|
||||||
searchString += serializeParam(name) + '=' + serializeParam(value);
|
|
||||||
});
|
});
|
||||||
return searchString;
|
return searchArray.join("&");
|
||||||
};
|
};
|
||||||
|
|
||||||
global.URLSearchParams = URLSearchParams;
|
global.URLSearchParams = URLSearchParams;
|
||||||
@@ -5237,18 +5259,26 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
var URL = function(url, base) {
|
var URL = function(url, base) {
|
||||||
if(typeof url !== 'string') url = String(url);
|
if(typeof url !== 'string') url = String(url);
|
||||||
|
|
||||||
var doc = document.implementation.createHTMLDocument('');
|
// Only create another document if the base is different from current location.
|
||||||
window.doc = doc;
|
var doc = document, baseElement;
|
||||||
if(base) {
|
if(base && (global.location === void 0 || base !== global.location.href)) {
|
||||||
var baseElement = doc.createElement('base');
|
doc = document.implementation.createHTMLDocument('');
|
||||||
|
baseElement = doc.createElement('base');
|
||||||
baseElement.href = base;
|
baseElement.href = base;
|
||||||
doc.head.appendChild(baseElement);
|
doc.head.appendChild(baseElement);
|
||||||
|
try {
|
||||||
|
if(baseElement.href.indexOf(base) !== 0) throw new Error(baseElement.href);
|
||||||
|
} catch (err) {
|
||||||
|
throw new Error("URL unable to set base " + base + " due to " + err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var anchorElement = doc.createElement('a');
|
var anchorElement = doc.createElement('a');
|
||||||
anchorElement.href = url;
|
anchorElement.href = url;
|
||||||
|
if (baseElement) {
|
||||||
doc.body.appendChild(anchorElement);
|
doc.body.appendChild(anchorElement);
|
||||||
anchorElement.href = anchorElement.href; // force href to refresh
|
anchorElement.href = anchorElement.href; // force href to refresh
|
||||||
|
}
|
||||||
|
|
||||||
if(anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
|
if(anchorElement.protocol === ':' || !/:/.test(anchorElement.href)) {
|
||||||
throw new TypeError('Invalid URL');
|
throw new TypeError('Invalid URL');
|
||||||
@@ -6283,6 +6313,9 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
||||||
quality: input
|
quality: input
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save to storage
|
||||||
|
player.storage.set({ quality: input });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -6315,6 +6348,30 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
|
// Remove duplicates in an array
|
||||||
|
function dedupe(array) {
|
||||||
|
if (!is$1.array(array)) {
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.filter(function (item, index) {
|
||||||
|
return array.indexOf(item) === index;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the closest value in an array
|
||||||
|
function closest(array, value) {
|
||||||
|
if (!is$1.array(array) || !array.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array.reduce(function (prev, curr) {
|
||||||
|
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
// Clone nested objects
|
// Clone nested objects
|
||||||
function cloneDeep(object) {
|
function cloneDeep(object) {
|
||||||
return JSON.parse(JSON.stringify(object));
|
return JSON.parse(JSON.stringify(object));
|
||||||
@@ -6493,30 +6550,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
// Remove duplicates in an array
|
|
||||||
function dedupe(array) {
|
|
||||||
if (!is$1.array(array)) {
|
|
||||||
return array;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array.filter(function (item, index) {
|
|
||||||
return array.indexOf(item) === index;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the closest value in an array
|
|
||||||
function closest(array, value) {
|
|
||||||
if (!is$1.array(array) || !array.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array.reduce(function (prev, curr) {
|
|
||||||
return Math.abs(curr - value) < Math.abs(prev - value) ? curr : prev;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==========================================================================
|
|
||||||
|
|
||||||
var Storage = function () {
|
var Storage = function () {
|
||||||
function Storage(player) {
|
function Storage(player) {
|
||||||
classCallCheck(this, Storage);
|
classCallCheck(this, Storage);
|
||||||
@@ -7001,20 +7034,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
this.elements.buttons[type] = button;
|
this.elements.buttons[type] = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle classname when pressed property is set
|
|
||||||
var className = this.config.classNames.controlPressed;
|
|
||||||
Object.defineProperty(button, 'pressed', {
|
|
||||||
enumerable: true,
|
|
||||||
get: function get() {
|
|
||||||
return hasClass(button, className);
|
|
||||||
},
|
|
||||||
set: function set() {
|
|
||||||
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
|
||||||
|
|
||||||
toggleClass(button, className, pressed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -7887,9 +7906,8 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// Focus the first item if key interaction
|
// Focus the first item if key interaction
|
||||||
if (show && is$1.keyboardEvent(input)) {
|
if (show && is$1.keyboardEvent(input)) {
|
||||||
controls.focusFirstMenuItem.call(this, null, true);
|
controls.focusFirstMenuItem.call(this, null, true);
|
||||||
}
|
} else if (!show && !hidden) {
|
||||||
// If closing, re-focus the button
|
// If closing, re-focus the button
|
||||||
else if (!show && !hidden) {
|
|
||||||
setFocus.call(this, button, is$1.keyboardEvent(input));
|
setFocus.call(this, button, is$1.keyboardEvent(input));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -8048,17 +8066,19 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
container.appendChild(controls.createTime.call(this, 'duration'));
|
container.appendChild(controls.createTime.call(this, 'duration'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle mute button
|
// Volume controls
|
||||||
if (this.config.controls.includes('mute')) {
|
if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {
|
||||||
container.appendChild(controls.createButton.call(this, 'mute'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Volume range control
|
|
||||||
if (this.config.controls.includes('volume')) {
|
|
||||||
var volume = createElement('div', {
|
var volume = createElement('div', {
|
||||||
class: 'plyr__volume'
|
class: 'plyr__volume'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Toggle mute button
|
||||||
|
if (this.config.controls.includes('mute')) {
|
||||||
|
volume.appendChild(controls.createButton.call(this, 'mute'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume range control
|
||||||
|
if (this.config.controls.includes('volume')) {
|
||||||
// Set the attributes
|
// Set the attributes
|
||||||
var attributes = {
|
var attributes = {
|
||||||
max: 1,
|
max: 1,
|
||||||
@@ -8072,6 +8092,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
})));
|
})));
|
||||||
|
|
||||||
this.elements.volume = volume;
|
this.elements.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
container.appendChild(volume);
|
container.appendChild(volume);
|
||||||
}
|
}
|
||||||
@@ -8233,6 +8254,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
this.elements.controls = container;
|
this.elements.controls = container;
|
||||||
|
|
||||||
|
// Set available quality levels
|
||||||
if (this.isHTML5) {
|
if (this.isHTML5) {
|
||||||
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
|
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
|
||||||
}
|
}
|
||||||
@@ -8345,6 +8367,33 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
controls.findElements.call(this);
|
controls.findElements.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add pressed property to buttons
|
||||||
|
if (!is$1.empty(this.elements.buttons)) {
|
||||||
|
var addProperty = function addProperty(button) {
|
||||||
|
var className = _this10.config.classNames.controlPressed;
|
||||||
|
Object.defineProperty(button, 'pressed', {
|
||||||
|
enumerable: true,
|
||||||
|
get: function get() {
|
||||||
|
return hasClass(button, className);
|
||||||
|
},
|
||||||
|
set: function set() {
|
||||||
|
var pressed = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
|
||||||
|
|
||||||
|
toggleClass(button, className, pressed);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle classname when pressed property is set
|
||||||
|
Object.values(this.elements.buttons).filter(Boolean).forEach(function (button) {
|
||||||
|
if (is$1.array(button)) {
|
||||||
|
button.filter(Boolean).forEach(addProperty);
|
||||||
|
} else {
|
||||||
|
addProperty(button);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Edge sometimes doesn't finish the paint so force a redraw
|
// Edge sometimes doesn't finish the paint so force a redraw
|
||||||
if (window.navigator.userAgent.includes('Edge')) {
|
if (window.navigator.userAgent.includes('Edge')) {
|
||||||
repaint(target);
|
repaint(target);
|
||||||
@@ -8462,7 +8511,8 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// * active: The state preferred by user settings or config
|
// * active: The state preferred by user settings or config
|
||||||
// * toggled: The real captions state
|
// * toggled: The real captions state
|
||||||
|
|
||||||
var languages = dedupe(Array.from(navigator.languages || navigator.language || navigator.userLanguage).map(function (language) {
|
var browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
|
||||||
|
var languages = dedupe(browserLanguages.map(function (language) {
|
||||||
return language.split('-')[0];
|
return language.split('-')[0];
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@@ -8885,7 +8935,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
// Quality default
|
// Quality default
|
||||||
quality: {
|
quality: {
|
||||||
default: 576,
|
default: 576,
|
||||||
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240, 'default']
|
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240]
|
||||||
},
|
},
|
||||||
|
|
||||||
// Set loops
|
// Set loops
|
||||||
@@ -9035,7 +9085,10 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',
|
'enterfullscreen', 'exitfullscreen', 'captionsenabled', 'captionsdisabled', 'languagechange', 'controlshidden', 'controlsshown', 'ready',
|
||||||
|
|
||||||
// YouTube
|
// YouTube
|
||||||
'statechange', 'qualitychange', 'qualityrequested',
|
'statechange',
|
||||||
|
|
||||||
|
// Quality
|
||||||
|
'qualitychange',
|
||||||
|
|
||||||
// Ads
|
// Ads
|
||||||
'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
|
'adsloaded', 'adscontentpause', 'adscontentresume', 'adstarted', 'adsmidpoint', 'adscomplete', 'adsallcomplete', 'adsimpression', 'adsclick'],
|
||||||
@@ -9344,9 +9397,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// iOS native fullscreen doesn't need the request step
|
// iOS native fullscreen doesn't need the request step
|
||||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||||
if (this.player.playing) {
|
|
||||||
this.target.webkitEnterFullscreen();
|
this.target.webkitEnterFullscreen();
|
||||||
}
|
|
||||||
} else if (!Fullscreen.native) {
|
} else if (!Fullscreen.native) {
|
||||||
toggleFallback.call(this, true);
|
toggleFallback.call(this, true);
|
||||||
} else if (!this.prefix) {
|
} else if (!this.prefix) {
|
||||||
@@ -10033,7 +10084,7 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
|
|
||||||
// Remove button states for fullscreen
|
// Remove button states for fullscreen
|
||||||
|
|
||||||
if (event.type === 'enterfullscreen') {
|
if (controls$$1 && event.type === 'enterfullscreen') {
|
||||||
controls$$1.pressed = false;
|
controls$$1.pressed = false;
|
||||||
controls$$1.hover = false;
|
controls$$1.hover = false;
|
||||||
}
|
}
|
||||||
@@ -10191,12 +10242,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
player.storage.set({ speed: player.speed });
|
player.storage.set({ speed: player.speed });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality request
|
|
||||||
on.call(player, player.media, 'qualityrequested', function (event) {
|
|
||||||
// Save to storage
|
|
||||||
player.storage.set({ quality: event.detail.quality });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Quality change
|
// Quality change
|
||||||
on.call(player, player.media, 'qualitychange', function (event) {
|
on.call(player, player.media, 'qualitychange', function (event) {
|
||||||
// Update UI
|
// Update UI
|
||||||
@@ -11270,43 +11315,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
return url.match(regex) ? RegExp.$2 : url;
|
return url.match(regex) ? RegExp.$2 : url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standardise YouTube quality unit
|
|
||||||
function mapQualityUnit(input) {
|
|
||||||
var qualities = {
|
|
||||||
hd2160: 2160,
|
|
||||||
hd1440: 1440,
|
|
||||||
hd1080: 1080,
|
|
||||||
hd720: 720,
|
|
||||||
large: 480,
|
|
||||||
medium: 360,
|
|
||||||
small: 240,
|
|
||||||
tiny: 144
|
|
||||||
};
|
|
||||||
|
|
||||||
var entry = Object.entries(qualities).find(function (entry) {
|
|
||||||
return entry.includes(input);
|
|
||||||
});
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
// Get the match corresponding to the input
|
|
||||||
return entry.find(function (value) {
|
|
||||||
return value !== input;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'default';
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapQualityUnits(levels) {
|
|
||||||
if (is$1.empty(levels)) {
|
|
||||||
return levels;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dedupe(levels.map(function (level) {
|
|
||||||
return mapQualityUnit(level);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set playback state and trigger change (only on actual change)
|
// Set playback state and trigger change (only on actual change)
|
||||||
function assurePlaybackState$1(play) {
|
function assurePlaybackState$1(play) {
|
||||||
if (play && !this.embed.hasPlayed) {
|
if (play && !this.embed.hasPlayed) {
|
||||||
@@ -11490,11 +11498,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
triggerEvent.call(player, player.media, 'error');
|
triggerEvent.call(player, player.media, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPlaybackQualityChange: function onPlaybackQualityChange() {
|
|
||||||
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
|
||||||
quality: player.media.quality
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onPlaybackRateChange: function onPlaybackRateChange(event) {
|
onPlaybackRateChange: function onPlaybackRateChange(event) {
|
||||||
// Get the instance
|
// Get the instance
|
||||||
var instance = event.target;
|
var instance = event.target;
|
||||||
@@ -11564,16 +11567,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality
|
|
||||||
Object.defineProperty(player.media, 'quality', {
|
|
||||||
get: function get() {
|
|
||||||
return mapQualityUnit(instance.getPlaybackQuality());
|
|
||||||
},
|
|
||||||
set: function set(input) {
|
|
||||||
instance.setPlaybackQuality(mapQualityUnit(input));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Volume
|
// Volume
|
||||||
var volume = player.config.volume;
|
var volume = player.config.volume;
|
||||||
|
|
||||||
@@ -11726,9 +11719,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
player.media.duration = instance.getDuration();
|
player.media.duration = instance.getDuration();
|
||||||
triggerEvent.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get quality
|
|
||||||
controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@@ -13594,11 +13584,6 @@ typeof navigator === "object" && (function (global, factory) {
|
|||||||
quality = value;
|
quality = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger request event
|
|
||||||
triggerEvent.call(this, this.media, 'qualityrequested', false, {
|
|
||||||
quality: quality
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update config
|
// Update config
|
||||||
config.selected = quality;
|
config.selected = quality;
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+16
-26
@@ -1,19 +1,10 @@
|
|||||||
{
|
{
|
||||||
"name": "plyr",
|
"name": "plyr",
|
||||||
"version": "3.4.0-beta.2",
|
"version": "3.4.2",
|
||||||
"description":
|
"description": "A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
||||||
"A simple, accessible and customizable HTML5, YouTube and Vimeo media player",
|
|
||||||
"homepage": "https://plyr.io",
|
"homepage": "https://plyr.io",
|
||||||
"author": "Sam Potts <sam@potts.es>",
|
"author": "Sam Potts <sam@potts.es>",
|
||||||
"keywords": [
|
"keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],
|
||||||
"HTML5 Video",
|
|
||||||
"HTML5 Audio",
|
|
||||||
"Media Player",
|
|
||||||
"DASH",
|
|
||||||
"Shaka",
|
|
||||||
"WordPress",
|
|
||||||
"HLS"
|
|
||||||
],
|
|
||||||
"main": "./dist/plyr.js",
|
"main": "./dist/plyr.js",
|
||||||
"browser": "./dist/plyr.min.js",
|
"browser": "./dist/plyr.min.js",
|
||||||
"sass": "./src/sass/plyr.scss",
|
"sass": "./src/sass/plyr.scss",
|
||||||
@@ -32,8 +23,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "gulp build",
|
"build": "gulp build",
|
||||||
"lint": "eslint src/js && npm run-script remark",
|
"lint": "eslint src/js && npm run-script remark",
|
||||||
"remark":
|
"remark": "remark -f --use 'validate-links=repository:\"sampotts/plyr\"' '{,!(node_modules),.?**/}*.md'",
|
||||||
"remark -f --use 'validate-links=repository:\"sampotts/plyr\"' '{,!(node_modules),.?**/}*.md'",
|
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -42,21 +32,21 @@
|
|||||||
"babel-plugin-external-helpers": "^6.22.0",
|
"babel-plugin-external-helpers": "^6.22.0",
|
||||||
"babel-preset-env": "^1.7.0",
|
"babel-preset-env": "^1.7.0",
|
||||||
"del": "^3.0.0",
|
"del": "^3.0.0",
|
||||||
"eslint": "^5.2.0",
|
"eslint": "^5.3.0",
|
||||||
"eslint-config-airbnb-base": "^13.0.0",
|
"eslint-config-airbnb-base": "^13.1.0",
|
||||||
"eslint-config-prettier": "^2.9.0",
|
"eslint-config-prettier": "^3.0.1",
|
||||||
"eslint-plugin-import": "^2.13.0",
|
"eslint-plugin-import": "^2.14.0",
|
||||||
"fastly-purge": "^1.0.1",
|
"fastly-purge": "^1.0.1",
|
||||||
"git-branch": "^2.0.1",
|
"git-branch": "^2.0.1",
|
||||||
"gulp": "^3.9.1",
|
"gulp": "^3.9.1",
|
||||||
"gulp-autoprefixer": "^5.0.0",
|
"gulp-autoprefixer": "^5.0.0",
|
||||||
"gulp-better-rollup": "^3.3.0",
|
"gulp-better-rollup": "^3.3.0",
|
||||||
"gulp-clean-css": "^3.9.4",
|
"gulp-clean-css": "^3.10.0",
|
||||||
"gulp-concat": "^2.6.1",
|
"gulp-concat": "^2.6.1",
|
||||||
"gulp-filter": "^5.1.0",
|
"gulp-filter": "^5.1.0",
|
||||||
"gulp-header": "^2.0.5",
|
"gulp-header": "^2.0.5",
|
||||||
"gulp-open": "^3.0.1",
|
"gulp-open": "^3.0.1",
|
||||||
"gulp-postcss": "^7.0.1",
|
"gulp-postcss": "^8.0.0",
|
||||||
"gulp-rename": "^1.4.0",
|
"gulp-rename": "^1.4.0",
|
||||||
"gulp-replace": "^1.0.0",
|
"gulp-replace": "^1.0.0",
|
||||||
"gulp-s3": "^0.11.0",
|
"gulp-s3": "^0.11.0",
|
||||||
@@ -71,17 +61,17 @@
|
|||||||
"prettier-eslint": "^8.8.2",
|
"prettier-eslint": "^8.8.2",
|
||||||
"prettier-stylelint": "^0.4.2",
|
"prettier-stylelint": "^0.4.2",
|
||||||
"remark-cli": "^5.0.0",
|
"remark-cli": "^5.0.0",
|
||||||
"remark-validate-links": "^7.0.0",
|
"remark-validate-links": "^7.1.0",
|
||||||
"rollup-plugin-babel": "^3.0.7",
|
"rollup-plugin-babel": "^3.0.7",
|
||||||
"rollup-plugin-commonjs": "^9.1.4",
|
"rollup-plugin-commonjs": "^9.1.5",
|
||||||
"rollup-plugin-node-resolve": "^3.3.0",
|
"rollup-plugin-node-resolve": "^3.3.0",
|
||||||
"run-sequence": "^2.2.1",
|
"run-sequence": "^2.2.1",
|
||||||
"stylelint": "^9.4.0",
|
"stylelint": "^9.4.0",
|
||||||
"stylelint-config-prettier": "^3.3.0",
|
"stylelint-config-prettier": "^4.0.0",
|
||||||
"stylelint-config-recommended": "^2.1.0",
|
"stylelint-config-recommended": "^2.1.0",
|
||||||
"stylelint-config-sass-guidelines": "^5.0.0",
|
"stylelint-config-sass-guidelines": "^5.0.0",
|
||||||
"stylelint-order": "^0.8.1",
|
"stylelint-order": "^1.0.0",
|
||||||
"stylelint-scss": "^3.2.0",
|
"stylelint-scss": "^3.3.0",
|
||||||
"stylelint-selector-bem-pattern": "^2.0.0",
|
"stylelint-selector-bem-pattern": "^2.0.0",
|
||||||
"through2": "^2.0.3"
|
"through2": "^2.0.3"
|
||||||
},
|
},
|
||||||
@@ -90,6 +80,6 @@
|
|||||||
"custom-event-polyfill": "^1.0.6",
|
"custom-event-polyfill": "^1.0.6",
|
||||||
"loadjs": "^3.5.4",
|
"loadjs": "^3.5.4",
|
||||||
"raven-js": "^3.26.4",
|
"raven-js": "^3.26.4",
|
||||||
"url-polyfill": "^1.0.13"
|
"url-polyfill": "^1.0.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,26 +8,26 @@ A simple, lightweight, accessible and customizable HTML5, YouTube and Vimeo medi
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* **Accessible** - full support for VTT captions and screen readers
|
- **Accessible** - full support for VTT captions and screen readers
|
||||||
* **[Customisable](#html)** - make the player look how you want with the markup you want
|
- **[Customisable](#html)** - make the player look how you want with the markup you want
|
||||||
* **Good HTML** - uses the _right_ elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no
|
- **Good HTML** - uses the _right_ elements. `<input type="range">` for volume and `<progress>` for progress and well, `<button>`s for buttons. There's no
|
||||||
`<span>` or `<a href="#">` button hacks
|
`<span>` or `<a href="#">` button hacks
|
||||||
* **Responsive** - works with any screen size
|
- **Responsive** - works with any screen size
|
||||||
* **HTML Video & Audio** - support for both formats
|
- **HTML Video & Audio** - support for both formats
|
||||||
* **[Embedded Video](#embeds)** - support for YouTube and Vimeo video playback
|
- **[Embedded Video](#embeds)** - support for YouTube and Vimeo video playback
|
||||||
* **[Monetization](#ads)** - make money from your videos
|
- **[Monetization](#ads)** - make money from your videos
|
||||||
* **[Streaming](#try-plyr-online)** - support for hls.js, Shaka and dash.js streaming playback
|
- **[Streaming](#try-plyr-online)** - support for hls.js, Shaka and dash.js streaming playback
|
||||||
* **[API](#api)** - toggle playback, volume, seeking, and more through a standardized API
|
- **[API](#api)** - toggle playback, volume, seeking, and more through a standardized API
|
||||||
* **[Events](#events)** - no messing around with Vimeo and YouTube APIs, all events are standardized across formats
|
- **[Events](#events)** - no messing around with Vimeo and YouTube APIs, all events are standardized across formats
|
||||||
* **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes
|
- **[Fullscreen](#fullscreen)** - supports native fullscreen with fallback to "full window" modes
|
||||||
* **[Shortcuts](#shortcuts)** - supports keyboard shortcuts
|
- **[Shortcuts](#shortcuts)** - supports keyboard shortcuts
|
||||||
* **Picture-in-Picture** - supports Safari's picture-in-picture mode
|
- **Picture-in-Picture** - supports Safari's picture-in-picture mode
|
||||||
* **Playsinline** - supports the `playsinline` attribute
|
- **Playsinline** - supports the `playsinline` attribute
|
||||||
* **Speed controls** - adjust speed on the fly
|
- **Speed controls** - adjust speed on the fly
|
||||||
* **Multiple captions** - support for multiple caption tracks
|
- **Multiple captions** - support for multiple caption tracks
|
||||||
* **i18n support** - support for internationalization of controls
|
- **i18n support** - support for internationalization of controls
|
||||||
* **No dependencies** - written in "vanilla" ES6 JavaScript, no jQuery required
|
- **No dependencies** - written in "vanilla" ES6 JavaScript, no jQuery required
|
||||||
* **SASS** - to include in your build processes
|
- **SASS** - to include in your build processes
|
||||||
|
|
||||||
Oh and yes, it works with Bootstrap.
|
Oh and yes, it works with Bootstrap.
|
||||||
|
|
||||||
@@ -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.
|
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
|
```html
|
||||||
<script src="https://cdn.plyr.io/3.4.0-beta.2/plyr.js"></script>
|
<script src="https://cdn.plyr.io/3.4.2/plyr.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
...or...
|
...or...
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<script src="https://cdn.plyr.io/3.4.0-beta.2/plyr.polyfilled.js"></script>
|
<script src="https://cdn.plyr.io/3.4.2/plyr.polyfilled.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
### CSS
|
### CSS
|
||||||
@@ -152,21 +152,21 @@ 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:
|
If you want to use our CDN (provided by [Fastly](https://www.fastly.com/)) for the default CSS, you can use the following:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<link rel="stylesheet" href="https://cdn.plyr.io/3.4.0-beta.2/plyr.css">
|
<link rel="stylesheet" href="https://cdn.plyr.io/3.4.2/plyr.css">
|
||||||
```
|
```
|
||||||
|
|
||||||
### SVG Sprite
|
### 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
|
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.4.0-beta.2/plyr.svg`.
|
reference, the CDN hosted SVG sprite can be found at `https://cdn.plyr.io/3.4.2/plyr.svg`.
|
||||||
|
|
||||||
## Ads
|
## Ads
|
||||||
|
|
||||||
Plyr has partnered up with [vi.ai](https://vi.ai/publisher-video-monetization/?aid=plyrio) to offer monetization options for your videos. Getting setup is easy:
|
Plyr has partnered up with [vi.ai](https://vi.ai/publisher-video-monetization/?aid=plyrio) to offer monetization options for your videos. Getting setup is easy:
|
||||||
|
|
||||||
* [Sign up for a vi.ai account](https://vi.ai/publisher-video-monetization/?aid=plyrio)
|
- [Sign up for a vi.ai account](https://vi.ai/publisher-video-monetization/?aid=plyrio)
|
||||||
* Grab your publisher ID from the code snippet
|
- Grab your publisher ID from the code snippet
|
||||||
* Enable ads in the [config options](#options) and enter your publisher ID
|
- Enable ads in the [config options](#options) and enter your publisher ID
|
||||||
|
|
||||||
Any questions regarding the ads can be sent straight to vi.ai and any issues with rendering raised through GitHub issues.
|
Any questions regarding the ads can be sent straight to vi.ai and any issues with rendering raised through GitHub issues.
|
||||||
|
|
||||||
@@ -213,10 +213,10 @@ WebVTT captions are supported. To add a caption track, check the HTML example ab
|
|||||||
|
|
||||||
You can specify a range of arguments for the constructor to use:
|
You can specify a range of arguments for the constructor to use:
|
||||||
|
|
||||||
* A CSS string selector that's compatible with [`querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
|
- A CSS string selector that's compatible with [`querySelector`](https://developer.mozilla.org/en-US/docs/Web/API/Document/querySelector)
|
||||||
* A [`HTMLElement`](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)
|
- A [`HTMLElement`](https://developer.mozilla.org/en/docs/Web/API/HTMLElement)
|
||||||
* A [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList)
|
- A [`NodeList`](https://developer.mozilla.org/en-US/docs/Web/API/NodeList)
|
||||||
* A [jQuery](https://jquery.com) object
|
- A [jQuery](https://jquery.com) object
|
||||||
|
|
||||||
_Note_: If a `NodeList`, `Array`, or jQuery object are passed, the first element will be used for setup. To setup multiple players, see [setting up multiple players](#setting-up-multiple-players) below.
|
_Note_: If a `NodeList`, `Array`, or jQuery object are passed, the first element will be used for setup. To setup multiple players, see [setting up multiple players](#setting-up-multiple-players) below.
|
||||||
|
|
||||||
@@ -290,7 +290,7 @@ Note the single quotes encapsulating the JSON and double quotes on the object ke
|
|||||||
| `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. |
|
| `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. |
|
| `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. |
|
| `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. |
|
||||||
| `blankUrl` | String | `https://cdn.plyr.io/static/blank.mp4` | Specify a URL or path to a blank video file used to properly cancel network requests. |
|
| `blankVideo` | String | `https://cdn.plyr.io/static/blank.mp4` | Specify a URL or path to a blank video file used to properly cancel network requests. |
|
||||||
| `autoplay` | Boolean | `false` | Autoplay the media on load. This is generally advised against on UX grounds. It is also disabled by default in some browsers. If the `autoplay` attribute is present on a `<video>` or `<audio>` element, this will be automatically set to true. |
|
| `autoplay` | Boolean | `false` | Autoplay the media on load. This is generally advised against on UX grounds. It is also disabled by default in some browsers. If the `autoplay` attribute is present on a `<video>` or `<audio>` element, this will be automatically set to true. |
|
||||||
| `autopause`¹ | Boolean | `true` | Only allow one player playing at once. |
|
| `autopause`¹ | Boolean | `true` | Only allow one player playing at once. |
|
||||||
| `seekTime` | Number | `10` | The time, in seconds, to seek when a user hits fast forward or rewind. |
|
| `seekTime` | Number | `10` | The time, in seconds, to seek when a user hits fast forward or rewind. |
|
||||||
@@ -392,7 +392,7 @@ player.fullscreen.active; // false;
|
|||||||
```
|
```
|
||||||
|
|
||||||
| Property | Getter | Setter | Description |
|
| Property | Getter | Setter | Description |
|
||||||
| -------------------- | ------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| -------------------- | ------ | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
|
| `isHTML5` | ✓ | - | Returns a boolean indicating if the current player is HTML5. |
|
||||||
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
|
| `isEmbed` | ✓ | - | Returns a boolean indicating if the current player is an embedded player. |
|
||||||
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
|
| `playing` | ✓ | - | Returns a boolean indicating if the current player is playing. |
|
||||||
@@ -565,6 +565,7 @@ player.on('ready', event => {
|
|||||||
| `loadstart` | Sent when loading of the media begins. |
|
| `loadstart` | Sent when loading of the media begins. |
|
||||||
| `loadeddata` | The first frame of the media has finished loading. |
|
| `loadeddata` | The first frame of the media has finished loading. |
|
||||||
| `loadedmetadata` | The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. |
|
| `loadedmetadata` | The media's metadata has finished loading; all attributes now contain as much useful information as they're going to. |
|
||||||
|
| `qualitychange` | The quality of playback has changed. |
|
||||||
| `canplay` | Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the `HAVE_ENOUGH_DATA` `readyState`. |
|
| `canplay` | Sent when enough data is available that the media can be played, at least for a couple of frames. This corresponds to the `HAVE_ENOUGH_DATA` `readyState`. |
|
||||||
| `canplaythrough` | Sent when the ready state changes to `CAN_PLAY_THROUGH`, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. _Note:_ Manually setting the `currentTime` will eventually fire a `canplaythrough` event in firefox. Other browsers might not fire this event. |
|
| `canplaythrough` | Sent when the ready state changes to `CAN_PLAY_THROUGH`, indicating that the entire media can be played without interruption, assuming the download rate remains at least at the current level. _Note:_ Manually setting the `currentTime` will eventually fire a `canplaythrough` event in firefox. Other browsers might not fire this event. |
|
||||||
| `stalled` | Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming. |
|
| `stalled` | Sent when the user agent is trying to fetch media data, but data is unexpectedly not forthcoming. |
|
||||||
@@ -576,10 +577,8 @@ player.on('ready', event => {
|
|||||||
#### YouTube only
|
#### YouTube only
|
||||||
|
|
||||||
| Event Type | Description |
|
| Event Type | Description |
|
||||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `statechange` | The state of the player has changed. The code can be accessed via `event.detail.code`. Possible values are `-1`: Unstarted, `0`: Ended, `1`: Playing, `2`: Paused, `3`: Buffering, `5`: Video cued. See the [YouTube Docs](https://developers.google.com/youtube/iframe_api_reference#onStateChange) for more information. |
|
| `statechange` | The state of the player has changed. The code can be accessed via `event.detail.code`. Possible values are `-1`: Unstarted, `0`: Ended, `1`: Playing, `2`: Paused, `3`: Buffering, `5`: Video cued. See the [YouTube Docs](https://developers.google.com/youtube/iframe_api_reference#onStateChange) for more information. |
|
||||||
| `qualitychange` | The quality of playback has changed. |
|
|
||||||
| `qualityrequested` | A change to playback quality has been requested. _Note:_ A change to quality can only be _requested_ via the API. There is no guarantee the quality will change to the level requested. You should listen to the `qualitychange` event for true changes. |
|
|
||||||
|
|
||||||
_Note:_ These events also bubble up the DOM. The event target will be the container element.
|
_Note:_ These events also bubble up the DOM. The event target will be the container element.
|
||||||
|
|
||||||
@@ -591,8 +590,8 @@ YouTube and Vimeo are currently supported and function much like a HTML5 video.
|
|||||||
to access the API's directly. You can do so via the `embed` property of your player object - e.g. `player.embed`. You can then use the relevant methods from the
|
to access the API's directly. You can do so via the `embed` property of your player object - e.g. `player.embed`. You can then use the relevant methods from the
|
||||||
third party APIs. More info on the respective API's here:
|
third party APIs. More info on the respective API's here:
|
||||||
|
|
||||||
* [YouTube iframe API Reference](https://developers.google.com/youtube/iframe_api_reference)
|
- [YouTube iframe API Reference](https://developers.google.com/youtube/iframe_api_reference)
|
||||||
* [Vimeo player.js Reference](https://github.com/vimeo/player.js)
|
- [Vimeo player.js Reference](https://github.com/vimeo/player.js)
|
||||||
|
|
||||||
_Note_: Not all API methods may work 100%. Your mileage may vary. It's better to use the Plyr API where possible.
|
_Note_: Not all API methods may work 100%. Your mileage may vary. It's better to use the Plyr API where possible.
|
||||||
|
|
||||||
@@ -652,9 +651,9 @@ const supported = Plyr.supported('video', 'html5', true);
|
|||||||
|
|
||||||
The arguments are:
|
The arguments are:
|
||||||
|
|
||||||
* Media type (`audio` or `video`)
|
- Media type (`audio` or `video`)
|
||||||
* Provider (`html5`, `youtube` or `vimeo`)
|
- Provider (`html5`, `youtube` or `vimeo`)
|
||||||
* Whether the player has the `playsinline` attribute (only applicable to iOS 10+)
|
- Whether the player has the `playsinline` attribute (only applicable to iOS 10+)
|
||||||
|
|
||||||
### Disable support programatically
|
### Disable support programatically
|
||||||
|
|
||||||
@@ -687,33 +686,33 @@ Plyr is developed by [@sam_potts](https://twitter.com/sam_potts) / [sampotts.me]
|
|||||||
|
|
||||||
Plyr costs money to run, not only my time. I donate my time for free as I enjoy building Plyr but unfortunately have to pay for domains, hosting, and more. Any help with costs is appreciated...
|
Plyr costs money to run, not only my time. I donate my time for free as I enjoy building Plyr but unfortunately have to pay for domains, hosting, and more. Any help with costs is appreciated...
|
||||||
|
|
||||||
* [Donate via Patron](https://www.patreon.com/plyr)
|
- [Donate via Patreon](https://www.patreon.com/plyr)
|
||||||
* [Donate via PayPal](https://www.paypal.me/pottsy/20usd)
|
- [Donate via PayPal](https://www.paypal.me/pottsy/20usd)
|
||||||
|
|
||||||
## Mentions
|
## Mentions
|
||||||
|
|
||||||
* [ProductHunt](https://www.producthunt.com/tech/plyr)
|
- [ProductHunt](https://www.producthunt.com/tech/plyr)
|
||||||
* [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
|
- [The Changelog](http://thechangelog.com/plyr-simple-html5-media-player-custom-controls-webvtt-captions/)
|
||||||
* [HTML5 Weekly #177](http://html5weekly.com/issues/177)
|
- [HTML5 Weekly #177](http://html5weekly.com/issues/177)
|
||||||
* [Responsive Design #149](http://us4.campaign-archive2.com/?u=559bc631fe5294fc66f5f7f89&id=451a61490f)
|
- [Responsive Design #149](http://us4.campaign-archive2.com/?u=559bc631fe5294fc66f5f7f89&id=451a61490f)
|
||||||
* [Web Design Weekly #174](https://web-design-weekly.com/2015/02/24/web-design-weekly-174/)
|
- [Web Design Weekly #174](https://web-design-weekly.com/2015/02/24/web-design-weekly-174/)
|
||||||
* [Hacker News](https://news.ycombinator.com/item?id=9136774)
|
- [Hacker News](https://news.ycombinator.com/item?id=9136774)
|
||||||
* [Web Platform Daily](http://webplatformdaily.org/releases/2015-03-04)
|
- [Web Platform Daily](http://webplatformdaily.org/releases/2015-03-04)
|
||||||
* [LayerVault Designer News](https://news.layervault.com/stories/45394-plyr--a-simple-html5-media-player)
|
- [LayerVault Designer News](https://news.layervault.com/stories/45394-plyr--a-simple-html5-media-player)
|
||||||
* [The Treehouse Show #131](https://teamtreehouse.com/library/episode-131-origami-react-responsive-hero-images)
|
- [The Treehouse Show #131](https://teamtreehouse.com/library/episode-131-origami-react-responsive-hero-images)
|
||||||
* [noupe.com](http://www.noupe.com/design/html5-plyr-is-a-responsive-and-accessible-video-player-94389.html)
|
- [noupe.com](http://www.noupe.com/design/html5-plyr-is-a-responsive-and-accessible-video-player-94389.html)
|
||||||
|
|
||||||
## Used by
|
## Used by
|
||||||
|
|
||||||
* [Selz.com](https://selz.com)
|
- [Selz.com](https://selz.com)
|
||||||
* [Peugeot.fr](http://www.peugeot.fr/marque-et-technologie/technologies/peugeot-i-cockpit.html)
|
- [Peugeot.fr](http://www.peugeot.fr/marque-et-technologie/technologies/peugeot-i-cockpit.html)
|
||||||
* [Peugeot.de](http://www.peugeot.de/modelle/modellberater/208-3-turer/fotos-videos.html)
|
- [Peugeot.de](http://www.peugeot.de/modelle/modellberater/208-3-turer/fotos-videos.html)
|
||||||
* [TomTom.com](http://prioritydriving.tomtom.com/)
|
- [TomTom.com](http://prioritydriving.tomtom.com/)
|
||||||
* [DIGBMX](http://digbmx.com/)
|
- [DIGBMX](http://digbmx.com/)
|
||||||
* [Grime Archive](https://grimearchive.com/)
|
- [Grime Archive](https://grimearchive.com/)
|
||||||
* [koel - A personal music streaming server that works.](http://koel.phanan.net/)
|
- [koel - A personal music streaming server that works.](http://koel.phanan.net/)
|
||||||
* [Oscar Radio](http://oscar-radio.xyz/)
|
- [Oscar Radio](http://oscar-radio.xyz/)
|
||||||
* [Sparkk TV](https://www.sparkktv.com/)
|
- [Sparkk TV](https://www.sparkktv.com/)
|
||||||
|
|
||||||
Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the above list. It'd be awesome to see how you're using Plyr :-)
|
Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the above list. It'd be awesome to see how you're using Plyr :-)
|
||||||
|
|
||||||
@@ -721,8 +720,8 @@ Let me know on [Twitter](https://twitter.com/sam_potts) I can add you to the abo
|
|||||||
|
|
||||||
Credit to the PayPal HTML5 Video player from which Plyr's caption functionality was originally ported from:
|
Credit to the PayPal HTML5 Video player from which Plyr's caption functionality was originally ported from:
|
||||||
|
|
||||||
* [PayPal's Accessible HTML5 Video Player](https://github.com/paypal/accessible-html5-video-player)
|
- [PayPal's Accessible HTML5 Video Player](https://github.com/paypal/accessible-html5-video-player)
|
||||||
* [An awesome guide for Plyr in Japanese!](http://syncer.jp/how-to-use-plyr-io) by [@arayutw](https://twitter.com/arayutw)
|
- [An awesome guide for Plyr in Japanese!](http://syncer.jp/how-to-use-plyr-io) by [@arayutw](https://twitter.com/arayutw)
|
||||||
|
|
||||||
## Thanks
|
## Thanks
|
||||||
|
|
||||||
|
|||||||
+3
-6
@@ -4,7 +4,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
import i18n from './i18n';
|
|
||||||
import support from './support';
|
import support from './support';
|
||||||
import { dedupe } from './utils/arrays';
|
import { dedupe } from './utils/arrays';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
@@ -18,6 +17,7 @@ import {
|
|||||||
} from './utils/elements';
|
} from './utils/elements';
|
||||||
import { on, triggerEvent } from './utils/events';
|
import { on, triggerEvent } from './utils/events';
|
||||||
import fetch from './utils/fetch';
|
import fetch from './utils/fetch';
|
||||||
|
import i18n from './utils/i18n';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import { getHTML } from './utils/strings';
|
import { getHTML } from './utils/strings';
|
||||||
import { parseUrl } from './utils/urls';
|
import { parseUrl } from './utils/urls';
|
||||||
@@ -83,11 +83,8 @@ const captions = {
|
|||||||
// * active: The state preferred by user settings or config
|
// * active: The state preferred by user settings or config
|
||||||
// * toggled: The real captions state
|
// * toggled: The real captions state
|
||||||
|
|
||||||
const languages = dedupe(
|
const browserLanguages = navigator.languages || [navigator.language || navigator.userLanguage || 'en'];
|
||||||
Array.from(navigator.languages || navigator.language || navigator.userLanguage).map(
|
const languages = dedupe(browserLanguages.map(language => language.split('-')[0]));
|
||||||
language => language.split('-')[0],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();
|
let language = (this.storage.get('language') || this.config.captions.language || 'auto').toLowerCase();
|
||||||
|
|
||||||
|
|||||||
@@ -68,19 +68,7 @@ const defaults = {
|
|||||||
// Quality default
|
// Quality default
|
||||||
quality: {
|
quality: {
|
||||||
default: 576,
|
default: 576,
|
||||||
options: [
|
options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240],
|
||||||
4320,
|
|
||||||
2880,
|
|
||||||
2160,
|
|
||||||
1440,
|
|
||||||
1080,
|
|
||||||
720,
|
|
||||||
576,
|
|
||||||
480,
|
|
||||||
360,
|
|
||||||
240,
|
|
||||||
'default', // YouTube's "auto"
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// Set loops
|
// Set loops
|
||||||
@@ -268,8 +256,9 @@ const defaults = {
|
|||||||
|
|
||||||
// YouTube
|
// YouTube
|
||||||
'statechange',
|
'statechange',
|
||||||
|
|
||||||
|
// Quality
|
||||||
'qualitychange',
|
'qualitychange',
|
||||||
'qualityrequested',
|
|
||||||
|
|
||||||
// Ads
|
// Ads
|
||||||
'adsloaded',
|
'adsloaded',
|
||||||
|
|||||||
Vendored
+40
-22
@@ -5,13 +5,13 @@
|
|||||||
|
|
||||||
import captions from './captions';
|
import captions from './captions';
|
||||||
import html5 from './html5';
|
import html5 from './html5';
|
||||||
import i18n from './i18n';
|
|
||||||
import support from './support';
|
import support from './support';
|
||||||
import { repaint, transitionEndEvent } from './utils/animation';
|
import { repaint, transitionEndEvent } from './utils/animation';
|
||||||
import { dedupe } from './utils/arrays';
|
import { dedupe } from './utils/arrays';
|
||||||
import browser from './utils/browser';
|
import browser from './utils/browser';
|
||||||
import { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, matches, removeElement, setAttributes, setFocus, toggleClass, toggleHidden } from './utils/elements';
|
import { createElement, emptyElement, getAttributesFromSelector, getElement, getElements, hasClass, matches, removeElement, setAttributes, setFocus, toggleClass, toggleHidden } from './utils/elements';
|
||||||
import { off, on } from './utils/events';
|
import { off, on } from './utils/events';
|
||||||
|
import i18n from './utils/i18n';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import loadSprite from './utils/loadSprite';
|
import loadSprite from './utils/loadSprite';
|
||||||
import { extend } from './utils/objects';
|
import { extend } from './utils/objects';
|
||||||
@@ -275,18 +275,6 @@ const controls = {
|
|||||||
this.elements.buttons[type] = button;
|
this.elements.buttons[type] = button;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle classname when pressed property is set
|
|
||||||
const className = this.config.classNames.controlPressed;
|
|
||||||
Object.defineProperty(button, 'pressed', {
|
|
||||||
enumerable: true,
|
|
||||||
get() {
|
|
||||||
return hasClass(button, className);
|
|
||||||
},
|
|
||||||
set(pressed = false) {
|
|
||||||
toggleClass(button, className, pressed);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
return button;
|
return button;
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -1142,9 +1130,8 @@ const controls = {
|
|||||||
// Focus the first item if key interaction
|
// Focus the first item if key interaction
|
||||||
if (show && is.keyboardEvent(input)) {
|
if (show && is.keyboardEvent(input)) {
|
||||||
controls.focusFirstMenuItem.call(this, null, true);
|
controls.focusFirstMenuItem.call(this, null, true);
|
||||||
}
|
} else if (!show && !hidden) {
|
||||||
// If closing, re-focus the button
|
// If closing, re-focus the button
|
||||||
else if (!show && !hidden) {
|
|
||||||
setFocus.call(this, button, is.keyboardEvent(input));
|
setFocus.call(this, button, is.keyboardEvent(input));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1297,17 +1284,19 @@ const controls = {
|
|||||||
container.appendChild(controls.createTime.call(this, 'duration'));
|
container.appendChild(controls.createTime.call(this, 'duration'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Toggle mute button
|
// Volume controls
|
||||||
if (this.config.controls.includes('mute')) {
|
if (this.config.controls.includes('mute') || this.config.controls.includes('volume')) {
|
||||||
container.appendChild(controls.createButton.call(this, 'mute'));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Volume range control
|
|
||||||
if (this.config.controls.includes('volume')) {
|
|
||||||
const volume = createElement('div', {
|
const volume = createElement('div', {
|
||||||
class: 'plyr__volume',
|
class: 'plyr__volume',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Toggle mute button
|
||||||
|
if (this.config.controls.includes('mute')) {
|
||||||
|
volume.appendChild(controls.createButton.call(this, 'mute'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Volume range control
|
||||||
|
if (this.config.controls.includes('volume')) {
|
||||||
// Set the attributes
|
// Set the attributes
|
||||||
const attributes = {
|
const attributes = {
|
||||||
max: 1,
|
max: 1,
|
||||||
@@ -1327,6 +1316,7 @@ const controls = {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.elements.volume = volume;
|
this.elements.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
container.appendChild(volume);
|
container.appendChild(volume);
|
||||||
}
|
}
|
||||||
@@ -1512,6 +1502,7 @@ const controls = {
|
|||||||
|
|
||||||
this.elements.controls = container;
|
this.elements.controls = container;
|
||||||
|
|
||||||
|
// Set available quality levels
|
||||||
if (this.isHTML5) {
|
if (this.isHTML5) {
|
||||||
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
|
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
|
||||||
}
|
}
|
||||||
@@ -1617,6 +1608,33 @@ const controls = {
|
|||||||
controls.findElements.call(this);
|
controls.findElements.call(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add pressed property to buttons
|
||||||
|
if (!is.empty(this.elements.buttons)) {
|
||||||
|
const addProperty = button => {
|
||||||
|
const className = this.config.classNames.controlPressed;
|
||||||
|
Object.defineProperty(button, 'pressed', {
|
||||||
|
enumerable: true,
|
||||||
|
get() {
|
||||||
|
return hasClass(button, className);
|
||||||
|
},
|
||||||
|
set(pressed = false) {
|
||||||
|
toggleClass(button, className, pressed);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Toggle classname when pressed property is set
|
||||||
|
Object.values(this.elements.buttons)
|
||||||
|
.filter(Boolean)
|
||||||
|
.forEach(button => {
|
||||||
|
if (is.array(button)) {
|
||||||
|
button.filter(Boolean).forEach(addProperty);
|
||||||
|
} else {
|
||||||
|
addProperty(button);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Edge sometimes doesn't finish the paint so force a redraw
|
// Edge sometimes doesn't finish the paint so force a redraw
|
||||||
if (window.navigator.userAgent.includes('Edge')) {
|
if (window.navigator.userAgent.includes('Edge')) {
|
||||||
repaint(target);
|
repaint(target);
|
||||||
|
|||||||
@@ -177,9 +177,7 @@ class Fullscreen {
|
|||||||
|
|
||||||
// iOS native fullscreen doesn't need the request step
|
// iOS native fullscreen doesn't need the request step
|
||||||
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
if (browser.isIos && this.player.config.fullscreen.iosNative) {
|
||||||
if (this.player.playing) {
|
|
||||||
this.target.webkitEnterFullscreen();
|
this.target.webkitEnterFullscreen();
|
||||||
}
|
|
||||||
} else if (!Fullscreen.native) {
|
} else if (!Fullscreen.native) {
|
||||||
toggleFallback.call(this, true);
|
toggleFallback.call(this, true);
|
||||||
} else if (!this.prefix) {
|
} else if (!this.prefix) {
|
||||||
|
|||||||
@@ -82,6 +82,9 @@ const html5 = {
|
|||||||
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
||||||
quality: input,
|
quality: input,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Save to storage
|
||||||
|
player.storage.set({ quality: input });
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
+1
-7
@@ -277,7 +277,7 @@ class Listeners {
|
|||||||
const { controls } = elements;
|
const { controls } = elements;
|
||||||
|
|
||||||
// Remove button states for fullscreen
|
// Remove button states for fullscreen
|
||||||
if (event.type === 'enterfullscreen') {
|
if (controls && event.type === 'enterfullscreen') {
|
||||||
controls.pressed = false;
|
controls.pressed = false;
|
||||||
controls.hover = false;
|
controls.hover = false;
|
||||||
}
|
}
|
||||||
@@ -430,12 +430,6 @@ class Listeners {
|
|||||||
player.storage.set({ speed: player.speed });
|
player.storage.set({ speed: player.speed });
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality request
|
|
||||||
on.call(player, player.media, 'qualityrequested', event => {
|
|
||||||
// Save to storage
|
|
||||||
player.storage.set({ quality: event.detail.quality });
|
|
||||||
});
|
|
||||||
|
|
||||||
// Quality change
|
// Quality change
|
||||||
on.call(player, player.media, 'qualitychange', event => {
|
on.call(player, player.media, 'qualitychange', event => {
|
||||||
// Update UI
|
// Update UI
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
|
|
||||||
/* global google */
|
/* global google */
|
||||||
|
|
||||||
import i18n from '../i18n';
|
|
||||||
import { createElement } from '../utils/elements';
|
import { createElement } from '../utils/elements';
|
||||||
import { triggerEvent } from '../utils/events';
|
import { triggerEvent } from '../utils/events';
|
||||||
|
import i18n from '../utils/i18n';
|
||||||
import is from '../utils/is';
|
import is from '../utils/is';
|
||||||
import loadScript from '../utils/loadScript';
|
import loadScript from '../utils/loadScript';
|
||||||
import { formatTime } from '../utils/time';
|
import { formatTime } from '../utils/time';
|
||||||
|
|||||||
@@ -2,9 +2,7 @@
|
|||||||
// YouTube plugin
|
// YouTube plugin
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import controls from '../controls';
|
|
||||||
import ui from '../ui';
|
import ui from '../ui';
|
||||||
import { dedupe } from '../utils/arrays';
|
|
||||||
import { createElement, replaceElement, toggleClass } from '../utils/elements';
|
import { createElement, replaceElement, toggleClass } from '../utils/elements';
|
||||||
import { triggerEvent } from '../utils/events';
|
import { triggerEvent } from '../utils/events';
|
||||||
import fetch from '../utils/fetch';
|
import fetch from '../utils/fetch';
|
||||||
@@ -23,37 +21,6 @@ function parseId(url) {
|
|||||||
return url.match(regex) ? RegExp.$2 : url;
|
return url.match(regex) ? RegExp.$2 : url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Standardise YouTube quality unit
|
|
||||||
function mapQualityUnit(input) {
|
|
||||||
const qualities = {
|
|
||||||
hd2160: 2160,
|
|
||||||
hd1440: 1440,
|
|
||||||
hd1080: 1080,
|
|
||||||
hd720: 720,
|
|
||||||
large: 480,
|
|
||||||
medium: 360,
|
|
||||||
small: 240,
|
|
||||||
tiny: 144,
|
|
||||||
};
|
|
||||||
|
|
||||||
const entry = Object.entries(qualities).find(entry => entry.includes(input));
|
|
||||||
|
|
||||||
if (entry) {
|
|
||||||
// Get the match corresponding to the input
|
|
||||||
return entry.find(value => value !== input);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'default';
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapQualityUnits(levels) {
|
|
||||||
if (is.empty(levels)) {
|
|
||||||
return levels;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dedupe(levels.map(level => mapQualityUnit(level)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set playback state and trigger change (only on actual change)
|
// Set playback state and trigger change (only on actual change)
|
||||||
function assurePlaybackState(play) {
|
function assurePlaybackState(play) {
|
||||||
if (play && !this.embed.hasPlayed) {
|
if (play && !this.embed.hasPlayed) {
|
||||||
@@ -225,11 +192,6 @@ const youtube = {
|
|||||||
triggerEvent.call(player, player.media, 'error');
|
triggerEvent.call(player, player.media, 'error');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onPlaybackQualityChange() {
|
|
||||||
triggerEvent.call(player, player.media, 'qualitychange', false, {
|
|
||||||
quality: player.media.quality,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onPlaybackRateChange(event) {
|
onPlaybackRateChange(event) {
|
||||||
// Get the instance
|
// Get the instance
|
||||||
const instance = event.target;
|
const instance = event.target;
|
||||||
@@ -299,16 +261,6 @@ const youtube = {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quality
|
|
||||||
Object.defineProperty(player.media, 'quality', {
|
|
||||||
get() {
|
|
||||||
return mapQualityUnit(instance.getPlaybackQuality());
|
|
||||||
},
|
|
||||||
set(input) {
|
|
||||||
instance.setPlaybackQuality(mapQualityUnit(input));
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Volume
|
// Volume
|
||||||
let { volume } = player.config;
|
let { volume } = player.config;
|
||||||
Object.defineProperty(player.media, 'volume', {
|
Object.defineProperty(player.media, 'volume', {
|
||||||
@@ -457,12 +409,6 @@ const youtube = {
|
|||||||
player.media.duration = instance.getDuration();
|
player.media.duration = instance.getDuration();
|
||||||
triggerEvent.call(player, player.media, 'durationchange');
|
triggerEvent.call(player, player.media, 'durationchange');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get quality
|
|
||||||
controls.setQualityMenu.call(
|
|
||||||
player,
|
|
||||||
mapQualityUnits(instance.getAvailableQualityLevels()),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|||||||
+1
-6
@@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr
|
// Plyr
|
||||||
// plyr.js v3.4.0-beta.2
|
// plyr.js v3.4.2
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
@@ -698,11 +698,6 @@ class Plyr {
|
|||||||
quality = value;
|
quality = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger request event
|
|
||||||
triggerEvent.call(this, this.media, 'qualityrequested', false, {
|
|
||||||
quality,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Update config
|
// Update config
|
||||||
config.selected = quality;
|
config.selected = quality;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
// Plyr Polyfilled Build
|
// Plyr Polyfilled Build
|
||||||
// plyr.js v3.4.0-beta.2
|
// plyr.js v3.4.2
|
||||||
// https://github.com/sampotts/plyr
|
// https://github.com/sampotts/plyr
|
||||||
// License: The MIT License (MIT)
|
// License: The MIT License (MIT)
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|||||||
+1
-1
@@ -4,11 +4,11 @@
|
|||||||
|
|
||||||
import captions from './captions';
|
import captions from './captions';
|
||||||
import controls from './controls';
|
import controls from './controls';
|
||||||
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 } from './utils/elements';
|
import { getElement, toggleClass } from './utils/elements';
|
||||||
import { ready, triggerEvent } from './utils/events';
|
import { ready, triggerEvent } from './utils/events';
|
||||||
|
import i18n from './utils/i18n';
|
||||||
import is from './utils/is';
|
import is from './utils/is';
|
||||||
import loadImage from './utils/loadImage';
|
import loadImage from './utils/loadImage';
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
// Plyr internationalization
|
// Plyr internationalization
|
||||||
// ==========================================================================
|
// ==========================================================================
|
||||||
|
|
||||||
import is from './utils/is';
|
import is from './is';
|
||||||
import { getDeep } from './utils/objects';
|
import { getDeep } from './objects';
|
||||||
import { replaceAll } from './utils/strings';
|
import { replaceAll } from './strings';
|
||||||
|
|
||||||
const i18n = {
|
const i18n = {
|
||||||
get(key = '', config = {}) {
|
get(key = '', config = {}) {
|
||||||
@@ -18,20 +18,24 @@
|
|||||||
> .plyr__control,
|
> .plyr__control,
|
||||||
.plyr__progress,
|
.plyr__progress,
|
||||||
.plyr__time,
|
.plyr__time,
|
||||||
.plyr__menu {
|
.plyr__menu,
|
||||||
margin-left: ($plyr-control-spacing / 2);
|
|
||||||
|
|
||||||
&:first-child,
|
|
||||||
&:first-child + [data-plyr='pause'] {
|
|
||||||
margin-left: 0;
|
|
||||||
margin-right: auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.plyr__volume {
|
.plyr__volume {
|
||||||
margin-left: ($plyr-control-spacing / 2);
|
margin-left: ($plyr-control-spacing / 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.plyr__menu + .plyr__control,
|
||||||
|
> .plyr__control + .plyr__menu,
|
||||||
|
> .plyr__control + .plyr__control,
|
||||||
|
.plyr__progress + .plyr__control {
|
||||||
|
margin-left: floor($plyr-control-spacing / 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
> .plyr__control:first-child,
|
||||||
|
> .plyr__control:first-child + [data-plyr='pause'] {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
// Hide empty controls
|
// Hide empty controls
|
||||||
&:empty {
|
&:empty {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -39,17 +43,12 @@
|
|||||||
|
|
||||||
@media (min-width: $plyr-bp-sm) {
|
@media (min-width: $plyr-bp-sm) {
|
||||||
> .plyr__control,
|
> .plyr__control,
|
||||||
|
.plyr__menu,
|
||||||
.plyr__progress,
|
.plyr__progress,
|
||||||
.plyr__time,
|
.plyr__time,
|
||||||
.plyr__menu {
|
.plyr__volume {
|
||||||
margin-left: $plyr-control-spacing;
|
margin-left: $plyr-control-spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
> .plyr__control + .plyr__control,
|
|
||||||
.plyr__menu + .plyr__control,
|
|
||||||
> .plyr__control + .plyr__menu {
|
|
||||||
margin-left: ($plyr-control-spacing / 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,12 +71,15 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
color: $plyr-video-control-color;
|
color: $plyr-video-control-color;
|
||||||
left: 0;
|
left: 0;
|
||||||
padding: ($plyr-control-spacing * 3.5) $plyr-control-spacing
|
padding: ($plyr-control-spacing * 2) ($plyr-control-spacing / 2) ($plyr-control-spacing / 2);
|
||||||
$plyr-control-spacing;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out;
|
transition: opacity 0.4s ease-in-out, transform 0.4s ease-in-out;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
|
|
||||||
|
@media (min-width: $plyr-bp-sm) {
|
||||||
|
padding: ($plyr-control-spacing * 3.5) $plyr-control-spacing $plyr-control-spacing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide video controls
|
// Hide video controls
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
color: $plyr-tooltip-color;
|
color: $plyr-tooltip-color;
|
||||||
font-size: $plyr-font-size-small;
|
font-size: $plyr-font-size-small;
|
||||||
font-weight: $plyr-font-weight-regular;
|
font-weight: $plyr-font-weight-regular;
|
||||||
|
left: 50%;
|
||||||
line-height: 1.3;
|
line-height: 1.3;
|
||||||
margin-bottom: ($plyr-tooltip-padding * 2);
|
margin-bottom: ($plyr-tooltip-padding * 2);
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
@@ -64,6 +65,7 @@
|
|||||||
|
|
||||||
// Last tooltip
|
// Last tooltip
|
||||||
.plyr__controls > .plyr__control:last-child .plyr__tooltip {
|
.plyr__controls > .plyr__control:last-child .plyr__tooltip {
|
||||||
|
left: auto;
|
||||||
right: 0;
|
right: 0;
|
||||||
transform: translate(0, 10px) scale(0.8);
|
transform: translate(0, 10px) scale(0.8);
|
||||||
transform-origin: 100% 100%;
|
transform-origin: 100% 100%;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
.plyr--video {
|
.plyr--video {
|
||||||
|
background: #000;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
// Menu open
|
// Menu open
|
||||||
|
|||||||
@@ -3,20 +3,23 @@
|
|||||||
// --------------------------------------------------------------
|
// --------------------------------------------------------------
|
||||||
|
|
||||||
.plyr__volume {
|
.plyr__volume {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
||||||
input[type='range'] {
|
input[type='range'] {
|
||||||
|
margin-left: ($plyr-control-spacing / 2);
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: $plyr-bp-sm) {
|
@media (min-width: $plyr-bp-sm) {
|
||||||
max-width: 50px;
|
max-width: 90px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: $plyr-bp-md) {
|
@media (min-width: $plyr-bp-md) {
|
||||||
max-width: 80px;
|
max-width: 110px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user