miru/app/js/playerHandler.js
2020-10-29 01:03:18 +01:00

500 lines
No EOL
14 KiB
JavaScript

const controls = document.getElementsByClassName('ctrl')
for (let item of controls) {
item.addEventListener("click", function () {
let func = this.dataset.name;
window[func]()
})
}
// event listeners
volume.addEventListener("input", () => updateVolume());
progress.addEventListener("input", dragBar);
progress.addEventListener("mouseup", dragBarEnd);
progress.addEventListener("touchend", dragBarEnd);
progress.addEventListener("click", dragBarEnd);
progress.addEventListener("mousedown", dragBarStart);
ptoggle.addEventListener("click", btnpp);
ptoggle.addEventListener("dblclick", btnfull);
player.addEventListener("fullscreenchange", updateFullscreen)
let playerData = {
octopusInstance: undefined
}
function resetVideo() {
!!playerData.octopusInstance ? playerData.octopusInstance.dispose() : ""
!!playerData.fonts ? playerData.fonts.forEach(file => {
URL.revokeObjectURL(file)
}) : ""
playerData = {
tracks: [],
headers: undefined,
styles: undefined,
subtitles: [],
subtitleStream: undefined,
octopusInstance: undefined,
fonts: [],
nowPlaying: undefined,
selected: undefined,
completed: undefined,
thumbnails: []
}
video.pause()
video.src = "";
video.load()
delete video
video.remove()
nowPlayingDisplay.textContent = playerData.nowPlaying || ""
dl.removeAttribute("href")
video = document.createElement("video")
if (settings.player7 && 'pictureInPictureEnabled' in document) {
video.setAttribute("autoPictureInPicture", "")
} else {
video.setAttribute("disablePictureInPicture", "")
bpip.setAttribute("disabled", "")
}
video.src = ""
video.id = "video"
video.setAttribute("preload", "none")
video.volume = volume.value / 100
video.style.setProperty("--sub-font", settings.subtitle1);
video.addEventListener("playing", resetBuffer);
video.addEventListener("canplay", resetBuffer);
video.addEventListener("loadeddata", initThumbnail);
video.addEventListener("loadedmetadata", updateDisplay);
video.addEventListener("ended", autoNext);
video.addEventListener("waiting", isBuffering);
video.addEventListener("timeupdate", updateDisplay);
video.addEventListener("timeupdate", updatePositionState);
video.addEventListener("timeupdate", checkCompletion);
player.prepend(video)
}
// progress bar and display
function updateDisplay() {
let progressPercent = (video.currentTime / video.duration * 100)
let bufferPercent = video.buffered.length == 0 ? 0 : video.buffered.end(video.buffered.length - 1) / video.duration * 100
progress.style.setProperty("--buffer", bufferPercent + "%");
updateBar(progressPercent || progress.value / 10);
createThumbnail(video);
}
function dragBar() {
video.pause()
updateBar(progress.value / 10)
let bg = playerData.thumbnails[Math.floor(currentTime / 5)]
thumb.src = bg || " "
}
function dragBarEnd() {
video.currentTime = currentTime || 0
playVideo()
}
async function dragBarStart() {
await video.pause()
updateBar(progress.value / 10)
}
let currentTime;
function updateBar(progressPercent) {
if (document.location.href.endsWith("#player")) {
currentTime = video.duration * progressPercent / 100
progress.style.setProperty("--progress", progressPercent + "%");
thumb.style.setProperty("--progress", progressPercent + "%");
elapsed.innerHTML = toTS(currentTime);
remaining.innerHTML = toTS(video.duration - currentTime);
progress.value = progressPercent * 10
progress.setAttribute("data-ts", toTS(currentTime))
}
}
// dynamic thumbnails
let canvas = document.createElement("canvas")
let context = canvas.getContext('2d')
let h
function initThumbnail() {
if (settings.player5) {
h = parseInt(150 / (video.videoWidth / video.videoHeight))
canvas.width = 150;
canvas.height = h;
thumb.style.setProperty("--height", h + "px");
}
}
function createThumbnail(vid) {
if (settings.player5) {
let index = Math.floor(vid.currentTime / 5)
if (!playerData.thumbnails[index] && h) {
context.fillRect(0, 0, 150, h);
context.drawImage(vid, 0, 0, 150, h);
playerData.thumbnails[index] = canvas.toDataURL("image/jpeg")
}
}
}
function finishThumbnails(url) {
if (settings.player5 && settings.player8) {
let thumbVid = document.createElement("video"),
index = 0
thumbVid.src = url
thumbVid.addEventListener('loadeddata', () => {
loadTime();
})
thumbVid.addEventListener('seeked', () => {
createThumbnail(thumbVid);
loadTime();
})
function loadTime() {
while (playerData.thumbnails[index] && index <= Math.floor(thumbVid.duration / 5)) {
index++
}
if (thumbVid.currentTime != thumbVid.duration) {
thumbVid.currentTime = index * 5
} else {
thumbVid.remove()
}
index++
}
}
}
//file download
function downloadFile(url, name) {
dl.href = url
dl.download = name
}
// bufering spinner
let buffer;
function resetBuffer() {
if (buffer) {
clearTimeout(buffer)
buffer = undefined
buffering.classList.add('hidden')
}
}
function isBuffering() {
buffer = setTimeout(displayBuffer, 150)
}
function displayBuffer() {
buffering.classList.remove('hidden')
resetTimer()
}
// immerse timeout
let immerseTime;
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
function immersePlayer() {
player.classList.add('immersed')
}
function resetTimer() {
clearTimeout(immerseTime);
player.classList.remove('immersed')
immerseTime = setTimeout(immersePlayer, parseInt(settings.player2) * 1000)
}
function toTS(sec) {
if (Number.isNaN(sec) || sec < 0) {
return "00:00";
}
let hours = Math.floor(sec / 3600)
let minutes = Math.floor((sec - (hours * 3600)) / 60)
let seconds = Math.floor(sec - (hours * 3600) - (minutes * 60));
if (minutes < 10) {
minutes = `0${minutes}`;
}
if (seconds < 10) {
seconds = `0${seconds}`;
}
if (hours > 0) {
return `${hours}:${minutes}:${seconds}`;
} else {
return `${minutes}:${seconds}`;
}
}
// play/pause button
async function playVideo() {
try {
await video.play();
bpp.innerHTML = "pause";
} catch (err) {
bpp.innerHTML = "play_arrow";
}
}
function btnpp() {
if (video.paused) {
playVideo();
} else {
bpp.innerHTML = "play_arrow";
video.pause();
}
}
function btnnext() {
nyaaSearch(playerData.nowPlaying[0], parseInt(playerData.nowPlaying[1]) + 1)
}
function autoNext() {
settings.player6 ? btnnext() : ""
}
// volume shit
let oldlevel;
function btnmute() {
if (video.volume == 0) {
updateVolume(oldlevel)
} else {
oldlevel = video.volume * 100
updateVolume(0)
}
}
function updateVolume(a) {
let level
if (a == null) {
level = volume.value;
} else {
level = a;
volume.value = a;
}
volume.style.setProperty("--volume-level", level + "%");
bmute.innerHTML = (level == 0) ? "volume_off" : "volume_up";
video.volume = level / 100
}
updateVolume(parseInt(settings.player1))
// PiP
async function btnpip() {
if (!playerData.octopusInstance) {
video !== document.pictureInPictureElement ? await video.requestPictureInPicture() : await document.exitPictureInPicture();
} else {
if (document.pictureInPictureElement) {
await document.exitPictureInPicture()
} else {
let canvas = document.createElement("canvas"),
subtitleCanvas = document.querySelector(".libassjs-canvas"),
canvasVideo = document.createElement("video"),
context = canvas.getContext("2d", { alpha: false }),
running = true
canvas.width = subtitleCanvas.width
canvas.height = subtitleCanvas.height
player.classList.add("pip")
function renderFrame() {
if (running) {
context.drawImage(video, 0, 0, canvas.width, canvas.height)
context.drawImage(subtitleCanvas, 0, 0)
window.requestAnimationFrame(renderFrame)
}
}
window.requestAnimationFrame(renderFrame)
canvasVideo.srcObject = canvas.captureStream()
canvasVideo.onloadeddata = async function () {
canvasVideo.play()
await canvasVideo.requestPictureInPicture()
}
canvasVideo.onleavepictureinpicture = () => {
running = false
canvasVideo.remove()
canvas.remove()
player.classList.remove("pip")
}
}
}
}
//miniplayer
if (!settings.player4) {
player.style.setProperty("--miniplayer-display", "none");
}
// theathe mode
function btntheatre() {
halfmoon.toggleSidebar();
}
// fullscreen
function btnfull() {
document.fullscreenElement ? document.exitFullscreen() : player.requestFullscreen();
}
function updateFullscreen() {
document.fullscreenElement ? bfull.innerHTML = "fullscreen_exit" : bfull.innerHTML = "fullscreen"
}
//seeking and skipping
function seek(a) {
if (a == 85 && video.currentTime < 10) {
video.currentTime = 90
} else if (a == 85 && (video.duration - video.currentTime) < 90) {
video.currentTime = video.duration
} else {
video.currentTime += a;
}
updateDisplay()
}
// subtitles, generates content every single time its opened because fuck knows when the parser will find new shit
let off
function btncap() {
let frag = document.createDocumentFragment()
off = document.createElement("a")
off.classList.add("dropdown-item", "pointer", "text-white")
off.innerHTML = "OFF"
off.onclick = () => {
selectLang("OFF")
}
frag.appendChild(off)
for (let track of video.textTracks) {
let template = document.createElement("a")
template.classList.add("dropdown-item", "pointer", "text-capitalize")
template.innerHTML = track.language || (!Object.values(video.textTracks).some(track => track.language == "eng" || track.language == "en") ? "eng" : track.label)
if (track.mode == "showing") {
template.classList.add("text-white")
off.classList.add("text-muted")
off.classList.remove("text-white")
} else {
template.classList.add("text-muted")
}
template.onclick = () => {
selectLang(track.language)
}
frag.appendChild(template)
}
subMenu.textContent = '';
subMenu.appendChild(frag)
}
function selectLang(lang) {
for (let track of video.textTracks) {
if (track.language == lang) {
track.mode = 'showing';
displayHeader(playerData.headers[playerData.tracks.indexOf(track)])
}
else {
track.mode = 'hidden';
}
}
btncap()
}
// keybinds
document.onkeydown = (a) => {
if (document.location.href.endsWith("#player")) {
switch (a.key) {
case " ":
btnpp();
break;
case "n":
btnnext();
break;
case "m":
btnmute();
break;
case "p":
btnpip();
break;
case "t":
btntheatre();
break;
case "c":
btncap();
break;
case "f":
btnfull();
break;
case "s":
seek(85);
break;
case "ArrowLeft":
seek(-parseInt(settings.player3));
break;
case "ArrowRight":
seek(parseInt(settings.player3));
break;
case "ArrowUp":
updateVolume(parseInt(volume.value) + 5)
break;
case "ArrowDown":
updateVolume(parseInt(volume.value) - 5)
break;
}
}
}
// media session
function selPlaying(sel) {
playerData.nowPlaying = sel
if ('mediaSession' in navigator) {
navigator.mediaSession.metadata = new MediaMetadata({
title: store[playerData.nowPlaying[0]] ? store[playerData.nowPlaying[0]].title.userPreferred : playerData.nowPlaying[0],
artist: "Episode " + playerData.nowPlaying[1],
album: "Miru",
artwork: [
{
src: store[playerData.nowPlaying[0]] ? store[playerData.nowPlaying[0]].coverImage.medium : "",
sizes: '128x128',
type: 'image/png'
}
]
});
}
nowPlayingDisplay.textContent = `EP ${playerData.nowPlaying[1]}`
}
function updatePositionState() {
if ('setPositionState' in navigator.mediaSession && video.duration) {
navigator.mediaSession.setPositionState({
duration: video.duration || 0,
playbackRate: video.playbackRate || 0,
position: video.currentTime || 0
});
}
}
if ('mediaSession' in navigator) {
navigator.mediaSession.setActionHandler('play', btnpp);
navigator.mediaSession.setActionHandler('pause', btnpp);
navigator.mediaSession.setActionHandler('seekbackward', () => {
seek(-parseInt(settings.player3));
});
navigator.mediaSession.setActionHandler('seekforward', () => {
seek(parseInt(settings.player3));
});
navigator.mediaSession.setActionHandler('nexttrack', btnnext);
}
//AL entry auto add
function checkCompletion(){
if(settings.other2 && video.duration - 120 < video.currentTime && !playerData.completed){
playerData.completed = true
alEntry()
}
}
resetVideo()