Merge pull request #1040 from friday/switches-get-stitches

Switches code optimizations
This commit is contained in:
Sam Potts
2018-06-17 00:39:35 +10:00
committed by GitHub
6 changed files with 125 additions and 246 deletions

89
src/js/controls.js vendored
View File

@ -119,28 +119,17 @@ const controls = {
}, },
// Create hidden text label // Create hidden text label
createLabel(type, attr) { createLabel(type, attr = {}) {
let text = i18n.get(type, this.config); // Skip i18n for abbreviations and brand names
const attributes = Object.assign({}, attr); const universals = {
pip: 'PIP',
airplay: 'AirPlay',
};
switch (type) { const text = universals[type] || i18n.get(type, this.config);
case 'pip': const attributes = Object.assign({}, attr, {
text = 'PIP'; class: [attr.class, this.config.classNames.hidden].filter(Boolean).join(' '),
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;
}
return createElement('span', attributes, text); return createElement('span', attributes, text);
}, },
@ -342,19 +331,12 @@ const controls = {
if (type !== 'volume') { if (type !== 'volume') {
progress.appendChild(createElement('span', null, '0')); progress.appendChild(createElement('span', null, '0'));
let suffix = ''; const suffixKey = ({
switch (type) { played: 'played',
case 'played': buffer: 'buffered',
suffix = i18n.get('played', this.config); })[type];
break;
case 'buffer': const suffix = suffixKey ? i18n.get(suffixKey, this.config) : '';
suffix = i18n.get('buffered', this.config);
break;
default:
break;
}
progress.innerText = `% ${suffix.toLowerCase()}`; progress.innerText = `% ${suffix.toLowerCase()}`;
} }
@ -724,32 +706,27 @@ const controls = {
let value = null; let value = null;
let list = container; let list = container;
switch (setting) { if (setting === 'captions') {
case 'captions': value = this.currentTrack;
value = this.currentTrack; } else {
break; value = !is.empty(input) ? input : this[setting];
default: // Get default
value = !is.empty(input) ? input : this[setting]; if (is.empty(value)) {
value = this.config[setting].default;
}
// Get default // Unsupported value
if (is.empty(value)) { if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) {
value = this.config[setting].default; this.debug.warn(`Unsupported value of '${value}' for ${setting}`);
} return;
}
// Unsupported value // Disabled value
if (!is.empty(this.options[setting]) && !this.options[setting].includes(value)) { if (!this.config[setting].options.includes(value)) {
this.debug.warn(`Unsupported value of '${value}' for ${setting}`); this.debug.warn(`Disabled value of '${value}' for ${setting}`);
return; return;
} }
// Disabled value
if (!this.config[setting].options.includes(value)) {
this.debug.warn(`Disabled value of '${value}' for ${setting}`);
return;
}
break;
} }
// Get the list if we need to // Get the list if we need to

View File

@ -46,21 +46,12 @@ const media = {
this.elements.wrapper.appendChild(this.elements.poster); this.elements.wrapper.appendChild(this.elements.poster);
} }
if (this.isEmbed) { if (this.isHTML5) {
switch (this.provider) {
case 'youtube':
youtube.setup.call(this);
break;
case 'vimeo':
vimeo.setup.call(this);
break;
default:
break;
}
} else if (this.isHTML5) {
html5.extend.call(this); html5.extend.call(this);
} else if (this.isYouTube) {
youtube.setup.call(this);
} else if (this.isVimeo) {
vimeo.setup.call(this);
} }
}, },
}; };

View File

