// @license magnet:?xt=urn:btih:1f739d935676111cfff4b4693e3816e664797050&dn=gpl-3.0.txt GPL-v3-or-Later function setup_playback(description) { document.getElementById("no-script").classList.remove("noscript"); document.getElementById("controls").classList.add("javascript"); video_manifest = description; console.log(description); player = document.getElementById("player"); player.addEventListener("pause", (event) => playStateChanged(false)); player.addEventListener("playing", (event) => playStateChanged(true)); filteredOptions = description.entries.filter(o => shouldOfferStream(o, description.entries)); if(filteredOptions.length == 0){ player.src = "invalid://invalid"; document.getElementById("unplayable-modal").showModal(); return; } player.src = filteredOptions[0].path; qualitySelector = document.getElementById("quality-selector"); filteredOptions.forEach(option => { opt = document.createElement("option") opt.value = option.path; opt.innerHTML = option.label; qualitySelector.appendChild(opt); }); startRes = findOptimalOptionForScreen(filteredOptions); qualitySelector.value = startRes.path qualitySelected(); doSpeedTest(startRes, filteredOptions); } function qualitySelected() { qualitySelector = document.getElementById("quality-selector"); player = document.getElementById("player"); paused = player.paused; time = player.currentTime; player.src = qualitySelector.value; player.load(); player.currentTime = time; if(!paused) { player.play(); } } function canPlayStream(stream) { if(stream.type !== "video") { return false; } player = document.getElementById("player"); return player.canPlayType(`${stream.mimetype}; codecs="${stream.metadata.codecs}"`); } function shouldOfferStream(stream, streams) { if(!canPlayStream(stream)) { return false; } if(stream.metadata.alternative_to == undefined) { return true; } return !hasHigherUsableAlternative(stream, streams); } function hasHigherUsableAlternative(stream, streams) { if(stream.metadata.alternative_to == undefined) { return false; } parent = streams.find(s => s.label == stream.metadata.alternative_to); if(canPlayStream(parent)) { return true; } return hasHigherUsableAlternative(parent, streams); } function findOptimalOptionForScreen(options) { screenSize = Math.max(window.screen.width, window.screen.height); screenSize = screenSize * window.devicePixelRatio filtered = options.filter(o => o.type === "video" && Math.max(o.metadata.size.split("x")[0], o.metadata.size.split("x")[1]) <= screenSize); console.log(filtered); if(filtered.length == 0){ return options[options.length - 1]; } return filtered[0]; } function downloadVideo() { document.getElementById("download-modal").showModal(); } function showInfo() { document.getElementById("info-modal").showModal(); } function shareVideo() { document.getElementById("share-modal").showModal(); } function playStateChanged(playing) { controls = document.getElementById("controls") if(playing) { controls.classList.remove("paused") } else { controls.classList.add("paused") } } function doSpeedTest(currentOption, options) { startTime = window.performance.now(); request = new XMLHttpRequest(); request.onreadystatechange = function() { if(request.readyState === 2) { // Reset start time, headers received. startTime = window.performance.now(); } if(request.readyState === 4 && (request.status === 200 || request.status === 206)) { endTime = window.performance.now(); size = request.response.size; rate = size / ((endTime - startTime) / 1000) console.log(`Detected connection rate: ${rate} bytes/sec`); filtered = options.filter(o => o.type === "video" && o.byterate < rate); if(filtered.length == 0) { filtered = [options[options.length - 1]]; } optimal = findOptimalOptionForScreen(filtered); if(optimal !== currentOption) { qualitySelector.value = optimal.path console.log("Switched res"); qualitySelected(); } else { console.log("Got it right first try B)"); } } } requestSize = Math.min(options[0].filesize, Math.round(options[0].byterate)); request.open("GET", options[0].path); request.responseType = "blob"; request.setRequestHeader("Range", `bytes=0-${requestSize}`); request.send(); } // @license-end