HTML5 quality selection

This commit is contained in:
Sam Potts
2018-04-02 22:40:03 +10:00
parent cce143a7da
commit 3395e8df90
27 changed files with 3011 additions and 1149 deletions

View File

@ -9,6 +9,7 @@
"ignore": ["attribute", "class"] "ignore": ["attribute", "class"]
} }
], ],
"string-no-newline": null,
"indentation": 4, "indentation": 4,
"string-quotes": "single", "string-quotes": "single",
"max-nesting-depth": 2, "max-nesting-depth": 2,

242
demo/dist/demo.js vendored
View File

@ -85,6 +85,15 @@ function serializer(replacer, cycleReplacer) {
}); });
var stringify_2 = stringify_1.getSerialize; var stringify_2 = stringify_1.getSerialize;
var stringify = Object.freeze({
default: stringify_1,
__moduleExports: stringify_1,
getSerialize: stringify_2
});
var stringify$1 = ( stringify && stringify_1 ) || stringify;
var _window = var _window =
typeof window !== 'undefined' typeof window !== 'undefined'
? window ? window
@ -592,7 +601,7 @@ function serializeException(ex, depth, maxSize) {
var serialized = serializeObject(ex, depth); var serialized = serializeObject(ex, depth);
if (jsonSize(stringify_1(serialized)) > maxSize) { if (jsonSize(stringify$1(serialized)) > maxSize) {
return serializeException(ex, depth - 1); return serializeException(ex, depth - 1);
} }
@ -630,7 +639,7 @@ function sanitize(input, sanitizeKeys) {
var safeInput; var safeInput;
try { try {
safeInput = JSON.parse(stringify_1(input)); safeInput = JSON.parse(stringify$1(input));
} catch (o_O) { } catch (o_O) {
return input; return input;
} }
@ -693,6 +702,78 @@ var utils = {
serializeKeysForMessage: serializeKeysForMessage, serializeKeysForMessage: serializeKeysForMessage,
sanitize: sanitize sanitize: sanitize
}; };
var utils_1 = utils.isObject;
var utils_2 = utils.isError;
var utils_3 = utils.isErrorEvent;
var utils_4 = utils.isUndefined;
var utils_5 = utils.isFunction;
var utils_6 = utils.isPlainObject;
var utils_7 = utils.isString;
var utils_8 = utils.isArray;
var utils_9 = utils.isEmptyObject;
var utils_10 = utils.supportsErrorEvent;
var utils_11 = utils.supportsFetch;
var utils_12 = utils.supportsReferrerPolicy;
var utils_13 = utils.supportsPromiseRejectionEvent;
var utils_14 = utils.wrappedCallback;
var utils_15 = utils.each;
var utils_16 = utils.objectMerge;
var utils_17 = utils.truncate;
var utils_18 = utils.objectFrozen;
var utils_19 = utils.hasKey;
var utils_20 = utils.joinRegExp;
var utils_21 = utils.urlencode;
var utils_22 = utils.uuid4;
var utils_23 = utils.htmlTreeAsString;
var utils_24 = utils.htmlElementAsString;
var utils_25 = utils.isSameException;
var utils_26 = utils.isSameStacktrace;
var utils_27 = utils.parseUrl;
var utils_28 = utils.fill;
var utils_29 = utils.safeJoin;
var utils_30 = utils.serializeException;
var utils_31 = utils.serializeKeysForMessage;
var utils_32 = utils.sanitize;
var utils$1 = Object.freeze({
default: utils,
__moduleExports: utils,
isObject: utils_1,
isError: utils_2,
isErrorEvent: utils_3,
isUndefined: utils_4,
isFunction: utils_5,
isPlainObject: utils_6,
isString: utils_7,
isArray: utils_8,
isEmptyObject: utils_9,
supportsErrorEvent: utils_10,
supportsFetch: utils_11,
supportsReferrerPolicy: utils_12,
supportsPromiseRejectionEvent: utils_13,
wrappedCallback: utils_14,
each: utils_15,
objectMerge: utils_16,
truncate: utils_17,
objectFrozen: utils_18,
hasKey: utils_19,
joinRegExp: utils_20,
urlencode: utils_21,
uuid4: utils_22,
htmlTreeAsString: utils_23,
htmlElementAsString: utils_24,
isSameException: utils_25,
isSameStacktrace: utils_26,
parseUrl: utils_27,
fill: utils_28,
safeJoin: utils_29,
serializeException: utils_30,
serializeKeysForMessage: utils_31,
sanitize: utils_32
});
var utils$2 = ( utils$1 && utils ) || utils$1;
/* /*
TraceKit - Cross brower stack traces TraceKit - Cross brower stack traces
@ -842,9 +923,9 @@ TraceKit.report = (function reportModuleWrapper() {
function traceKitWindowOnError(msg, url, lineNo, colNo, ex) { function traceKitWindowOnError(msg, url, lineNo, colNo, ex) {
var stack = null; var stack = null;
// If 'ex' is ErrorEvent, get real Error from inside // If 'ex' is ErrorEvent, get real Error from inside
var exception = utils.isErrorEvent(ex) ? ex.error : ex; var exception = utils$2.isErrorEvent(ex) ? ex.error : ex;
// If 'msg' is ErrorEvent, get real message from inside // If 'msg' is ErrorEvent, get real message from inside
var message = utils.isErrorEvent(msg) ? msg.message : msg; var message = utils$2.isErrorEvent(msg) ? msg.message : msg;
if (lastExceptionStack) { if (lastExceptionStack) {
TraceKit.computeStackTrace.augmentStackTraceWithInitialElement( TraceKit.computeStackTrace.augmentStackTraceWithInitialElement(
@ -854,7 +935,7 @@ TraceKit.report = (function reportModuleWrapper() {
message message
); );
processLastException(); processLastException();
} else if (exception && utils.isError(exception)) { } else if (exception && utils$2.isError(exception)) {
// non-string `exception` arg; attempt to extract stack trace // non-string `exception` arg; attempt to extract stack trace
// New chrome and blink send along a real error object // New chrome and blink send along a real error object
@ -1321,6 +1402,12 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
var tracekit = TraceKit; var tracekit = TraceKit;
var tracekit$1 = Object.freeze({
default: tracekit,
__moduleExports: tracekit
});
/* /*
* JavaScript MD5 * JavaScript MD5
* https://github.com/blueimp/JavaScript-MD5 * https://github.com/blueimp/JavaScript-MD5
@ -1588,6 +1675,12 @@ function md5(string, key, raw) {
var md5_1 = md5; var md5_1 = md5;
var md5$1 = Object.freeze({
default: md5_1,
__moduleExports: md5_1
});
function RavenConfigError(message) { function RavenConfigError(message) {
this.name = 'RavenConfigError'; this.name = 'RavenConfigError';
this.message = message; this.message = message;
@ -1597,6 +1690,12 @@ RavenConfigError.prototype.constructor = RavenConfigError;
var configError = RavenConfigError; var configError = RavenConfigError;
var configError$1 = Object.freeze({
default: configError,
__moduleExports: configError
});
var wrapMethod = function(console, level, callback) { var wrapMethod = function(console, level, callback) {
var originalConsoleLevel = console[level]; var originalConsoleLevel = console[level];
var originalConsole = console; var originalConsole = console;
@ -1610,14 +1709,14 @@ var wrapMethod = function(console, level, callback) {
console[level] = function() { console[level] = function() {
var args = [].slice.call(arguments); var args = [].slice.call(arguments);
var msg = utils.safeJoin(args, ' '); var msg = utils$2.safeJoin(args, ' ');
var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}}; var data = {level: sentryLevel, logger: 'console', extra: {arguments: args}};
if (level === 'assert') { if (level === 'assert') {
if (args[0] === false) { if (args[0] === false) {
// Default browsers message // Default browsers message
msg = msg =
'Assertion failed: ' + (utils.safeJoin(args.slice(1), ' ') || 'console.assert'); 'Assertion failed: ' + (utils$2.safeJoin(args.slice(1), ' ') || 'console.assert');
data.extra.arguments = args.slice(1); data.extra.arguments = args.slice(1);
callback && callback(msg, data); callback && callback(msg, data);
} }
@ -1637,6 +1736,22 @@ var wrapMethod = function(console, level, callback) {
var console$1 = { var console$1 = {
wrapMethod: wrapMethod wrapMethod: wrapMethod
}; };
var console_1 = console$1.wrapMethod;
var console$2 = Object.freeze({
default: console$1,
__moduleExports: console$1,
wrapMethod: console_1
});
var TraceKit$1 = ( tracekit$1 && tracekit ) || tracekit$1;
var md5$2 = ( md5$1 && md5_1 ) || md5$1;
var RavenConfigError$1 = ( configError$1 && configError ) || configError$1;
var require$$0 = ( console$2 && console$1 ) || console$2;
/*global XDomainRequest:false */ /*global XDomainRequest:false */
@ -1646,35 +1761,35 @@ var console$1 = {
var isError$1 = utils.isError; var isError$1 = utils$2.isError;
var isObject$1 = utils.isObject; var isObject$1 = utils$2.isObject;
var isPlainObject$1 = utils.isPlainObject; var isPlainObject$1 = utils$2.isPlainObject;
var isErrorEvent$1 = utils.isErrorEvent; var isErrorEvent$1 = utils$2.isErrorEvent;
var isUndefined$1 = utils.isUndefined; var isUndefined$1 = utils$2.isUndefined;
var isFunction$1 = utils.isFunction; var isFunction$1 = utils$2.isFunction;
var isString$1 = utils.isString; var isString$1 = utils$2.isString;
var isArray$1 = utils.isArray; var isArray$1 = utils$2.isArray;
var isEmptyObject$1 = utils.isEmptyObject; var isEmptyObject$1 = utils$2.isEmptyObject;
var each$1 = utils.each; var each$1 = utils$2.each;
var objectMerge$1 = utils.objectMerge; var objectMerge$1 = utils$2.objectMerge;
var truncate$1 = utils.truncate; var truncate$1 = utils$2.truncate;
var objectFrozen$1 = utils.objectFrozen; var objectFrozen$1 = utils$2.objectFrozen;
var hasKey$1 = utils.hasKey; var hasKey$1 = utils$2.hasKey;
var joinRegExp$1 = utils.joinRegExp; var joinRegExp$1 = utils$2.joinRegExp;
var urlencode$1 = utils.urlencode; var urlencode$1 = utils$2.urlencode;
var uuid4$1 = utils.uuid4; var uuid4$1 = utils$2.uuid4;
var htmlTreeAsString$1 = utils.htmlTreeAsString; var htmlTreeAsString$1 = utils$2.htmlTreeAsString;
var isSameException$1 = utils.isSameException; var isSameException$1 = utils$2.isSameException;
var isSameStacktrace$1 = utils.isSameStacktrace; var isSameStacktrace$1 = utils$2.isSameStacktrace;
var parseUrl$1 = utils.parseUrl; var parseUrl$1 = utils$2.parseUrl;
var fill$1 = utils.fill; var fill$1 = utils$2.fill;
var supportsFetch$1 = utils.supportsFetch; var supportsFetch$1 = utils$2.supportsFetch;
var supportsReferrerPolicy$1 = utils.supportsReferrerPolicy; var supportsReferrerPolicy$1 = utils$2.supportsReferrerPolicy;
var serializeKeysForMessage$1 = utils.serializeKeysForMessage; var serializeKeysForMessage$1 = utils$2.serializeKeysForMessage;
var serializeException$1 = utils.serializeException; var serializeException$1 = utils$2.serializeException;
var sanitize$1 = utils.sanitize; var sanitize$1 = utils$2.sanitize;
var wrapConsoleMethod = console$1.wrapMethod; var wrapConsoleMethod = require$$0.wrapMethod;
var dsnKeys = 'source protocol user pass host port path'.split(' '), var dsnKeys = 'source protocol user pass host port path'.split(' '),
dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/; dsnPattern = /^(?:(\w+):)?\/\/(?:(\w+)(:\w+)?@)?([\w\.-]+)(?::(\d+))?(\/.*)/;
@ -1781,7 +1896,7 @@ Raven.prototype = {
debug: false, debug: false,
TraceKit: tracekit, // alias to TraceKit TraceKit: TraceKit$1, // alias to TraceKit
/* /*
* Configure Raven with a DSN and extra options * Configure Raven with a DSN and extra options
@ -1862,7 +1977,7 @@ Raven.prototype = {
} }
globalOptions.instrument = instrument; globalOptions.instrument = instrument;
tracekit.collectWindowErrors = !!globalOptions.collectWindowErrors; TraceKit$1.collectWindowErrors = !!globalOptions.collectWindowErrors;
// return for chaining // return for chaining
return self; return self;
@ -1879,7 +1994,7 @@ Raven.prototype = {
install: function() { install: function() {
var self = this; var self = this;
if (self.isSetup() && !self._isRavenInstalled) { if (self.isSetup() && !self._isRavenInstalled) {
tracekit.report.subscribe(function() { TraceKit$1.report.subscribe(function() {
self._handleOnErrorStackInfo.apply(self, arguments); self._handleOnErrorStackInfo.apply(self, arguments);
}); });
@ -2043,7 +2158,7 @@ Raven.prototype = {
* @return {Raven} * @return {Raven}
*/ */
uninstall: function() { uninstall: function() {
tracekit.report.uninstall(); TraceKit$1.report.uninstall();
this._detachPromiseRejectionHandler(); this._detachPromiseRejectionHandler();
this._unpatchFunctionToString(); this._unpatchFunctionToString();
@ -2138,7 +2253,7 @@ Raven.prototype = {
// raises an exception different from the one we asked to // raises an exception different from the one we asked to
// report on. // report on.
try { try {
var stack = tracekit.computeStackTrace(ex); var stack = TraceKit$1.computeStackTrace(ex);
this._handleStackInfo(stack, options); this._handleStackInfo(stack, options);
} catch (ex1) { } catch (ex1) {
if (ex !== ex1) { if (ex !== ex1) {
@ -2154,7 +2269,7 @@ Raven.prototype = {
var options = objectMerge$1(currentOptions, { var options = objectMerge$1(currentOptions, {
message: message:
'Non-Error exception captured with keys: ' + serializeKeysForMessage$1(exKeys), 'Non-Error exception captured with keys: ' + serializeKeysForMessage$1(exKeys),
fingerprint: [md5_1(exKeys)], fingerprint: [md5$2(exKeys)],
extra: currentOptions.extra || {} extra: currentOptions.extra || {}
}); });
options.extra.__serialized__ = serializeException$1(ex); options.extra.__serialized__ = serializeException$1(ex);
@ -2203,7 +2318,7 @@ Raven.prototype = {
// null exception name so `Error` isn't prefixed to msg // null exception name so `Error` isn't prefixed to msg
ex.name = null; ex.name = null;
var stack = tracekit.computeStackTrace(ex); var stack = TraceKit$1.computeStackTrace(ex);
// stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1] // stack[0] is `throw new Error(msg)` call itself, we are interested in the frame that was just before that, stack[1]
var initialCall = isArray$1(stack.stack) && stack.stack[1]; var initialCall = isArray$1(stack.stack) && stack.stack[1];
@ -2350,7 +2465,7 @@ Raven.prototype = {
*/ */
getContext: function() { getContext: function() {
// lol javascript // lol javascript
return JSON.parse(stringify_1(this._globalContext)); return JSON.parse(stringify$1(this._globalContext));
}, },
/* /*
@ -2486,12 +2601,12 @@ Raven.prototype = {
var lastEventId = options.eventId || this.lastEventId(); var lastEventId = options.eventId || this.lastEventId();
if (!lastEventId) { if (!lastEventId) {
throw new configError('Missing eventId'); throw new RavenConfigError$1('Missing eventId');
} }
var dsn = options.dsn || this._dsn; var dsn = options.dsn || this._dsn;
if (!dsn) { if (!dsn) {
throw new configError('Missing DSN'); throw new RavenConfigError$1('Missing DSN');
} }
var encode = encodeURIComponent; var encode = encodeURIComponent;
@ -3133,11 +3248,11 @@ Raven.prototype = {
try { try {
while (i--) dsn[dsnKeys[i]] = m[i] || ''; while (i--) dsn[dsnKeys[i]] = m[i] || '';
} catch (e) { } catch (e) {
throw new configError('Invalid DSN: ' + str); throw new RavenConfigError$1('Invalid DSN: ' + str);
} }
if (dsn.pass && !this._globalOptions.allowSecretKey) { if (dsn.pass && !this._globalOptions.allowSecretKey) {
throw new configError( throw new RavenConfigError$1(
'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key' 'Do not specify your secret key in the DSN. See: http://bit.ly/raven-secret-key'
); );
} }
@ -3658,7 +3773,7 @@ Raven.prototype = {
} }
if (supportsFetch$1()) { if (supportsFetch$1()) {
evaluatedFetchParameters.body = stringify_1(opts.data); evaluatedFetchParameters.body = stringify$1(opts.data);
var defaultFetchOptions = objectMerge$1({}, this._fetchDefaults); var defaultFetchOptions = objectMerge$1({}, this._fetchDefaults);
var fetchOptions = objectMerge$1(defaultFetchOptions, evaluatedFetchParameters); var fetchOptions = objectMerge$1(defaultFetchOptions, evaluatedFetchParameters);
@ -3733,7 +3848,7 @@ Raven.prototype = {
}); });
} }
request.send(stringify_1(opts.data)); request.send(stringify$1(opts.data));
}, },
_evaluateHash: function(hash) { _evaluateHash: function(hash) {
@ -3775,6 +3890,14 @@ Raven.prototype.setReleaseContext = Raven.prototype.setRelease;
var raven = Raven; var raven = Raven;
var raven$1 = Object.freeze({
default: raven,
__moduleExports: raven
});
var RavenConstructor = ( raven$1 && raven ) || raven$1;
/** /**
* Enforces a single instance of the Raven client, and the * Enforces a single instance of the Raven client, and the
* main entry point for Raven. If you are a consumer of the * main entry point for Raven. If you are a consumer of the
@ -3790,7 +3913,7 @@ var _window$3 =
: typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {}; : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
var _Raven = _window$3.Raven; var _Raven = _window$3.Raven;
var Raven$1 = new raven(); var Raven$1 = new RavenConstructor();
/* /*
* Allow multiple versions of Raven to be installed. * Allow multiple versions of Raven to be installed.
@ -3841,7 +3964,7 @@ var singleton = Raven$1;
* *
* It should "just work". * It should "just work".
*/ */
var Client = raven; var Client = RavenConstructor;
singleton.Client = Client; singleton.Client = Client;
// ========================================================================== // ==========================================================================
@ -3960,8 +4083,21 @@ singleton.Client = Client;
type: 'video', type: 'video',
title: 'View From A Blue Moon', title: 'View From A Blue Moon',
sources: [{ sources: [{
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4', src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4',
type: 'video/mp4' type: 'video/mp4',
size: 576
}, {
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4',
type: 'video/mp4',
size: 720
}, {
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4',
type: 'video/mp4',
size: 1080
}, {
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4',
type: 'video/mp4',
size: 1440
}], }],
poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg', poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',
tracks: [{ tracks: [{

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -93,16 +93,18 @@
<main> <main>
<video controls crossorigin playsinline poster="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg" id="player"> <video controls crossorigin playsinline poster="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg" id="player">
<!-- Video files --> <!-- Video files -->
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" type="video/mp4"> <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" type="video/mp4" size="576">
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.webm" type="video/webm"> <source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4" type="video/mp4" size="720">
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4" type="video/mp4" size="1080">
<source src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4" type="video/mp4" size="1440">
<!-- Text track file --> <!-- Caption files -->
<track kind="captions" label="English" srclang="en" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt" <track kind="captions" label="English" srclang="en" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.en.vtt"
default> default>
<track kind="captions" label="Français" srclang="fr" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt"> <track kind="captions" label="Français" srclang="fr" src="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.fr.vtt">
<!-- Fallback for browsers that don't support the <video> element --> <!-- Fallback for browsers that don't support the <video> element -->
<a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4" download>Download</a> <a href="https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4" download>Download</a>
</video> </video>
<ul> <ul>
@ -169,7 +171,7 @@
</aside> </aside>
<!-- Polyfills --> <!-- Polyfills -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries" <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=es6,Array.prototype.includes,CustomEvent,Object.entries,Object.values"
crossorigin="anonymous"></script> crossorigin="anonymous"></script>
<!-- Plyr core script --> <!-- Plyr core script -->

View File

@ -119,10 +119,28 @@ import Raven from 'raven-js';
player.source = { player.source = {
type: 'video', type: 'video',
title: 'View From A Blue Moon', title: 'View From A Blue Moon',
sources: [{ sources: [
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.mp4', {
type: 'video/mp4', src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-576p.mp4',
}], type: 'video/mp4',
size: 576,
},
{
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-720p.mp4',
type: 'video/mp4',
size: 720,
},
{
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1080p.mp4',
type: 'video/mp4',
size: 1080,
},
{
src: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-1440p.mp4',
type: 'video/mp4',
size: 1440,
},
],
poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg', poster: 'https://cdn.plyr.io/static/demo/View_From_A_Blue_Moon_Trailer-HD.jpg',
tracks: [ tracks: [
{ {

405
dist/plyr.js vendored
View File

@ -77,15 +77,15 @@ var defaults = {
// Sprite (for icons) // Sprite (for icons)
loadSprite: true, loadSprite: true,
iconPrefix: 'plyr', iconPrefix: 'plyr',
iconUrl: 'https://cdn.plyr.io/3.0.10/plyr.svg', iconUrl: 'https://cdn.plyr.io/3.0.11/plyr.svg',
// Blank video (used to prevent errors on source change) // Blank video (used to prevent errors on source change)
blankVideo: 'https://cdn.plyr.io/static/blank.mp4', blankVideo: 'https://cdn.plyr.io/static/blank.mp4',
// Quality default // Quality default
quality: { quality: {
default: 'default', default: 720,
options: ['hd2160', 'hd1440', 'hd1080', 'hd720', 'large', 'medium', 'small', 'tiny', 'default'] options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240, 'default']
}, },
// Set loops // Set loops
@ -1339,15 +1339,19 @@ var utils = {
// Trigger event // Trigger event
dispatchEvent: function dispatchEvent(element, type, bubbles, detail) { dispatchEvent: function dispatchEvent(element) {
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
var bubbles = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
var detail = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
// Bail if no element // Bail if no element
if (!utils.is.element(element) || !utils.is.string(type)) { if (!utils.is.element(element) || utils.is.empty(type)) {
return; return;
} }
// Create and dispatch the event // Create and dispatch the event
var event = new CustomEvent(type, { var event = new CustomEvent(type, {
bubbles: utils.is.boolean(bubbles) ? bubbles : false, bubbles: bubbles,
detail: Object.assign({}, detail, { detail: Object.assign({}, detail, {
plyr: utils.is.plyr(this) ? this : null plyr: utils.is.plyr(this) ? this : null
}) })
@ -1526,6 +1530,18 @@ var utils = {
}, },
// Remove duplicates in an array
dedupe: function dedupe(array) {
if (!utils.is.array(array)) {
return array;
}
return array.filter(function (item, index) {
return array.indexOf(item) === index;
});
},
// Get the provider for a given URL // Get the provider for a given URL
getProviderByUrl: function getProviderByUrl(url) { getProviderByUrl: function getProviderByUrl(url) {
// YouTube // YouTube
@ -2427,8 +2443,8 @@ var ui = {
// Reset loop state // Reset loop state
this.loop = null; this.loop = null;
// Reset quality options // Reset quality setting
this.options.quality = []; this.quality = null;
// Reset volume display // Reset volume display
ui.updateVolume.call(this); ui.updateVolume.call(this);
@ -2700,6 +2716,159 @@ var ui = {
// ========================================================================== // ==========================================================================
var html5 = {
getSources: function getSources() {
if (!this.isHTML5) {
return null;
}
return this.media.querySelectorAll('source');
},
// Get quality levels
getQualityOptions: function getQualityOptions() {
if (!this.isHTML5) {
return null;
}
// Get sources
var sources = html5.getSources.call(this);
if (utils.is.empty(sources)) {
return null;
}
// Get <source> with size attribute
var sizes = Array.from(sources).filter(function (source) {
return !utils.is.empty(source.getAttribute('size'));
});
// If none, bail
if (utils.is.empty(sizes)) {
return null;
}
// Reduce to unique list
return utils.dedupe(sizes.map(function (source) {
return Number(source.getAttribute('size'));
}));
},
extend: function extend() {
if (!this.isHTML5) {
return;
}
var player = this;
// Quality
Object.defineProperty(player.media, 'quality', {
get: function get() {
// Get sources
var sources = html5.getSources.call(player);
if (utils.is.empty(sources)) {
return null;
}
var matches = Array.from(sources).filter(function (source) {
return source.getAttribute('src') === player.source;
});
if (utils.is.empty(matches)) {
return null;
}
return Number(matches[0].getAttribute('size'));
},
set: function set(input) {
// Get sources
var sources = html5.getSources.call(player);
if (utils.is.empty(sources)) {
return;
}
// Get matches for requested size
var matches = Array.from(sources).filter(function (source) {
return Number(source.getAttribute('size')) === input;
});
// No matches for requested size
if (utils.is.empty(matches)) {
return;
}
// Get supported sources
var supported = matches.filter(function (source) {
return support.mime.call(player, source.getAttribute('type'));
});
// No supported sources
if (utils.is.empty(supported)) {
return;
}
// Trigger change event
utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
quality: input
});
// Get current state
var currentTime = player.currentTime,
playing = player.playing;
// Set new source
player.media.src = supported[0].getAttribute('src');
// Load new source
player.media.load();
// Resume playing
if (playing) {
player.play();
}
// Restore time
player.currentTime = currentTime;
// Trigger change event
utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
quality: input
});
}
});
},
// Cancel current network requests
// See https://github.com/sampotts/plyr/issues/174
cancelRequests: function cancelRequests() {
if (!this.isHTML5) {
return;
}
// Remove child sources
utils.removeElement(html5.getSources());
// Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
this.media.setAttribute('src', this.config.blankVideo);
// Load the new empty source
// This will cancel existing requests
// See https://github.com/sampotts/plyr/issues/174
this.media.load();
// Debugging
this.debug.log('Cancelled network requests');
}
};
// ==========================================================================
// Sniff out the browser // Sniff out the browser
var browser$1 = utils.getBrowser(); var browser$1 = utils.getBrowser();
@ -3100,8 +3269,8 @@ var controls = {
}, },
// Set the YouTube quality menu // Set the quality menu
// TODO: Support for HTML5 // TODO: Vimeo support
setQualityMenu: function setQualityMenu(options) { setQualityMenu: function setQualityMenu(options) {
var _this2 = this; var _this2 = this;
@ -3118,12 +3287,10 @@ var controls = {
this.options.quality = options.filter(function (quality) { this.options.quality = options.filter(function (quality) {
return _this2.config.quality.options.includes(quality); return _this2.config.quality.options.includes(quality);
}); });
} else {
this.options.quality = this.config.quality.options;
} }
// Toggle the pane and tab // Toggle the pane and tab
var toggle = !utils.is.empty(this.options.quality) && this.isYouTube; var toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleTab.call(this, type, toggle); controls.toggleTab.call(this, type, toggle);
// If we're hiding, nothing more to do // If we're hiding, nothing more to do
@ -3139,22 +3306,26 @@ var controls = {
var label = ''; var label = '';
switch (quality) { switch (quality) {
case 'hd2160': case 2160:
label = '4K'; label = '4K';
break; break;
case 'hd1440': case 1440:
label = 'WQHD'; label = 'WQHD';
break; break;
case 'hd1080': case 1080:
label = 'HD'; label = 'HD';
break; break;
case 'hd720': case 720:
label = 'HD'; label = 'HD';
break; break;
case 576:
label = 'SD';
break;
default: default:
break; break;
} }
@ -3166,8 +3337,13 @@ var controls = {
return controls.createBadge.call(_this2, label); return controls.createBadge.call(_this2, label);
}; };
this.options.quality.forEach(function (quality) { // Sort options by the config and then render options
return controls.createMenuItem.call(_this2, quality, list, type, controls.getLabel.call(_this2, 'quality', quality), getBadge(quality)); this.options.quality.sort(function (a, b) {
var sorting = _this2.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(function (quality) {
var label = controls.getLabel.call(_this2, 'quality', quality);
controls.createMenuItem.call(_this2, quality, list, type, label, getBadge(quality));
}); });
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
@ -3182,28 +3358,10 @@ var controls = {
return value === 1 ? 'Normal' : value + '&times;'; return value === 1 ? 'Normal' : value + '&times;';
case 'quality': case 'quality':
switch (value) { if (utils.is.number(value)) {
case 'hd2160': return value + 'p';
return '2160P';
case 'hd1440':
return '1440P';
case 'hd1080':
return '1080P';
case 'hd720':
return '720P';
case 'large':
return '480P';
case 'medium':
return '360P';
case 'small':
return '240P';
case 'tiny':
return 'Tiny';
case 'default':
return 'Auto';
default:
return value;
} }
return utils.toTitleCase(value);
case 'captions': case 'captions':
return controls.getLanguage.call(this); return controls.getLanguage.call(this);
@ -3215,7 +3373,7 @@ var controls = {
// Update the selected setting // Update the selected setting
updateSetting: function updateSetting(setting, container) { updateSetting: function updateSetting(setting, container, input) {
var pane = this.elements.settings.panes[setting]; var pane = this.elements.settings.panes[setting];
var value = null; var value = null;
var list = container; var list = container;
@ -3226,7 +3384,7 @@ var controls = {
break; break;
default: default:
value = this[setting]; value = !utils.is.empty(input) ? input : this[setting];
// Get default // Get default
if (utils.is.empty(value)) { if (utils.is.empty(value)) {
@ -3234,7 +3392,7 @@ var controls = {
} }
// Unsupported value // Unsupported value
if (!this.options[setting].includes(value)) { if (!utils.is.empty(this.options[setting]) && !this.options[setting].includes(value)) {
this.debug.warn('Unsupported value of \'' + value + '\' for ' + setting); this.debug.warn('Unsupported value of \'' + value + '\' for ' + setting);
return; return;
} }
@ -3428,10 +3586,13 @@ var controls = {
// Check if we need to hide/show the settings menu // Check if we need to hide/show the settings menu
checkMenu: function checkMenu() { checkMenu: function checkMenu() {
var speedHidden = this.elements.settings.tabs.speed.getAttribute('hidden') !== null; var tabs = this.elements.settings.tabs;
var languageHidden = this.elements.settings.tabs.captions.getAttribute('hidden') !== null;
utils.toggleHidden(this.elements.settings.menu, speedHidden && languageHidden); var visible = !utils.is.empty(tabs) && Object.values(tabs).some(function (tab) {
return !tab.hidden;
});
utils.toggleHidden(this.elements.settings.menu, !visible);
}, },
@ -3827,6 +3988,10 @@ var controls = {
controls.setSpeedMenu.call(this); controls.setSpeedMenu.call(this);
if (this.isHTML5) {
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
}
return container; return container;
}, },
@ -4285,13 +4450,16 @@ var Listeners = function () {
_this3.player.storage.set({ speed: _this3.player.speed }); _this3.player.storage.set({ speed: _this3.player.speed });
}); });
// Quality change // Quality request
utils.on(this.player.media, 'qualitychange', function () { utils.on(this.player.media, 'qualityrequested', function (event) {
// Update UI
controls.updateSetting.call(_this3.player, 'quality');
// Save to storage // Save to storage
_this3.player.storage.set({ quality: _this3.player.quality }); _this3.player.storage.set({ quality: event.detail.quality });
});
// Quality change
utils.on(this.player.media, 'qualitychange', function (event) {
// Update UI
controls.updateSetting.call(_this3.player, 'quality', null, event.detail.quality);
}); });
// Caption language change // Caption language change
@ -5280,6 +5448,66 @@ var Ads = function () {
// ========================================================================== // ==========================================================================
// Standardise YouTube quality unit
function mapQualityUnit(input) {
switch (input) {
case 'hd2160':
return 2160;
case 2160:
return 'hd2160';
case 'hd1440':
return 1440;
case 1440:
return 'hd1440';
case 'hd1080':
return 1080;
case 1080:
return 'hd1080';
case 'hd720':
return 720;
case 720:
return 'hd720';
case 'large':
return 480;
case 480:
return 'large';
case 'medium':
return 360;
case 360:
return 'medium';
case 'small':
return 240;
case 240:
return 'small';
default:
return 'default';
}
}
function mapQualityUnits(levels) {
if (utils.is.empty(levels)) {
return levels;
}
return utils.dedupe(levels.map(function (level) {
return mapQualityUnit(level);
}));
}
var youtube = { var youtube = {
setup: function setup() { setup: function setup() {
var _this = this; var _this = this;
@ -5444,14 +5672,10 @@ var youtube = {
utils.dispatchEvent.call(player, player.media, 'error'); utils.dispatchEvent.call(player, player.media, 'error');
}, },
onPlaybackQualityChange: function onPlaybackQualityChange(event) { onPlaybackQualityChange: function onPlaybackQualityChange() {
// Get the instance utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
var instance = event.target; quality: player.media.quality
});
// Get current quality
player.media.quality = instance.getPlaybackQuality();
utils.dispatchEvent.call(player, player.media, 'qualitychange');
}, },
onPlaybackRateChange: function onPlaybackRateChange(event) { onPlaybackRateChange: function onPlaybackRateChange(event) {
// Get the instance // Get the instance
@ -5516,15 +5740,18 @@ var youtube = {
// Quality // Quality
Object.defineProperty(player.media, 'quality', { Object.defineProperty(player.media, 'quality', {
get: function get() { get: function get() {
return instance.getPlaybackQuality(); return mapQualityUnit(instance.getPlaybackQuality());
}, },
set: function set(input) { set: function set(input) {
var quality = input;
// Set via API
instance.setPlaybackQuality(mapQualityUnit(quality));
// Trigger request event // Trigger request event
utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, { utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
quality: input quality: quality
}); });
instance.setPlaybackQuality(input);
} }
}); });
@ -5681,7 +5908,7 @@ var youtube = {
} }
// Get quality // Get quality
controls.setQualityMenu.call(player, instance.getAvailableQualityLevels()); controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
break; break;
@ -6103,32 +6330,9 @@ var media = {
} }
} else if (this.isHTML5) { } else if (this.isHTML5) {
ui.setTitle.call(this); ui.setTitle.call(this);
html5.extend.call(this);
} }
},
// Cancel current network requests
// See https://github.com/sampotts/plyr/issues/174
cancelRequests: function cancelRequests() {
if (!this.isHTML5) {
return;
}
// Remove child sources
utils.removeElement(this.media.querySelectorAll('source'));
// Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
this.media.setAttribute('src', this.config.blankVideo);
// Load the new empty source
// This will cancel existing requests
// See https://github.com/sampotts/plyr/issues/174
this.media.load();
// Debugging
this.debug.log('Cancelled network requests');
} }
}; };
@ -6162,11 +6366,12 @@ var source = {
} }
// Cancel current network requests // Cancel current network requests
media.cancelRequests.call(this); html5.cancelRequests.call(this);
// Destroy instance and re-setup // Destroy instance and re-setup
this.destroy.call(this, function () { this.destroy.call(this, function () {
// TODO: Reset menus here // Reset quality options
_this2.options.quality = [];
// Remove elements // Remove elements
utils.removeElement(_this2.media); utils.removeElement(_this2.media);
@ -7325,8 +7530,8 @@ var Plyr = function () {
/** /**
* Set playback quality * Set playback quality
* Currently YouTube only * Currently HTML5 & YouTube only
* @param {string} input - Quality level * @param {number} input - Quality level
*/ */
}, { }, {
@ -7334,18 +7539,22 @@ var Plyr = function () {
set: function set$$1(input) { set: function set$$1(input) {
var quality = null; var quality = null;
if (utils.is.string(input)) { if (!utils.is.empty(input)) {
quality = input; quality = Number(input);
} }
if (!utils.is.string(quality)) { if (!utils.is.number(quality) || quality === 0) {
quality = this.storage.get('quality'); quality = this.storage.get('quality');
} }
if (!utils.is.string(quality)) { if (!utils.is.number(quality)) {
quality = this.config.quality.selected; quality = this.config.quality.selected;
} }
if (!utils.is.number(quality)) {
quality = this.config.quality.default;
}
if (!this.options.quality.includes(quality)) { if (!this.options.quality.includes(quality)) {
this.debug.warn('Unsupported quality option (' + quality + ')'); this.debug.warn('Unsupported quality option (' + quality + ')');
return; return;

2
dist/plyr.js.map vendored

File diff suppressed because one or more lines are too long

2
dist/plyr.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2821
dist/plyr.polyfilled.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@
"eslint": "^4.19.1", "eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0", "eslint-config-airbnb-base": "^12.1.0",
"eslint-config-prettier": "^2.9.0", "eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.9.0", "eslint-plugin-import": "^2.10.0",
"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",
@ -41,12 +41,12 @@
"rollup-plugin-commonjs": "^9.1.0", "rollup-plugin-commonjs": "^9.1.0",
"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.1.3", "stylelint": "^9.2.0",
"stylelint-config-prettier": "^3.0.4", "stylelint-config-prettier": "^3.0.4",
"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": "^0.8.1",
"stylelint-scss": "^2.5.0", "stylelint-scss": "^3.0.0",
"stylelint-selector-bem-pattern": "^2.0.0" "stylelint-selector-bem-pattern": "^2.0.0"
}, },
"keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"], "keywords": ["HTML5 Video", "HTML5 Audio", "Media Player", "DASH", "Shaka", "WordPress", "HLS"],

72
src/js/controls.js vendored
View File

@ -7,6 +7,7 @@ import utils from './utils';
import ui from './ui'; import ui from './ui';
import i18n from './i18n'; import i18n from './i18n';
import captions from './captions'; import captions from './captions';
import html5 from './html5';
// Sniff out the browser // Sniff out the browser
const browser = utils.getBrowser(); const browser = utils.getBrowser();
@ -435,8 +436,8 @@ const controls = {
utils.toggleHidden(pane, !toggle); utils.toggleHidden(pane, !toggle);
}, },
// Set the YouTube quality menu // Set the quality menu
// TODO: Support for HTML5 // TODO: Vimeo support
setQualityMenu(options) { setQualityMenu(options) {
// Menu required // Menu required
if (!utils.is.element(this.elements.settings.panes.quality)) { if (!utils.is.element(this.elements.settings.panes.quality)) {
@ -449,12 +450,10 @@ const controls = {
// Set options if passed and filter based on config // Set options if passed and filter based on config
if (utils.is.array(options)) { if (utils.is.array(options)) {
this.options.quality = options.filter(quality => this.config.quality.options.includes(quality)); this.options.quality = options.filter(quality => this.config.quality.options.includes(quality));
} else {
this.options.quality = this.config.quality.options;
} }
// Toggle the pane and tab // Toggle the pane and tab
const toggle = !utils.is.empty(this.options.quality) && this.isYouTube; const toggle = !utils.is.empty(this.options.quality) && this.options.quality.length > 1;
controls.toggleTab.call(this, type, toggle); controls.toggleTab.call(this, type, toggle);
// If we're hiding, nothing more to do // If we're hiding, nothing more to do
@ -470,22 +469,26 @@ const controls = {
let label = ''; let label = '';
switch (quality) { switch (quality) {
case 'hd2160': case 2160:
label = '4K'; label = '4K';
break; break;
case 'hd1440': case 1440:
label = 'WQHD'; label = 'WQHD';
break; break;
case 'hd1080': case 1080:
label = 'HD'; label = 'HD';
break; break;
case 'hd720': case 720:
label = 'HD'; label = 'HD';
break; break;
case 576:
label = 'SD';
break;
default: default:
break; break;
} }
@ -497,9 +500,14 @@ const controls = {
return controls.createBadge.call(this, label); return controls.createBadge.call(this, label);
}; };
this.options.quality.forEach(quality => // Sort options by the config and then render options
controls.createMenuItem.call(this, quality, list, type, controls.getLabel.call(this, 'quality', quality), getBadge(quality)), this.options.quality.sort((a, b) => {
); const sorting = this.config.quality.options;
return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1;
}).forEach(quality => {
const label = controls.getLabel.call(this, 'quality', quality);
controls.createMenuItem.call(this, quality, list, type, label, getBadge(quality));
});
controls.updateSetting.call(this, type, list); controls.updateSetting.call(this, type, list);
}, },
@ -512,28 +520,10 @@ const controls = {
return value === 1 ? 'Normal' : `${value}&times;`; return value === 1 ? 'Normal' : `${value}&times;`;
case 'quality': case 'quality':
switch (value) { if (utils.is.number(value)) {
case 'hd2160': return `${value}p`;
return '2160P';
case 'hd1440':
return '1440P';
case 'hd1080':
return '1080P';
case 'hd720':
return '720P';
case 'large':
return '480P';
case 'medium':
return '360P';
case 'small':
return '240P';
case 'tiny':
return 'Tiny';
case 'default':
return 'Auto';
default:
return value;
} }
return utils.toTitleCase(value);
case 'captions': case 'captions':
return controls.getLanguage.call(this); return controls.getLanguage.call(this);
@ -544,7 +534,7 @@ const controls = {
}, },
// Update the selected setting // Update the selected setting
updateSetting(setting, container) { updateSetting(setting, container, input) {
const pane = this.elements.settings.panes[setting]; const pane = this.elements.settings.panes[setting];
let value = null; let value = null;
let list = container; let list = container;
@ -555,7 +545,7 @@ const controls = {
break; break;
default: default:
value = this[setting]; value = !utils.is.empty(input) ? input : this[setting];
// Get default // Get default
if (utils.is.empty(value)) { if (utils.is.empty(value)) {
@ -563,7 +553,7 @@ const controls = {
} }
// Unsupported value // Unsupported value
if (!this.options[setting].includes(value)) { if (!utils.is.empty(this.options[setting]) && !this.options[setting].includes(value)) {
this.debug.warn(`Unsupported value of '${value}' for ${setting}`); this.debug.warn(`Unsupported value of '${value}' for ${setting}`);
return; return;
} }
@ -767,10 +757,10 @@ const controls = {
// Check if we need to hide/show the settings menu // Check if we need to hide/show the settings menu
checkMenu() { checkMenu() {
const speedHidden = this.elements.settings.tabs.speed.getAttribute('hidden') !== null; const { tabs } = this.elements.settings;
const languageHidden = this.elements.settings.tabs.captions.getAttribute('hidden') !== null; const visible = !utils.is.empty(tabs) && Object.values(tabs).some(tab => !tab.hidden);
utils.toggleHidden(this.elements.settings.menu, speedHidden && languageHidden); utils.toggleHidden(this.elements.settings.menu, !visible);
}, },
// Show/hide menu // Show/hide menu
@ -1179,6 +1169,10 @@ const controls = {
controls.setSpeedMenu.call(this); controls.setSpeedMenu.call(this);
if (this.isHTML5) {
controls.setQualityMenu.call(this, html5.getQualityOptions.call(this));
}
return container; return container;
}, },

View File

@ -63,17 +63,19 @@ const defaults = {
// Quality default // Quality default
quality: { quality: {
default: 'default', default: 720,
options: [ options: [
'hd2160', 4320,
'hd1440', 2880,
'hd1080', 2160,
'hd720', 1440,
'large', 1080,
'medium', 720,
'small', 576,
'tiny', 480,
'default', 360,
240,
'default', // YouTube's "auto"
], ],
}, },

146
src/js/html5.js Normal file
View File

@ -0,0 +1,146 @@
// ==========================================================================
// Plyr HTML5 helpers
// ==========================================================================
import support from './support';
import utils from './utils';
const html5 = {
getSources() {
if (!this.isHTML5) {
return null;
}
return this.media.querySelectorAll('source');
},
// Get quality levels
getQualityOptions() {
if (!this.isHTML5) {
return null;
}
// Get sources
const sources = html5.getSources.call(this);
if (utils.is.empty(sources)) {
return null;
}
// Get <source> with size attribute
const sizes = Array.from(sources).filter(source => !utils.is.empty(source.getAttribute('size')));
// If none, bail
if (utils.is.empty(sizes)) {
return null;
}
// Reduce to unique list
return utils.dedupe(sizes.map(source => Number(source.getAttribute('size'))));
},
extend() {
if (!this.isHTML5) {
return;
}
const player = this;
// Quality
Object.defineProperty(player.media, 'quality', {
get() {
// Get sources
const sources = html5.getSources.call(player);
if (utils.is.empty(sources)) {
return null;
}
const matches = Array.from(sources).filter(source => source.getAttribute('src') === player.source);
if (utils.is.empty(matches)) {
return null;
}
return Number(matches[0].getAttribute('size'));
},
set(input) {
// Get sources
const sources = html5.getSources.call(player);
if (utils.is.empty(sources)) {
return;
}
// Get matches for requested size
const matches = Array.from(sources).filter(source => Number(source.getAttribute('size')) === input);
// No matches for requested size
if (utils.is.empty(matches)) {
return;
}
// Get supported sources
const supported = matches.filter(source => support.mime.call(player, source.getAttribute('type')));
// No supported sources
if (utils.is.empty(supported)) {
return;
}
// Trigger change event
utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
quality: input,
});
// Get current state
const { currentTime, playing } = player;
// Set new source
player.media.src = supported[0].getAttribute('src');
// Load new source
player.media.load();
// Resume playing
if (playing) {
player.play();
}
// Restore time
player.currentTime = currentTime;
// Trigger change event
utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
quality: input,
});
},
});
},
// Cancel current network requests
// See https://github.com/sampotts/plyr/issues/174
cancelRequests() {
if (!this.isHTML5) {
return;
}
// Remove child sources
utils.removeElement(html5.getSources());
// Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
this.media.setAttribute('src', this.config.blankVideo);
// Load the new empty source
// This will cancel existing requests
// See https://github.com/sampotts/plyr/issues/174
this.media.load();
// Debugging
this.debug.log('Cancelled network requests');
},
};
export default html5;

View File

@ -355,13 +355,16 @@ class Listeners {
this.player.storage.set({ speed: this.player.speed }); this.player.storage.set({ speed: this.player.speed });
}); });
// Quality change // Quality request
utils.on(this.player.media, 'qualitychange', () => { utils.on(this.player.media, 'qualityrequested', event => {
// Update UI
controls.updateSetting.call(this.player, 'quality');
// Save to storage // Save to storage
this.player.storage.set({ quality: this.player.quality }); this.player.storage.set({ quality: event.detail.quality });
});
// Quality change
utils.on(this.player.media, 'qualitychange', event => {
// Update UI
controls.updateSetting.call(this.player, 'quality', null, event.detail.quality);
}); });
// Caption language change // Caption language change

View File

@ -6,6 +6,7 @@ import support from './support';
import utils from './utils'; import utils from './utils';
import youtube from './plugins/youtube'; import youtube from './plugins/youtube';
import vimeo from './plugins/vimeo'; import vimeo from './plugins/vimeo';
import html5 from './html5';
import ui from './ui'; import ui from './ui';
// Sniff out the browser // Sniff out the browser
@ -75,32 +76,10 @@ const media = {
} }
} else if (this.isHTML5) { } else if (this.isHTML5) {
ui.setTitle.call(this); ui.setTitle.call(this);
html5.extend.call(this);
} }
}, },
// Cancel current network requests
// See https://github.com/sampotts/plyr/issues/174
cancelRequests() {
if (!this.isHTML5) {
return;
}
// Remove child sources
utils.removeElement(this.media.querySelectorAll('source'));
// Set blank video src attribute
// This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error
// Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection
this.media.setAttribute('src', this.config.blankVideo);
// Load the new empty source
// This will cancel existing requests
// See https://github.com/sampotts/plyr/issues/174
this.media.load();
// Debugging
this.debug.log('Cancelled network requests');
},
}; };
export default media; export default media;

View File

@ -6,6 +6,64 @@ import utils from './../utils';
import controls from './../controls'; import controls from './../controls';
import ui from './../ui'; import ui from './../ui';
// Standardise YouTube quality unit
function mapQualityUnit(input) {
switch (input) {
case 'hd2160':
return 2160;
case 2160:
return 'hd2160';
case 'hd1440':
return 1440;
case 1440:
return 'hd1440';
case 'hd1080':
return 1080;
case 1080:
return 'hd1080';
case 'hd720':
return 720;
case 720:
return 'hd720';
case 'large':
return 480;
case 480:
return 'large';
case 'medium':
return 360;
case 360:
return 'medium';
case 'small':
return 240;
case 240:
return 'small';
default:
return 'default';
}
}
function mapQualityUnits(levels) {
if (utils.is.empty(levels)) {
return levels;
}
return utils.dedupe(levels.map(level => mapQualityUnit(level)));
}
const youtube = { const youtube = {
setup() { setup() {
// Add embed class for responsive // Add embed class for responsive
@ -168,14 +226,10 @@ const youtube = {
utils.dispatchEvent.call(player, player.media, 'error'); utils.dispatchEvent.call(player, player.media, 'error');
}, },
onPlaybackQualityChange(event) { onPlaybackQualityChange() {
// Get the instance utils.dispatchEvent.call(player, player.media, 'qualitychange', false, {
const instance = event.target; quality: player.media.quality,
});
// Get current quality
player.media.quality = instance.getPlaybackQuality();
utils.dispatchEvent.call(player, player.media, 'qualitychange');
}, },
onPlaybackRateChange(event) { onPlaybackRateChange(event) {
// Get the instance // Get the instance
@ -240,15 +294,18 @@ const youtube = {
// Quality // Quality
Object.defineProperty(player.media, 'quality', { Object.defineProperty(player.media, 'quality', {
get() { get() {
return instance.getPlaybackQuality(); return mapQualityUnit(instance.getPlaybackQuality());
}, },
set(input) { set(input) {
const quality = input;
// Set via API
instance.setPlaybackQuality(mapQualityUnit(quality));
// Trigger request event // Trigger request event
utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, { utils.dispatchEvent.call(player, player.media, 'qualityrequested', false, {
quality: input, quality,
}); });
instance.setPlaybackQuality(input);
}, },
}); });
@ -401,7 +458,7 @@ const youtube = {
} }
// Get quality // Get quality
controls.setQualityMenu.call(player, instance.getAvailableQualityLevels()); controls.setQualityMenu.call(player, mapQualityUnits(instance.getAvailableQualityLevels()));
break; break;

View File

@ -670,24 +670,28 @@ class Plyr {
/** /**
* Set playback quality * Set playback quality
* Currently YouTube only * Currently HTML5 & YouTube only
* @param {string} input - Quality level * @param {number} input - Quality level
*/ */
set quality(input) { set quality(input) {
let quality = null; let quality = null;
if (utils.is.string(input)) { if (!utils.is.empty(input)) {
quality = input; quality = Number(input);
} }
if (!utils.is.string(quality)) { if (!utils.is.number(quality) || quality === 0) {
quality = this.storage.get('quality'); quality = this.storage.get('quality');
} }
if (!utils.is.string(quality)) { if (!utils.is.number(quality)) {
quality = this.config.quality.selected; quality = this.config.quality.selected;
} }
if (!utils.is.number(quality)) {
quality = this.config.quality.default;
}
if (!this.options.quality.includes(quality)) { if (!this.options.quality.includes(quality)) {
this.debug.warn(`Unsupported quality option (${quality})`); this.debug.warn(`Unsupported quality option (${quality})`);
return; return;

View File

@ -4,6 +4,7 @@
import { providers } from './types'; import { providers } from './types';
import utils from './utils'; import utils from './utils';
import html5 from './html5';
import media from './media'; import media from './media';
import ui from './ui'; import ui from './ui';
import support from './support'; import support from './support';
@ -31,13 +32,14 @@ const source = {
} }
// Cancel current network requests // Cancel current network requests
media.cancelRequests.call(this); html5.cancelRequests.call(this);
// Destroy instance and re-setup // Destroy instance and re-setup
this.destroy.call( this.destroy.call(
this, this,
() => { () => {
// TODO: Reset menus here // Reset quality options
this.options.quality = [];
// Remove elements // Remove elements
utils.removeElement(this.media); utils.removeElement(this.media);

View File

@ -71,8 +71,8 @@ const ui = {
// Reset loop state // Reset loop state
this.loop = null; this.loop = null;
// Reset quality options // Reset quality setting
this.options.quality = []; this.quality = null;
// Reset volume display // Reset volume display
ui.updateVolume.call(this); ui.updateVolume.call(this);

View File

@ -586,15 +586,15 @@ const utils = {
}, },
// Trigger event // Trigger event
dispatchEvent(element, type, bubbles, detail) { dispatchEvent(element, type = '', bubbles = false, detail = {}) {
// Bail if no element // Bail if no element
if (!utils.is.element(element) || !utils.is.string(type)) { if (!utils.is.element(element) || utils.is.empty(type)) {
return; return;
} }
// Create and dispatch the event // Create and dispatch the event
const event = new CustomEvent(type, { const event = new CustomEvent(type, {
bubbles: utils.is.boolean(bubbles) ? bubbles : false, bubbles,
detail: Object.assign({}, detail, { detail: Object.assign({}, detail, {
plyr: utils.is.plyr(this) ? this : null, plyr: utils.is.plyr(this) ? this : null,
}), }),
@ -737,6 +737,15 @@ const utils = {
return utils.extend(target, ...sources); return utils.extend(target, ...sources);
}, },
// Remove duplicates in an array
dedupe(array) {
if (!utils.is.array(array)) {
return array;
}
return array.filter((item, index) => array.indexOf(item) === index);
},
// Get the provider for a given URL // Get the provider for a given URL
getProviderByUrl(url) { getProviderByUrl(url) {
// YouTube // YouTube

223
yarn.lock
View File

@ -8,6 +8,26 @@
dependencies: dependencies:
"@babel/highlight" "7.0.0-beta.42" "@babel/highlight" "7.0.0-beta.42"
"@babel/core@^7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.42.tgz#b3a838fddbd19663369a0b4892189fd8d3f82001"
dependencies:
"@babel/code-frame" "7.0.0-beta.42"
"@babel/generator" "7.0.0-beta.42"
"@babel/helpers" "7.0.0-beta.42"
"@babel/template" "7.0.0-beta.42"
"@babel/traverse" "7.0.0-beta.42"
"@babel/types" "7.0.0-beta.42"
babylon "7.0.0-beta.42"
convert-source-map "^1.1.0"
debug "^3.1.0"
json5 "^0.5.0"
lodash "^4.2.0"
micromatch "^2.3.11"
resolve "^1.3.2"
semver "^5.4.1"
source-map "^0.5.0"
"@babel/generator@7.0.0-beta.42": "@babel/generator@7.0.0-beta.42":
version "7.0.0-beta.42" version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.42.tgz#777bb50f39c94a7e57f73202d833141f8159af33" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.42.tgz#777bb50f39c94a7e57f73202d833141f8159af33"
@ -38,6 +58,14 @@
dependencies: dependencies:
"@babel/types" "7.0.0-beta.42" "@babel/types" "7.0.0-beta.42"
"@babel/helpers@7.0.0-beta.42":
version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.42.tgz#151c1c4e9da1b6ce83d54c1be5fb8c9c57aa5044"
dependencies:
"@babel/template" "7.0.0-beta.42"
"@babel/traverse" "7.0.0-beta.42"
"@babel/types" "7.0.0-beta.42"
"@babel/highlight@7.0.0-beta.42": "@babel/highlight@7.0.0-beta.42":
version "7.0.0-beta.42" version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.42.tgz#a502a1c0d6f99b2b0e81d468a1b0c0e81e3f3623" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.42.tgz#a502a1c0d6f99b2b0e81d468a1b0c0e81e3f3623"
@ -55,7 +83,7 @@
babylon "7.0.0-beta.42" babylon "7.0.0-beta.42"
lodash "^4.2.0" lodash "^4.2.0"
"@babel/traverse@^7.0.0-beta.40": "@babel/traverse@7.0.0-beta.42", "@babel/traverse@^7.0.0-beta.40", "@babel/traverse@^7.0.0-beta.42":
version "7.0.0-beta.42" version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.42.tgz#f4bf4d1e33d41baf45205e2d0463591d57326285" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.42.tgz#f4bf4d1e33d41baf45205e2d0463591d57326285"
dependencies: dependencies:
@ -95,6 +123,13 @@
normalize-path "^2.0.1" normalize-path "^2.0.1"
through2 "^2.0.3" through2 "^2.0.3"
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
dependencies:
call-me-maybe "^1.0.1"
glob-to-regexp "^0.3.0"
abbrev@1: abbrev@1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@ -853,7 +888,7 @@ babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0:
lodash "^4.17.4" lodash "^4.17.4"
to-fast-properties "^1.0.3" to-fast-properties "^1.0.3"
babylon@7.0.0-beta.42, babylon@^7.0.0-beta.40: babylon@7.0.0-beta.42, babylon@^7.0.0-beta.40, babylon@^7.0.0-beta.42:
version "7.0.0-beta.42" version "7.0.0-beta.42"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.42.tgz#67cfabcd4f3ec82999d29031ccdea89d0ba99657" resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.42.tgz#67cfabcd4f3ec82999d29031ccdea89d0ba99657"
@ -1003,6 +1038,10 @@ cache-base@^1.0.1:
union-value "^1.0.0" union-value "^1.0.0"
unset-value "^1.0.0" unset-value "^1.0.0"
call-me-maybe@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
caller-path@^0.1.0: caller-path@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
@ -1323,7 +1362,7 @@ contains-path@^0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a"
convert-source-map@1.X, convert-source-map@^1.5.0: convert-source-map@1.X, convert-source-map@^1.1.0, convert-source-map@^1.5.0:
version "1.5.1" version "1.5.1"
resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.1.tgz#b8278097b9bc229365de5c62cf5fcaed8b5599e5"
@ -1738,23 +1777,23 @@ eslint-import-resolver-node@^0.3.1:
debug "^2.6.9" debug "^2.6.9"
resolve "^1.5.0" resolve "^1.5.0"
eslint-module-utils@^2.1.1: eslint-module-utils@^2.2.0:
version "2.1.1" version "2.2.0"
resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz#b270362cd88b1a48ad308976ce7fa54e98411746"
dependencies: dependencies:
debug "^2.6.8" debug "^2.6.8"
pkg-dir "^1.0.0" pkg-dir "^1.0.0"
eslint-plugin-import@^2.9.0: eslint-plugin-import@^2.10.0:
version "2.9.0" version "2.10.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.10.0.tgz#fa09083d5a75288df9c6c7d09fe12255985655e7"
dependencies: dependencies:
builtin-modules "^1.1.1" builtin-modules "^1.1.1"
contains-path "^0.1.0" contains-path "^0.1.0"
debug "^2.6.8" debug "^2.6.8"
doctrine "1.5.0" doctrine "1.5.0"
eslint-import-resolver-node "^0.3.1" eslint-import-resolver-node "^0.3.1"
eslint-module-utils "^2.1.1" eslint-module-utils "^2.2.0"
has "^1.0.1" has "^1.0.1"
lodash "^4.17.4" lodash "^4.17.4"
minimatch "^3.0.3" minimatch "^3.0.3"
@ -2045,6 +2084,16 @@ fast-deep-equal@^1.0.0:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
fast-glob@^2.0.2:
version "2.2.0"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.0.tgz#e9d032a69b86bef46fc03d935408f02fb211d9fc"
dependencies:
"@mrmlnc/readdir-enhanced" "^2.2.1"
glob-parent "^3.1.0"
is-glob "^4.0.0"
merge2 "^1.2.1"
micromatch "^3.1.8"
fast-json-stable-stringify@^2.0.0: fast-json-stable-stringify@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
@ -2256,6 +2305,10 @@ get-stdin@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
get-stdin@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
get-stream@^3.0.0: get-stream@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@ -2289,6 +2342,13 @@ glob-parent@^2.0.0:
dependencies: dependencies:
is-glob "^2.0.0" is-glob "^2.0.0"
glob-parent@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
dependencies:
is-glob "^3.1.0"
path-dirname "^1.0.0"
glob-stream@^3.1.5: glob-stream@^3.1.5:
version "3.1.18" version "3.1.18"
resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b" resolved "https://registry.yarnpkg.com/glob-stream/-/glob-stream-3.1.18.tgz#9170a5f12b790306fdfe598f313f8f7954fd143b"
@ -2300,6 +2360,10 @@ glob-stream@^3.1.5:
through2 "^0.6.1" through2 "^0.6.1"
unique-stream "^1.0.0" unique-stream "^1.0.0"
glob-to-regexp@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
glob-watcher@^0.0.6: glob-watcher@^0.0.6:
version "0.0.6" version "0.0.6"
resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b" resolved "https://registry.yarnpkg.com/glob-watcher/-/glob-watcher-0.0.6.tgz#b95b4a8df74b39c83298b0c05c978b4d9a3b710b"
@ -2414,6 +2478,18 @@ globby@^7.0.0:
pify "^3.0.0" pify "^3.0.0"
slash "^1.0.0" slash "^1.0.0"
globby@^8.0.0:
version "8.0.1"
resolved "https://registry.yarnpkg.com/globby/-/globby-8.0.1.tgz#b5ad48b8aa80b35b814fc1281ecc851f1d2b5b50"
dependencies:
array-union "^1.0.1"
dir-glob "^2.0.0"
fast-glob "^2.0.2"
glob "^7.1.2"
ignore "^3.3.5"
pify "^3.0.0"
slash "^1.0.0"
globjoin@^0.1.4: globjoin@^0.1.4:
version "0.1.4" version "0.1.4"
resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
@ -2853,6 +2929,10 @@ import-lazy@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
import-lazy@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc"
import-local@^0.1.1: import-local@^0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/import-local/-/import-local-0.1.1.tgz#b1179572aacdc11c6a91009fb430dbcab5f668a8" resolved "https://registry.yarnpkg.com/import-local/-/import-local-0.1.1.tgz#b1179572aacdc11c6a91009fb430dbcab5f668a8"
@ -3042,7 +3122,7 @@ is-extglob@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0"
is-extglob@^2.1.0: is-extglob@^2.1.0, is-extglob@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
@ -3074,6 +3154,12 @@ is-glob@^3.1.0:
dependencies: dependencies:
is-extglob "^2.1.0" is-extglob "^2.1.0"
is-glob@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.0.tgz#9521c76845cc2610a85203ddf080a958c2ffabc0"
dependencies:
is-extglob "^2.1.1"
is-hexadecimal@^1.0.0: is-hexadecimal@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69" resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.1.tgz#6e084bbc92061fbb0971ec58b6ce6d404e24da69"
@ -3326,7 +3412,7 @@ json-stringify-safe@~5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb"
json5@^0.5.1: json5@^0.5.0, json5@^0.5.1:
version "0.5.1" version "0.5.1"
resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
@ -3864,6 +3950,10 @@ meow@^4.0.0:
redent "^2.0.0" redent "^2.0.0"
trim-newlines "^2.0.0" trim-newlines "^2.0.0"
merge2@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.1.tgz#271d2516ff52d4af7f7b710b8bf3e16e183fef66"
micromatch@^2.3.11: micromatch@^2.3.11:
version "2.3.11" version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
@ -3900,6 +3990,24 @@ micromatch@^3.0.4:
snapdragon "^0.8.1" snapdragon "^0.8.1"
to-regex "^3.0.1" to-regex "^3.0.1"
micromatch@^3.1.8:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
dependencies:
arr-diff "^4.0.0"
array-unique "^0.3.2"
braces "^2.3.1"
define-property "^2.0.2"
extend-shallow "^3.0.2"
extglob "^2.0.4"
fragment-cache "^0.2.1"
kind-of "^6.0.2"
nanomatch "^1.2.9"
object.pick "^1.3.0"
regex-not "^1.0.0"
snapdragon "^0.8.1"
to-regex "^3.0.2"
mime-db@~1.33.0: mime-db@~1.33.0:
version "1.33.0" version "1.33.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
@ -4348,6 +4456,10 @@ pascalcase@^0.1.1:
version "0.1.1" version "0.1.1"
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
path-dirname@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
path-exists@^2.0.0: path-exists@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
@ -4502,12 +4614,29 @@ postcss-html@^0.15.0:
remark "^9.0.0" remark "^9.0.0"
unist-util-find-all-after "^1.0.1" unist-util-find-all-after "^1.0.1"
postcss-html@^0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/postcss-html/-/postcss-html-0.18.0.tgz#992a84117cc56f9f28915fbadba576489641e652"
dependencies:
"@babel/core" "^7.0.0-beta.42"
"@babel/traverse" "^7.0.0-beta.42"
babylon "^7.0.0-beta.42"
htmlparser2 "^3.9.2"
remark "^9.0.0"
unist-util-find-all-after "^1.0.1"
postcss-less@^1.1.0: postcss-less@^1.1.0:
version "1.1.3" version "1.1.3"
resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.3.tgz#6930525271bfe38d5793d33ac09c1a546b87bb51" resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.3.tgz#6930525271bfe38d5793d33ac09c1a546b87bb51"
dependencies: dependencies:
postcss "^5.2.16" postcss "^5.2.16"
postcss-less@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-1.1.5.tgz#a6f0ce180cf3797eeee1d4adc0e9e6d6db665609"
dependencies:
postcss "^5.2.16"
postcss-media-query-parser@^0.2.3: postcss-media-query-parser@^0.2.3:
version "0.2.3" version "0.2.3"
resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244"
@ -5119,6 +5248,12 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.5.0:
dependencies: dependencies:
path-parse "^1.0.5" path-parse "^1.0.5"
resolve@^1.3.2:
version "1.6.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.6.0.tgz#0fbd21278b27b4004481c395349e7aba60a9ff5c"
dependencies:
path-parse "^1.0.5"
restore-cursor@^2.0.0: restore-cursor@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
@ -5237,7 +5372,7 @@ semver-diff@^2.0.0:
dependencies: dependencies:
semver "^5.0.3" semver "^5.0.3"
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0: "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1:
version "5.5.0" version "5.5.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab" resolved "https://registry.yarnpkg.com/semver/-/semver-5.5.0.tgz#dc4bbc7a6ca9d916dee5d43516f0092b58f7b8ab"
@ -5620,7 +5755,7 @@ stylelint-order@^0.8.0, stylelint-order@^0.8.1:
postcss "^6.0.14" postcss "^6.0.14"
postcss-sorting "^3.1.0" postcss-sorting "^3.1.0"
stylelint-scss@^2.0.0, stylelint-scss@^2.5.0: stylelint-scss@^2.0.0:
version "2.5.0" version "2.5.0"
resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-2.5.0.tgz#ac4c83474c53b19cc1f9e93d332786cf89c8d217" resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-2.5.0.tgz#ac4c83474c53b19cc1f9e93d332786cf89c8d217"
dependencies: dependencies:
@ -5630,6 +5765,16 @@ stylelint-scss@^2.0.0, stylelint-scss@^2.5.0:
postcss-selector-parser "^3.1.1" postcss-selector-parser "^3.1.1"
postcss-value-parser "^3.3.0" postcss-value-parser "^3.3.0"
stylelint-scss@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/stylelint-scss/-/stylelint-scss-3.0.0.tgz#15beb887117ccef20668a3f4728eb5be5fbda045"
dependencies:
lodash "^4.17.4"
postcss-media-query-parser "^0.2.3"
postcss-resolve-nested-selector "^0.1.1"
postcss-selector-parser "^3.1.1"
postcss-value-parser "^3.3.0"
stylelint-selector-bem-pattern@^2.0.0: stylelint-selector-bem-pattern@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/stylelint-selector-bem-pattern/-/stylelint-selector-bem-pattern-2.0.0.tgz#9a6130c9c90963b30e925c917079d6c8fed73f45" resolved "https://registry.yarnpkg.com/stylelint-selector-bem-pattern/-/stylelint-selector-bem-pattern-2.0.0.tgz#9a6130c9c90963b30e925c917079d6c8fed73f45"
@ -5639,7 +5784,7 @@ stylelint-selector-bem-pattern@^2.0.0:
postcss-bem-linter "^3.0.0" postcss-bem-linter "^3.0.0"
stylelint ">=3.0.2" stylelint ">=3.0.2"
stylelint@>=3.0.2, stylelint@^9.1.1, stylelint@^9.1.3: stylelint@>=3.0.2, stylelint@^9.1.1:
version "9.1.3" version "9.1.3"
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.1.3.tgz#8260f2a221b98e4afafd9b2b8a785d2e38cbb8a4" resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.1.3.tgz#8260f2a221b98e4afafd9b2b8a785d2e38cbb8a4"
dependencies: dependencies:
@ -5728,6 +5873,52 @@ stylelint@^8.1.1:
svg-tags "^1.0.0" svg-tags "^1.0.0"
table "^4.0.1" table "^4.0.1"
stylelint@^9.2.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-9.2.0.tgz#f77a82518106074c1a795e962fd780da2c8af43b"
dependencies:
autoprefixer "^8.0.0"
balanced-match "^1.0.0"
chalk "^2.0.1"
cosmiconfig "^4.0.0"
debug "^3.0.0"
execall "^1.0.0"
file-entry-cache "^2.0.0"
get-stdin "^6.0.0"
globby "^8.0.0"
globjoin "^0.1.4"
html-tags "^2.0.0"
ignore "^3.3.3"
import-lazy "^3.1.0"
imurmurhash "^0.1.4"
known-css-properties "^0.6.0"
lodash "^4.17.4"
log-symbols "^2.0.0"
mathml-tag-names "^2.0.1"
meow "^4.0.0"
micromatch "^2.3.11"
normalize-selector "^0.2.0"
pify "^3.0.0"
postcss "^6.0.16"
postcss-html "^0.18.0"
postcss-less "^1.1.5"
postcss-media-query-parser "^0.2.3"
postcss-reporter "^5.0.0"
postcss-resolve-nested-selector "^0.1.1"
postcss-safe-parser "^3.0.1"
postcss-sass "^0.3.0"
postcss-scss "^1.0.2"
postcss-selector-parser "^3.1.0"
postcss-value-parser "^3.3.0"
resolve-from "^4.0.0"
signal-exit "^3.0.2"
specificity "^0.3.1"
string-width "^2.1.0"
style-search "^0.1.0"
sugarss "^1.0.0"
svg-tags "^1.0.0"
table "^4.0.1"
sugarss@^1.0.0: sugarss@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.1.tgz#be826d9003e0f247735f92365dc3fd7f1bae9e44" resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-1.0.1.tgz#be826d9003e0f247735f92365dc3fd7f1bae9e44"
@ -5909,7 +6100,7 @@ to-regex-range@^2.1.0:
is-number "^3.0.0" is-number "^3.0.0"
repeat-string "^1.6.1" repeat-string "^1.6.1"
to-regex@^3.0.1: to-regex@^3.0.1, to-regex@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
dependencies: dependencies: