403 lines
16 KiB
JavaScript
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&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();
|
|
}());
|