// ========================================================================== // Plyr HTML5 helpers // ========================================================================== import support from './support'; import { removeElement } from './utils/elements'; import { triggerEvent } from './utils/events'; import is from './utils/is'; import { silencePromise } from './utils/promise'; import { setAspectRatio } from './utils/style'; const html5 = { getSources() { if (!this.isHTML5) { return []; } const sources = Array.from(this.media.querySelectorAll('source')); // Filter out unsupported sources (if type is specified) return sources.filter((source) => { const type = source.getAttribute('type'); if (is.empty(type)) { return true; } return support.mime.call(this, type); }); }, // Get quality levels getQualityOptions() { // Whether we're forcing all options (e.g. for streaming) if (this.config.quality.forced) { return this.config.quality.options; } // Get sizes from elements return html5.getSources .call(this) .map((source) => Number(source.getAttribute('size'))) .filter(Boolean); }, setup() { if (!this.isHTML5) { 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() { // Get sources const sources = html5.getSources.call(player); const source = sources.find((s) => s.getAttribute('src') === player.source); // Return size, if match is found return source && Number(source.getAttribute('size')); }, set(input) { if (player.quality === input) { return; } // If we're using an an external handler... if (player.config.quality.forced && is.function(player.config.quality.onChange)) { player.config.quality.onChange(input); } else { // Get sources const sources = html5.getSources.call(player); // Get first match for requested size const source = sources.find((s) => Number(s.getAttribute('size')) === input); // No matching source found if (!source) { return; } // Get current state const { currentTime, paused, preload, readyState, playbackRate } = player.media; // Set new source player.media.src = source.getAttribute('src'); // Prevent loading if preload="none" and the current source isn't loaded (#1044) if (preload !== 'none' || readyState) { // Restore time player.once('loadedmetadata', () => { player.speed = playbackRate; player.currentTime = currentTime; // Resume playing if (!paused) { silencePromise(player.play()); } }); // Load new source player.media.load(); } } // Trigger change event triggerEvent.call(player, player.media, 'qualitychange', false, { quality: input, }); }, }); }, // Cancel current network requests // See https://github.com/sampotts/plyr/issues/174 cancelRequests() { if (!this.isHTML5) { return; } // Remove child sources removeElement(html5.getSources.call(this)); // Set blank video src attribute // This is to prevent a MEDIA_ERR_SRC_NOT_SUPPORTED error // Info: http://stackoverflow.com/questions/32231579/how-to-properly-dispose-of-an-html5-video-and-close-socket-or-connection this.media.setAttribute('src', this.config.blankVideo); // Load the new empty source // This will cancel existing requests // See https://github.com/sampotts/plyr/issues/174 this.media.load(); // Debugging this.debug.log('Cancelled network requests'); }, }; export default html5;