@ -200,46 +200,22 @@ const youtube = {
}, },
events: { events: {
onError(event) { onError(event) {
// If we've already fired an error, don't do it again // YouTube may fire onError twice, so only handle it once
// YouTube fires onError twice if (!player.media.error) {
if (is.object(player.media.error)) { const code = event.data;
return; // 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() { onPlaybackQualityChange() {
triggerEvent.call(player, player.media, 'qualitychange', false, { triggerEvent.call(player, player.media, 'qualitychange', false, {

View File

@ -1028,50 +1028,37 @@ class Plyr {
// Stop playback // Stop playback
this.stop(); this.stop();
// Type specific stuff // Provider specific stuff
switch (`${this.provider}:${this.type}`) { if (this.isHTML5) {
case 'html5:video': // Clear timeout
case 'html5:audio': clearTimeout(this.timers.loading);
// Clear timeout
clearTimeout(this.timers.loading);
// Restore native video controls // Restore native video controls
ui.toggleNativeControls.call(this, true); ui.toggleNativeControls.call(this, true);
// Clean up // Clean up
done(); 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': // Clean up
// Clear timers done();
clearInterval(this.timers.buffering); } else if (this.isVimeo) {
clearInterval(this.timers.playing); // Destroy Vimeo API
// then clean up (wait, to prevent postmessage errors)
if (this.embed !== null) {
this.embed.unload().then(done);
}
// Destroy YouTube API // Vimeo does not always return
if (this.embed !== null && is.function(this.embed.destroy)) { setTimeout(done, 200);
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;
} }
} }

View File

@ -8,6 +8,7 @@ import media from './media';
import support from './support'; import support from './support';
import ui from './ui'; import ui from './ui';
import { createElement, insertElement, removeElement } from './utils/elements'; import { createElement, insertElement, removeElement } from './utils/elements';
import { getDeep } from './utils/objects';
import is from './utils/is'; import is from './utils/is';
const source = { const source = {
@ -27,7 +28,7 @@ const source = {
// Update source // Update source
// Sources are not checked for support so be careful // Sources are not checked for support so be careful
change(input) { change(input) {
if (!is.object(input) || !('sources' in input) || !input.sources.length) { if (!getDeep(input, 'sources.length')) {
this.debug.warn('Invalid source format'); this.debug.warn('Invalid source format');
return; return;
} }
@ -52,32 +53,19 @@ const source = {
} }
// Set the type and provider // Set the type and provider
this.type = input.type; const { sources, type } = input;
this.provider = !is.empty(input.sources[0].provider) ? input.sources[0].provider : providers.html5; const [{ provider = providers.html5, src }] = sources;
const tagName = provider === 'html5' ? type : 'div';
const attributes = provider === 'html5' ? {} : { src };
// Check for support Object.assign(this, {
this.supported = support.check(this.type, this.provider, this.config.playsinline); provider,
type,
// Create new markup // Check for support
switch (`${this.provider}:${this.type}`) { supported: support.check(type, provider, this.config.playsinline),
case 'html5:video': // Create new element
this.media = createElement('video'); media: createElement(tagName, attributes),
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;
}
// Inject the new element // Inject the new element
this.elements.container.appendChild(this.media); this.elements.container.appendChild(this.media);
@ -114,7 +102,7 @@ const source = {
// Set new sources for html5 // Set new sources for html5
if (this.isHTML5) { if (this.isHTML5) {
source.insertElements.call(this, 'source', input.sources); source.insertElements.call(this, 'source', sources);
} }
// Set video title // Set video title

View File

@ -7,6 +7,15 @@ import browser from './utils/browser';
import { createElement } from './utils/elements'; import { createElement } from './utils/elements';
import is from './utils/is'; 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 // Check for feature support
const support = { const support = {
// Basic support // Basic support
@ -16,31 +25,9 @@ const support = {
// Check for support // Check for support
// Basic functionality vs full UI // Basic functionality vs full UI
check(type, provider, playsinline) { check(type, provider, playsinline) {
let api = false;
let ui = false;
const canPlayInline = browser.isIPhone && playsinline && support.playsinline; const canPlayInline = browser.isIPhone && playsinline && support.playsinline;
const api = support[type] || provider !== 'html5';
switch (`${provider}:${type}`) { const ui = api && support.rangeInput && (type !== 'video' || !browser.isIPhone || canPlayInline);
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;
}
return { return {
api, api,
@ -63,56 +50,29 @@ const support = {
// Check for mime type support against a player instance // Check for mime type support against a player instance
// Credits: http://diveintohtml5.info/everything.html // Credits: http://diveintohtml5.info/everything.html
// Related: http://www.leanbackplayer.com/test/h5mt.html // Related: http://www.leanbackplayer.com/test/h5mt.html
mime(type) { mime(inputType) {
const { media } = this; const [mediaType] = inputType.split('/');
if (!this.isHTML5 || mediaType !== this.type) {
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) {
return false; return false;
} }
// If we got this far, we're stuffed let type;
return false; 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 // Check for textTracks support