182 lines
5.5 KiB
JavaScript
Executable File
182 lines
5.5 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) => {
|
|
self.setVideoSource(videoName)
|
|
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
|
|
}
|