eirtube/html/static/js/player/quality.js

182 lines
5.6 KiB
JavaScript
Executable File

export default (modules, q, qa) => {
let self
let lastLoading = modules.globals.dlStatus > 0 && modules.globals.dlStatus < 3
let videoSource = modules.globals.videoPath
// Watch for incomplete downloaded video
let downloading = false
if (modules.globals.dlStatus > 0 && modules.globals.dlStatus < 3) {
downloading = true
modules.cacheInfo.pingCache(`${modules.globals.data.videoId}-${videoSource.split("&quality=")[1] || modules.globals.startingFormat.qualityLabel}`, () => {
downloading = false
self.reloadSource()
}, 1000 * 2)
}
// If video is still downloading and skips to the end, try to reload source and rewind
if (downloading) {
let lastSafeTime
function updateLastSafeTime() {
lastSafeTime = modules.globals.video.currentTime
if (downloading)
setTimeout(updateLastSafeTime, 1000 * 1.5)
}
updateLastSafeTime()
modules.globals.video.addEventListener("ended", () => {
modules.controls.hideControls(false)
if (downloading) {
modules.globals.video.currentTime = lastSafeTime
self.reloadSource()
}
})
}
self = {
downloadMp4Btn: document.getElementById("download-btn"),
downloadOggBtn: document.getElementById("download-ogg-btn"),
safeQualities: {},
lastToast: null,
setQualityButtons: enable => {
for (const btn of qa(".videoControls .settingsPopout .settingsPage[data-name='quality'] .setting.quality"))
btn.toggleAttribute("disabled", !enable)
self.downloadMp4Btn.toggleAttribute("disabled", !enable)
self.downloadOggBtn.toggleAttribute("disabled", !enable)
},
startLoadingQuality: quality => {
self.setQualityButtons(false)
newToastWhenReady("yellow", "loading", `Loading ${quality}...`, true)
.then(toast => {
self.lastToast = toast;
if (!lastLoading) {
toast.container.remove()
self.lastToast = null
}
})
},
qualitySelected: quality => {
quality = quality || modules.globals.startingFormat.qualityLabel
modules.controls.setQualityButtonActive(quality)
if (lastLoading)
return
lastLoading = true
self.startLoadingQuality(quality)
let rateLimitToast
let doFetch
doFetch = () => {
fetch(`/watch?v=${modules.globals.data.videoId}&quality=${quality}${modules.player.startingTime ? `&t=${modules.player.startingTime}` : ""}`)
.then(r => {
if (r.status == 200)
self.waitForNewVideoLoad(`${modules.globals.data.videoId}`, quality)
else if (r.status == 429) {
newToastWhenReady("red", "loading", `Too many requests. Trying again in ${r.headers.get("retry-after")} seconds...`, true)
.then(toast => rateLimitToast = toast)
setTimeout(() => {
if (rateLimitToast)
setToastRemove(rateLimitToast.container)
doFetch()
}, 1000 * Number(r.headers.get("retry-after")))
}
else {
newToastWhenReady("red", "x", `Failed to switch quality (${r.status}: ${r.statusText})`)
setTimeout(doFetch, 1000 * 10)
}
})
}
doFetch()
},
waitForNewVideoLoad: (videoName, quality) => {
modules.cacheInfo.pingCache(`${videoName}-${quality}`, () => self.videoDownloaded(`/getVideo?v=${videoName}&q=${quality}`, quality), 1000 * 3)
},
setVideoSource: (newSource, dontReload) => {
videoSource = newSource
if (!dontReload)
self.reloadSource()
},
videoDownloaded: (videoName, quality, initial) => {
self.setVideoSource(videoName, initial)
self.safeQualities[quality] = true
modules.controls.onVideoDownloaded(quality)
// "Done!" toast
if (self.lastToast)
newToastWhenReady("green", "check", "Done!")
lastLoading = false
self.setQualityButtons(true)
self.downloadMp4Btn.href = `${videoName}&dl=1`
// Remove last "loading" toast if applicable
if (self.lastToast && self.lastToast.container)
setToastRemove(self.lastToast.container)
self.lastToast = null
},
reloadSource() {
let lastTime = modules.globals.video.currentTime
modules.globals.video.src = videoSource
modules.globals.video.currentTime = lastTime
modules.globals.video.load()
modules.globals.video.pause()
if (modules.player.lastPlaying)
modules.globals.video.play()
modules.globals.video.focus()
}
}
// Autoload HD video
function preloadHDVideo() {
const f = modules.globals.targetFormat
self.downloadMp4Btn.innerHTML = `Download ${f.cloudtube__label.replace(" *", "")} (${f.eirtube__size})`
lastLoading = true
self.startLoadingQuality(f.qualityLabel)
self.waitForNewVideoLoad(modules.globals.data.videoId, f.qualityLabel)
}
const preloadRatelimitRegex = /([\d]+p) in (\d\d?) seconds.../
if (modules.globals.awaitingNewFormat) {
let preloadRatelimited = false
for (const toast of document.getElementsByClassName("toast-container")) {
const innerToast = toast.querySelector(".toast")
const text = innerToast.childNodes[1].textContent
// Look for ratelimited preload text
const match = text.match(preloadRatelimitRegex)
if (match) {
preloadRatelimited = true
const seconds = Number(match[2])
innerToast.childNodes[1].textContent = text.replace("You may download", "Preloading")
toast.classList.add("nofade")
setTimeout(() => {
if (toast)
setToastRemove(toast)
self.qualitySelected(modules.globals.targetFormat.qualityLabel)
}, (seconds + 0.5) * 1000)
break
}
}
if (!preloadRatelimited)
preloadHDVideo()
}
self.downloadOggBtn.addEventListener("click", event => {
newToastWhenReady("yellow", "loading", "Extracting audio...", true)
})
// Reload source if error
modules.globals.video.addEventListener("error", () => setTimeout(self.reloadSource, 1000 * 2))
return self
}