123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440 |
- /*!
- * @source: here!
- * @base: https://github.com/dominic-p/videojs-resolution-selector
- *
- * @licstart The following is the entire license notice for the
- * JavaScript code in this page.
- *
- * Copyleft 2016 Jesus Estupiñán Medina
- *
- * The JavaScript code in this page is free software: you can
- * redistribute it and/or modify it under the terms of the GNU
- * General Public License (GNU GPL) as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option)
- * any later version. The code is distributed WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute non-source (e.g., minimized or compacted) forms of
- * that code without the copy of the GNU GPL normally required by
- * section 4, provided you include this license notice and a URL
- * through which recipients can access the Corresponding Source.
- *
- * @licend The above is the entire license notice
- * for the JavaScript code in this page.
- *
- */
- /**
- * LibreVideoJS Resolution Selector
- *
- * This plugin for LibreVideo.js adds a resolution selector option
- * to the toolbar. Usage:
- *
- * <video>
- * <source data-res="480" src="..." />
- * <source data-res="240" src="..." />
- * </video>
- */
- (function( _V_ ) {
- /***********************************************************************************
- * Define some helper functions
- ***********************************************************************************/
- var methods = {
- /**
- * Utility function for merging 2 objects recursively. It treats
- * arrays like plain objects and it relies on a for...in loop which will
- * break if the Object prototype is messed with.
- *
- * @param (object) destination The object to modify and return
- * @param (object) source The object to use to overwrite the first
- * object
- *
- * @returns (object) The modified first object is returned
- */
- extend : function( destination, source ) {
- for ( var prop in source ) {
- // Sanity check
- if ( ! source.hasOwnProperty( prop ) ) { continue; }
- // Enable recursive (deep) object extension
- if ( typeof source[prop] == 'object' && null !== source[prop] ) {
- destination[prop] = methods.extend( destination[prop] || {}, source[prop] );
- } else {
- destination[prop] = source[prop];
- }
- }
- return destination;
- },
- /**
- * In a future version, this can be made more intelligent,
- * but for now, we'll just add a "p" at the end if we are passed
- * numbers.
- *
- * @param (string) res The resolution to make a label for
- *
- * @returns (string) The label text string
- */
- res_label : function( res ) {
- return ( /^\d+$/.test( res ) ) ? res + 'p' : res;
- },
- matchResolution: function(resStack, res) {
- },
- /**
- * returns a dummy object that implements the basic get/set
- * functionality of the Cookies library. Used in the case where
- * the Cookies library is not present
- */
- buildCookiesDummy: function() {
- return {
- get: function(key) {
- return "";
- },
- set: function(key, val) {
- return false;
- }
- };
- }
- };
- /***********************************************************************************
- * Setup our resolution menu items
- ***********************************************************************************/
- _V_.ResolutionMenuItem = _V_.MenuItem.extend({
- /** @constructor */
- init : function( player, options ){
- // Modify options for parent MenuItem class's init.
- options.label = methods.res_label( options.res );
- options.selected = ( options.res.toString() === player.getCurrentRes().toString() );
- // Call the parent constructor
- _V_.MenuItem.call( this, player, options );
- // Store the resolution as a call property
- this.resolution = options.res;
- // Register our click handler
- this.on( 'click', this.onClick );
- // Toggle the selected class whenever the resolution changes
- player.on( 'changeRes', _V_.bind( this, function() {
- if ( this.resolution == player.getCurrentRes() ) {
- this.selected( true );
- } else {
- this.selected( false );
- }
- }));
- }
- });
- // Handle clicks on the menu items
- _V_.ResolutionMenuItem.prototype.onClick = function() {
- var player = this.player(),
- video_el = player.el().firstChild,
- current_time = player.currentTime(),
- is_paused = player.paused(),
- button_nodes = player.controlBar.resolutionSelector.el().firstChild.children,
- button_node_count = button_nodes.length;
- // Do nothing if we aren't changing resolutions
- if ( player.getCurrentRes() == this.resolution ) { return; }
- // Make sure the loadedmetadata event will fire
- if ( 'none' == video_el.preload ) { video_el.preload = 'metadata'; }
- // Change the source and make sure we don't start the video over
- player.src( player.availableRes[this.resolution] ).one( 'loadedmetadata', function() {
- player.currentTime( current_time );
- if ( ! is_paused ) { player.play(); }
- });
- // Save the newly selected resolution in our player options property
- player.currentRes = this.resolution;
- // Update the button text
- while ( button_node_count > 0 ) {
- button_node_count--;
- if ( 'librevjs-current-res' == button_nodes[button_node_count].className ) {
- button_nodes[button_node_count].innerHTML = methods.res_label( this.resolution );
- break;
- }
- }
- // Update the classes to reflect the currently selected resolution
- player.trigger( 'changeRes' );
- };
- /***********************************************************************************
- * Setup our resolution menu title item
- ***********************************************************************************/
- _V_.ResolutionTitleMenuItem = _V_.MenuItem.extend({
- init : function( player, options ) {
- // Call the parent constructor
- _V_.MenuItem.call( this, player, options );
- // No click handler for the menu title
- this.off( 'click' );
- }
- });
- /***********************************************************************************
- * Define our resolution selector button
- ***********************************************************************************/
- _V_.ResolutionSelector = _V_.MenuButton.extend({
- /** @constructor */
- init : function( player, options ) {
- // Add our list of available resolutions to the player object
- player.availableRes = options.available_res;
- // Call the parent constructor
- _V_.MenuButton.call( this, player, options );
- }
- });
- // Create a menu item for each available resolution
- _V_.ResolutionSelector.prototype.createItems = function() {
- var player = this.player(),
- items = [],
- current_res;
- // Add the menu title item
- items.push( new _V_.ResolutionTitleMenuItem( player, {
- el : _V_.Component.prototype.createEl( 'li', {
- className : 'librevjs-menu-title librevjs-res-menu-title',
- innerHTML : 'Calidad'
- })
- }));
- // Add an item for each available resolution
- for ( current_res in player.availableRes ) {
- // Don't add an item for the length attribute
- if ( 'length' == current_res ) { continue; }
- items.push( new _V_.ResolutionMenuItem( player, {
- res : current_res
- }));
- }
- // Sort the available resolutions in descending order
- items.sort(function( a, b ) {
- if ( typeof a.resolution == 'undefined' ) {
- return -1;
- } else {
- return parseInt( b.resolution ) - parseInt( a.resolution );
- }
- });
- return items;
- };
- /***********************************************************************************
- * Register the plugin with cliplibrejs, main plugin function
- ***********************************************************************************/
- _V_.plugin( 'resolutionSelector', function( options ) {
- // Only enable the plugin on HTML5 videos
- if ( ! this.el().firstChild.canPlayType ) { return; }
- var player = this,
- sources = player.options().sources,
- i = sources.length,
- j,
- found_type,
- // Override default options with those provided
- settings = methods.extend({
- default_res : '', // (string) The resolution that should be selected by default ( '480' or '480,1080,240' )
- force_types : false // (array) List of media types. If passed, we need to have source for each type in each resolution or that resolution will not be an option
- }, options || {} ),
- available_res = { length : 0 },
- current_res,
- resolutionSelector,
- // Split default resolutions if set and valid, otherwise default to an empty array
- default_resolutions = ( settings.default_res && typeof settings.default_res == 'string' ) ? settings.default_res.split( ',' ) : [],
- cookieNamespace = 'cliplibrejs.resolutionSelector',
- resCookieName = cookieNamespace + '.res',
- cookieRef = (typeof(Cookies) === "function") ? Cookies : methods.buildCookiesDummy();
- // Get all of the available resoloutions
- while ( i > 0 ) {
- i--;
- // Skip sources that don't have data-res attributes
- if ( ! sources[i]['data-res'] ) { continue; }
- current_res = sources[i]['data-res'];
- if ( typeof available_res[current_res] !== 'object' ) {
- available_res[current_res] = [];
- available_res.length++;
- }
- available_res[current_res].push( sources[i] );
- }
- // Check for forced types
- if ( settings.force_types ) {
- // Loop through all available resoultions
- for ( current_res in available_res ) {
- // Don't count the length property as a resolution
- if ( 'length' == current_res ) { continue; }
- i = settings.force_types.length;
- // For each resolution loop through the required types
- while ( i > 0 ) {
- i--;
- j = available_res[current_res].length;
- found_types = 0;
- // For each required type loop through the available sources to check if its there
- while ( j > 0 ) {
- j--;
- if ( settings.force_types[i] === available_res[current_res][j].type ) {
- found_types++;
- }
- } // End loop through current resolution sources
- if ( found_types < settings.force_types.length ) {
- delete available_res[current_res];
- available_res.length--;
- break;
- }
- } // End loop through required types
- } // End loop through resolutions
- }
- // Make sure we have at least 2 available resolutions before we add the button
- if ( available_res.length < 2 ) { return; }
- var resCookie = cookieRef.get(resCookieName)
- if (resCookie) {
- // rebuild the default_resolutions stack with the cookie's resolution on top
- default_resolutions = [resCookie].concat(default_resolutions);
- }
- // Loop through the choosen default resolutions if there were any
- for ( i = 0; i < default_resolutions.length; i++ ) {
- // Set the video to start out with the first available default res
- if ( available_res[default_resolutions[i]] ) {
- player.src( available_res[default_resolutions[i]] );
- player.currentRes = default_resolutions[i];
- break;
- }
- }
- // Helper function to get the current resolution
- player.getCurrentRes = function() {
- if ( typeof player.currentRes !== 'undefined' ) {
- return player.currentRes;
- } else {
- try {
- return res = player.options().sources[0]['data-res'];
- } catch(e) {
- return '';
- }
- }
- };
- // Get the started resolution
- current_res = player.getCurrentRes();
- if ( current_res ) { current_res = methods.res_label( current_res ); }
- // Add the resolution selector button
- resolutionSelector = new _V_.ResolutionSelector( player, {
- el : _V_.Component.prototype.createEl( null, {
- className : 'librevjs-res-button librevjs-menu-button librevjs-control',
- innerHTML : '<div class="librevjs-control-content"><span class="librevjs-current-res">' + ( current_res || 'Quality' ) + '</span></div>',
- role : 'button',
- 'aria-live' : 'polite', // let the screen reader user know that the text of the button may change
- tabIndex : 0
- }),
- available_res : available_res
- });
- // Attach an event to remember previous res selection via cookie
- this.on('changeRes', function() {
- cookieRef.set(resCookieName, player.getCurrentRes());
- });
- // Attach an event to update player.src once on loadedmetadata
- // if a resolution was previously set
- this.one('loadedmetadata', function() {
- var resCookie = cookieRef.get(resCookieName);
- if (resCookie) {
- player.src(player.availableRes[resCookie]);
- player.currentRes = resCookie;
- player.trigger( 'changeRes' );
- }
- });
- // Add the button to the control bar object and the DOM
- player.controlBar.resolutionSelector = player.controlBar.addChild( resolutionSelector );
- });
- })( cliplibrejs );
|