Better-Youtube-Plus/src/scripts/betterYoutube.js

403 lines
16 KiB
JavaScript

(function() {
// Declare variables
let slugInputTag, ytThumbImgMenu, ytEnhancerMenu; // Menu systems
let ytThumbnailBttn, ytMaxDefaultImg, ytHqDefaultImg, // Buttons & Images
ytLoopBttn, ytFloatBttn, ytAMaxDefaultImg, ytAHqDefaultImg;
let mastHead, mainContentArea, playerWindow; // Youtube Player container
let video, containerOfPlyrWndow, poppedContainer; // Video accessor
let part, videoSlug, temp; // Image part
let videoTimeLength, videoTimeCurent, ytRangeStart, ytRangeEnd,
ytdVideoIntervalLoop;
let loopingInterval = false;
let count = 0;
let OSName = "";
// Options for the observer (which mutations to observe)
const config = { attributes: true };
const preSetupProc = () => {
if (navigator.appVersion.indexOf("Win")!=-1) OSName = "Windows";
if (navigator.appVersion.indexOf("Mac")!=-1) OSName = "MacOS";
if (navigator.appVersion.indexOf("X11")!=-1) OSName = "UNIX";
if (navigator.appVersion.indexOf("Linux")!=-1) OSName ="Linux";
video = document.getElementsByTagName("video")[0]; // Video Controler
slugInputTag = document.createElement("INPUT");
ytRangeEnd = document.createElement("INPUT");
slugInputTag.id = "slugCopyZone";
ytRangeEnd.id = "rangeEndID";
slugInputTag.type = "text";
ytRangeEnd.type = "text";
// We need to wait for info to load before getting full duration
setTimeout(function () {
videoTimeLength = document.getElementsByClassName("ytp-time-duration")[0].innerHTML;
if (!document.getElementById("rangeEndID")) {
} else {
ytRangeEnd = document.getElementById("rangeEndID");
}
ytRangeEnd.value = videoTimeLength;
}, 1000);
if (!document.getElementById("slugCopyZone")) {
document.body.appendChild(slugInputTag);
} else {
slugInputTag = document.getElementById("slugCopyZone");
}
slugInputTag.value = video.baseURI.slice(32, 32+11);
}
const setupProc = () => {
poppedContainer = document.createElement("DIV");
ytThumbImgMenu = document.createElement("DIV");
ytEnhancerMenu = document.createElement("DIV");
ytThumbnailBttn = document.createElement("IMG");
ytDownloadBttn = document.createElement("IMG");
ytLoopBttn = document.createElement("IMG");
ytFloatBttn = document.createElement("IMG");
ytMaxDefaultImg = document.createElement("IMG");
ytHqDefaultImg = document.createElement("IMG");
ytMqDefaultImg = document.createElement("IMG");
ytSdDefaultImg = document.createElement("IMG");
ytAMaxDefaultImg = document.createElement("A");
ytAHqDefaultImg = document.createElement("A");
ytAMedDefaultImg = document.createElement("A");
ytASdDefaultImg = document.createElement("A");
ytIfrm = document.createElement("IFRAME");
// Loop range controls
ytRangeSection = document.createElement("SECTION");
ytRangeStart = document.createElement("INPUT");
// Get nodes for page work
containerOfPlyrWndow = document.getElementById("player-container"); // Container of actual player - Used for floating window
part = "https://img.youtube.com/vi/";
// Append to nodes as required
ytThumbnailBttn.title = "Video Thumbnails...";
ytLoopBttn.title = "Start Loop...";
ytFloatBttn.title = "Float Video Container";
ytRangeStart.title = "Loop Range Start";
ytRangeEnd.title = "Loop Range End";
ytRangeStart.type = "text";
ytRangeStart.value = "0:00";
// Insert
ytEnhancerMenu.appendChild(ytThumbnailBttn);
ytEnhancerMenu.appendChild(ytLoopBttn);
ytEnhancerMenu.appendChild(ytRangeSection);
ytEnhancerMenu.appendChild(ytFloatBttn);
if (OSName.includes("MacOS") || OSName.includes("UNIX") ||
OSName.includes("Linux")) {
console.log("System supports downloader...");
console.log("OS is : " + OSName);
ytEnhancerMenu.appendChild(ytDownloadBttn);
}
ytRangeSection.append(ytRangeStart);
ytRangeSection.append(ytRangeEnd);
document.body.appendChild(poppedContainer);
document.body.appendChild(ytThumbImgMenu);
document.body.appendChild(ytEnhancerMenu);
ytAMaxDefaultImg.appendChild(ytMaxDefaultImg);
ytAHqDefaultImg.appendChild(ytHqDefaultImg);
ytAMedDefaultImg.appendChild(ytMqDefaultImg);
ytASdDefaultImg.appendChild(ytSdDefaultImg);
ytThumbImgMenu.appendChild(ytAMaxDefaultImg);
ytThumbImgMenu.appendChild(ytAHqDefaultImg);
ytThumbImgMenu.appendChild(ytAMedDefaultImg);
ytThumbImgMenu.appendChild(ytASdDefaultImg);
poppedContainer.appendChild(ytIfrm);
// Set onclick actions
ytThumbnailBttn.addEventListener("click", showThumbImageVew);
ytLoopBttn.addEventListener("click", setLoop);
ytFloatBttn.addEventListener("click", toggleFloat);
ytDownloadBttn.addEventListener("click", downloadVideo);
video.addEventListener("wheel", manageVolume);
// Observer target for fullscreen action...
targetNode = document.getElementsByTagName('ytd-app')[0];
// Create an observer instance linked to the callback function
const observer = new MutationObserver(mutationcallback);
// Start observing the target node for configured mutations
observer.observe(targetNode, config);
// Dragable window for floating video
dragVideo(poppedContainer);
ytThumbnailBttn.src = browser.extension.getURL("/icons/thumbnailOff.png");
ytLoopBttn.src = browser.extension.getURL("/icons/loopFalse.png");
ytFloatBttn.src = browser.extension.getURL("/icons/floatPlayer.png");
ytDownloadBttn.src = browser.extension.getURL("/icons/downloadVid.png");
// Set trget of Thumbnails of video
ytAMaxDefaultImg.target = "_blank";
ytAHqDefaultImg.target = "_blank";
ytAMedDefaultImg.target = "_blank";
ytASdDefaultImg.target = "_blank";
// Theming & Apply Styles
ytThumbImgMenu.className = "ytThumbMenuStyle";
ytMaxDefaultImg.className = "thumbImageStyle";
ytHqDefaultImg.className = "thumbImageStyle";
ytMqDefaultImg.className = "thumbImageStyle";
ytSdDefaultImg.className = "thumbImageStyle";
ytEnhancerMenu.className = "ytMenuStyle";
ytThumbnailBttn.className = "imageStyle";
ytLoopBttn.className = "imageStyle";
ytFloatBttn.className = "imageStyle";
ytDownloadBttn.className = "imageStyle";
ytEnhancerMenu.id = "enhancerMenuIDRef";
poppedContainer.id = "draggable";
ytRangeStart.id = "rangeStartID";
ytRangeEnd.id = "rangeEndID";
poppedContainer.style.display = "none";
ytEnhancerMenu.style.display = "block";
slugInputTag.style.display = "block";
ytIfrm.setAttribute("allow", "accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture");
ytIfrm.setAttribute("frameborder", "0");
ytIfrm.setAttribute("autoplay", "");
ytIfrm.setAttribute("allowfullscreen", "true");
ytIfrm.setAttribute("width", "650px");
ytIfrm.setAttribute("height", "400px");
}
// Functions
// Callback function to execute when mutations are observed
const mutationcallback = (mutationsList, observer) => {
for(let mutation of mutationsList) {
if (mutation.type === 'attributes') {
controlManager(mutation.target);
}
}
};
const controlManager = (elm) => {
attrib = elm.getAttribute('masthead-hidden_');
if (attrib == null) { // if out of fullscreen
ytEnhancerMenu.style.display = "block";
slugInputTag.style.display = "block";
} else { // if fullscreen
ytEnhancerMenu.style.display = "none";
slugInputTag.style.display = "none";
}
}
const downloadVideo = () => {
browser.runtime.sendMessage( { "url": video.baseURI } );
}
const showThumbImageVew = (e) => {
videoSlug = video.baseURI.slice(32, 32+11); // Used for setting up thumbnails
if (ytThumbImgMenu.style.display == "block") {
ytThumbImgMenu.style.display = "none";
ytThumbnailBttn.src = browser.extension.getURL("/icons/thumbnailOff.png");
} else {
ytAMaxDefaultImg.href = part + videoSlug + "/maxresdefault.jpg";
ytAHqDefaultImg.href = part + videoSlug + "/hqdefault.jpg";
ytAMedDefaultImg.href = part + videoSlug + "/mqdefault.jpg";
ytASdDefaultImg.href = part + videoSlug + "/sddefault.jpg";
ytMaxDefaultImg.src = part + videoSlug + "/maxresdefault.jpg";
ytHqDefaultImg.src = part + videoSlug + "/hqdefault.jpg";
ytMqDefaultImg.src = part + videoSlug + "/mqdefault.jpg";
ytSdDefaultImg.src = part + videoSlug + "/sddefault.jpg";
ytMaxDefaultImg.title = "Max Resolution Default";
ytHqDefaultImg.title = "High Quality Default";
ytMqDefaultImg.title = "Medium Quality Default";
ytSdDefaultImg.title = "Standard Quality Default";
ytThumbnailBttn.src = browser.extension.getURL("/icons/thumbnailOn.png");
ytThumbImgMenu.style.display = "block";
}
return;
}
const setLoop = (e) => {
let start = ytRangeStart.value.trim();
let end = ytRangeEnd.value.trim();
if (loopingInterval) {
console.log("Unsetting interval for loop check...");
clearInterval(ytdVideoIntervalLoop);
loopingInterval = false;
ytLoopBttn.title = "Start Loop...";
ytLoopBttn.src = browser.extension.getURL("/icons/loopFalse.png");
return ;
}
if (start.includes("0:00") && end.includes(videoTimeLength)) {
if (video.loop == false) {
console.log("Setting default loop marker...");
video.loop = true;
ytLoopBttn.title = "Stop Loop...";
ytLoopBttn.src = browser.extension.getURL("/icons/loopTrue.png");
} else {
console.log("Unsetting default loop marker...");
video.loop = false;
ytLoopBttn.title = "Start Loop...";
ytLoopBttn.src = browser.extension.getURL("/icons/loopFalse.png");
}
return ;
} else {
const getTotalSize = (array) => {
let size = 0.0;
let hours = 0.0;
let minutes = 0.0;
let seconds = 0.0;
if (array.length === 2) {
minutes = parseFloat(array[0]) * 60.0;
seconds = parseFloat(array[1]);
size = minutes + seconds;
} else if (array.length === 3) {
hours = parseFloat(array[0]) * 3600.0;
minutes = parseFloat(array[1]) * 60.0;
seconds = parseFloat(array[2]);
size = hours + minutes + seconds;
}
return size;
}
const checkLoopStuff = () => {
videoTimeCurent = video.currentTime;
if (videoTimeCurent > totalEnd ||
videoTimeCurent < totalStart) {
video.currentTime = totalStart;
}
}
// Make sure start and end are proper
let totalStart = getTotalSize(start.split(":"));
let totalEnd = getTotalSize(end.split(":"));
if (totalStart < 0.0 || totalStart > video.duration) { return ; }
if (totalEnd < 0.0 || totalEnd > video.duration) { return ; }
// Setup interval check for 1 sec and compare value of current pos to end
ytLoopBttn.title = "Stop Loop...";
ytLoopBttn.src = browser.extension.getURL("/icons/loopTrue.png");
loopingInterval = true;
console.log("Setting interval for loop check...");
ytdVideoIntervalLoop = setInterval(checkLoopStuff, 1000);
}
}
const toggleFloat = () => {
let mainPlayer = document.getElementById("player-container-outer");
var ifrmBody = (ytIfrm.contentWindow || ytIfrm.contentDocument);
if (ifrmBody.document) ifrmBody = ifrmBody.document;
if (poppedContainer.style.display == "none"){
video.pause();
mainPlayer.style.display = "none";
ytIfrm.src = "https://www.youtube.com/embed/" + video.baseURI.slice(32, 32+11) +
"?autoplay=1&amp;start=" + Math.floor(video.currentTime);
poppedContainer.style.display = "block";
} else {
video.currentTime = ifrmBody.getElementsByTagName("video")[0].currentTime;
poppedContainer.style.display = "none";
mainPlayer.style.display = "";
ytIfrm.src = "";
video.play();
}
}
const setVideoStyle = (w, h, pr) => {
let elm = document.getElementsByClassName("ytp-right-controls")[0];
video.style.width = w;
video.style.height = h;
elm.style.paddingRight = pr;
console.log("W: " + w + "\nH: " + h + "\npr: " + pr);
console.log(video.style);
}
const manageVolume = (e) => {
let delta;
e.preventDefault(); // Keep page from scrolling while in video area
// Detect scroll direction
if (e.wheelDelta) delta = e.wheelDelta; else delta = -1 * e.deltaY;
// Vol UP || Vol DOWN
if (delta > 0) video.volume += 0.05; else if (delta < 0) video.volume -= 0.05;
}
const dragVideo = (elmnt) => {
let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
elmnt.onmousedown = dragMouseDown;
function dragMouseDown(e) {
e = e || window.event;
pauseEvent(e);
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
const elementDrag = (e) => {
e = e || window.event;
pauseEvent(e);
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
const closeDragElement = (e) => {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
const pauseEvent = (e) => {
if(e.stopPropagation) e.stopPropagation();
if(e.preventDefault) e.preventDefault();
e.cancelBubble = true;
e.returnValue = false;
return false;
}
}
const checkPg = () => {
if (!document.getElementById("enhancerMenuIDRef")) {
let existCondition = setInterval(function() {
if (document.getElementById("masthead-container")) {
clearInterval(existCondition);
preSetupProc();
setupProc();
count = 0;
} else {
if (count == 12) { // ~ 6 sec through half sec loops
count = 0;
clearInterval(existCondition);
} else {
count++;
}
}
}, 500); // check every 500ms
} else {
preSetupProc();
}
}
// Start init
checkPg();
}());