From 2aa967aba93cb485ea2c4d10615cee505a354d15 Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 12:33:30 +0200 Subject: [PATCH 1/9] Replace switch in source.js with destructuring --- src/js/source.js | 42 +++++++++++++++--------------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/src/js/source.js b/src/js/source.js index d4a66963..c62db15a 100644 --- a/src/js/source.js +++ b/src/js/source.js @@ -8,6 +8,7 @@ import media from './media'; import support from './support'; import ui from './ui'; import { createElement, insertElement, removeElement } from './utils/elements'; +import { getDeep } from './utils/objects'; import is from './utils/is'; const source = { @@ -27,7 +28,7 @@ const source = { // Update source // Sources are not checked for support so be careful change(input) { - if (!is.object(input) || !('sources' in input) || !input.sources.length) { + if (!getDeep(input, 'sources.length')) { this.debug.warn('Invalid source format'); return; } @@ -52,32 +53,19 @@ const source = { } // Set the type and provider - this.type = input.type; - this.provider = !is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5; + const { sources, type } = input; + const [{ provider = providers.html5, src }] = sources; + const tagName = provider === 'html5' ? type : 'div'; + const attributes = provider === 'html5' ? {} : { src }; - // Check for support - this.supported = support.check(this.type, this.provider, this.config.playsinline); - - // Create new markup - switch (`${this.provider}:${this.type}`) { - case 'html5:video': - this.media = createElement('video'); - break; - - case 'html5:audio': - this.media = createElement('audio'); - break; - - case 'youtube:video': - case 'vimeo:video': - this.media = createElement('div', { - src: input.sources[0].src, - }); - break; - - default: - break; - } + Object.assign(this, { + provider, + type, + // Check for support + supported: support.check(type, provider, this.config.playsinline), + // Create new element + media: createElement(tagName, attributes), + }); // Inject the new element this.elements.container.appendChild(this.media); @@ -114,7 +102,7 @@ const source = { // Set new sources for html5 if (this.isHTML5) { - source.insertElements.call(this, 'source', input.sources); + source.insertElements.call(this, 'source', sources); } // Set video title From 87ea5e14b46d606b5c33d753dec2d96fbec4d074 Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 12:56:58 +0200 Subject: [PATCH 2/9] Replace provider switch plyr.js with conditions --- src/js/plyr.js | 65 ++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 39 deletions(-) diff --git a/src/js/plyr.js b/src/js/plyr.js index 753db775..0217ded8 100644 --- a/src/js/plyr.js +++ b/src/js/plyr.js @@ -1028,50 +1028,37 @@ class Plyr { // Stop playback this.stop(); - // Type specific stuff - switch (`${this.provider}:${this.type}`) { - case 'html5:video': - case 'html5:audio': - // Clear timeout - clearTimeout(this.timers.loading); + // Provider specific stuff + if (this.isHTML5) { + // Clear timeout + clearTimeout(this.timers.loading); - // Restore native video controls - ui.toggleNativeControls.call(this, true); + // Restore native video controls + ui.toggleNativeControls.call(this, true); - // Clean up - done(); + // Clean up + done(); + } else if (this.isYouTube) { + // Clear timers + clearInterval(this.timers.buffering); + clearInterval(this.timers.playing); - break; + // Destroy YouTube API + if (this.embed !== null && is.function(this.embed.destroy)) { + this.embed.destroy(); + } - case 'youtube:video': - // Clear timers - clearInterval(this.timers.buffering); - clearInterval(this.timers.playing); + // Clean up + done(); + } else if (this.isVimeo) { + // Destroy Vimeo API + // then clean up (wait, to prevent postmessage errors) + if (this.embed !== null) { + this.embed.unload().then(done); + } - // Destroy YouTube API - if (this.embed !== null && is.function(this.embed.destroy)) { - this.embed.destroy(); - } - - // Clean up - done(); - - break; - - case 'vimeo:video': - // Destroy Vimeo API - // then clean up (wait, to prevent postmessage errors) - if (this.embed !== null) { - this.embed.unload().then(done); - } - - // Vimeo does not always return - setTimeout(done, 200); - - break; - - default: - break; + // Vimeo does not always return + setTimeout(done, 200); } } From 213cfe8c8401bed8cd84756ff019d1f5b48ad94f Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 12:42:50 +0200 Subject: [PATCH 3/9] Replace switch in media.js with simpler conditions --- src/js/media.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/js/media.js b/src/js/media.js index 189112a1..eb37d441 100644 --- a/src/js/media.js +++ b/src/js/media.js @@ -46,21 +46,12 @@ const media = { this.elements.wrapper.appendChild(this.elements.poster); } - if (this.isEmbed) { - switch (this.provider) { - case 'youtube': - youtube.setup.call(this); - break; - - case 'vimeo': - vimeo.setup.call(this); - break; - - default: - break; - } - } else if (this.isHTML5) { + if (this.isHTML5) { html5.extend.call(this); + } else if (this.isYouTube) { + youtube.setup.call(this); + } else if (this.isVimeo) { + vimeo.setup.call(this); } }, }; From c373ed72d78a221c03190e93f1e49d78c1e2b93f Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 14:20:10 +0200 Subject: [PATCH 4/9] Replace switch in YouTube error handler with object literal --- src/js/plugins/youtube.js | 54 +++++++++++---------------------------- 1 file changed, 15 insertions(+), 39 deletions(-) diff --git a/src/js/plugins/youtube.js b/src/js/plugins/youtube.js index a1e52b48..e383e50f 100644 --- a/src/js/plugins/youtube.js +++ b/src/js/plugins/youtube.js @@ -200,46 +200,22 @@ const youtube = { }, events: { onError(event) { - // If we've already fired an error, don't do it again - // YouTube fires onError twice - if (is.object(player.media.error)) { - return; + // YouTube may fire onError twice, so only handle it once + if (!player.media.error) { + const code = event.data; + // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError + const message = ({ + 2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.', + 5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.', + 100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.', + 101: 'The owner of the requested video does not allow it to be played in embedded players.', + 150: 'The owner of the requested video does not allow it to be played in embedded players.', + }[code]) || 'An unknown error occured'; + + player.media.error = { code, message }; + + triggerEvent.call(player, player.media, 'error'); } - - const detail = { - code: event.data, - }; - - // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError - switch (event.data) { - case 2: - detail.message = - 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.'; - break; - - case 5: - detail.message = - 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.'; - break; - - case 100: - detail.message = - 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.'; - break; - - case 101: - case 150: - detail.message = 'The owner of the requested video does not allow it to be played in embedded players.'; - break; - - default: - detail.message = 'An unknown error occured'; - break; - } - - player.media.error = detail; - - triggerEvent.call(player, player.media, 'error'); }, onPlaybackQualityChange() { triggerEvent.call(player, player.media, 'qualitychange', false, { From 88735e314646a2aaf0cf38935dcf11eff8290ebd Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 12:48:37 +0200 Subject: [PATCH 5/9] Replace switch in controls.updateSetting with condition --- src/js/controls.js | 41 ++++++++++++++++++----------------------- 1 file changed, 18 insertions(+), 23 deletions(-) diff --git a/src/js/controls.js b/src/js/controls.js index f091555f..efb718fe 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -724,32 +724,27 @@ const controls = { let value = null; let list = container; - switch (setting) { - case 'captions': - value = this.currentTrack; - break; + if (setting === 'captions') { + value = this.currentTrack; + } else { + value = !is.empty(input) ? input : this[setting]; - default: - value = !is.empty(input) ? input : this[setting]; + // Get default + if (is.empty(value)) { + value = this.config[setting].default; + } - // Get default - if (is.empty(value)) { - value = this.config[setting].default; - } + // Unsupported value + if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) { + this.debug.warn(`Unsupported value of '${value}' for ${setting}`); + return; + } - // Unsupported value - if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) { - this.debug.warn(`Unsupported value of '${value}' for ${setting}`); - return; - } - - // Disabled value - if (!this.config[setting].options.includes(value)) { - this.debug.warn(`Disabled value of '${value}' for ${setting}`); - return; - } - - break; + // Disabled value + if (!this.config[setting].options.includes(value)) { + this.debug.warn(`Disabled value of '${value}' for ${setting}`); + return; + } } // Get the list if we need to From 2d6732d5801fb19ad24f180f0adea7233b57f088 Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 15:11:59 +0200 Subject: [PATCH 6/9] Replace switch in controls.createLabel with object literal --- src/js/controls.js | 31 ++++++++++--------------------- 1 file changed, 10 insertions(+), 21 deletions(-) diff --git a/src/js/controls.js b/src/js/controls.js index efb718fe..1cbaa752 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -119,28 +119,17 @@ const controls = { }, // Create hidden text label - createLabel(type, attr) { - let text = i18n.get(type, this.config); - const attributes = Object.assign({}, attr); + createLabel(type, attr = {}) { + // Skip i18n for abbreviations and brand names + const universals = { + pip: 'PIP', + airplay: 'AirPlay', + }; - switch (type) { - case 'pip': - text = 'PIP'; - break; - - case 'airplay': - text = 'AirPlay'; - break; - - default: - break; - } - - if ('class' in attributes) { - attributes.class += ` ${this.config.classNames.hidden}`; - } else { - attributes.class = this.config.classNames.hidden; - } + const text = universals[type] || i18n.get(type, this.config); + const attributes = Object.assign({}, attr, { + class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '), + }); return createElement('span', attributes, text); }, From 64bb206d85e5f7415d5ff81821e19fb107c30877 Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 14:06:28 +0200 Subject: [PATCH 7/9] Replace switch in support.check with simpler conditions --- src/js/support.js | 26 ++------------------------ 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/src/js/support.js b/src/js/support.js index 7eabae3c..e6ce30c4 100644 --- a/src/js/support.js +++ b/src/js/support.js @@ -16,31 +16,9 @@ const support = { // Check for support // Basic functionality vs full UI check(type, provider, playsinline) { - let api = false; - let ui = false; const canPlayInline = browser.isIPhone && playsinline && support.playsinline; - - switch (`${provider}:${type}`) { - case 'html5:video': - api = support.video; - ui = api && support.rangeInput && (!browser.isIPhone || canPlayInline); - break; - - case 'html5:audio': - api = support.audio; - ui = api && support.rangeInput; - break; - - case 'youtube:video': - case 'vimeo:video': - api = true; - ui = support.rangeInput && (!browser.isIPhone || canPlayInline); - break; - - default: - api = support.audio && support.video; - ui = api && support.rangeInput; - } + const api = support[type] || provider !== 'html5'; + const ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline); return { api, From 2a186e425bd83bddea65247d1352cc7b0114fab0 Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 15:07:37 +0200 Subject: [PATCH 8/9] Replace switch in support.mime with object literal and conditions, and make it return boolean --- src/js/support.js | 76 ++++++++++++++++++----------------------------- 1 file changed, 29 insertions(+), 47 deletions(-) diff --git a/src/js/support.js b/src/js/support.js index e6ce30c4..6395293f 100644 --- a/src/js/support.js +++ b/src/js/support.js @@ -7,6 +7,15 @@ import browser from './utils/browser'; import { createElement } from './utils/elements'; import is from './utils/is'; +// Default codecs for checking mimetype support +const defaultCodecs = { + 'audio/ogg': 'vorbis', + 'audio/wav': '1', + 'video/webm': 'vp8, vorbis', + 'video/mp4': 'avc1.42E01E, mp4a.40.2', + 'video/ogg': 'theora', +}; + // Check for feature support const support = { // Basic support @@ -41,56 +50,29 @@ const support = { // Check for mime type support against a player instance // Credits: http://diveintohtml5.info/everything.html // Related: http://www.leanbackplayer.com/test/h5mt.html - mime(type) { - const { media } = this; - - try { - // Bail if no checking function - if (!this.isHTML5 || !is.function(media.canPlayType)) { - return false; - } - - // Check directly if codecs specified - if (type.includes('codecs=')) { - return media.canPlayType(type).replace(/no/, ''); - } - - // Type specific checks - if (this.isVideo) { - switch (type) { - case 'video/webm': - return media.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/no/, ''); - - case 'video/mp4': - return media.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"').replace(/no/, ''); - - case 'video/ogg': - return media.canPlayType('video/ogg; codecs="theora"').replace(/no/, ''); - - default: - return false; - } - } else if (this.isAudio) { - switch (type) { - case 'audio/mpeg': - return media.canPlayType('audio/mpeg;').replace(/no/, ''); - - case 'audio/ogg': - return media.canPlayType('audio/ogg; codecs="vorbis"').replace(/no/, ''); - - case 'audio/wav': - return media.canPlayType('audio/wav; codecs="1"').replace(/no/, ''); - - default: - return false; - } - } - } catch (e) { + mime(inputType) { + const [mediaType] = inputType.split('/'); + if (!this.isHTML5 || mediaType !== this.type) { return false; } - // If we got this far, we're stuffed - return false; + let type; + if (inputType && inputType.includes('codecs=')) { + // Use input directly + type = inputType; + } else if (inputType === 'audio/mpeg') { + // Skip codec + type = 'audio/mpeg;'; + } else if (inputType in defaultCodecs) { + // Use codec + type = `${inputType}; codecs="${defaultCodecs[inputType]}"`; + } + + try { + return Boolean(type && this.media.canPlayType(type).replace(/no/, '')); + } catch (err) { + return false; + } }, // Check for textTracks support From 99c10aa1fc2010c659a412568096ee24900f0eac Mon Sep 17 00:00:00 2001 From: Albin Larsson Date: Fri, 15 Jun 2018 17:06:36 +0200 Subject: [PATCH 9/9] Replace switch in controls.createProgress with object literal --- src/js/controls.js | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/js/controls.js b/src/js/controls.js index 1cbaa752..19c531af 100644 --- a/src/js/controls.js +++ b/src/js/controls.js @@ -331,19 +331,12 @@ const controls = { if (type !== 'volume') { progress.appendChild(createElement('span', null, '0')); - let suffix = ''; - switch (type) { - case 'played': - suffix = i18n.get('played', this.config); - break; + const suffixKey = ({ + played: 'played', + buffer: 'buffered', + })[type]; - case 'buffer': - suffix = i18n.get('buffered', this.config); - break; - - default: - break; - } + const suffix = suffixKey ? i18n.get(suffixKey, this.config) : ''; progress.innerText = `% ${suffix.toLowerCase()}`; }