bashtube/webroot/js/player.js

486 lines
16 KiB
JavaScript

window.addEventListener('DOMContentLoaded', (event) => {
const autoplayInput = document.querySelector('#autoplayInput');
const videoStreamInput = document.querySelector('#videoStreamInput');
const audioStreamInput = document.querySelector('#audioStreamInput');
const subsInput = document.querySelector('#subsInput');
const speedInput = document.querySelector("#speedInput");
const loopInput = document.querySelector("#loopInput");
const controlbar = document.querySelector(".html5-video-controls")
const video = document.getElementById('player_video');
const audio = document.getElementById('player_audio');
const movie = document.getElementById('movie_player');
let fps = 30;
const searchParams = new URLSearchParams(window.location.search.slice(1))
let startTime = 0;
if (searchParams.get("t")) {
const [, hours, minutes, seconds] = /^(?:(?:([0-9]+)[h:])?(?:([0-9]+)[m:]))?([0-9]+)s?$/.exec(searchParams.get("t"));
if (hours) startTime = parseInt(hours, 10) * 3600;
if (minutes) startTime += parseInt(minutes, 10) * 60;
if (seconds) startTime += parseInt(seconds, 10);
}
console.log(startTime);
loopInput.checked = false;
subs = JSON.parse(document.getElementById('yt_subs').innerText)
formats = JSON.parse(document.getElementById('yt_formats').innerText)
.filter((fmt) => isFormatSupported(fmt) === true)
.sort((a, b) => {
if (a.vcodec === 'none' && b.vcodec !== 'none') {
return -1;
}
if (a.vcodec !== 'none' && b.vcodec === 'none') {
return 1;
}
if (a.vcodec !== 'none' && b.vcodec !== 'none') {
return b.height - a.height;
}
if (a.acodec !== 'none' && b.acodec !== 'none') {
return b.abr - a.abr;
}
});
console.log(formats);
if (localStorage.getItem("videoStream") == null || localStorage.getItem("videoStream") == "") {
const videoFormat = formats.find((fmt) => fmt.vcodec !== 'none');
const audioFormat = videoFormat.acodec === 'none' ? formats.find((fmt) => fmt.acodec !== 'none') : null;
console.log('selected video format', videoFormat);
console.log('selected audio format', audioFormat);
fps = videoFormat.fps;
selectStreams(videoFormat, audioFormat)
} else {
let videoFormat = formats.find((fmt) => fmt.format_id == localStorage.getItem("videoStream"));
if (videoFormat == null) {
videoFormat = formats.find((fmt) => fmt.vcodec !== 'none');
}
let audioFormat = videoFormat.acodec === 'none' ? formats.find((fmt) => fmt.format_id == localStorage.getItem("audioStream")) : null;
if (audioFormat == null) {
audioFormat = videoFormat.acodec === 'none' ? formats.find((fmt) => fmt.acodec !== 'none') : null;
}
console.log('selected video format', videoFormat);
console.log('selected audio format', audioFormat);
fps = videoFormat.fps;
selectStreams(videoFormat, audioFormat)
}
video.preload="auto";
audio.preload="auto";
if (localStorage.getItem("volume") != null) {
setVolume(localStorage.getItem("volume"));
}
const playButton = document.querySelector('.ytp-button[aria-label="Play"]');
function toggleVideo(play) {
const { classList } = playButton;
const shouldPlay = typeof play === 'boolean' ? play : video.paused;
try {
if (shouldPlay) {
classList.remove('ytp-button-play');
classList.add('ytp-button-pause');
handleMouse("frame");
if (video.ended) {
video.currentTime = 0;
audio.currentTime = 0;
playbackWait();
} else {
video.play();
if (audio.src) {
audio.play();
}
}
} else {
classList.remove('ytp-button-pause');
classList.add('ytp-button-play');
clearTimeout(mouseMoveTimeout);
video.pause();
if (audio.src) {
audio.currentTime = video.currentTime; // sync audio to video on pause
audio.pause();
}
if (video.currentTime == video.duration && loopInput.checked == true) {
video.currentTime = 0;
audio.currentTime = 0;
playbackWait();
}
}
} catch (e) {
console.error(e);
}
}
function updateTime() {
document.querySelector('.ytp-time-current').innerHTML =
Math.floor(video.currentTime / 60) +
':' +
Math.floor(video.currentTime % 60)
.toString()
.padStart(2, '0');
if (isNaN(video.duration)) {
document.querySelector('.ytp-time-duration').innerHTML = '0:00';
} else {
document.querySelector('.ytp-time-duration').innerHTML =
Math.floor(video.duration / 60) +
':' +
Math.floor(video.duration % 60)
.toString()
.padStart(2, '0');
}
document.querySelector('.ytp-play-progress').style.transform = 'scaleX(' + video.currentTime / video.duration + ')';
document.querySelector('.html5-scrubber-button').style.left = (video.currentTime / video.duration) * 100 + '%';
}
function scrub(e) {
const w = document.querySelector('.ytp-progress-list').getBoundingClientRect();
const amount = (e.clientX - w.x) / w.width;
video.currentTime = video.duration * amount;
audio.currentTime = audio.duration * amount;
console.log(e);
}
function volume(e) {
const v = document.querySelector('.ytp-volume-slider').getBoundingClientRect();
const amount = (e.clientX - v.x) / v.width;
setVolume(amount);
}
function setVolume(amount) {
if (audio.src) {
audio.volume = amount;
localStorage.setItem("volume", audio.volume);
} else {
video.volume = amount;
localStorage.setItem("volume", video.volume);
}
document.querySelector('.ytp-volume-slider-foreground').style.left = amount * 51 + 'px';
const icon = document.querySelector('.ytp-button-volume');
if (amount == 0) {
icon.dataset.value = 'off';
} else if (amount < 0.2) {
icon.dataset.value = 'min';
} else if (amount < 0.4) {
icon.dataset.value = 'quiet';
} else if (amount < 0.6) {
icon.dataset.value = 'normal';
} else if (amount < 0.8) {
icon.dataset.value = 'loud';
} else {
icon.dataset.value = 'max';
}
}
function toggleFullscreen() {
if (document.fullscreenElement || document.mozFullScreenElement || document.webkitFullscreenElement) {
if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.cancelFullScreen) {
document.cancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
} else {
if (movie.requestFullscreen) {
movie.requestFullscreen();
} else if (movie.mozRequestFullScreen) {
movie.mozRequestFullScreen();
} else if (movie.webkitRequestFullscreen) {
movie.webkitRequestFullscreen();
}
}
}
function toggleSettings() {
let menu = document.querySelector('.settings_menu');
if(menu.style.display == "block") {
menu.style.display = "none";
} else {
menu.style.display = "block";
}
}
function applyStreams() {
localStorage.setItem("videoStream", videoStreamInput.value);
localStorage.setItem("audioStream", audioStreamInput.value);
localStorage.setItem("autoplay", autoplayInput.checked);
const videoFormat = formats.find((fmt) => fmt.format_id == videoStreamInput.value);
const audioFormat = videoFormat.acodec === 'none' ? formats.find((fmt) => fmt.format_id == audioStreamInput.value) : null;
selectStreams(videoFormat, audioFormat)
}
function resetStreams() {
localStorage.removeItem("videoStream");
localStorage.removeItem("audioStream");
}
function seekAbsolute(t) {
video.pause();
video.currentTime=t;
if(audio) {
audio.pause();
audio.currentTime=t;
}
}
function seekRelative(t, play) {
video.pause();
video.currentTime=video.currentTime+t;
if(audio) {
audio.pause();
audio.currentTime=video.currentTime;
}
if(play != false) {
playbackWait();
}
}
function handleSubsChange(e) {
Array.from(video.textTracks).forEach((e) => {e.mode='disabled'});
Array.from(video.textTracks)[parseInt(subsInput.value)].mode='showing';
}
function handleKeyboard(e) {
console.log(e)
if (e.target.name != "search_query" && !e.ctrlKey && !e.altKey) {
if (e.key == "ArrowLeft") { // go ahead, complain this is not a switch
seekRelative(-5);
e.preventDefault();
} else if (e.key == "ArrowRight") {
seekRelative(5);
e.preventDefault();
} else if (e.key == " " || e.key == "k") {
toggleVideo();
e.preventDefault();
} else if (e.key == "j") {
seekRelative(-10);
} else if (e.key == "l") {
seekRelative(10);
} else if (e.key == "f") {
toggleFullscreen();
} else if (e.key == ">") {
if (speedInput.selectedIndex != 6) speedInput.selectedIndex += 1;
changeSpeed();
} else if (e.key == "<") {
if (speedInput.selectedIndex != 0) speedInput.selectedIndex -= 1;
changeSpeed();
} else if (e.key == ".") {
if (video.paused) {
seekRelative(1/fps, false);
}
} else if (e.key == ",") {
if (video.paused) {
seekRelative(-1/fps, false);
}
}
}
}
let mouseMoveTimeout;
function handleMouse(type, e) {
movie.classList.remove("hide-cursor");
controlbar.style="transform: translateY(0px);";
clearTimeout(mouseMoveTimeout);
if(video.paused == false) {
if(type != "controls") {
mouseMoveTimeout = setTimeout(() => {
controlbar.style="transform: translateY(40px);";
movie.classList.add("hide-cursor");
}, 2000);
} else if (type == "controls") {
mouseMoveTimeout = setTimeout(() => {
controlbar.style="transform: translateY(40px);";
movie.classList.add("hide-cursor");
}, 8000);
}
}
}
function handleProtected(e) {
console.log(e)
if(e.originalTarget.error.code == 4 && ! e.originalTarget.currentSrc.startsWith("https://"+window.location.hostname)) {
e.target.src="https://"+window.location.hostname+"/proxy?url="+encodeURIComponent(encodeURIComponent(e.originalTarget.currentSrc))
}
}
function changeSpeed() {
video.playbackRate = parseFloat(speedInput.value);
audio.playbackRate = parseFloat(speedInput.value);
}
function getMimeType(fmt) {
const mainType = fmt.vcodec !== 'none' ? 'video' : 'audio';
let secondary = {
m4a: 'mp4',
}[fmt.ext] || fmt.ext;
const codecs = [fmt.vcodec, fmt.acodec].filter(c => c && c !== 'none').join(', ');
return `${mainType}/${secondary}; codecs="${codecs}"`;
}
function isFormatSupported(fmt) {
//// currently, we remove other formats in the backend
//if (!['http', 'https'].includes(fmt.protocol))
// return false;
// must be very old: https://developer.mozilla.org/en-US/docs/Web/API/MediaSource/isTypeSupported#browser_compatibility
if (!('MediaSource' in window)) {
if (['avc1', 'none'].includes(fmt.vcodec.substring(0, 4))
&& ['mp4a', 'none'].includes(fmt.acodec.substring(0, 4))) {
return true;
}
return false;
}
return MediaSource.isTypeSupported(getMimeType(fmt));
}
function selectStreams(videoFormat, audioFormat) {
video.src = videoFormat.url;
if (audioFormat) {
audio.src = audioFormat.url;
}
}
function playbackWait() {
const waiting = setInterval(()=> {
if (document.querySelector("video").readyState == 4) {
clearInterval(waiting);
setTimeout(() => {
toggleVideo(true);
},150); // let the video buffer a tiny bit more
} else {
console.log("waiting...")
}
},100);
}
// document.querySelector('.ytp-button-play').addEventListener('click', () => toggleVideo());
document.querySelector('.ytp-settings-button').addEventListener('click', () => toggleSettings());
document.querySelector('#applyStreams').addEventListener('click', () => applyStreams());
document.querySelector('#resetStreams').addEventListener('click', () => resetStreams());
playButton.addEventListener('click', () => toggleVideo());
video.addEventListener('click', () => toggleVideo());
video.addEventListener('dblclick', () => toggleFullscreen());
let videoWaiting = false;
let audioWaiting = false;
video.addEventListener('waiting', () => {
toggleVideo(false);
videoWaiting = true;
});
video.addEventListener('playing', () => {
videoWaiting = false;
console.log(`videoWaiting ${videoWaiting}, audioWaiting ${audioWaiting}`);
if (!audioWaiting) {
toggleVideo(true);
}
});
audio.addEventListener('waiting', () => {
toggleVideo(false);
audioWaiting = true;
});
audio.addEventListener('playing', () => {
audioWaiting = false;
console.log(`videoWaiting ${videoWaiting}, audioWaiting ${audioWaiting}`);
if (!videoWaiting) {
toggleVideo(true);
}
});
video.addEventListener('timeupdate', () => updateTime());
video.addEventListener('ended', () => toggleVideo(false)); // just to change the classes
video.addEventListener('ended', () => console.log("event fired")); // just to change the classes
document.querySelector('.ytp-progress-list').addEventListener('click', (e) => scrub(e));
// document.querySelector('.ytp-play-progress').addEventListener('click', (e) => scrub(e));
document.querySelector('.ytp-volume-slider').addEventListener('click', (e) => volume(e));
document.querySelector('.ytp-button-fullscreen-enter').addEventListener('click', () => toggleFullscreen());
document.querySelector('video').addEventListener('error', (e) => handleProtected(e));
document.querySelector('audio').addEventListener('error', (e) => handleProtected(e));
document.querySelector('body').addEventListener('keydown', (e) => handleKeyboard(e));
document.querySelector('.html5-video-container').addEventListener('mousemove', (e) => handleMouse("frame", e));
controlbar.addEventListener('mousemove', (e) => handleMouse("controls", e));
speedInput.addEventListener('change', () => changeSpeed());
speedInput.selectedIndex=2;
subsInput.addEventListener('change', () => handleSubsChange());
seekAbsolute(startTime);
if(localStorage.getItem("autoplay") == "true") {
toggleVideo(true);
document.querySelector('#autoplayInput').checked = true;
playbackWait();
}
setTimeout(() => {
controlbar.style="transform: translateY(40px);";
}, 2000);
// formats
console.log("w dzisiejszym menu")
let uwu = document.createElement("option");
uwu.value = ''
uwu.innerText = ''
audioStreamInput.append(uwu);
let selectedAudioIndex = 0;
let selectedVideoIndex = 0;
formats.forEach((e) => {
let uwu = document.createElement("option");
uwu.value = e.format_id;
if (e.acodec == "none") {
uwu.innerText = `${e.ext} ${e.height}p (${e.format_id})`;
if (uwu.value == localStorage.getItem("videoStream")) {
selectedVideoIndex = videoStreamInput.length;
console.log(selectedVideoIndex)
}
videoStreamInput.append(uwu);
console.log(`- ${e.format_id}, czyli ${e.height}p`)
} else if (e.vcodec == "none") {
uwu.innerText = `${e.acodec} ${e.abr}kbps (${e.format_id})`;
if (uwu.value == localStorage.getItem("audioStream")) {
selectedAudioIndex = audioStreamInput.length;
console.log(selectedAudioIndex)
}
audioStreamInput.append(uwu);
console.log(`- ${e.format_id}, czyli ${e.acodec} ${e.abr}kbps`)
} else {
uwu.innerText = `${e.ext} ${e.height}p (${e.format_id})`;
if (uwu.value == localStorage.getItem("videoStream")) {
selectedVideoIndex = videoStreamInput.length;
console.log(selectedVideoIndex)
}
videoStreamInput.append(uwu);
console.log(`A TAKŻE SPECJALNEGO GOŚCIA ${e.format_id}, czyli ${e.height}p WRAZ Z RODZINĄ`)
}
})
uwu = document.createElement('option');
uwu.innerText='';
uwu.value=-1;
subsInput.appendChild(uwu);
let subsIndex = 0;
subs.forEach((e) => {
let track = document.createElement('track');
let uwu = document.createElement('option');
track.src="https://"+window.location.hostname+"/proxy?url="+encodeURIComponent(e.url);
track.srclang=e.lang;
track.label=e.lang;
track.kind="subtitles";
console.log(track.src)
video.appendChild(track);
uwu.innerText=e.lang;
uwu.value=subsIndex;
subsInput.appendChild(uwu);
subsIndex=subsIndex+1;
})
videoStreamInput.selectedIndex = selectedVideoIndex;
audioStreamInput.selectedIndex = selectedAudioIndex;
});