From 5c611fddea241eb2d0bb65f85d9a05dbe9276a4f Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Fri, 22 Apr 2022 13:43:32 +0300 Subject: [PATCH 01/40] Partial MPD support --- src/js/config/defaults.js | 20 +++- src/js/config/types.js | 1 + src/js/controls.js | 81 +++++++++++++++- src/js/listeners.js | 8 +- src/js/media.js | 3 + src/js/plugins/mpd.js | 133 +++++++++++++++++++++++++++ src/js/plugins/preview-thumbnails.js | 2 +- src/js/plyr.d.ts | 12 ++- src/js/plyr.js | 72 +++++++++++++-- src/js/ui.js | 8 +- src/js/utils/i18n.js | 1 + src/js/utils/style.js | 4 +- 12 files changed, 326 insertions(+), 19 deletions(-) create mode 100644 src/js/plugins/mpd.js diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index e301022e4..f90cb3faa 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -70,7 +70,7 @@ const defaults = { quality: { default: 576, // The options to display in the UI, if available for the source media - options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], + options: [0x7fffffff, 4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], forced: false, onChange: null, }, @@ -89,6 +89,14 @@ const defaults = { options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4], }, + audioTrack: { + default: 'Default', + // The options to display in the UI, if available for the source media + options: ['Default'], + forced: false, + onChange: null, + }, + // Keyboard shortcut settings keyboard: { focused: true, @@ -145,7 +153,7 @@ const defaults = { // 'download', 'fullscreen', ], - settings: ['captions', 'quality', 'speed'], + settings: ['captions', 'quality', 'speed', 'audioTrack'], // Localisation i18n: { @@ -174,6 +182,7 @@ const defaults = { pip: 'PIP', menuBack: 'Go back to previous menu', speed: 'Speed', + audioTrack: 'Audio track', normal: 'Normal', quality: 'Quality', loop: 'Loop', @@ -184,6 +193,9 @@ const defaults = { disabled: 'Disabled', enabled: 'Enabled', advertisement: 'Ad', + qualityLabel: { + 0x7fffffff: 'Auto', + }, qualityBadge: { 2160: '4K', 1440: 'HD', @@ -274,6 +286,9 @@ const defaults = { // Quality 'qualitychange', + // MPEG-DASH + 'audiotrackchange', + // Ads 'adsloaded', 'adscontentpause', @@ -317,6 +332,7 @@ const defaults = { speed: '[data-plyr="speed"]', language: '[data-plyr="language"]', quality: '[data-plyr="quality"]', + audioTrack: '[data-plyr="audioTrack"]', }, display: { currentTime: '.plyr__time--current', diff --git a/src/js/config/types.js b/src/js/config/types.js index 31e488eb8..29b30f84d 100644 --- a/src/js/config/types.js +++ b/src/js/config/types.js @@ -6,6 +6,7 @@ export const providers = { html5: 'html5', youtube: 'youtube', vimeo: 'vimeo', + mpd: 'mpd', }; export const types = { diff --git a/src/js/controls.js b/src/js/controls.js index 3044b5b18..bb4e59f60 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -7,6 +7,7 @@ import RangeTouch from 'rangetouch'; import captions from './captions'; import html5 from './html5'; +import mpd from './plugins/mpd'; import support from './support'; import { repaint, transitionEndEvent } from './utils/animation'; import { dedupe } from './utils/arrays'; @@ -526,6 +527,11 @@ const controls = { this.speed = parseFloat(value); break; + case 'audioTrack': + this.audioTrack = value; + // controls.updateSetting.call(this, type, list); + break; + default: break; } @@ -824,7 +830,9 @@ const controls = { let value = null; let list = container; - if (setting === 'captions') { + if (setting === 'audioTrack') { + value = this.audioTrack; + } else if (setting === 'captions') { value = this.currentTrack; } else { value = !is.empty(input) ? input : this[setting]; @@ -872,6 +880,15 @@ const controls = { // Translate a value into a nice label getLabel(setting, value) { switch (setting) { + case 'audioTrack': + const label = i18n.get(`audioTrack.${value}`, this.config); + + if (!label.length) { + return `${value}`; + } + + return label; + case 'speed': return value === 1 ? i18n.get('normal', this.config) : `${value}×`; @@ -1096,6 +1113,54 @@ const controls = { controls.updateSetting.call(this, type, list); }, + setAudioTrackMenu(options) { + console.log(this.elements.settings.panels); + // Menu required + if (!is.element(this.elements.settings.panels.audioTrack)) { + return; + } + + const type = 'audioTrack'; + const list = this.elements.settings.panels.audioTrack.querySelector('[role="menu"]'); + + // Set options if passed and filter based on uniqueness and config + if (is.array(options)) { + this.options.audioTrack = dedupe(options); + } + + // Toggle the pane and tab + const toggle = !is.empty(this.options.audioTrack) && this.options.audioTrack.length > 1; + controls.toggleMenuButton.call(this, type, toggle); + + // Empty the menu + emptyElement(list); + + // Check if we need to toggle the parent + controls.checkMenu.call(this); + + // If we're hiding, nothing more to do + if (!toggle) { + return; + } + + // Sort options by the config and then render options + this.options.audioTrack + .sort((a, b) => { + const sorting = this.config.audioTrack.options; + return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1; + }) + .forEach((audioTrack) => { + controls.createMenuItem.call(this, { + value: audioTrack, + list, + type, + title: controls.getLabel.call(this, 'audioTrack', audioTrack), + }); + }); + + controls.updateSetting.call(this, type, list); + }, + // Check if we need to hide/show the settings menu checkMenu() { const { buttons } = this.elements.settings; @@ -1272,6 +1337,7 @@ const controls = { createTime, setQualityMenu, setSpeedMenu, + setAudioTrackMenu, showMenuPanel, } = controls; this.elements.controls = null; @@ -1614,6 +1680,18 @@ const controls = { setQualityMenu.call(this, html5.getQualityOptions.call(this)); } + if (this.isMPD) { + setQualityMenu.call(this, mpd.getQualityOptions.call(this)); + this.dash.on('periodSwitchCompleted', () => { + setQualityMenu.call(this, mpd.getQualityOptions.call(this)); + }); + + setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); + this.dash.on('periodSwitchCompleted', () => { + setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); + }); + } + setSpeedMenu.call(this); return container; @@ -1666,6 +1744,7 @@ const controls = { seektime: this.config.seekTime, speed: this.speed, quality: this.quality, + audioTrack: this.audioTrack, captions: captions.getLabel.call(this), // TODO: Looping // loop: 'None', diff --git a/src/js/listeners.js b/src/js/listeners.js index 38a344007..91d8da8e3 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -386,7 +386,7 @@ class Listeners { // Handle the media finishing on.call(player, player.media, 'ended', () => { // Show poster on end - if (player.isHTML5 && player.isVideo && player.config.resetOnEnd) { + if ((player.isHTML5 || player.isMPD) && player.isVideo && player.config.resetOnEnd) { // Restart player.restart(); @@ -493,6 +493,12 @@ class Listeners { controls.updateSetting.call(player, 'quality', null, event.detail.quality); }); + // Audio track change + on.call(player, player.media, 'audiotrackchange', (event) => { + // Update UI + controls.updateSetting.call(player, 'audioTrack', null, event.detail.audioTrack); + }); + // Update download link when ready and if quality changes on.call(player, player.media, 'ready qualitychange', () => { controls.setDownloadUrl.call(player); diff --git a/src/js/media.js b/src/js/media.js index 4584fea35..a89d7d125 100644 --- a/src/js/media.js +++ b/src/js/media.js @@ -3,6 +3,7 @@ // ========================================================================== import html5 from './html5'; +import mpd from './plugins/mpd'; import vimeo from './plugins/vimeo'; import youtube from './plugins/youtube'; import { createElement, toggleClass, wrap } from './utils/elements'; @@ -48,6 +49,8 @@ const media = { if (this.isHTML5) { html5.setup.call(this); + } else if (this.isMPD) { + mpd.setup.call(this); } else if (this.isYouTube) { youtube.setup.call(this); } else if (this.isVimeo) { diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js new file mode 100644 index 000000000..787a6d996 --- /dev/null +++ b/src/js/plugins/mpd.js @@ -0,0 +1,133 @@ +// ========================================================================== +// Plyr MPEG-DASH helpers +// ========================================================================== + +import { triggerEvent } from '../utils/events'; +import is from '../utils/is'; +import { setAspectRatio } from '../utils/style'; + +const mpd = { + // Get quality levels + getQualityOptions() { + const qualityList = this.dash.getBitrateInfoListFor('video').map((bitrate) => { + return bitrate.height; + }); + + return [0x7fffffff, ...qualityList]; + }, + + getAudioTrackOptions() { + const audioTrackList = this.dash.getTracksFor('audio').map((audioTrack) => { + return audioTrack.id; + }); + + return audioTrackList; + }, + + setup() { + if (!this.isMPD) { + return; + } + + const player = this; + + // Set speed options from config + player.options.speed = player.config.speed.options; + + // Set aspect ratio if fixed + if (!is.empty(this.config.ratio)) { + setAspectRatio.call(player); + } + + // Quality + Object.defineProperty(player.media, 'quality', { + get() { + const currentIndex = player.dash.getQualityFor('video'); + console.log("get", "quality", currentIndex); + if(currentIndex){ + return player.dash.getBitrateInfoListFor('video')[currentIndex].height; + } + return 0x7fffffff; + }, + set(input) { + const cfg = { + 'streaming': { + 'abr': { + 'autoSwitchBitrate': {} + } + } + }; + + if (input === 0x7fffffff) { + cfg.streaming.abr.autoSwitchBitrate['video'] = true; + player.dash.updateSettings(cfg); + } else { + const currentIndex = player.dash.getQualityFor('video'); + const currentHeight = (currentIndex) ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; + for (const bitrate of player.dash.getBitrateInfoListFor('video')) { + if (bitrate.height === input) { + // Disable auto switch quality + cfg.streaming.abr.autoSwitchBitrate['video'] = false; + player.dash.updateSettings(cfg); + // Update quality + player.dash.setQualityFor('video', bitrate.qualityIndex, (bitrate.height > currentHeight)); + break; + } + } + } + + // If we're using an external handler... + if (player.config.quality.forced && is.function(player.config.quality.onChange)) { + player.config.quality.onChange(input); + } + + // Trigger change event + triggerEvent.call(player, player.media, 'qualitychange', false, { + quality: input, + }); + }, + }); + + // Audio track + Object.defineProperty(player.media, 'audioTrack', { + get() { + try { + const currentTrack = player.dash.getCurrentTrackFor('audio'); + if (currentTrack) { + return currentTrack.id; + } + return "Default"; + }catch(e){} + }, + set(input) { + const cfg = { + 'streaming': { + 'trackSwitchMode': { + 'audio': 'alwaysReplace' + } + } + }; + for (const track of player.dash.getTracksFor('audio')) { + if (track.id === input) { + // Update audio track + player.dash.updateSettings(cfg); + player.dash.setCurrentTrack(track); + break; + } + } + + // If we're using an external handler... + if (player.config.audioTrack.forced && is.function(player.config.audioTrack.onChange)) { + player.config.audioTrack.onChange(input); + } + + // Trigger change event + triggerEvent.call(player, player.media, 'audiotrackchange', false, { + audioTrack: input, + }); + }, + }); + }, +}; + +export default mpd; diff --git a/src/js/plugins/preview-thumbnails.js b/src/js/plugins/preview-thumbnails.js index efc678f7c..349fcf3ac 100644 --- a/src/js/plugins/preview-thumbnails.js +++ b/src/js/plugins/preview-thumbnails.js @@ -100,7 +100,7 @@ class PreviewThumbnails { } get enabled() { - return this.player.isHTML5 && this.player.isVideo && this.player.config.previewThumbnails.enabled; + return (this.player.isHTML5 || this.player.isMPD) && this.player.isVideo && this.player.config.previewThumbnails.enabled; } load = () => { diff --git a/src/js/plyr.d.ts b/src/js/plyr.d.ts index 70339eb93..d9b242a1b 100644 --- a/src/js/plyr.d.ts +++ b/src/js/plyr.d.ts @@ -27,6 +27,11 @@ declare class Plyr { */ readonly isHTML5: boolean; + /** + * Indicates if the current player is MPEG-DASH. + */ + readonly isMPD: boolean; + /** * Indicates if the current player is an embedded player. */ @@ -251,7 +256,7 @@ declare class Plyr { declare namespace Plyr { type MediaType = 'audio' | 'video'; - type Provider = 'html5' | 'youtube' | 'vimeo'; + type Provider = 'html5' | 'youtube' | 'vimeo' | 'mpd'; type StandardEventMap = { progress: PlyrEvent; playing: PlyrEvent; @@ -514,6 +519,11 @@ declare namespace Plyr { */ youtube?: object; + /** + * MPEG-DASH Player Options. + */ + mpd?: object; + /** * Preview Thumbnails Options. */ diff --git a/src/js/plyr.js b/src/js/plyr.js index 89162294e..e68ac07cb 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -13,6 +13,7 @@ import Console from './console'; import controls from './controls'; import Fullscreen from './fullscreen'; import html5 from './html5'; +import mpd from './plugins/mpd'; import Listeners from './listeners'; import media from './media'; import Ads from './plugins/ads'; @@ -50,7 +51,12 @@ class Plyr { this.touch = support.touch; // Set the media element - this.media = target; + if (window.dashjs && target instanceof window.dashjs.constructor) { + this.media = target.getVideoElement(); + this.dash = target; + } else { + this.media = target; + } // String selector passed if (is.string(this.media)) { @@ -219,7 +225,7 @@ class Plyr { case 'video': case 'audio': this.type = type; - this.provider = providers.html5; + this.provider = this.dash ? providers.mpd : providers.html5; // Get config from attributes if (this.media.hasAttribute('crossorigin')) { @@ -292,7 +298,7 @@ class Plyr { // Setup interface // If embed but not fully supported, build interface now to avoid flash of controls - if (this.isHTML5 || (this.isEmbed && !this.supported.ui)) { + if (this.isHTML5 || this.isMPD || (this.isEmbed && !this.supported.ui)) { ui.build.call(this); } @@ -308,7 +314,7 @@ class Plyr { } // Autoplay if required - if (this.isHTML5 && this.config.autoplay) { + if ((this.isHTML5 || this.isMPD) && this.config.autoplay) { this.once('canplay', () => silencePromise(this.play())); } @@ -344,6 +350,10 @@ class Plyr { return this.provider === providers.vimeo; } + get isMPD() { + return this.provider === providers.mpd; + } + get isVideo() { return this.type === types.video; } @@ -427,7 +437,7 @@ class Plyr { * Stop playback */ stop = () => { - if (this.isHTML5) { + if (this.isHTML5 || this.isMPD) { this.pause(); this.restart(); } else if (is.function(this.media.stop)) { @@ -631,7 +641,7 @@ class Plyr { */ get hasAudio() { // Assume yes for all non HTML5 (as we can't tell...) - if (!this.isHTML5) { + if (!this.isHTML5 || !this.isMPD) { return true; } @@ -724,6 +734,54 @@ class Plyr { return 16; } + /** + * Set audio track + */ + set audioTrack(input) { + const config = this.config.audioTrack; + const options = this.options.audioTrack; + + if (!options.length) { + return; + } + + let audioTrack = [ + !is.empty(input) && input, + this.storage.get('audioTrack'), + config.selected, + config.default, + ].find((e)=>{return !is.empty(e)}); + + let updateStorage = true; + + if (!options.includes(audioTrack)) { + const value = closest(options, audioTrack); + this.debug.warn(`Unsupported audioTrack option: ${audioTrack}, using ${value} instead`); + audioTrack = value; + + // Don't update storage if quality is not supported + updateStorage = false; + } + + // Update config + config.selected = audioTrack; + + // Set quality + this.media.audioTrack = audioTrack; + + // Save to storage + if (updateStorage) { + this.storage.set({ audioTrack }); + } + } + + /** + * Get current audio track + */ + get audioTrack() { + return this.media.audioTrack; + } + /** * Set playback quality * Currently HTML5 & YouTube only @@ -1199,7 +1257,7 @@ class Plyr { clearTimeout(this.timers.resized); // Provider specific stuff - if (this.isHTML5) { + if (this.isHTML5 || this.isMPD) { // Restore native video controls ui.toggleNativeControls.call(this, true); diff --git a/src/js/ui.js b/src/js/ui.js index 31eadf294..83206d0da 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -20,7 +20,7 @@ const ui = { // Toggle native HTML5 media controls toggleNativeControls(toggle = false) { - if (toggle && this.isHTML5) { + if (toggle && (this.isHTML5 || this.isMPD)) { this.media.setAttribute('controls', ''); } else { this.media.removeAttribute('controls'); @@ -57,7 +57,7 @@ const ui = { ui.toggleNativeControls.call(this); // Setup captions for HTML5 - if (this.isHTML5) { + if (this.isHTML5 || this.isMPD) { captions.setup.call(this); } @@ -92,11 +92,11 @@ const ui = { toggleClass( this.elements.container, this.config.classNames.pip.supported, - support.pip && this.isHTML5 && this.isVideo, + support.pip && (this.isHTML5 || this.isMPD) && this.isVideo, ); // Check for airplay support - toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); + toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && (this.isHTML5 || this.isMPD)); // Add iOS class toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos); diff --git a/src/js/utils/i18n.js b/src/js/utils/i18n.js index 708685272..34b2c14c6 100644 --- a/src/js/utils/i18n.js +++ b/src/js/utils/i18n.js @@ -13,6 +13,7 @@ const resources = { html5: 'HTML5', vimeo: 'Vimeo', youtube: 'YouTube', + mpd: 'MPEG-DASH', }; const i18n = { diff --git a/src/js/utils/style.js b/src/js/utils/style.js index e05e058f0..134d05922 100644 --- a/src/js/utils/style.js +++ b/src/js/utils/style.js @@ -74,7 +74,7 @@ export function getAspectRatio(input) { } // Get from HTML5 video - if (ratio === null && this.isHTML5) { + if (ratio === null && (this.isHTML5 || this.isMPD)) { const { videoWidth, videoHeight } = this.media; ratio = [videoWidth, videoHeight]; } @@ -115,7 +115,7 @@ export function setAspectRatio(input) { } else { this.media.style.transform = `translateY(-${offset}%)`; } - } else if (this.isHTML5) { + } else if (this.isHTML5 || this.isMPD) { wrapper.classList.add(this.config.classNames.videoFixedRatio); } From 1dca9c5465e416262f1ccc79c9a466a613777ad1 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Fri, 22 Apr 2022 21:26:09 +0300 Subject: [PATCH 02/40] mpd: remove unnecessary code --- src/js/controls.js | 13 +++++-------- src/js/plugins/mpd.js | 3 ++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/js/controls.js b/src/js/controls.js index bb4e59f60..6e71ea330 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -529,7 +529,6 @@ const controls = { case 'audioTrack': this.audioTrack = value; - // controls.updateSetting.call(this, type, list); break; default: @@ -1114,7 +1113,6 @@ const controls = { }, setAudioTrackMenu(options) { - console.log(this.elements.settings.panels); // Menu required if (!is.element(this.elements.settings.panels.audioTrack)) { return; @@ -1681,14 +1679,13 @@ const controls = { } if (this.isMPD) { - setQualityMenu.call(this, mpd.getQualityOptions.call(this)); - this.dash.on('periodSwitchCompleted', () => { + const updateSettings = () => { setQualityMenu.call(this, mpd.getQualityOptions.call(this)); - }); - - setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); - this.dash.on('periodSwitchCompleted', () => { setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); + }; + updateSettings(); + this.dash.on('periodSwitchCompleted', () => { + updateSettings(); }); } diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 787a6d996..b1a162f01 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -43,7 +43,6 @@ const mpd = { Object.defineProperty(player.media, 'quality', { get() { const currentIndex = player.dash.getQualityFor('video'); - console.log("get", "quality", currentIndex); if(currentIndex){ return player.dash.getBitrateInfoListFor('video')[currentIndex].height; } @@ -59,9 +58,11 @@ const mpd = { }; if (input === 0x7fffffff) { + // Auto quality cfg.streaming.abr.autoSwitchBitrate['video'] = true; player.dash.updateSettings(cfg); } else { + // Get quality by height const currentIndex = player.dash.getQualityFor('video'); const currentHeight = (currentIndex) ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; for (const bitrate of player.dash.getBitrateInfoListFor('video')) { From 25955c6f894a3867dec2a449615ebf368f1b0357 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Fri, 22 Apr 2022 22:01:54 +0300 Subject: [PATCH 03/40] mpd: Update current quality logic --- src/js/plugins/mpd.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index b1a162f01..19ff34b30 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -42,11 +42,16 @@ const mpd = { // Quality Object.defineProperty(player.media, 'quality', { get() { + const settings = player.dash.getSettings(); + if (settings.streaming && settings.streaming.abr && settings.streaming.abr.autoSwitchBitrate && settings.streaming.abr.autoSwitchBitrate.video) { + return 0x7fffffff; + } const currentIndex = player.dash.getQualityFor('video'); - if(currentIndex){ - return player.dash.getBitrateInfoListFor('video')[currentIndex].height; + const bitrateList = player.dash.getBitrateInfoListFor('video'); + if(typeof currentIndex === 'number' && bitrateList[currentIndex]){ + return bitrateList[currentIndex].height; } - return 0x7fffffff; + return 0; }, set(input) { const cfg = { From 1c6bbb53be4e16a42d80efe0c9da405246ebe0f6 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Fri, 22 Apr 2022 22:28:05 +0300 Subject: [PATCH 04/40] mpd: Video track change --- src/js/config/defaults.js | 19 +++++++--- src/js/controls.js | 79 +++++++++++++++++++++++++++++++++++++-- src/js/listeners.js | 6 +++ src/js/plugins/mpd.js | 48 +++++++++++++++++++++++- src/js/plyr.js | 48 ++++++++++++++++++++++++ 5 files changed, 189 insertions(+), 11 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index f90cb3faa..d0e6b7620 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -90,9 +90,15 @@ const defaults = { }, audioTrack: { - default: 'Default', - // The options to display in the UI, if available for the source media - options: ['Default'], + default: 'default', + options: ['default'], + forced: false, + onChange: null, + }, + + videoTrack: { + default: 'default', + options: ['default'], forced: false, onChange: null, }, @@ -153,7 +159,7 @@ const defaults = { // 'download', 'fullscreen', ], - settings: ['captions', 'quality', 'speed', 'audioTrack'], + settings: ['captions', 'quality', 'speed', 'audioTrack', 'videoTrack'], // Localisation i18n: { @@ -182,7 +188,8 @@ const defaults = { pip: 'PIP', menuBack: 'Go back to previous menu', speed: 'Speed', - audioTrack: 'Audio track', + audioTrack: 'Audio Track', + videoTrack: 'Video Track', normal: 'Normal', quality: 'Quality', loop: 'Loop', @@ -288,6 +295,7 @@ const defaults = { // MPEG-DASH 'audiotrackchange', + 'videotrackchange', // Ads 'adsloaded', @@ -333,6 +341,7 @@ const defaults = { language: '[data-plyr="language"]', quality: '[data-plyr="quality"]', audioTrack: '[data-plyr="audioTrack"]', + videoTrack: '[data-plyr="videoTrack"]', }, display: { currentTime: '.plyr__time--current', diff --git a/src/js/controls.js b/src/js/controls.js index 6e71ea330..d90a662bf 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -531,6 +531,10 @@ const controls = { this.audioTrack = value; break; + case 'videoTrack': + this.videoTrack = value; + break; + default: break; } @@ -831,6 +835,8 @@ const controls = { if (setting === 'audioTrack') { value = this.audioTrack; + } else if (setting === 'videoTrack') { + value = this.videoTrack; } else if (setting === 'captions') { value = this.currentTrack; } else { @@ -880,13 +886,28 @@ const controls = { getLabel(setting, value) { switch (setting) { case 'audioTrack': - const label = i18n.get(`audioTrack.${value}`, this.config); + if(value) { + const label = i18n.get(`audioTrack.${value}`, this.config); + + if (!label.length) { + return `${value}`; + } - if (!label.length) { - return `${value}`; + return label; } + return 'Audio Track'; - return label; + case 'videoTrack': + if(value) { + const label = i18n.get(`videoTrack.${value}`, this.config); + + if (!label.length) { + return `${value}`; + } + + return label; + } + return 'Video Track'; case 'speed': return value === 1 ? i18n.get('normal', this.config) : `${value}×`; @@ -1159,6 +1180,53 @@ const controls = { controls.updateSetting.call(this, type, list); }, + setVideoTrackMenu(options) { + // Menu required + if (!is.element(this.elements.settings.panels.videoTrack)) { + return; + } + + const type = 'videoTrack'; + const list = this.elements.settings.panels.videoTrack.querySelector('[role="menu"]'); + + // Set options if passed and filter based on uniqueness and config + if (is.array(options)) { + this.options.videoTrack = dedupe(options); + } + + // Toggle the pane and tab + const toggle = !is.empty(this.options.videoTrack) && this.options.videoTrack.length > 1; + controls.toggleMenuButton.call(this, type, toggle); + + // Empty the menu + emptyElement(list); + + // Check if we need to toggle the parent + controls.checkMenu.call(this); + + // If we're hiding, nothing more to do + if (!toggle) { + return; + } + + // Sort options by the config and then render options + this.options.videoTrack + .sort((a, b) => { + const sorting = this.config.videoTrack.options; + return sorting.indexOf(a) > sorting.indexOf(b) ? 1 : -1; + }) + .forEach((videoTrack) => { + controls.createMenuItem.call(this, { + value: videoTrack, + list, + type, + title: controls.getLabel.call(this, 'videoTrack', videoTrack), + }); + }); + + controls.updateSetting.call(this, type, list); + }, + // Check if we need to hide/show the settings menu checkMenu() { const { buttons } = this.elements.settings; @@ -1336,6 +1404,7 @@ const controls = { setQualityMenu, setSpeedMenu, setAudioTrackMenu, + setVideoTrackMenu, showMenuPanel, } = controls; this.elements.controls = null; @@ -1682,6 +1751,7 @@ const controls = { const updateSettings = () => { setQualityMenu.call(this, mpd.getQualityOptions.call(this)); setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); + setVideoTrackMenu.call(this, mpd.getVideoTrackOptions.call(this)); }; updateSettings(); this.dash.on('periodSwitchCompleted', () => { @@ -1742,6 +1812,7 @@ const controls = { speed: this.speed, quality: this.quality, audioTrack: this.audioTrack, + videoTrack: this.videoTrack, captions: captions.getLabel.call(this), // TODO: Looping // loop: 'None', diff --git a/src/js/listeners.js b/src/js/listeners.js index 91d8da8e3..0f2c50af4 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -499,6 +499,12 @@ class Listeners { controls.updateSetting.call(player, 'audioTrack', null, event.detail.audioTrack); }); + // Video track change + on.call(player, player.media, 'videotrackchange', (event) => { + // Update UI + controls.updateSetting.call(player, 'videoTrack', null, event.detail.videoTrack); + }); + // Update download link when ready and if quality changes on.call(player, player.media, 'ready qualitychange', () => { controls.setDownloadUrl.call(player); diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 19ff34b30..4bc298c38 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -24,6 +24,14 @@ const mpd = { return audioTrackList; }, + getVideoTrackOptions() { + const videoTrackList = this.dash.getTracksFor('video').map((videoTrack) => { + return videoTrack.id; + }); + + return videoTrackList; + }, + setup() { if (!this.isMPD) { return; @@ -102,8 +110,10 @@ const mpd = { if (currentTrack) { return currentTrack.id; } - return "Default"; - }catch(e){} + }catch(e){ + + } + return "default"; }, set(input) { const cfg = { @@ -133,6 +143,40 @@ const mpd = { }); }, }); + + // Video track + Object.defineProperty(player.media, 'videoTrack', { + get() { + try { + const currentTrack = player.dash.getCurrentTrackFor('video'); + if (currentTrack) { + return currentTrack.id; + } + }catch(e){ + + } + return "default"; + }, + set(input) { + for (const track of player.dash.getTracksFor('video')) { + if (track.id === input) { + // Update video track + player.dash.setCurrentTrack(track); + break; + } + } + + // If we're using an external handler... + if (player.config.videoTrack.forced && is.function(player.config.videoTrack.onChange)) { + player.config.videoTrack.onChange(input); + } + + // Trigger change event + triggerEvent.call(player, player.media, 'videotrackchange', false, { + videoTrack: input, + }); + }, + }); }, }; diff --git a/src/js/plyr.js b/src/js/plyr.js index e68ac07cb..27dabb638 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -782,6 +782,54 @@ class Plyr { return this.media.audioTrack; } + /** + * Set video track + */ + set videoTrack(input) { + const config = this.config.videoTrack; + const options = this.options.videoTrack; + + if (!options.length) { + return; + } + + let videoTrack = [ + !is.empty(input) && input, + this.storage.get('videoTrack'), + config.selected, + config.default, + ].find((e)=>{return !is.empty(e)}); + + let updateStorage = true; + + if (!options.includes(videoTrack)) { + const value = closest(options, videoTrack); + this.debug.warn(`Unsupported videoTrack option: ${videoTrack}, using ${value} instead`); + videoTrack = value; + + // Don't update storage if quality is not supported + updateStorage = false; + } + + // Update config + config.selected = videoTrack; + + // Set quality + this.media.videoTrack = videoTrack; + + // Save to storage + if (updateStorage) { + this.storage.set({ videoTrack }); + } + } + + /** + * Get current video track + */ + get videoTrack() { + return this.media.videoTrack; + } + /** * Set playback quality * Currently HTML5 & YouTube only From e7b7f8862be8574a626057ffb3f621a9ac2991e0 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Fri, 22 Apr 2022 23:10:18 +0300 Subject: [PATCH 05/40] mpd: Events for track change --- src/js/config/defaults.js | 3 +++ src/js/controls.js | 12 +++--------- src/js/listeners.js | 21 +++++++++++++++++++++ src/js/plugins/mpd.js | 21 +++++++++++++++++++++ 4 files changed, 48 insertions(+), 9 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index d0e6b7620..c64c3abd5 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -296,6 +296,9 @@ const defaults = { // MPEG-DASH 'audiotrackchange', 'videotrackchange', + 'qualitylistupdate', + 'audiotracklistupdate', + 'videotracklistupdate', // Ads 'adsloaded', diff --git a/src/js/controls.js b/src/js/controls.js index d90a662bf..ce7e8dfad 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -1748,15 +1748,9 @@ const controls = { } if (this.isMPD) { - const updateSettings = () => { - setQualityMenu.call(this, mpd.getQualityOptions.call(this)); - setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); - setVideoTrackMenu.call(this, mpd.getVideoTrackOptions.call(this)); - }; - updateSettings(); - this.dash.on('periodSwitchCompleted', () => { - updateSettings(); - }); + setQualityMenu.call(this, mpd.getQualityOptions.call(this)); + setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); + setVideoTrackMenu.call(this, mpd.getVideoTrackOptions.call(this)); } setSpeedMenu.call(this); diff --git a/src/js/listeners.js b/src/js/listeners.js index 0f2c50af4..09570e76c 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -505,6 +505,27 @@ class Listeners { controls.updateSetting.call(player, 'videoTrack', null, event.detail.videoTrack); }); + // Quality list update + on.call(player, player.media, 'qualitylistupdate', (event) => { + // Update UI + console.log(event.detail); + controls.setQualityMenu.call(player, event.detail.list); + }); + + // Audio track list update + on.call(player, player.media, 'audiotracklistupdate', (event) => { + // Update UI + console.log(event.detail); + controls.setAudioTrackMenu.call(player, event.detail.list); + }); + + // Video track list update + on.call(player, player.media, 'videotracklistupdate', (event) => { + // Update UI + console.log(event.detail); + controls.setVideoTrackMenu.call(player, event.detail.list); + }); + // Update download link when ready and if quality changes on.call(player, player.media, 'ready qualitychange', () => { controls.setDownloadUrl.call(player); diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 4bc298c38..eaea56785 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -141,6 +141,9 @@ const mpd = { triggerEvent.call(player, player.media, 'audiotrackchange', false, { audioTrack: input, }); + triggerEvent.call(player, player.media, 'qualitylistupdate', false, { + list: mpd.getQualityOptions.call(player), + }); }, }); @@ -175,8 +178,26 @@ const mpd = { triggerEvent.call(player, player.media, 'videotrackchange', false, { videoTrack: input, }); + triggerEvent.call(player, player.media, 'qualitylistupdate', false, { + list: mpd.getQualityOptions.call(player), + }); }, }); + + // Update settings list + const triggerEvents = () => { + triggerEvent.call(player, player.media, 'qualitylistupdate', false, { + list: mpd.getQualityOptions.call(player), + }); + triggerEvent.call(player, player.media, 'audiotracklistupdate', false, { + list: mpd.getAudioTrackOptions.call(player), + }); + triggerEvent.call(player, player.media, 'videotracklistupdate', false, { + list: mpd.getVideoTrackOptions.call(player), + }); + } + + player.dash.on('periodSwitchCompleted', triggerEvents); }, }; From c6e9ed649f860e3da5d3dc0c36b7d5f68f7764e0 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 07:42:05 +0300 Subject: [PATCH 06/40] mpd: Label support and tracks without `id` --- src/js/config/defaults.js | 10 ++++ src/js/controls.js | 30 ++++++---- src/js/listeners.js | 15 ++++- src/js/plugins/mpd.js | 121 ++++++++++++++++++++++++++++++++------ 4 files changed, 144 insertions(+), 32 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index c64c3abd5..9ca7eeeec 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -211,6 +211,14 @@ const defaults = { 576: 'SD', 480: 'SD', }, + audioTrackLabel: { + mpdLabels: {}, + labels: {}, + }, + videoTrackLabel: { + mpdLabels: {}, + labels: {}, + }, }, // URLs @@ -299,6 +307,8 @@ const defaults = { 'qualitylistupdate', 'audiotracklistupdate', 'videotracklistupdate', + 'audiotracklabelsupdate', + 'videotracklabelsupdate', // Ads 'adsloaded', diff --git a/src/js/controls.js b/src/js/controls.js index ce7e8dfad..2976105ec 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -887,27 +887,37 @@ const controls = { switch (setting) { case 'audioTrack': if(value) { - const label = i18n.get(`audioTrack.${value}`, this.config); + let label; - if (!label.length) { - return `${value}`; + label = i18n.get(`audioTrackLabel.labels.${value}`, this.config); + if (label.length) { + return label; } - return label; + label = i18n.get(`audioTrackLabel.mpdLabels.${value}`, this.config); + if (label.length) { + return label; + } + + return `${value}`; } - return 'Audio Track'; case 'videoTrack': if(value) { - const label = i18n.get(`videoTrack.${value}`, this.config); + let label; - if (!label.length) { - return `${value}`; + label = i18n.get(`videoTrackLabel.labels.${value}`, this.config); + if (label.length) { + return label; } - return label; + label = i18n.get(`videoTrackLabel.mpdLabels.${value}`, this.config); + if (label.length) { + return label; + } + + return `${value}`; } - return 'Video Track'; case 'speed': return value === 1 ? i18n.get('normal', this.config) : `${value}×`; diff --git a/src/js/listeners.js b/src/js/listeners.js index 09570e76c..b28f7dab9 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -508,24 +508,33 @@ class Listeners { // Quality list update on.call(player, player.media, 'qualitylistupdate', (event) => { // Update UI - console.log(event.detail); controls.setQualityMenu.call(player, event.detail.list); }); // Audio track list update on.call(player, player.media, 'audiotracklistupdate', (event) => { // Update UI - console.log(event.detail); controls.setAudioTrackMenu.call(player, event.detail.list); }); // Video track list update on.call(player, player.media, 'videotracklistupdate', (event) => { // Update UI - console.log(event.detail); controls.setVideoTrackMenu.call(player, event.detail.list); }); + // Audio track labels update + on.call(player, player.media, 'audiotracklabelsupdate', (event) => { + player.config.i18n.audioTrackLabel.mpdLabels = event.detail.list; + controls.setAudioTrackMenu.call(player, player.options.audioTrack); + }); + + // Video track labels update + on.call(player, player.media, 'videotracklabelsupdate', (event) => { + player.config.i18n.videoTrackLabel.mpdLabels = event.detail.list; + controls.setVideoTrackMenu.call(player, player.options.videoTrack); + }); + // Update download link when ready and if quality changes on.call(player, player.media, 'ready qualitychange', () => { controls.setDownloadUrl.call(player); diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index eaea56785..853955b31 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -7,7 +7,61 @@ import is from '../utils/is'; import { setAspectRatio } from '../utils/style'; const mpd = { - // Get quality levels + getTrackName(track) { + if(track.id){ + return track.id; + } + return `_index${track.index}`; + }, + + getTrackLabel(track) { + // Normal label + const browserLanguage = navigator.language; + for (const label of track.labels) { + if (label.lang && label.lang === browserLanguage) { + return label.text; + } + } + if(track.labels[0]){ + return track.labels[0].text; + } + + // No label + const outputStr = []; + if(track.lang){ + outputStr.push(`Lang: ${track.lang}`); + } + if(track.id){ + outputStr.push(`ID: ${track.id}`); + } + outputStr.push(`Index: ${track.index}`); + return outputStr.join(", "); + }, + + getVideoTrackLabels() { + const labels = {}; + + for (const track of this.dash.getTracksFor('video')) { + const name = mpd.getTrackName.call(this, track); + const text = mpd.getTrackLabel.call(this, track); + labels[name] = text; + } + + return labels; + }, + + getAudioTrackLabels() { + const labels = {}; + + for (const track of this.dash.getTracksFor('audio')) { + const name = mpd.getTrackName.call(this, track); + const text = mpd.getTrackLabel.call(this, track); + labels[name] = text; + } + + return labels; + }, + getQualityOptions() { const qualityList = this.dash.getBitrateInfoListFor('video').map((bitrate) => { return bitrate.height; @@ -18,7 +72,7 @@ const mpd = { getAudioTrackOptions() { const audioTrackList = this.dash.getTracksFor('audio').map((audioTrack) => { - return audioTrack.id; + return mpd.getTrackName.call(this, audioTrack); }); return audioTrackList; @@ -26,7 +80,7 @@ const mpd = { getVideoTrackOptions() { const videoTrackList = this.dash.getTracksFor('video').map((videoTrack) => { - return videoTrack.id; + return mpd.getTrackName.call(this, videoTrack); }); return videoTrackList; @@ -108,12 +162,11 @@ const mpd = { try { const currentTrack = player.dash.getCurrentTrackFor('audio'); if (currentTrack) { - return currentTrack.id; + return mpd.getTrackName.call(player, currentTrack); } }catch(e){ } - return "default"; }, set(input) { const cfg = { @@ -123,12 +176,25 @@ const mpd = { } } }; - for (const track of player.dash.getTracksFor('audio')) { - if (track.id === input) { - // Update audio track - player.dash.updateSettings(cfg); - player.dash.setCurrentTrack(track); - break; + player.dash.updateSettings(cfg); + + const match = input.match(/^_index([0-9]+)$/); + if (match) { + const index = parseInt(match[1]); + for (const track of player.dash.getTracksFor('audio')) { + if (track.index === index) { + // Update video track + player.dash.setCurrentTrack(track); + break; + } + } + } else { + for (const track of player.dash.getTracksFor('audio')) { + if (track.id === input) { + // Update audio track + player.dash.setCurrentTrack(track); + break; + } } } @@ -153,19 +219,30 @@ const mpd = { try { const currentTrack = player.dash.getCurrentTrackFor('video'); if (currentTrack) { - return currentTrack.id; + return mpd.getTrackName.call(player, currentTrack); } }catch(e){ } - return "default"; }, set(input) { - for (const track of player.dash.getTracksFor('video')) { - if (track.id === input) { - // Update video track - player.dash.setCurrentTrack(track); - break; + const match = input.match(/^_index([0-9]+)$/); + if (match) { + const index = parseInt(match[1]); + for (const track of player.dash.getTracksFor('video')) { + if (track.index === index) { + // Update video track + player.dash.setCurrentTrack(track); + break; + } + } + } else { + for (const track of player.dash.getTracksFor('video')) { + if (track.id === input) { + // Update video track + player.dash.setCurrentTrack(track); + break; + } } } @@ -195,7 +272,13 @@ const mpd = { triggerEvent.call(player, player.media, 'videotracklistupdate', false, { list: mpd.getVideoTrackOptions.call(player), }); - } + triggerEvent.call(player, player.media, 'audiotracklabelsupdate', false, { + list: mpd.getAudioTrackLabels.call(player), + }); + triggerEvent.call(player, player.media, 'videotracklabelsupdate', false, { + list: mpd.getVideoTrackLabels.call(player), + }); + }; player.dash.on('periodSwitchCompleted', triggerEvents); }, From 231bbfeb454792cb4f4812a211cae7da053fdd83 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 08:01:55 +0300 Subject: [PATCH 07/40] mpd: Refactor some functions --- src/js/plugins/mpd.js | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 853955b31..73555c3c0 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -116,29 +116,29 @@ const mpd = { return 0; }, set(input) { - const cfg = { - 'streaming': { - 'abr': { - 'autoSwitchBitrate': {} - } - } + const dashConfig = { + streaming: { + abr: { + autoSwitchBitrate: {}, + }, + }, }; if (input === 0x7fffffff) { - // Auto quality - cfg.streaming.abr.autoSwitchBitrate['video'] = true; - player.dash.updateSettings(cfg); + // Enabling auto switch quality + dashConfig.streaming.abr.autoSwitchBitrate.video = true; + player.dash.updateSettings(dashConfig); } else { // Get quality by height const currentIndex = player.dash.getQualityFor('video'); const currentHeight = (currentIndex) ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; for (const bitrate of player.dash.getBitrateInfoListFor('video')) { if (bitrate.height === input) { - // Disable auto switch quality - cfg.streaming.abr.autoSwitchBitrate['video'] = false; - player.dash.updateSettings(cfg); + // Disabling auto switch quality + dashConfig.streaming.abr.autoSwitchBitrate.video = false; + player.dash.updateSettings(dashConfig); // Update quality - player.dash.setQualityFor('video', bitrate.qualityIndex, (bitrate.height > currentHeight)); + player.dash.setQualityFor('video', bitrate.qualityIndex, bitrate.height > currentHeight); break; } } @@ -169,14 +169,14 @@ const mpd = { } }, set(input) { - const cfg = { - 'streaming': { - 'trackSwitchMode': { - 'audio': 'alwaysReplace' - } - } - }; - player.dash.updateSettings(cfg); + // Replace already buffered frames + player.dash.updateSettings({ + streaming: { + trackSwitchMode: { + audio: 'alwaysReplace', + }, + }, + }); const match = input.match(/^_index([0-9]+)$/); if (match) { From bc93372d48bf0c76d01dcae50195dbd29c62309c Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 08:32:26 +0300 Subject: [PATCH 08/40] mpd: Add MPD support to `ads` plugin --- src/js/plugins/ads.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/plugins/ads.js b/src/js/plugins/ads.js index 486115fa8..d73716a8c 100644 --- a/src/js/plugins/ads.js +++ b/src/js/plugins/ads.js @@ -67,7 +67,7 @@ class Ads { const { config } = this; return ( - this.player.isHTML5 && + (this.player.isHTML5 || this.player.isMPD) && this.player.isVideo && config.enabled && (!is.empty(config.publisherId) || is.url(config.tagUrl)) From 8086e93ac120ba39184d146fc5f82ccfbe097016 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 08:37:44 +0300 Subject: [PATCH 09/40] mpd: Remove caption setup call when MPD --- src/js/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/ui.js b/src/js/ui.js index 83206d0da..cb86cd01f 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -57,7 +57,7 @@ const ui = { ui.toggleNativeControls.call(this); // Setup captions for HTML5 - if (this.isHTML5 || this.isMPD) { + if (this.isHTML5) { captions.setup.call(this); } From 4f8c0acfb786a67af2bfecf9d89e86f64f865c10 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 08:42:58 +0300 Subject: [PATCH 10/40] mpd: Labels for tracks --- src/js/controls.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/js/controls.js b/src/js/controls.js index 2976105ec..53a182cd6 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -1758,6 +1758,8 @@ const controls = { } if (this.isMPD) { + this.config.i18n.audioTrackLabel.mpdLabels = mpd.getAudioTrackLabels.call(this); + this.config.i18n.videoTrackLabel.mpdLabels = mpd.getVideoTrackLabels.call(this); setQualityMenu.call(this, mpd.getQualityOptions.call(this)); setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); setVideoTrackMenu.call(this, mpd.getVideoTrackOptions.call(this)); From de09dcf7c37c002b70646ee58cc7dcc3b3820bc1 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 08:47:51 +0300 Subject: [PATCH 11/40] mpd: playsinline --- src/js/plyr.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/js/plyr.js b/src/js/plyr.js index 27dabb638..49a64d9a4 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -318,6 +318,11 @@ class Plyr { this.once('canplay', () => silencePromise(this.play())); } + // playsinline for MPD + if (this.isMPD && this.config.playsinline) { + this.media.setAttribute('playsinline', ''); + } + // Seek time will be recorded (in listeners.js) so we can prevent hiding controls for a few seconds after seek this.lastSeekTime = 0; From 9b931949b03810f8aeef1dec00f28a6fe364ccdf Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 09:01:38 +0300 Subject: [PATCH 12/40] mpd: Support for int `id` --- src/js/plugins/mpd.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 73555c3c0..1b6682d03 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -178,7 +178,10 @@ const mpd = { }, }); - const match = input.match(/^_index([0-9]+)$/); + let match; + if (typeof input === 'string') { + match = input.match(/^_index([0-9]+)$/); + } if (match) { const index = parseInt(match[1]); for (const track of player.dash.getTracksFor('audio')) { @@ -226,7 +229,10 @@ const mpd = { } }, set(input) { - const match = input.match(/^_index([0-9]+)$/); + let match; + if (typeof input === 'string') { + match = input.match(/^_index([0-9]+)$/); + } if (match) { const index = parseInt(match[1]); for (const track of player.dash.getTracksFor('video')) { From 68a4b56f5b6a2e709cd8bc430dfb6ddc86da0bc3 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 10:33:44 +0300 Subject: [PATCH 13/40] mpd: Disable AirPlay support (DASH.js incompatible) --- src/js/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/ui.js b/src/js/ui.js index cb86cd01f..20fde62cd 100644 --- a/src/js/ui.js +++ b/src/js/ui.js @@ -96,7 +96,7 @@ const ui = { ); // Check for airplay support - toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && (this.isHTML5 || this.isMPD)); + toggleClass(this.elements.container, this.config.classNames.airplay.supported, support.airplay && this.isHTML5); // Add iOS class toggleClass(this.elements.container, this.config.classNames.isIos, browser.isIos); From 87a053404da2e9e0f6e41a79c567118b9743a2a3 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 10:47:14 +0300 Subject: [PATCH 14/40] mpd: Choosing the best bitrate --- src/js/plugins/mpd.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 1b6682d03..ee945189a 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -63,10 +63,12 @@ const mpd = { }, getQualityOptions() { - const qualityList = this.dash.getBitrateInfoListFor('video').map((bitrate) => { - return bitrate.height; - }); - + const qualityList = []; + for (const bitrate of this.dash.getBitrateInfoListFor('video')) { + if(!qualityList.includes(bitrate.height)){ + qualityList.push(bitrate.height); + } + } return [0x7fffffff, ...qualityList]; }, @@ -132,7 +134,17 @@ const mpd = { // Get quality by height const currentIndex = player.dash.getQualityFor('video'); const currentHeight = (currentIndex) ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; - for (const bitrate of player.dash.getBitrateInfoListFor('video')) { + const bitrateList = player.dash.getBitrateInfoListFor('video'); + bitrateList.sort(function(a,b){ + if (a.bitrate < b.bitrate) { + return 1; + } + if (a.bitrate > b.bitrate) { + return -1; + } + return 0; + }); + for (const bitrate of bitrateList) { if (bitrate.height === input) { // Disabling auto switch quality dashConfig.streaming.abr.autoSwitchBitrate.video = false; From 9dda8c911530a6ec94fb86cf908953bc0b0ec92e Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 11:13:44 +0300 Subject: [PATCH 15/40] mpd: `audioTrackLabel.mpdLabels` to `audioTrackMPDLabel` --- src/js/config/defaults.js | 18 ++++-------------- src/js/controls.js | 12 ++++++------ src/js/listeners.js | 4 ++-- src/js/plugins/mpd.js | 6 +++--- 4 files changed, 15 insertions(+), 25 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index 9ca7eeeec..19d481513 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -70,7 +70,7 @@ const defaults = { quality: { default: 576, // The options to display in the UI, if available for the source media - options: [0x7fffffff, 4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], + options: [2147483647, 4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], forced: false, onChange: null, }, @@ -90,15 +90,13 @@ const defaults = { }, audioTrack: { - default: 'default', - options: ['default'], + options: [], forced: false, onChange: null, }, videoTrack: { - default: 'default', - options: ['default'], + options: [], forced: false, onChange: null, }, @@ -201,7 +199,7 @@ const defaults = { enabled: 'Enabled', advertisement: 'Ad', qualityLabel: { - 0x7fffffff: 'Auto', + 2147483647: 'Auto', }, qualityBadge: { 2160: '4K', @@ -211,14 +209,6 @@ const defaults = { 576: 'SD', 480: 'SD', }, - audioTrackLabel: { - mpdLabels: {}, - labels: {}, - }, - videoTrackLabel: { - mpdLabels: {}, - labels: {}, - }, }, // URLs diff --git a/src/js/controls.js b/src/js/controls.js index 53a182cd6..4f9db303a 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -889,12 +889,12 @@ const controls = { if(value) { let label; - label = i18n.get(`audioTrackLabel.labels.${value}`, this.config); + label = i18n.get(`audioTrackLabel.${value}`, this.config); if (label.length) { return label; } - label = i18n.get(`audioTrackLabel.mpdLabels.${value}`, this.config); + label = i18n.get(`audioTrackMPDLabel.${value}`, this.config); if (label.length) { return label; } @@ -906,12 +906,12 @@ const controls = { if(value) { let label; - label = i18n.get(`videoTrackLabel.labels.${value}`, this.config); + label = i18n.get(`videoTrackLabel.${value}`, this.config); if (label.length) { return label; } - label = i18n.get(`videoTrackLabel.mpdLabels.${value}`, this.config); + label = i18n.get(`videoTrackMPDLabel.${value}`, this.config); if (label.length) { return label; } @@ -1758,8 +1758,8 @@ const controls = { } if (this.isMPD) { - this.config.i18n.audioTrackLabel.mpdLabels = mpd.getAudioTrackLabels.call(this); - this.config.i18n.videoTrackLabel.mpdLabels = mpd.getVideoTrackLabels.call(this); + this.config.i18n.audioTrackMPDLabel = mpd.getAudioTrackLabels.call(this); + this.config.i18n.videoTrackMPDLabel = mpd.getVideoTrackLabels.call(this); setQualityMenu.call(this, mpd.getQualityOptions.call(this)); setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); setVideoTrackMenu.call(this, mpd.getVideoTrackOptions.call(this)); diff --git a/src/js/listeners.js b/src/js/listeners.js index b28f7dab9..06d5c532e 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -525,13 +525,13 @@ class Listeners { // Audio track labels update on.call(player, player.media, 'audiotracklabelsupdate', (event) => { - player.config.i18n.audioTrackLabel.mpdLabels = event.detail.list; + player.config.i18n.audioTrackMPDLabel = event.detail.list; controls.setAudioTrackMenu.call(player, player.options.audioTrack); }); // Video track labels update on.call(player, player.media, 'videotracklabelsupdate', (event) => { - player.config.i18n.videoTrackLabel.mpdLabels = event.detail.list; + player.config.i18n.videoTrackMPDLabel = event.detail.list; controls.setVideoTrackMenu.call(player, player.options.videoTrack); }); diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index ee945189a..c230d2f5d 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -69,7 +69,7 @@ const mpd = { qualityList.push(bitrate.height); } } - return [0x7fffffff, ...qualityList]; + return [2147483647, ...qualityList]; }, getAudioTrackOptions() { @@ -108,7 +108,7 @@ const mpd = { get() { const settings = player.dash.getSettings(); if (settings.streaming && settings.streaming.abr && settings.streaming.abr.autoSwitchBitrate && settings.streaming.abr.autoSwitchBitrate.video) { - return 0x7fffffff; + return 2147483647; } const currentIndex = player.dash.getQualityFor('video'); const bitrateList = player.dash.getBitrateInfoListFor('video'); @@ -126,7 +126,7 @@ const mpd = { }, }; - if (input === 0x7fffffff) { + if (input === 2147483647) { // Enabling auto switch quality dashConfig.streaming.abr.autoSwitchBitrate.video = true; player.dash.updateSettings(dashConfig); From 44449f699f939a16305b934b7485f9bb7be1eca5 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 11:19:39 +0300 Subject: [PATCH 16/40] mpd: Remove `forced` from `audioTrack` & `videoTrack` --- src/js/config/defaults.js | 2 -- src/js/plugins/mpd.js | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index 19d481513..475a5688e 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -91,13 +91,11 @@ const defaults = { audioTrack: { options: [], - forced: false, onChange: null, }, videoTrack: { options: [], - forced: false, onChange: null, }, diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index c230d2f5d..dffb5eaf0 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -157,7 +157,7 @@ const mpd = { } // If we're using an external handler... - if (player.config.quality.forced && is.function(player.config.quality.onChange)) { + if (is.function(player.config.quality.onChange)) { player.config.quality.onChange(input); } @@ -214,7 +214,7 @@ const mpd = { } // If we're using an external handler... - if (player.config.audioTrack.forced && is.function(player.config.audioTrack.onChange)) { + if (is.function(player.config.audioTrack.onChange)) { player.config.audioTrack.onChange(input); } @@ -265,7 +265,7 @@ const mpd = { } // If we're using an external handler... - if (player.config.videoTrack.forced && is.function(player.config.videoTrack.onChange)) { + if (is.function(player.config.videoTrack.onChange)) { player.config.videoTrack.onChange(input); } From 232b48500645aaf02c67c2674c42d6e48f90fa40 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 11:35:43 +0300 Subject: [PATCH 17/40] mpd: `(e)=>{return !is.empty(e)}` to `e => e` --- src/js/plyr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/plyr.js b/src/js/plyr.js index 49a64d9a4..4c307b871 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -755,7 +755,7 @@ class Plyr { this.storage.get('audioTrack'), config.selected, config.default, - ].find((e)=>{return !is.empty(e)}); + ].find(e => e); let updateStorage = true; @@ -803,7 +803,7 @@ class Plyr { this.storage.get('videoTrack'), config.selected, config.default, - ].find((e)=>{return !is.empty(e)}); + ].find(e => e); let updateStorage = true; From f13b1e14bc8928d1f732ebd406c6067b69c21162 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 11:36:13 +0300 Subject: [PATCH 18/40] mpd: Changing some comments --- src/js/listeners.js | 2 ++ src/js/plyr.js | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/js/listeners.js b/src/js/listeners.js index 06d5c532e..a2619a4ca 100644 --- a/src/js/listeners.js +++ b/src/js/listeners.js @@ -525,12 +525,14 @@ class Listeners { // Audio track labels update on.call(player, player.media, 'audiotracklabelsupdate', (event) => { + // Update UI player.config.i18n.audioTrackMPDLabel = event.detail.list; controls.setAudioTrackMenu.call(player, player.options.audioTrack); }); // Video track labels update on.call(player, player.media, 'videotracklabelsupdate', (event) => { + // Update UI player.config.i18n.videoTrackMPDLabel = event.detail.list; controls.setVideoTrackMenu.call(player, player.options.videoTrack); }); diff --git a/src/js/plyr.js b/src/js/plyr.js index 4c307b871..ba44cf264 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -771,7 +771,7 @@ class Plyr { // Update config config.selected = audioTrack; - // Set quality + // Set audio track this.media.audioTrack = audioTrack; // Save to storage @@ -819,7 +819,7 @@ class Plyr { // Update config config.selected = videoTrack; - // Set quality + // Set video track this.media.videoTrack = videoTrack; // Save to storage From 3735316144228ef61690817db3f826eb3b8b2d36 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 11:38:37 +0300 Subject: [PATCH 19/40] mpd: Add values to `.ts` file --- src/js/plyr.d.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/js/plyr.d.ts b/src/js/plyr.d.ts index d9b242a1b..19018da98 100644 --- a/src/js/plyr.d.ts +++ b/src/js/plyr.d.ts @@ -102,6 +102,16 @@ declare class Plyr { */ quality: number; + /** + * Gets or sets the audio track for the player. The setter accepts a value from the options specified in your config. + */ + audioTrack: string; + + /** + * Gets or sets the video track for the player. The setter accepts a value from the options specified in your config. + */ + videoTrack: string; + /** * Gets or sets the current loop state of the player. */ From f27b5b9dc4d5811006fb8cff858ccd9296744f1a Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 11:50:06 +0300 Subject: [PATCH 20/40] mpd: Add some comments --- src/js/config/defaults.js | 3 +++ src/js/controls.js | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index 475a5688e..783602219 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -70,6 +70,7 @@ const defaults = { quality: { default: 576, // The options to display in the UI, if available for the source media + // 2147483647 - "Auto" for MPEG-DASH options: [2147483647, 4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], forced: false, onChange: null, @@ -89,11 +90,13 @@ const defaults = { options: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 4], }, + // Audio Tracks (MPEG-DASH) audioTrack: { options: [], onChange: null, }, + // Video Tracks (MPEG-DASH) videoTrack: { options: [], onChange: null, diff --git a/src/js/controls.js b/src/js/controls.js index 4f9db303a..b36db75e9 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -1143,6 +1143,7 @@ const controls = { controls.updateSetting.call(this, type, list); }, + // Set a list of available audio tracks setAudioTrackMenu(options) { // Menu required if (!is.element(this.elements.settings.panels.audioTrack)) { @@ -1190,6 +1191,7 @@ const controls = { controls.updateSetting.call(this, type, list); }, + // Set a list of available video tracks setVideoTrackMenu(options) { // Menu required if (!is.element(this.elements.settings.panels.videoTrack)) { @@ -1758,8 +1760,10 @@ const controls = { } if (this.isMPD) { + // Get track labels this.config.i18n.audioTrackMPDLabel = mpd.getAudioTrackLabels.call(this); this.config.i18n.videoTrackMPDLabel = mpd.getVideoTrackLabels.call(this); + // Set available tracks and quality levels setQualityMenu.call(this, mpd.getQualityOptions.call(this)); setAudioTrackMenu.call(this, mpd.getAudioTrackOptions.call(this)); setVideoTrackMenu.call(this, mpd.getVideoTrackOptions.call(this)); From 2c67dbae116ada20b3b34c2665b51b23e4a78514 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:06:02 +0300 Subject: [PATCH 21/40] mpd: Add comments to `mpd.js` file --- src/js/plugins/mpd.js | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index dffb5eaf0..39654cec0 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -7,6 +7,7 @@ import is from '../utils/is'; import { setAspectRatio } from '../utils/style'; const mpd = { + // Get name of track getTrackName(track) { if(track.id){ return track.id; @@ -14,6 +15,7 @@ const mpd = { return `_index${track.index}`; }, + // Get human-like name of track getTrackLabel(track) { // Normal label const browserLanguage = navigator.language; @@ -26,7 +28,7 @@ const mpd = { return track.labels[0].text; } - // No label + // When label doesn't exist const outputStr = []; if(track.lang){ outputStr.push(`Lang: ${track.lang}`); @@ -38,30 +40,29 @@ const mpd = { return outputStr.join(", "); }, + // Get video labels getVideoTrackLabels() { const labels = {}; - for (const track of this.dash.getTracksFor('video')) { const name = mpd.getTrackName.call(this, track); const text = mpd.getTrackLabel.call(this, track); labels[name] = text; } - return labels; }, + // Get audio labels getAudioTrackLabels() { const labels = {}; - for (const track of this.dash.getTracksFor('audio')) { const name = mpd.getTrackName.call(this, track); const text = mpd.getTrackLabel.call(this, track); labels[name] = text; } - return labels; }, + // Get quality levels getQualityOptions() { const qualityList = []; for (const bitrate of this.dash.getBitrateInfoListFor('video')) { @@ -69,22 +70,23 @@ const mpd = { qualityList.push(bitrate.height); } } + // 2147483647 - "Auto" return [2147483647, ...qualityList]; }, + // Get audio tracks getAudioTrackOptions() { const audioTrackList = this.dash.getTracksFor('audio').map((audioTrack) => { return mpd.getTrackName.call(this, audioTrack); }); - return audioTrackList; }, + // Get video tracks getVideoTrackOptions() { const videoTrackList = this.dash.getTracksFor('video').map((videoTrack) => { return mpd.getTrackName.call(this, videoTrack); }); - return videoTrackList; }, @@ -106,16 +108,17 @@ const mpd = { // Quality Object.defineProperty(player.media, 'quality', { get() { + // Check "auto" attribute const settings = player.dash.getSettings(); if (settings.streaming && settings.streaming.abr && settings.streaming.abr.autoSwitchBitrate && settings.streaming.abr.autoSwitchBitrate.video) { return 2147483647; } + // Get quality value const currentIndex = player.dash.getQualityFor('video'); const bitrateList = player.dash.getBitrateInfoListFor('video'); if(typeof currentIndex === 'number' && bitrateList[currentIndex]){ return bitrateList[currentIndex].height; } - return 0; }, set(input) { const dashConfig = { @@ -126,6 +129,7 @@ const mpd = { }, }; + // If "auto" if (input === 2147483647) { // Enabling auto switch quality dashConfig.streaming.abr.autoSwitchBitrate.video = true; @@ -134,6 +138,7 @@ const mpd = { // Get quality by height const currentIndex = player.dash.getQualityFor('video'); const currentHeight = (currentIndex) ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; + // Sorting bitrates by DESC const bitrateList = player.dash.getBitrateInfoListFor('video'); bitrateList.sort(function(a,b){ if (a.bitrate < b.bitrate) { @@ -144,6 +149,7 @@ const mpd = { } return 0; }); + // Brute all bitrates for (const bitrate of bitrateList) { if (bitrate.height === input) { // Disabling auto switch quality @@ -171,6 +177,7 @@ const mpd = { // Audio track Object.defineProperty(player.media, 'audioTrack', { get() { + // Try-catch in case of empty streamInfo try { const currentTrack = player.dash.getCurrentTrackFor('audio'); if (currentTrack) { @@ -195,6 +202,7 @@ const mpd = { match = input.match(/^_index([0-9]+)$/); } if (match) { + // Brute by index const index = parseInt(match[1]); for (const track of player.dash.getTracksFor('audio')) { if (track.index === index) { @@ -204,6 +212,7 @@ const mpd = { } } } else { + // Brute by id for (const track of player.dash.getTracksFor('audio')) { if (track.id === input) { // Update audio track @@ -231,6 +240,7 @@ const mpd = { // Video track Object.defineProperty(player.media, 'videoTrack', { get() { + // Try-catch in case of empty streamInfo try { const currentTrack = player.dash.getCurrentTrackFor('video'); if (currentTrack) { @@ -246,6 +256,7 @@ const mpd = { match = input.match(/^_index([0-9]+)$/); } if (match) { + // Brute by index const index = parseInt(match[1]); for (const track of player.dash.getTracksFor('video')) { if (track.index === index) { @@ -255,6 +266,7 @@ const mpd = { } } } else { + // Brute by id for (const track of player.dash.getTracksFor('video')) { if (track.id === input) { // Update video track @@ -279,7 +291,7 @@ const mpd = { }, }); - // Update settings list + // Update settings list when perion changed const triggerEvents = () => { triggerEvent.call(player, player.media, 'qualitylistupdate', false, { list: mpd.getQualityOptions.call(player), From fa4d22307d03ef0667d0ab2c80d3a40542c29adc Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:07:47 +0300 Subject: [PATCH 22/40] mpd: Little refactoring --- src/js/plugins/mpd.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 39654cec0..204bed305 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -183,7 +183,7 @@ const mpd = { if (currentTrack) { return mpd.getTrackName.call(player, currentTrack); } - }catch(e){ + }catch{ } }, @@ -246,7 +246,7 @@ const mpd = { if (currentTrack) { return mpd.getTrackName.call(player, currentTrack); } - }catch(e){ + }catch{ } }, @@ -292,7 +292,7 @@ const mpd = { }); // Update settings list when perion changed - const triggerEvents = () => { + player.dash.on('periodSwitchCompleted', ()=>{ triggerEvent.call(player, player.media, 'qualitylistupdate', false, { list: mpd.getQualityOptions.call(player), }); @@ -308,9 +308,7 @@ const mpd = { triggerEvent.call(player, player.media, 'videotracklabelsupdate', false, { list: mpd.getVideoTrackLabels.call(player), }); - }; - - player.dash.on('periodSwitchCompleted', triggerEvents); + }); }, }; From 8f6bffe7433c5fa87f483633ce063ea65a796477 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:13:11 +0300 Subject: [PATCH 23/40] mpd: Remove dirty hack from switch-case construction --- src/js/controls.js | 48 ++++++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/js/controls.js b/src/js/controls.js index b36db75e9..3b01e2542 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -885,40 +885,38 @@ const controls = { // Translate a value into a nice label getLabel(setting, value) { switch (setting) { - case 'audioTrack': - if(value) { - let label; + case 'audioTrack': { + let label; - label = i18n.get(`audioTrackLabel.${value}`, this.config); - if (label.length) { - return label; - } - - label = i18n.get(`audioTrackMPDLabel.${value}`, this.config); - if (label.length) { - return label; - } + label = i18n.get(`audioTrackLabel.${value}`, this.config); + if (label.length) { + return label; + } - return `${value}`; + label = i18n.get(`audioTrackMPDLabel.${value}`, this.config); + if (label.length) { + return label; } - case 'videoTrack': - if(value) { - let label; + return `${value}`; + } - label = i18n.get(`videoTrackLabel.${value}`, this.config); - if (label.length) { - return label; - } + case 'videoTrack': { + let label; - label = i18n.get(`videoTrackMPDLabel.${value}`, this.config); - if (label.length) { - return label; - } + label = i18n.get(`videoTrackLabel.${value}`, this.config); + if (label.length) { + return label; + } - return `${value}`; + label = i18n.get(`videoTrackMPDLabel.${value}`, this.config); + if (label.length) { + return label; } + return `${value}`; + } + case 'speed': return value === 1 ? i18n.get('normal', this.config) : `${value}×`; From a683e13d2fde06978dc56ab32a965a4962a0bcc5 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:20:57 +0300 Subject: [PATCH 24/40] mpd: Lint all changed files --- src/js/plugins/mpd.js | 53 ++++++++++++++++++---------- src/js/plugins/preview-thumbnails.js | 4 ++- src/js/plyr.js | 19 ++++------ 3 files changed, 43 insertions(+), 33 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 204bed305..722e4c170 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -9,7 +9,7 @@ import { setAspectRatio } from '../utils/style'; const mpd = { // Get name of track getTrackName(track) { - if(track.id){ + if (track.id) { return track.id; } return `_index${track.index}`; @@ -19,30 +19,32 @@ const mpd = { getTrackLabel(track) { // Normal label const browserLanguage = navigator.language; + // eslint-disable-next-line no-restricted-syntax for (const label of track.labels) { if (label.lang && label.lang === browserLanguage) { return label.text; } } - if(track.labels[0]){ + if (track.labels[0]) { return track.labels[0].text; } // When label doesn't exist const outputStr = []; - if(track.lang){ + if (track.lang) { outputStr.push(`Lang: ${track.lang}`); } - if(track.id){ + if (track.id) { outputStr.push(`ID: ${track.id}`); } outputStr.push(`Index: ${track.index}`); - return outputStr.join(", "); + return outputStr.join(', '); }, // Get video labels getVideoTrackLabels() { const labels = {}; + // eslint-disable-next-line no-restricted-syntax for (const track of this.dash.getTracksFor('video')) { const name = mpd.getTrackName.call(this, track); const text = mpd.getTrackLabel.call(this, track); @@ -54,6 +56,7 @@ const mpd = { // Get audio labels getAudioTrackLabels() { const labels = {}; + // eslint-disable-next-line no-restricted-syntax for (const track of this.dash.getTracksFor('audio')) { const name = mpd.getTrackName.call(this, track); const text = mpd.getTrackLabel.call(this, track); @@ -65,8 +68,9 @@ const mpd = { // Get quality levels getQualityOptions() { const qualityList = []; + // eslint-disable-next-line no-restricted-syntax for (const bitrate of this.dash.getBitrateInfoListFor('video')) { - if(!qualityList.includes(bitrate.height)){ + if (!qualityList.includes(bitrate.height)) { qualityList.push(bitrate.height); } } @@ -110,15 +114,21 @@ const mpd = { get() { // Check "auto" attribute const settings = player.dash.getSettings(); - if (settings.streaming && settings.streaming.abr && settings.streaming.abr.autoSwitchBitrate && settings.streaming.abr.autoSwitchBitrate.video) { + if ( + settings.streaming && + settings.streaming.abr && + settings.streaming.abr.autoSwitchBitrate && + settings.streaming.abr.autoSwitchBitrate.video + ) { return 2147483647; } // Get quality value const currentIndex = player.dash.getQualityFor('video'); const bitrateList = player.dash.getBitrateInfoListFor('video'); - if(typeof currentIndex === 'number' && bitrateList[currentIndex]){ + if (typeof currentIndex === 'number' && bitrateList[currentIndex]) { return bitrateList[currentIndex].height; } + return undefined; }, set(input) { const dashConfig = { @@ -137,10 +147,10 @@ const mpd = { } else { // Get quality by height const currentIndex = player.dash.getQualityFor('video'); - const currentHeight = (currentIndex) ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; + const currentHeight = currentIndex ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; // Sorting bitrates by DESC const bitrateList = player.dash.getBitrateInfoListFor('video'); - bitrateList.sort(function(a,b){ + bitrateList.sort(function (a, b) { if (a.bitrate < b.bitrate) { return 1; } @@ -150,6 +160,7 @@ const mpd = { return 0; }); // Brute all bitrates + // eslint-disable-next-line no-restricted-syntax for (const bitrate of bitrateList) { if (bitrate.height === input) { // Disabling auto switch quality @@ -183,9 +194,9 @@ const mpd = { if (currentTrack) { return mpd.getTrackName.call(player, currentTrack); } - }catch{ - - } + // eslint-disable-next-line no-empty + } catch {} + return undefined; }, set(input) { // Replace already buffered frames @@ -203,7 +214,8 @@ const mpd = { } if (match) { // Brute by index - const index = parseInt(match[1]); + const index = parseInt(match[1], 10); + // eslint-disable-next-line no-restricted-syntax for (const track of player.dash.getTracksFor('audio')) { if (track.index === index) { // Update video track @@ -213,6 +225,7 @@ const mpd = { } } else { // Brute by id + // eslint-disable-next-line no-restricted-syntax for (const track of player.dash.getTracksFor('audio')) { if (track.id === input) { // Update audio track @@ -246,9 +259,9 @@ const mpd = { if (currentTrack) { return mpd.getTrackName.call(player, currentTrack); } - }catch{ - - } + // eslint-disable-next-line no-empty + } catch {} + return undefined; }, set(input) { let match; @@ -257,7 +270,8 @@ const mpd = { } if (match) { // Brute by index - const index = parseInt(match[1]); + const index = parseInt(match[1], 10); + // eslint-disable-next-line no-restricted-syntax for (const track of player.dash.getTracksFor('video')) { if (track.index === index) { // Update video track @@ -267,6 +281,7 @@ const mpd = { } } else { // Brute by id + // eslint-disable-next-line no-restricted-syntax for (const track of player.dash.getTracksFor('video')) { if (track.id === input) { // Update video track @@ -292,7 +307,7 @@ const mpd = { }); // Update settings list when perion changed - player.dash.on('periodSwitchCompleted', ()=>{ + player.dash.on('periodSwitchCompleted', () => { triggerEvent.call(player, player.media, 'qualitylistupdate', false, { list: mpd.getQualityOptions.call(player), }); diff --git a/src/js/plugins/preview-thumbnails.js b/src/js/plugins/preview-thumbnails.js index 349fcf3ac..2f59734a9 100644 --- a/src/js/plugins/preview-thumbnails.js +++ b/src/js/plugins/preview-thumbnails.js @@ -100,7 +100,9 @@ class PreviewThumbnails { } get enabled() { - return (this.player.isHTML5 || this.player.isMPD) && this.player.isVideo && this.player.config.previewThumbnails.enabled; + return ( + (this.player.isHTML5 || this.player.isMPD) && this.player.isVideo && this.player.config.previewThumbnails.enabled + ); } load = () => { diff --git a/src/js/plyr.js b/src/js/plyr.js index ba44cf264..cbed06f71 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -13,7 +13,6 @@ import Console from './console'; import controls from './controls'; import Fullscreen from './fullscreen'; import html5 from './html5'; -import mpd from './plugins/mpd'; import Listeners from './listeners'; import media from './media'; import Ads from './plugins/ads'; @@ -750,12 +749,9 @@ class Plyr { return; } - let audioTrack = [ - !is.empty(input) && input, - this.storage.get('audioTrack'), - config.selected, - config.default, - ].find(e => e); + let audioTrack = [!is.empty(input) && input, this.storage.get('audioTrack'), config.selected, config.default].find( + (e) => e, + ); let updateStorage = true; @@ -798,12 +794,9 @@ class Plyr { return; } - let videoTrack = [ - !is.empty(input) && input, - this.storage.get('videoTrack'), - config.selected, - config.default, - ].find(e => e); + let videoTrack = [!is.empty(input) && input, this.storage.get('videoTrack'), config.selected, config.default].find( + (e) => e, + ); let updateStorage = true; From 6f95c16a5b34a2bf8ded50a428022c8f1b927808 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:43:56 +0300 Subject: [PATCH 25/40] mpd: Replace some `for` to `Array.prototype.find` --- src/js/plugins/mpd.js | 71 +++++++++++++++++-------------------------- 1 file changed, 28 insertions(+), 43 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 722e4c170..51abb96fe 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -159,17 +159,14 @@ const mpd = { } return 0; }); - // Brute all bitrates - // eslint-disable-next-line no-restricted-syntax - for (const bitrate of bitrateList) { - if (bitrate.height === input) { - // Disabling auto switch quality - dashConfig.streaming.abr.autoSwitchBitrate.video = false; - player.dash.updateSettings(dashConfig); - // Update quality - player.dash.setQualityFor('video', bitrate.qualityIndex, bitrate.height > currentHeight); - break; - } + // Find quality + const quality = bitrateList.find((e) => e.height === input); + // Disabling auto switch quality + dashConfig.streaming.abr.autoSwitchBitrate.video = false; + player.dash.updateSettings(dashConfig); + // Update quality + if (quality) { + player.dash.setQualityFor('video', quality.qualityIndex, quality.height > currentHeight); } } @@ -213,25 +210,19 @@ const mpd = { match = input.match(/^_index([0-9]+)$/); } if (match) { - // Brute by index + // Find by index const index = parseInt(match[1], 10); - // eslint-disable-next-line no-restricted-syntax - for (const track of player.dash.getTracksFor('audio')) { - if (track.index === index) { - // Update video track - player.dash.setCurrentTrack(track); - break; - } + const track = player.dash.getTracksFor('audio').find((e) => e.index === index); + // Update video track + if (track) { + player.dash.setCurrentTrack(track); } } else { - // Brute by id - // eslint-disable-next-line no-restricted-syntax - for (const track of player.dash.getTracksFor('audio')) { - if (track.id === input) { - // Update audio track - player.dash.setCurrentTrack(track); - break; - } + // Find by id + const track = player.dash.getTracksFor('audio').find((e) => e.id === input); + // Update audio track + if (track) { + player.dash.setCurrentTrack(track); } } @@ -269,25 +260,19 @@ const mpd = { match = input.match(/^_index([0-9]+)$/); } if (match) { - // Brute by index + // Find by index const index = parseInt(match[1], 10); - // eslint-disable-next-line no-restricted-syntax - for (const track of player.dash.getTracksFor('video')) { - if (track.index === index) { - // Update video track - player.dash.setCurrentTrack(track); - break; - } + const track = player.dash.getTracksFor('video').find((e) => e.index === index); + // Update video track + if (track) { + player.dash.setCurrentTrack(track); } } else { - // Brute by id - // eslint-disable-next-line no-restricted-syntax - for (const track of player.dash.getTracksFor('video')) { - if (track.id === input) { - // Update video track - player.dash.setCurrentTrack(track); - break; - } + // Find by id + const track = player.dash.getTracksFor('video').find((e) => e.id === input); + // Update video track + if (track) { + player.dash.setCurrentTrack(track); } } From 36a98976847cc1e8855c97e4efcf03da9dbc57a1 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:44:12 +0300 Subject: [PATCH 26/40] mpd: Replace some `for` to `Array.prototype.forEach` --- src/js/plugins/mpd.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 51abb96fe..f04280cb8 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -44,36 +44,33 @@ const mpd = { // Get video labels getVideoTrackLabels() { const labels = {}; - // eslint-disable-next-line no-restricted-syntax - for (const track of this.dash.getTracksFor('video')) { + this.dash.getTracksFor('video').forEach((track) => { const name = mpd.getTrackName.call(this, track); const text = mpd.getTrackLabel.call(this, track); labels[name] = text; - } + }); return labels; }, // Get audio labels getAudioTrackLabels() { const labels = {}; - // eslint-disable-next-line no-restricted-syntax - for (const track of this.dash.getTracksFor('audio')) { + this.dash.getTracksFor('audio').forEach((track) => { const name = mpd.getTrackName.call(this, track); const text = mpd.getTrackLabel.call(this, track); labels[name] = text; - } + }); return labels; }, // Get quality levels getQualityOptions() { const qualityList = []; - // eslint-disable-next-line no-restricted-syntax - for (const bitrate of this.dash.getBitrateInfoListFor('video')) { + this.dash.getBitrateInfoListFor('video').forEach((bitrate) => { if (!qualityList.includes(bitrate.height)) { qualityList.push(bitrate.height); } - } + }); // 2147483647 - "Auto" return [2147483647, ...qualityList]; }, From 3ce2cec0f457d106bad826adf33095f1bce0e32f Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:48:19 +0300 Subject: [PATCH 27/40] mpd: Remove `try-catch` --- src/js/plugins/mpd.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index f04280cb8..17a5c051a 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -182,14 +182,12 @@ const mpd = { // Audio track Object.defineProperty(player.media, 'audioTrack', { get() { - // Try-catch in case of empty streamInfo - try { + if (player.dash.getActiveStream()) { const currentTrack = player.dash.getCurrentTrackFor('audio'); if (currentTrack) { return mpd.getTrackName.call(player, currentTrack); } - // eslint-disable-next-line no-empty - } catch {} + } return undefined; }, set(input) { @@ -241,14 +239,12 @@ const mpd = { // Video track Object.defineProperty(player.media, 'videoTrack', { get() { - // Try-catch in case of empty streamInfo - try { + if (player.dash.getActiveStream()) { const currentTrack = player.dash.getCurrentTrackFor('video'); if (currentTrack) { return mpd.getTrackName.call(player, currentTrack); } - // eslint-disable-next-line no-empty - } catch {} + } return undefined; }, set(input) { From e6a64b76d9d69f911447d827e1cc885c29c45647 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 12:51:05 +0300 Subject: [PATCH 28/40] mpd: Replace `for` to `find` --- src/js/plugins/mpd.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 17a5c051a..7ade29d50 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -18,12 +18,9 @@ const mpd = { // Get human-like name of track getTrackLabel(track) { // Normal label - const browserLanguage = navigator.language; - // eslint-disable-next-line no-restricted-syntax - for (const label of track.labels) { - if (label.lang && label.lang === browserLanguage) { - return label.text; - } + const labelByLanguage = track.labels.find((e) => e.lang && e.lang === navigator.language); + if (labelByLanguage) { + return labelByLanguage; } if (track.labels[0]) { return track.labels[0].text; From decdb95b4377bc971ab836878398156275958928 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 14:17:41 +0300 Subject: [PATCH 29/40] mpd: Remove dirty hack in `quality` config --- src/js/config/defaults.js | 3 +-- src/js/plugins/mpd.js | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index 783602219..bb699b212 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -70,8 +70,7 @@ const defaults = { quality: { default: 576, // The options to display in the UI, if available for the source media - // 2147483647 - "Auto" for MPEG-DASH - options: [2147483647, 4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], + options: [4320, 2880, 2160, 1440, 1080, 720, 576, 480, 360, 240], forced: false, onChange: null, }, diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 7ade29d50..d1a15d3fc 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -68,8 +68,23 @@ const mpd = { qualityList.push(bitrate.height); } }); - // 2147483647 - "Auto" - return [2147483647, ...qualityList]; + // "Auto" + qualityList.push(2147483647); + // Sort by DESC + qualityList.sort(function (a, b) { + const aInt = parseInt(a, 10); + const bInt = parseInt(b, 10); + if (aInt < bInt) { + return 1; + } + if (aInt > bInt) { + return -1; + } + return 0; + }); + // Update supported options + this.config.quality.options = qualityList; + return qualityList; }, // Get audio tracks From 635ea23206d5065d6f7f2bb669e9ca08ec4d0aa5 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 14:44:06 +0300 Subject: [PATCH 30/40] mpd: Config overwrites --- src/js/config/defaults.js | 4 +--- src/js/plugins/mpd.js | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/js/config/defaults.js b/src/js/config/defaults.js index bb699b212..ab386ce8d 100644 --- a/src/js/config/defaults.js +++ b/src/js/config/defaults.js @@ -198,9 +198,7 @@ const defaults = { disabled: 'Disabled', enabled: 'Enabled', advertisement: 'Ad', - qualityLabel: { - 2147483647: 'Auto', - }, + qualityAuto: 'Auto', qualityBadge: { 2160: '4K', 1440: 'HD', diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index d1a15d3fc..46090c997 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -3,6 +3,7 @@ // ========================================================================== import { triggerEvent } from '../utils/events'; +import i18n from '../utils/i18n'; import is from '../utils/is'; import { setAspectRatio } from '../utils/style'; @@ -82,8 +83,10 @@ const mpd = { } return 0; }); - // Update supported options - this.config.quality.options = qualityList; + if (this.config.quality.allowOverwrite) { + // Update supported options + this.config.quality.options = qualityList; + } return qualityList; }, @@ -110,6 +113,14 @@ const mpd = { const player = this; + // Config hacks + // "Auto" + player.config.quality.options.unshift(2147483647); + if (!player.config.i18n.qualityLabel) { + player.config.i18n.qualityLabel = {}; + } + player.config.i18n.qualityLabel[2147483647] = i18n.get('qualityAuto', player.config); + // Set speed options from config player.options.speed = player.config.speed.options; From a88bc919238ecb05cdcbd240ae6c351a5a8856c5 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 23 Apr 2022 14:55:10 +0300 Subject: [PATCH 31/40] mpd: `2147483647` to `qualityAutoMagicValue` --- src/js/plugins/mpd.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 46090c997..6243cd4bd 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -8,6 +8,9 @@ import is from '../utils/is'; import { setAspectRatio } from '../utils/style'; const mpd = { + // Reserved value that must not be the same as other values + qualityAutoMagicValue: 2147483647, + // Get name of track getTrackName(track) { if (track.id) { @@ -70,7 +73,7 @@ const mpd = { } }); // "Auto" - qualityList.push(2147483647); + qualityList.push(mpd.qualityAutoMagicValue); // Sort by DESC qualityList.sort(function (a, b) { const aInt = parseInt(a, 10); @@ -115,11 +118,11 @@ const mpd = { // Config hacks // "Auto" - player.config.quality.options.unshift(2147483647); + player.config.quality.options.unshift(mpd.qualityAutoMagicValue); if (!player.config.i18n.qualityLabel) { player.config.i18n.qualityLabel = {}; } - player.config.i18n.qualityLabel[2147483647] = i18n.get('qualityAuto', player.config); + player.config.i18n.qualityLabel[mpd.qualityAutoMagicValue] = i18n.get('qualityAuto', player.config); // Set speed options from config player.options.speed = player.config.speed.options; @@ -140,7 +143,7 @@ const mpd = { settings.streaming.abr.autoSwitchBitrate && settings.streaming.abr.autoSwitchBitrate.video ) { - return 2147483647; + return mpd.qualityAutoMagicValue; } // Get quality value const currentIndex = player.dash.getQualityFor('video'); @@ -160,7 +163,7 @@ const mpd = { }; // If "auto" - if (input === 2147483647) { + if (input === mpd.qualityAutoMagicValue) { // Enabling auto switch quality dashConfig.streaming.abr.autoSwitchBitrate.video = true; player.dash.updateSettings(dashConfig); From 6ec4a365195bed34d454dc2761dbf306f666c3dd Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sun, 24 Apr 2022 19:23:22 +0300 Subject: [PATCH 32/40] mpd: Why didn't anyone tell me about this before? --- src/js/plugins/mpd.js | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 6243cd4bd..57d250382 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -75,17 +75,7 @@ const mpd = { // "Auto" qualityList.push(mpd.qualityAutoMagicValue); // Sort by DESC - qualityList.sort(function (a, b) { - const aInt = parseInt(a, 10); - const bInt = parseInt(b, 10); - if (aInt < bInt) { - return 1; - } - if (aInt > bInt) { - return -1; - } - return 0; - }); + qualityList.sort((a, b) => b - a); if (this.config.quality.allowOverwrite) { // Update supported options this.config.quality.options = qualityList; @@ -173,15 +163,7 @@ const mpd = { const currentHeight = currentIndex ? player.dash.getBitrateInfoListFor('video')[currentIndex].height : 0; // Sorting bitrates by DESC const bitrateList = player.dash.getBitrateInfoListFor('video'); - bitrateList.sort(function (a, b) { - if (a.bitrate < b.bitrate) { - return 1; - } - if (a.bitrate > b.bitrate) { - return -1; - } - return 0; - }); + bitrateList.sort((a, b) => b.bitrate - a.bitrate); // Find quality const quality = bitrateList.find((e) => e.height === input); // Disabling auto switch quality From 671f42aad599c4bdf605c432ce47ba31013e6eaa Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sun, 24 Apr 2022 20:33:29 +0300 Subject: [PATCH 33/40] mpd: Why didn't anyone tell me about this before? x2 --- src/js/plugins/mpd.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index 57d250382..a7a199a70 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -9,7 +9,7 @@ import { setAspectRatio } from '../utils/style'; const mpd = { // Reserved value that must not be the same as other values - qualityAutoMagicValue: 2147483647, + qualityAutoMagicValue: Infinity, // Get name of track getTrackName(track) { From 9a4db8cb8d2d49ab49fc1f15747c5da5b323f85d Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 7 May 2022 18:55:49 +0300 Subject: [PATCH 34/40] mpd: MPEG-DASH in main page --- demo/index.html | 37 ++++++++++++++++++++++++++++++++++++- demo/src/js/sources.js | 9 +++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/demo/index.html b/demo/index.html index d23eda7a7..de14c8d5a 100644 --- a/demo/index.html +++ b/demo/index.html @@ -48,6 +48,9 @@ href="https://cdn.plyr.io/static/fonts/gordita-bold.woff2" /> + + + + From 29eb53ea24cfd015bbe600f941f3b926b1bc4308 Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 7 May 2022 21:16:48 +0300 Subject: [PATCH 39/40] mpd: Move "Auto" to bottom --- src/js/plugins/mpd.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index a7a199a70..d0c4f282b 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -107,8 +107,9 @@ const mpd = { const player = this; // Config hacks - // "Auto" - player.config.quality.options.unshift(mpd.qualityAutoMagicValue); + if (!player.config.quality.options.includes(mpd.qualityAutoMagicValue)) { + player.config.quality.options.push(mpd.qualityAutoMagicValue); + } if (!player.config.i18n.qualityLabel) { player.config.i18n.qualityLabel = {}; } From e8dc3f8828b08f990c1494681c59e02cab6b90ee Mon Sep 17 00:00:00 2001 From: Vladimir Avchenov Date: Sat, 7 May 2022 21:18:15 +0300 Subject: [PATCH 40/40] mpd: Move "Auto" to bottom x2 --- src/js/plugins/mpd.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/plugins/mpd.js b/src/js/plugins/mpd.js index d0c4f282b..e9319acc4 100644 --- a/src/js/plugins/mpd.js +++ b/src/js/plugins/mpd.js @@ -72,10 +72,10 @@ const mpd = { qualityList.push(bitrate.height); } }); - // "Auto" - qualityList.push(mpd.qualityAutoMagicValue); // Sort by DESC qualityList.sort((a, b) => b - a); + // "Auto" + qualityList.push(mpd.qualityAutoMagicValue); if (this.config.quality.allowOverwrite) { // Update supported options this.config.quality.options = qualityList;