// @license http://www.gnu.org/licenses/agpl-3.0.html AGPL-3.0 (function () { if (Hls.isSupported()) { var videoSources = document.querySelectorAll("video source[type='application/vnd.apple.mpegurl']"); videoSources.forEach(function (source) { var playlist = source.src; var oldVideo = source.parentNode; var autoplay = oldVideo.classList.contains("hls_autoplay"); // If HLS is supported natively then don't use hls.js if (oldVideo.canPlayType(source.type)) { if (autoplay) { oldVideo.play(); } return; } // Replace video with copy that will have all "source" elements removed var newVideo = oldVideo.cloneNode(true); var allSources = newVideo.querySelectorAll("source"); allSources.forEach(function (source) { source.remove(); }); // Empty source to enable play event newVideo.src = "about:blank"; oldVideo.parentNode.replaceChild(newVideo, oldVideo); function initializeHls() { newVideo.removeEventListener('play', initializeHls); var hls = new Hls({ autoStartLoad: false }); hls.loadSource(playlist); hls.attachMedia(newVideo); hls.on(Hls.Events.MANIFEST_PARSED, function () { hls.loadLevel = hls.levels.length - 1; var availableLevels = hls.levels.map(function(level) { return { height: level.height, width: level.width, bitrate: level.bitrate, }; }); addQualitySelector(newVideo, hls, availableLevels); hls.startLoad(); newVideo.play(); }); hls.on(Hls.Events.ERROR, function (event, data) { var errorType = data.type; var errorFatal = data.fatal; if (errorFatal) { switch (errorType) { case Hls.ErrorType.NETWORK_ERROR: hls.startLoad(); break; case Hls.ErrorType.MEDIA_ERROR: hls.recoverMediaError(); break; default: hls.destroy(); break; } } console.error("HLS error", data); }); } function addQualitySelector(videoElement, hlsInstance, availableLevels) { var qualitySelector = document.createElement('select'); qualitySelector.classList.add('quality-selector'); var last = availableLevels.length - 1; availableLevels.forEach(function (level, index) { var option = document.createElement('option'); option.value = index.toString(); var bitrate = (level.bitrate / 1_000).toFixed(0); option.text = level.height + 'p (' + bitrate + ' kbps)'; if (index === last) { option.selected = "selected"; } qualitySelector.appendChild(option); }); qualitySelector.selectedIndex = availableLevels.length - 1; qualitySelector.addEventListener('change', function () { var selectedIndex = qualitySelector.selectedIndex; hlsInstance.nextLevel = selectedIndex; hlsInstance.startLoad(); }); videoElement.parentNode.appendChild(qualitySelector); } newVideo.addEventListener('play', initializeHls); if (autoplay) { newVideo.play(); } }); } else { var videos = document.querySelectorAll("video.hls_autoplay"); videos.forEach(function (video) { video.setAttribute("autoplay", ""); }); } })(); // @license-end