From dfc6b0e389fe624d300ca1aa1078cf468e9b22bb Mon Sep 17 00:00:00 2001 From: 7Ds7 <7Ds7@users.noreply.github.com> Date: Wed, 15 Jan 2020 19:50:47 +0100 Subject: [PATCH 1/7] VideoJs warnings - plugin is now registerPlugin - videojs.addClass is now videojs.dom.addClass --- lib/videojs-resolution-switcher.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/videojs-resolution-switcher.js b/lib/videojs-resolution-switcher.js index eae1c38..f2a926d 100644 --- a/lib/videojs-resolution-switcher.js +++ b/lib/videojs-resolution-switcher.js @@ -58,11 +58,11 @@ this.controlText('Quality'); if(options.dynamicLabel){ - videojs.addClass(this.label, 'vjs-resolution-button-label'); + videojs.dom.addClass(this.label, 'vjs-resolution-button-label'); this.el().appendChild(this.label); }else{ var staticLabel = document.createElement('span'); - videojs.addClass(staticLabel, 'vjs-menu-icon'); + videojs.dom.addClass(staticLabel, 'vjs-menu-icon'); this.el().appendChild(staticLabel); } player.on('updateSources', videojs.bind( this, this.update ) ); @@ -362,6 +362,6 @@ }; // register the plugin - videojs.plugin('videoJsResolutionSwitcher', videoJsResolutionSwitcher); + videojs.registerPlugin('videoJsResolutionSwitcher', videoJsResolutionSwitcher); })(window, videojs); })(); From 9c23135d3b08075ea20840bd421432b251e8f80c Mon Sep 17 00:00:00 2001 From: 7Ds7 <7Ds7@users.noreply.github.com> Date: Tue, 18 Feb 2020 19:00:13 +0100 Subject: [PATCH 2/7] More changes to videojs 7 - Make resolution hover - changed to handleTechSeeked_ - force resolution switch to change label --- lib/videojs-resolution-switcher.js | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/lib/videojs-resolution-switcher.js b/lib/videojs-resolution-switcher.js index f2a926d..0f281e3 100644 --- a/lib/videojs-resolution-switcher.js +++ b/lib/videojs-resolution-switcher.js @@ -31,16 +31,20 @@ MenuItem.call(this, player, options); this.src = options.src; - player.on('resolutionchange', videojs.bind(this, this.update)); + player.on('resolutionchange', videojs.bind(this, this.update)) } } ); ResolutionMenuItem.prototype.handleClick = function(event){ - MenuItem.prototype.handleClick.call(this,event); + MenuItem.prototype.handleClick.call(this, event); this.player_.currentResolution(this.options_.label); + // this.player_.updateSrc(this.player_.options_.sources) + // MenuButton.prototype.update.call(this); }; ResolutionMenuItem.prototype.update = function(){ - var selection = this.player_.currentResolution(); - this.selected(this.options_.label === selection.label); + var selection = (this.player_ && this.player_.currentResolution() ) ? this.player_.currentResolution() : null ; + if ( selection ) { + this.selected(this.options_.label === selection.label); + } }; MenuItem.registerComponent('ResolutionMenuItem', ResolutionMenuItem); @@ -56,7 +60,6 @@ MenuButton.call(this, player, options); this.el().setAttribute('aria-label','Quality'); this.controlText('Quality'); - if(options.dynamicLabel){ videojs.dom.addClass(this.label, 'vjs-resolution-button-label'); this.el().appendChild(this.label); @@ -65,6 +68,14 @@ videojs.dom.addClass(staticLabel, 'vjs-menu-icon'); this.el().appendChild(staticLabel); } + + // Make hover on resolution button + this.el().addEventListener('mouseover', function(e) { + videojs.dom.addClass(this, 'vjs-hover'); + }); + + // force update of resolution to change label + player.on('resolutionchange', videojs.bind(this, this.update)) player.on('updateSources', videojs.bind( this, this.update ) ); } } ); @@ -94,6 +105,7 @@ return MenuButton.prototype.update.call(this); }; ResolutionMenuButton.prototype.buildCSSClass = function(){ + videojs.dom.addClass(this.el(), 'vjs-resolution-button') return MenuButton.prototype.buildCSSClass.call( this ) + ' vjs-resolution-button'; }; MenuButton.registerComponent('ResolutionMenuButton', ResolutionMenuButton); @@ -151,7 +163,6 @@ */ player.currentResolution = function(label, customSourcePicker){ if(label == null) { return this.currentResolutionState; } - // Lookup sources for label if(!this.groupedSrc || !this.groupedSrc.label || !this.groupedSrc.label[label]){ return; @@ -181,7 +192,8 @@ player.handleTechSeeked_(); if(!isPaused){ // Start playing and hide loadingSpinner (flash issue ?) - player.play().handleTechSeeked_(); + player.play(); + player.handleTechSeeked_(); } player.trigger('resolutionchange'); }); From c1105b5f6c123807665f2dc342b981a6de145158 Mon Sep 17 00:00:00 2001 From: 7Ds7 <7Ds7@users.noreply.github.com> Date: Tue, 18 Feb 2020 19:02:02 +0100 Subject: [PATCH 3/7] Removed commented lines --- lib/videojs-resolution-switcher.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/videojs-resolution-switcher.js b/lib/videojs-resolution-switcher.js index 0f281e3..f9ed46a 100644 --- a/lib/videojs-resolution-switcher.js +++ b/lib/videojs-resolution-switcher.js @@ -37,8 +37,6 @@ ResolutionMenuItem.prototype.handleClick = function(event){ MenuItem.prototype.handleClick.call(this, event); this.player_.currentResolution(this.options_.label); - // this.player_.updateSrc(this.player_.options_.sources) - // MenuButton.prototype.update.call(this); }; ResolutionMenuItem.prototype.update = function(){ var selection = (this.player_ && this.player_.currentResolution() ) ? this.player_.currentResolution() : null ; From 5d904fb1e01f29c1223728abe63168ee97573eb8 Mon Sep 17 00:00:00 2001 From: 7Ds7 <7Ds7@users.noreply.github.com> Date: Tue, 18 Feb 2020 19:03:47 +0100 Subject: [PATCH 4/7] bump videojs version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index aa8ab26..eace52f 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,6 @@ "videojs-youtube": "^2.0.8" }, "peerDependencies": { - "video.js": "^5.8" + "video.js": "^7.4.1" } } From 8e1345f95e7d2553184d60a44924946490a95df6 Mon Sep 17 00:00:00 2001 From: 7Ds7 <7Ds7@users.noreply.github.com> Date: Tue, 25 Feb 2020 03:38:28 +0100 Subject: [PATCH 5/7] bumped videojs devDependency --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index eace52f..bb254d8 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "grunt-contrib-qunit": "^1.1", "grunt-contrib-uglify": "^1.0", "grunt-contrib-watch": "^1.0", - "video.js": "^5.8", + "video.js": "^7.4.1", "qunitjs": "^1.22", "videojs-youtube": "^2.0.8" }, From 2e2942abffd018e9f0c4f82b5d6d8b2b7f86c827 Mon Sep 17 00:00:00 2001 From: 7Ds7 <7Ds7@users.noreply.github.com> Date: Tue, 25 Feb 2020 03:42:55 +0100 Subject: [PATCH 6/7] Fixing lint errors --- lib/videojs-resolution-switcher.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/videojs-resolution-switcher.js b/lib/videojs-resolution-switcher.js index f9ed46a..de87221 100644 --- a/lib/videojs-resolution-switcher.js +++ b/lib/videojs-resolution-switcher.js @@ -31,7 +31,7 @@ MenuItem.call(this, player, options); this.src = options.src; - player.on('resolutionchange', videojs.bind(this, this.update)) + player.on('resolutionchange', videojs.bind(this, this.update)); } } ); ResolutionMenuItem.prototype.handleClick = function(event){ @@ -73,7 +73,7 @@ }); // force update of resolution to change label - player.on('resolutionchange', videojs.bind(this, this.update)) + player.on('resolutionchange', videojs.bind(this, this.update)); player.on('updateSources', videojs.bind( this, this.update ) ); } } ); @@ -103,7 +103,7 @@ return MenuButton.prototype.update.call(this); }; ResolutionMenuButton.prototype.buildCSSClass = function(){ - videojs.dom.addClass(this.el(), 'vjs-resolution-button') + videojs.dom.addClass(this.el(), 'vjs-resolution-button'); return MenuButton.prototype.buildCSSClass.call( this ) + ' vjs-resolution-button'; }; MenuButton.registerComponent('ResolutionMenuButton', ResolutionMenuButton); From 976d4e1335323b8af8e915959d0a556c7e21c67e Mon Sep 17 00:00:00 2001 From: BinaryUnit Date: Tue, 5 Sep 2023 05:15:40 +0100 Subject: [PATCH 7/7] Changes for videojs 8 --- lib/videojs-resolution-switcher.css | 25 +- lib/videojs-resolution-switcher.js | 682 ++++++++++++++-------------- package.json | 4 +- 3 files changed, 338 insertions(+), 373 deletions(-) diff --git a/lib/videojs-resolution-switcher.css b/lib/videojs-resolution-switcher.css index 3c7ef67..374cf64 100644 --- a/lib/videojs-resolution-switcher.css +++ b/lib/videojs-resolution-switcher.css @@ -5,27 +5,4 @@ font-style: normal; font-size: 1.8em; line-height: 1.67em; -} - -.vjs-resolution-button .vjs-resolution-button-label { - font-size: 1em; - line-height: 3em; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - text-align: center; - box-sizing: inherit; -} - -.vjs-resolution-button .vjs-menu .vjs-menu-content { - width: 4em; - left: 50%; /* Center the menu, in it's parent */ - margin-left: -2em; /* half of width, to center */ -} - -.vjs-resolution-button .vjs-menu li { - text-transform: none; - font-size: 1em; -} +} \ No newline at end of file diff --git a/lib/videojs-resolution-switcher.js b/lib/videojs-resolution-switcher.js index de87221..379e71f 100644 --- a/lib/videojs-resolution-switcher.js +++ b/lib/videojs-resolution-switcher.js @@ -3,375 +3,363 @@ * Modified by Pierre Kraft and Derk-Jan Hartman * Licensed under the Apache-2.0 license. */ -(function() { - /* jshint eqnull: true*/ - /* global require */ - 'use strict'; - var videojs = null; - if(typeof window.videojs === 'undefined' && typeof require === 'function') { - videojs = require('video.js'); - } else { - videojs = window.videojs; +class ResolutionMenuItem extends videojs.getComponent('MenuItem') { + constructor(player, options) { + options.selectable = true; + super(player, options); + this.src = options.src; + player.on('resolutionchange', () => this.update()); } - (function(window, videojs) { - var videoJsResolutionSwitcher, - defaults = { - ui: true - }; + handleClick(event) { + super.handleClick(event); + this.player_.currentResolution(this.options_.label); + } - /* - * Resolution menu item - */ - var MenuItem = videojs.getComponent('MenuItem'); - var ResolutionMenuItem = videojs.extend(MenuItem, { - constructor: function(player, options){ - options.selectable = true; - // Sets this.player_, this.options_ and initializes the component - MenuItem.call(this, player, options); - this.src = options.src; - - player.on('resolutionchange', videojs.bind(this, this.update)); + update() { + const selection = this.player_.currentResolution(); + this.selected(this.options_.label === selection.label); + } +} + +videojs.registerComponent('ResolutionMenuItem', ResolutionMenuItem); + +class ResolutionMenuButton extends videojs.getComponent('MenuButton') { + constructor(player, options) { + super(player, options); + options.label = 'Quality'; + this.el().setAttribute('aria-label', 'Quality'); + this.controlText('Quality'); + + if (options.dynamicLabel) { + const dynamicLabel = document.createElement('span'); + videojs.dom.addClass(dynamicLabel, 'vjs-resolution-button-label'); + //this.el().appendChild(dynamicLabel); + this.menuButton_.el().appendChild(dynamicLabel); + this.label = dynamicLabel; // Assign the dynamicLabel to this.label + } else { + debugger + const staticLabel = document.createElement('span'); + videojs.dom.addClass(staticLabel, 'vjs-menu-icon'); + // this.el().appendChild(staticLabel); + this.menuButton_.el().appendChild(staticLabel); + this.label = staticLabel; // Assign the staticLabel to this.label + } + + this.label = this.label || document.createElement('span'); // Add this line to initialize this.label + player.on('updateSources', () => this.update()); + // Just update the label + player.on('resolutionchange', () => { + if (this.label && this.options().dynamicLabel) { + this.label.innerHTML = this.player_.currentResolution() ? this.player_.currentResolution().label : ''; } - } ); - ResolutionMenuItem.prototype.handleClick = function(event){ - MenuItem.prototype.handleClick.call(this, event); - this.player_.currentResolution(this.options_.label); - }; - ResolutionMenuItem.prototype.update = function(){ - var selection = (this.player_ && this.player_.currentResolution() ) ? this.player_.currentResolution() : null ; - if ( selection ) { - this.selected(this.options_.label === selection.label); + }); + } + + createItems() { + const menuItems = []; + const labels = (this.sources && this.sources.label) || {}; + + for (const key in labels) { + if (labels.hasOwnProperty(key)) { + menuItems.push( + new ResolutionMenuItem(this.player_, { + label: key, + src: labels[key], + selected: key === (this.currentSelection ? this.currentSelection.label : false), + }), + ); } - }; - MenuItem.registerComponent('ResolutionMenuItem', ResolutionMenuItem); - - /* - * Resolution menu button - */ - var MenuButton = videojs.getComponent('MenuButton'); - var ResolutionMenuButton = videojs.extend(MenuButton, { - constructor: function(player, options){ - this.label = document.createElement('span'); - options.label = 'Quality'; - // Sets this.player_, this.options_ and initializes the component - MenuButton.call(this, player, options); - this.el().setAttribute('aria-label','Quality'); - this.controlText('Quality'); - if(options.dynamicLabel){ - videojs.dom.addClass(this.label, 'vjs-resolution-button-label'); - this.el().appendChild(this.label); - }else{ - var staticLabel = document.createElement('span'); - videojs.dom.addClass(staticLabel, 'vjs-menu-icon'); - this.el().appendChild(staticLabel); - } + } - // Make hover on resolution button - this.el().addEventListener('mouseover', function(e) { - videojs.dom.addClass(this, 'vjs-hover'); - }); + return menuItems; + } - // force update of resolution to change label - player.on('resolutionchange', videojs.bind(this, this.update)); - player.on('updateSources', videojs.bind( this, this.update ) ); - } - } ); - ResolutionMenuButton.prototype.createItems = function(){ - var menuItems = []; - var labels = (this.sources && this.sources.label) || {}; - - // FIXME order is not guaranteed here. - for (var key in labels) { - if (labels.hasOwnProperty(key)) { - menuItems.push(new ResolutionMenuItem( - this.player_, - { - label: key, - src: labels[key], - selected: key === (this.currentSelection ? this.currentSelection.label : false) - }) - ); - } - } - return menuItems; - }; - ResolutionMenuButton.prototype.update = function(){ - this.sources = this.player_.getGroupedSrc(); - this.currentSelection = this.player_.currentResolution(); + labelUpdate() { + this.sources = this.player_.getGroupedSrc(); + this.currentSelection = this.player_.currentResolution(); + if (this.label) { this.label.innerHTML = this.currentSelection ? this.currentSelection.label : ''; - return MenuButton.prototype.update.call(this); - }; - ResolutionMenuButton.prototype.buildCSSClass = function(){ - videojs.dom.addClass(this.el(), 'vjs-resolution-button'); - return MenuButton.prototype.buildCSSClass.call( this ) + ' vjs-resolution-button'; - }; - MenuButton.registerComponent('ResolutionMenuButton', ResolutionMenuButton); - - /** - * Initialize the plugin. - * @param {object} [options] configuration for the plugin - */ - videoJsResolutionSwitcher = function(options) { - var settings = videojs.mergeOptions(defaults, options), - player = this, - groupedSrc = {}, - currentSources = {}, - currentResolutionState = {}; - - /** - * Updates player sources or returns current source URL - * @param {Array} [src] array of sources [{src: '', type: '', label: '', res: ''}] - * @returns {Object|String|Array} videojs player object if used as setter or current source URL, object, or array of sources - */ - player.updateSrc = function(src){ - //Return current src if src is not given - if(!src){ return player.src(); } - - // Only add those sources which we can (maybe) play - src = src.filter( function(source) { - try { - return ( player.canPlayType( source.type ) !== '' ); - } catch (e) { - // If a Tech doesn't yet have canPlayType just add it - return true; - } - }); - //Sort sources - this.currentSources = src.sort(compareResolutions); - this.groupedSrc = bucketSources(this.currentSources); - // Pick one by default - var chosen = chooseSrc(this.groupedSrc, this.currentSources); - this.currentResolutionState = { - label: chosen.label, - sources: chosen.sources - }; - - player.trigger('updateSources'); - player.setSourcesSanitized(chosen.sources, chosen.label); - player.trigger('resolutionchange'); - return player; - }; + } + } - /** - * Returns current resolution or sets one when label is specified - * @param {String} [label] label name - * @param {Function} [customSourcePicker] custom function to choose source. Takes 2 arguments: sources, label. Must return player object. - * @returns {Object} current resolution object {label: '', sources: []} if used as getter or player object if used as setter - */ - player.currentResolution = function(label, customSourcePicker){ - if(label == null) { return this.currentResolutionState; } - // Lookup sources for label - if(!this.groupedSrc || !this.groupedSrc.label || !this.groupedSrc.label[label]){ - return; - } - var sources = this.groupedSrc.label[label]; - // Remember player state - var currentTime = player.currentTime(); - var isPaused = player.paused(); - - // Hide bigPlayButton - if(!isPaused && this.player_.options_.bigPlayButton){ - this.player_.bigPlayButton.hide(); - } + update() { + this.sources = this.player_.getGroupedSrc(); + this.currentSelection = this.player_.currentResolution(); + if (this.label) { + this.label.innerHTML = this.currentSelection ? this.currentSelection.label : ''; + } + return super.update(); + } + + buildCSSClass() { + return super.buildCSSClass() + ' vjs-resolution-button'; + } +} + +videojs.registerComponent('ResolutionMenuButton', ResolutionMenuButton); + +const videoJsResolutionSwitcher = function (options) { + var defaults = { + // Default options for the plugin + ui: true, + default: 'low', // Default resolution [{Number}, 'low', 'high'], + dynamicLabel: true // Display dynamic labels or gear symbol + }; + + var settings = videojs.obj.merge(defaults, options), + player = this, + groupedSrc = {}, + currentSources = {}, + currentResolutionState = {}; + + /** + * Updates player sources or returns current source URL + * @param {Array} [src] array of sources [{src: '', type: '', label: '', res: ''}] + * @returns {Object|String|Array} videojs player object if used as setter or current source URL, object, or array of sources + */ + player.updateSrc = function (src) { + //Return current src if src is not given + if (!src) { return player.src(); } + + // Only add those sources which we can (maybe) play + src = src.filter(function (source) { + try { + return (player.canPlayType(source.type) !== ''); + } catch (e) { + // If a Tech doesn't yet have canPlayType just add it + return true; + } + }); + //Sort sources + this.currentSources = src.sort(compareResolutions); + this.groupedSrc = bucketSources(this.currentSources); + // Pick one by default + var chosen = chooseSrc(this.groupedSrc, this.currentSources); + this.currentResolutionState = { + label: chosen.label, + sources: chosen.sources + }; - // Change player source and wait for loadeddata event, then play video - // loadedmetadata doesn't work right now for flash. - // Probably because of https://github.com/videojs/video-js-swf/issues/124 - // If player preload is 'none' and then loadeddata not fired. So, we need timeupdate event for seek handle (timeupdate doesn't work properly with flash) - var handleSeekEvent = 'loadeddata'; - if(this.player_.techName_ !== 'Youtube' && this.player_.preload() === 'none' && this.player_.techName_ !== 'Flash') { - handleSeekEvent = 'timeupdate'; + player.trigger('updateSources'); + player.setSourcesSanitized(chosen.sources, chosen.label); + player.trigger('resolutionchange'); + return player; + }; + + /** + * Returns current resolution or sets one when label is specified + * @param {String} [label] label name + * @param {Function} [customSourcePicker] custom function to choose source. Takes 2 arguments: sources, label. Must return player object. + * @returns {Object} current resolution object {label: '', sources: []} if used as getter or player object if used as setter + */ + player.currentResolution = function (label, customSourcePicker) { + if (label == null) { return this.currentResolutionState; } + + // Lookup sources for label + if (!this.groupedSrc || !this.groupedSrc.label || !this.groupedSrc.label[label]) { + return; + } + var sources = this.groupedSrc.label[label]; + // Remember player state + var currentTime = player.currentTime(); + var isPaused = player.paused(); + + // Hide bigPlayButton + if (!isPaused && this.player_.options_.bigPlayButton) { + this.player_.bigPlayButton.hide(); + } + + // Change player source and wait for loadeddata event, then play video + // loadedmetadata doesn't work right now for flash. + // Probably because of https://github.com/videojs/video-js-swf/issues/124 + // If player preload is 'none' and then loadeddata not fired. So, we need timeupdate event for seek handle (timeupdate doesn't work properly with flash) + var handleSeekEvent = 'loadeddata'; + if (this.player_.techName_ !== 'Youtube' && this.player_.preload() === 'none' && this.player_.techName_ !== 'Flash') { + handleSeekEvent = 'timeupdate'; + } + player + .setSourcesSanitized(sources, label, customSourcePicker || settings.customSourcePicker) + .one(handleSeekEvent, function () { + player.currentTime(currentTime); + if (!isPaused) { + player.play(); } - player - .setSourcesSanitized(sources, label, customSourcePicker || settings.customSourcePicker) - .one(handleSeekEvent, function() { - player.currentTime(currentTime); - player.handleTechSeeked_(); - if(!isPaused){ - // Start playing and hide loadingSpinner (flash issue ?) - player.play(); - player.handleTechSeeked_(); - } - player.trigger('resolutionchange'); - }); - return player; - }; + player.trigger('resolutionchange'); + }); + return player; + }; + + /** + * Returns grouped sources by label, resolution and type + * @returns {Object} grouped sources: { label: { key: [] }, res: { key: [] }, type: { key: [] } } + */ + player.getGroupedSrc = function () { + return this.groupedSrc; + }; + + player.setSourcesSanitized = function (sources, label, customSourcePicker) { + this.currentResolutionState = { + label: label, + sources: sources + }; + if (typeof customSourcePicker === 'function') { + return customSourcePicker(player, sources, label); + } + player.src(sources.map(function (src) { + return { src: src.src, type: src.type, res: src.res }; + })); + return player; + }; + + /** + * Method used for sorting list of sources + * @param {Object} a - source object with res property + * @param {Object} b - source object with res property + * @returns {Number} result of comparation + */ + function compareResolutions(a, b) { + if (!a.res || !b.res) { return 0; } + return (+b.res) - (+a.res); + } - /** - * Returns grouped sources by label, resolution and type - * @returns {Object} grouped sources: { label: { key: [] }, res: { key: [] }, type: { key: [] } } - */ - player.getGroupedSrc = function(){ - return this.groupedSrc; - }; + /** + * Group sources by label, resolution and type + * @param {Array} src Array of sources + * @returns {Object} grouped sources: { label: { key: [] }, res: { key: [] }, type: { key: [] } } + */ + function bucketSources(src) { + var resolutions = { + label: {}, + res: {}, + type: {} + }; + src.map(function (source) { + initResolutionKey(resolutions, 'label', source); + initResolutionKey(resolutions, 'res', source); + initResolutionKey(resolutions, 'type', source); + + appendSourceToKey(resolutions, 'label', source); + appendSourceToKey(resolutions, 'res', source); + appendSourceToKey(resolutions, 'type', source); + }); + return resolutions; + } - player.setSourcesSanitized = function(sources, label, customSourcePicker) { - this.currentResolutionState = { - label: label, - sources: sources - }; - if(typeof customSourcePicker === 'function'){ - return customSourcePicker(player, sources, label); - } - player.src(sources.map(function(src) { - return {src: src.src, type: src.type, res: src.res}; - })); - return player; - }; + function initResolutionKey(resolutions, key, source) { + if (resolutions[key][source[key]] == null) { + resolutions[key][source[key]] = []; + } + } - /** - * Method used for sorting list of sources - * @param {Object} a - source object with res property - * @param {Object} b - source object with res property - * @returns {Number} result of comparation - */ - function compareResolutions(a, b){ - if(!a.res || !b.res){ return 0; } - return (+b.res)-(+a.res); - } + function appendSourceToKey(resolutions, key, source) { + resolutions[key][source[key]].push(source); + } - /** - * Group sources by label, resolution and type - * @param {Array} src Array of sources - * @returns {Object} grouped sources: { label: { key: [] }, res: { key: [] }, type: { key: [] } } - */ - function bucketSources(src){ - var resolutions = { - label: {}, - res: {}, - type: {} - }; - src.map(function(source) { - initResolutionKey(resolutions, 'label', source); - initResolutionKey(resolutions, 'res', source); - initResolutionKey(resolutions, 'type', source); - - appendSourceToKey(resolutions, 'label', source); - appendSourceToKey(resolutions, 'res', source); - appendSourceToKey(resolutions, 'type', source); - }); - return resolutions; - } + /** + * Choose src if option.default is specified + * @param {Object} groupedSrc {res: { key: [] }} + * @param {Array} src Array of sources sorted by resolution used to find high and low res + * @returns {Object} {res: string, sources: []} + */ + function chooseSrc(groupedSrc, src) { + var selectedRes = settings['default']; // use array access as default is a reserved keyword + var selectedLabel = ''; + if (selectedRes === 'high') { + selectedRes = src[0].res; + selectedLabel = src[0].label; + } else if (selectedRes === 'low' || selectedRes == null || !groupedSrc.res[selectedRes]) { + // Select low-res if default is low or not set + selectedRes = src[src.length - 1].res; + selectedLabel = src[src.length - 1].label; + } else if (groupedSrc.res[selectedRes]) { + selectedLabel = groupedSrc.res[selectedRes][0].label; + } + + return { res: selectedRes, label: selectedLabel, sources: groupedSrc.res[selectedRes] }; + } - function initResolutionKey(resolutions, key, source) { - if(resolutions[key][source[key]] == null) { - resolutions[key][source[key]] = []; - } - } + function initResolutionForYt(player) { + // Map youtube qualities names + var _yts = { + highres: { res: 1080, label: '1080', yt: 'highres' }, + hd1080: { res: 1080, label: '1080', yt: 'hd1080' }, + hd720: { res: 720, label: '720', yt: 'hd720' }, + large: { res: 480, label: '480', yt: 'large' }, + medium: { res: 360, label: '360', yt: 'medium' }, + small: { res: 240, label: '240', yt: 'small' }, + tiny: { res: 144, label: '144', yt: 'tiny' }, + auto: { res: 0, label: 'auto', yt: 'auto' } + }; + // Overwrite default sourcePicker function + var _customSourcePicker = function (_player, _sources, _label) { + // Note that setPlayebackQuality is a suggestion. YT does not always obey it. + player.tech_.ytPlayer.setPlaybackQuality(_sources[0]._yt); + player.trigger('updateSources'); + return player; + }; + settings.customSourcePicker = _customSourcePicker; - function appendSourceToKey(resolutions, key, source) { - resolutions[key][source[key]].push(source); - } + // Init resolution + player.tech_.ytPlayer.setPlaybackQuality('auto'); - /** - * Choose src if option.default is specified - * @param {Object} groupedSrc {res: { key: [] }} - * @param {Array} src Array of sources sorted by resolution used to find high and low res - * @returns {Object} {res: string, sources: []} - */ - function chooseSrc(groupedSrc, src){ - var selectedRes = settings['default']; // use array access as default is a reserved keyword - var selectedLabel = ''; - if (selectedRes === 'high') { - selectedRes = src[0].res; - selectedLabel = src[0].label; - } else if (selectedRes === 'low' || selectedRes == null || !groupedSrc.res[selectedRes]) { - // Select low-res if default is low or not set - selectedRes = src[src.length - 1].res; - selectedLabel = src[src.length -1].label; - } else if (groupedSrc.res[selectedRes]) { - selectedLabel = groupedSrc.res[selectedRes][0].label; + // This is triggered when the resolution actually changes + player.tech_.ytPlayer.addEventListener('onPlaybackQualityChange', function (event) { + for (var res in _yts) { + if (res.yt === event.data) { + player.currentResolution(res.label, _customSourcePicker); + return; } - - return {res: selectedRes, label: selectedLabel, sources: groupedSrc.res[selectedRes]}; } - - function initResolutionForYt(player){ - // Map youtube qualities names - var _yts = { - highres: {res: 1080, label: '1080', yt: 'highres'}, - hd1080: {res: 1080, label: '1080', yt: 'hd1080'}, - hd720: {res: 720, label: '720', yt: 'hd720'}, - large: {res: 480, label: '480', yt: 'large'}, - medium: {res: 360, label: '360', yt: 'medium'}, - small: {res: 240, label: '240', yt: 'small'}, - tiny: {res: 144, label: '144', yt: 'tiny'}, - auto: {res: 0, label: 'auto', yt: 'auto'} - }; - // Overwrite default sourcePicker function - var _customSourcePicker = function(_player, _sources, _label){ - // Note that setPlayebackQuality is a suggestion. YT does not always obey it. - player.tech_.ytPlayer.setPlaybackQuality(_sources[0]._yt); - player.trigger('updateSources'); - return player; - }; - settings.customSourcePicker = _customSourcePicker; - - // Init resolution - player.tech_.ytPlayer.setPlaybackQuality('auto'); - - // This is triggered when the resolution actually changes - player.tech_.ytPlayer.addEventListener('onPlaybackQualityChange', function(event){ - for(var res in _yts) { - if(res.yt === event.data) { - player.currentResolution(res.label, _customSourcePicker); - return; - } - } + }); + + // We must wait for play event + player.one('play', function () { + var qualities = player.tech_.ytPlayer.getAvailableQualityLevels(); + var _sources = []; + + qualities.map(function (q) { + _sources.push({ + src: player.src().src, + type: player.src().type, + label: _yts[q].label, + res: _yts[q].res, + _yt: _yts[q].yt }); + }); - // We must wait for play event - player.one('play', function(){ - var qualities = player.tech_.ytPlayer.getAvailableQualityLevels(); - var _sources = []; - - qualities.map(function(q){ - _sources.push({ - src: player.src().src, - type: player.src().type, - label: _yts[q].label, - res: _yts[q].res, - _yt: _yts[q].yt - }); - }); - - player.groupedSrc = bucketSources(_sources); - var chosen = {label: 'auto', res: 0, sources: player.groupedSrc.label.auto}; - - this.currentResolutionState = { - label: chosen.label, - sources: chosen.sources - }; - - player.trigger('updateSources'); - player.setSourcesSanitized(chosen.sources, chosen.label, _customSourcePicker); - }); - } + player.groupedSrc = bucketSources(_sources); + var chosen = { label: 'auto', res: 0, sources: player.groupedSrc.label.auto }; - player.ready(function(){ - if( settings.ui ) { - var menuButton = new ResolutionMenuButton(player, settings); - player.controlBar.resolutionSwitcher = player.controlBar.el_.insertBefore(menuButton.el_, player.controlBar.getChild('fullscreenToggle').el_); - player.controlBar.resolutionSwitcher.dispose = function(){ - this.parentNode.removeChild(this); - }; - } - if(player.options_.sources.length > 1){ - // tech: Html5 and Flash - // Create resolution switcher for videos form tag inside