lbry-desktop/ui/component/viewers/videoViewer/internal/plugins/videojs-hls-quality-selector/plugin.js

261 lines
6.7 KiB
JavaScript
Raw Normal View History

import videojs from 'video.js';
import {version as VERSION} from './package.json';
import ConcreteButton from './ConcreteButton';
import ConcreteMenuItem from './ConcreteMenuItem';
// Default options for the plugin.
const defaults = {};
// Cross-compatibility for Video.js 5 and 6.
const registerPlugin = videojs.registerPlugin || videojs.plugin;
// const dom = videojs.dom || videojs;
/**
* VideoJS HLS Quality Selector Plugin class.
*/
class HlsQualitySelectorPlugin {
/**
* Plugin Constructor.
*
* @param {Player} player - The videojs player instance.
* @param {Object} options - The plugin options.
*/
constructor(player, options) {
this.player = player;
this.config = options;
if (!this.player.qualityLevels) {
console.warn(`WARNING: Missing video.js quality levels plugin (required)`);
return;
}
this.setupPlugin();
}
setupPlugin() {
// Create the quality button.
this.createQualityButton();
// Bind event listeners
this.bindPlayerEvents();
// Listen for source changes
this.player.on('loadedmetadata', (e) => {
console.log(`Loaded Metadata detected by plugin!`, e);
this.updatePlugin();
});
}
updatePlugin() {
console.log(`Updating Quality Selector...`);
// If there is quality levels plugin and the HLS tech exists
// then continue.
if (this.getHls()) {
console.log('Show quality selector');
// Show quality selector
this._qualityButton.show();
} else {
console.log('Hide quality selector');
console.log('Source type does not support multiple qulaity levels...');
// Hide quality selector
this._qualityButton.hide();
}
}
/**
* Returns HLS Plugin
*
* @return {*} - videojs-hls-contrib plugin.
*/
getHls() {
return this.player.tech({ IWillNotUseThisInPlugins: true }).hls;
}
/**
* Binds listener for quality level changes.
*/
bindPlayerEvents() {
this.player.qualityLevels().on('addqualitylevel', this.onAddQualityLevel.bind(this));
}
/**
* Adds the quality menu button to the player control bar.
*/
createQualityButton() {
const player = this.player;
this._qualityButton = new ConcreteButton(player);
const placementIndex = player.controlBar.children().length - 2;
const concreteButtonInstance = player.controlBar.addChild(this._qualityButton,
{componentClass: 'qualitySelector'},
this.config.placementIndex || placementIndex);
concreteButtonInstance.addClass('vjs-quality-selector');
if (!this.config.displayCurrentQuality) {
const icon = ` ${this.config.vjsIconClass || 'vjs-icon-hd'}`;
concreteButtonInstance
.menuButton_.$('.vjs-icon-placeholder').className += icon;
} else {
this.setButtonInnerText('auto');
}
concreteButtonInstance.removeClass('vjs-hidden');
}
/**
*Set inner button text.
*
* @param {string} text - the text to display in the button.
*/
setButtonInnerText(text) {
this._qualityButton
.menuButton_.$('.vjs-icon-placeholder').innerHTML = text;
}
/**
* Builds individual quality menu items.
*
* @param {Object} item - Individual quality menu item.
* @return {ConcreteMenuItem} - Menu item
*/
getQualityMenuItem(item) {
const player = this.player;
return new ConcreteMenuItem(player, item, this._qualityButton, this);
}
/**
* Executed when a quality level is added from HLS playlist.
*/
onAddQualityLevel() {
const player = this.player;
const qualityList = player.qualityLevels();
const levels = qualityList.levels_ || [];
const levelItems = [];
for (let i = 0; i < levels.length; ++i) {
if (!levelItems.filter(_existingItem => {
return _existingItem.item && _existingItem.item.value === levels[i].height;
}).length) {
const levelItem = this.getQualityMenuItem.call(this, {
label: levels[i].height + 'p',
value: levels[i].height
});
levelItems.push(levelItem);
}
}
levelItems.sort((current, next) => {
if ((typeof current !== 'object') || (typeof next !== 'object')) {
return -1;
}
if (current.item.value < next.item.value) {
return -1;
}
if (current.item.value > next.item.value) {
return 1;
}
return 0;
});
levelItems.push(this.getQualityMenuItem.call(this, {
label: player.localize('Auto'),
value: 'auto',
selected: true
}));
if (this._qualityButton) {
this._qualityButton.createItems = function() {
return levelItems;
};
this._qualityButton.update();
}
}
/**
* Sets quality (based on media height)
*
* @param {number} height - A number representing HLS playlist.
*/
setQuality(height) {
const qualityList = this.player.qualityLevels();
// Set quality on plugin
this._currentQuality = height;
if (this.config.displayCurrentQuality) {
this.setButtonInnerText(height === 'auto' ? height : `${height}p`);
}
for (let i = 0; i < qualityList.length; ++i) {
const quality = qualityList[i];
quality.enabled = (quality.height === height || height === 'auto');
}
this._qualityButton.unpressButton();
}
/**
* Return the current set quality or 'auto'
*
* @return {string} the currently set quality
*/
getCurrentQuality() {
return this._currentQuality || 'auto';
}
}
/**
* Function to invoke when the player is ready.
*
* This is a great place for your plugin to initialize itself. When this
* function is called, the player will have its DOM and child components
* in place.
*
* @function onPlayerReady
* @param {Player} player
* A Video.js player object.
*
* @param {Object} [options={}]
* A plain object containing options for the plugin.
*/
const onPlayerReady = (player, options) => {
player.addClass('vjs-hls-quality-selector');
player.hlsQualitySelector = new HlsQualitySelectorPlugin(player, options);
};
/**
* A video.js plugin.
*
* In the plugin function, the value of `this` is a video.js `Player`
* instance. You cannot rely on the player being in a "ready" state here,
* depending on how the plugin is invoked. This may or may not be important
* to you; if not, remove the wait for "ready"!
*
* @function hlsQualitySelector
* @param {Object} [options={}]
* An object of options left to the plugin author to define.
*/
const hlsQualitySelector = function(options) {
this.ready(() => {
onPlayerReady(this, videojs.mergeOptions(defaults, options));
});
};
// Register the plugin with video.js.
registerPlugin('hlsQualitySelector', hlsQualitySelector);
// Include the version number.
hlsQualitySelector.VERSION = VERSION;
export default hlsQualitySelector;