(function() { const menuTemplate = `
` const slugTemplate = `
Volume
` const thumbnailTemplate = ` ` const popedContainerTemplate = ` ` // Declare other variables let ytThumbImgMenu, ytEnhancerMenu, ytEnhancerMenu2; // Menu systems let ytThumbnailBttn, ytLoopBttn, ytFloatBttn, ytDownloadBttn; // Menu Buttons let ytMaxDefaultImg, ytHqDefaultImg, ytAMaxDefaultImg, ytAHqDefaultImg; // Thumbnail images let mainContentArea, playerWindow, containerOfPlyrWndow, video; // Youtube Player container let videoTimeLength, videoTimeCurent, ytRangeStart, ytRangeEnd, slugInputTag, endlessPlayTag, ytVideoIntervalLoop; let poppedContainer, videoSlug, volumeLbl, part; let loopingInterval = false; let shouldHideVol = true; let OSName = ""; let count = 0; // confirm dialog elm const isYoutubeMusic = window.location.hostname === 'music.youtube.com'; let dialogElementQueryRef = isYoutubeMusic ? 'ytmusic-you-there-renderer' : 'yt-confirm-dialog-renderer'; // Options for the observer (which mutations to observe) let observer, observer2; const observerConfig = { attributes: true }; const observerConfig2 = { childList: true, subtree: true }; const preSetupProc = () => { // Look to add saving image from video elm. // path = "/html/body/ytd-app/div/ytd-page-manager/ytd-watch-flexy/div[4]/div[1]/div/div[1]/div/div/div/ytd-player/div/div/div[1]/video" // elm = document.evaluate(path, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue; 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"; // check if we've loaded elements already... if (!document.getElementById("slugCopyZone")) { document.body.insertAdjacentHTML( 'beforeend', slugTemplate ); document.body.insertAdjacentHTML( 'beforeend', menuTemplate ); document.body.insertAdjacentHTML( 'beforeend', thumbnailTemplate ); document.body.insertAdjacentHTML( 'beforeend', popedContainerTemplate ); controlsWereLoaded = false; } else { controlsWereLoaded = true; } ytEnhancerMenu = document.getElementById("enhancerMenuID"); ytEnhancerMenu2 = document.getElementById("enhancerMenuID2"); ytThumbnailBttn = document.getElementById("ytThumbnailBttn"); ytLoopBttn = document.getElementById("ytLoopBttn"); ytRangeEnd = document.getElementById("rangeEndID"); ytRangeStart = document.getElementById("rangeStartID"); ytFloatBttn = document.getElementById("ytFloatBttn"); ytDownloadBttn = document.getElementById("ytDownloadBttn"); volumeContainer = document.getElementById("volumeContainerID"); volumeLbl = document.getElementById("volumeValueLbl"); endlessPlayTag = document.getElementById("endlessPlayID"); ytThumbImgMenu = document.getElementById("ytThumbMenuID"); ytAMaxDefaultImg = document.getElementById("ytAMaxDefaultImgID"); ytAHqDefaultImg = document.getElementById("ytAHqDefaultImgID"); ytAMedDefaultImg = document.getElementById("ytAMedDefaultImgID"); ytASdDefaultImg = document.getElementById("ytASdDefaultImgID"); ytMaxDefaultImg = document.getElementById("ytMaxDefaultImgID"); ytHqDefaultImg = document.getElementById("ytHqDefaultImgID"); ytMqDefaultImg = document.getElementById("ytMqDefaultImgID"); ytSdDefaultImg = document.getElementById("ytSdDefaultImgID"); poppedContainer = document.getElementById("draggable"); ytIfrm = document.getElementById("popIframe"); slugInputTag = document.getElementById("slugCopyZone"); // Video Controler video = document.getElementsByTagName("video")[0]; // Container of actual player (Used for floating window) containerOfPlyrWndow = document.getElementById("player-container"); } const setupProc = () => { part = "https://img.youtube.com/vi/"; slugInputTag.value = video.baseURI.slice(32, 32+11); ytRangeStart.value = "0:00"; // We need to wait for info to load before getting full duration setTimeout(function () { videoTimeLength = document.getElementsByClassName("ytp-time-duration")[0].innerText; ytRangeEnd.value = videoTimeLength; }, 2000); // Only setting these up if we need to load controls' info if (!controlsWereLoaded) { setbuttonImage(ytThumbnailBttn, "/icons/thumbnailOff.png"); setbuttonImage(ytLoopBttn, "/icons/loopFalse.png"); setbuttonImage(ytFloatBttn, "/icons/floatPlayer.png"); setbuttonImage(ytDownloadBttn, "/icons/downloadVid.png"); // Set onclick actions ytThumbnailBttn.addEventListener("click", showThumbImageVew); ytLoopBttn.addEventListener("click", setLoop); ytFloatBttn.addEventListener("click", toggleFloat); endlessPlayTag.addEventListener("click", toggleEndlessPlay); ytDownloadBttn.addEventListener("click", downloadVideo); video.addEventListener("wheel", manageVolume); // Dragable window for floating video event setup dragVideo(poppedContainer); // Remove download button if system doesn't support youtube-dl functionality if (!OSName.includes("MacOS") && !OSName.includes("UNIX") && !OSName.includes("Linux")) { console.log("System does not support downloader..."); ytEnhancerMenu.removeChild(ytDownloadBttn); } } // ---- Hide controls if fullscreen using obsever ---- // Observer target for fullscreen action... let targetNode = document.getElementsByTagName('ytd-app')[0]; // Create an observer instance linked to the callback function observer = new MutationObserver(mutationCallback); // Start observing the target node for configured mutations observer.observe(targetNode, observerConfig); // ---- Endless play obsever ---- // Create an observer instance linked to the callback function observer2 = new MutationObserver(mutationCallback); // Start observing the target node for configured mutations if (endlessPlayTag.checked == true) { endlessPlayTag.setAttribute("checked", true); console.log("Endless play checked. Starting observer..."); observer2.observe(document, observerConfig2); } } // 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); } else if (mutation.type === 'childList') { let elm = document.querySelector(dialogElementQueryRef).parentElement; elmDisplayState = elm.style.display; if (elmDisplayState !== 'none') { clickDialog(); } } } }; const controlManager = (elm) => { attrib = elm.getAttribute('masthead-hidden_'); if (attrib == null) { // if out of fullscreen ytEnhancerMenu.style.display = "block"; ytEnhancerMenu2.style.display = "block"; } else { // if fullscreen ytEnhancerMenu.style.display = "none"; ytEnhancerMenu2.style.display = "none"; } } const clickDialog = () => { console.log("Clicking dialog confirm to continue playing..."); document .querySelector(dialogElementQueryRef) .querySelector('yt-button-renderer[dialog-confirm]') .click(); } const toggleEndlessPlay = () => { isChecked = endlessPlayTag.getAttribute("checked"); if (isChecked) { endlessPlayTag.setAttribute("checked", false); console.log("Stopping endless play..."); observer2.disconnect(); } else { endlessPlayTag.setAttribute("checked", true); console.log("Starting endless play..."); observer2.observe(confirmDialogElement, observerConfig2); } console.log(observer2); } const showThumbImageVew = (e) => { videoSlug = video.baseURI.slice(32, 32+11); // Used for setting up thumbnails if (ytThumbImgMenu.style.display == "block") { ytThumbImgMenu.style.display = "none"; setbuttonImage(ytThumbnailBttn, "/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"; setbuttonImage(ytThumbnailBttn, "/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(ytVideoIntervalLoop); loopingInterval = false; ytLoopBttn.title = "Start Loop..."; let ipath = browser.extension.getURL("/icons/loopFalse.png"); setbuttonImage(ytLoopBttn, ipath); 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..."; let ipath = browser.extension.getURL("/icons/loopTrue.png"); setbuttonImage(ytLoopBttn, ipath); } else { console.log("Unsetting default loop marker..."); video.loop = false; ytLoopBttn.title = "Start Loop..."; let ipath = browser.extension.getURL("/icons/loopFalse.png"); setbuttonImage(ytLoopBttn, ipath); } 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..."; let ipath = browser.extension.getURL("/icons/loopTrue.png"); setbuttonImage(ytLoopBttn, ipath); loopingInterval = true; console.log("Setting interval for loop check..."); ytVideoIntervalLoop = 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 shouldHideVol = false; volumeContainer.style.display = "block"; // Detect scroll direction let incramentType = "+"; if (e.wheelDelta) delta = e.wheelDelta; else delta = -1 * e.deltaY; // Vol UP || Vol DOWN let tmpVol = video.volume.toFixed(2); let volume = Math.round((tmpVol * 100), 2).toFixed(0); if (delta > 0) { incramentType = "+"; while ((volume % 5) !== 0) { volume += 1; } video.volume = (volume/100) + 0.05; } else if (delta < 0) { incramentType = "-"; while ((volume % 5) !== 0) { volume -= 1; } video.volume = (volume/100) - 0.05; } volumeLbl.innerText = incramentType + Math.round((video.volume * 100), 1).toFixed(0); setTimeout(function () { if (shouldHideVol) { volumeContainer.style.display = "none"; } }, 1000); shouldHideVol = true; } 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 downloadVideo = () => { browser.runtime.sendMessage( { "url": video.baseURI } ); } const setbuttonImage = (elm, path) => { elm.style.backgroundImage = "url('" + browser.extension.getURL(path); + "')"; } // Start init preSetupProc(); setupProc(); }());