// ==UserScript== // @name YouTube Fullscreen Enhancer // @description This userscript improves YouTube's fullscreen mode by enabling the customization of the viewing experience. Users can hide the video title, player controls, and annotations, as well as stabilize captions when pausing or resuming playback. All these features can be easily toggled. // @author Wanten // @copyright 2024 Wanten // @license MIT // @supportURL https://github.com/WantenMN/youtube-fullscreen-enhancer/issues // @icon https://youtube.com/favicon.ico // @homepageURL https://github.com/WantenMN/youtube-fullscreen-enhancer // @namespace https://greasyfork.org/en/scripts/460569 // @version 0.2 // @match http*://*.youtube.com/watch* // @match http*://youtube.com/watch* // @match http*://*.youtu.be/watch* // @match http*://youtu.be/watch* // @run-at document-end // @grant GM_addStyle // @downloadURL none // ==/UserScript== (function () { "use strict"; const playIconSVG = ``; const defaultStyle = `.ytp-bezel { display: none !important; }`; const toggleStyle = ` .ytp-chrome-top, .ytp-gradient-top, .ytp-gradient-bottom, .ytp-chrome-bottom { display: none !important; } .caption-window, .caption-window.ytp-caption-window-bottom, .caption-window ytp-caption-window-top { margin-bottom: 0 !important; margin-top: 0 !important; } `; const playIconContainerEleStyle = { position: "absolute", zIndex: 100, width: "100%", height: "0", bottom: "0", background: "red", }; const playIconEleStyle = { position: "absolute", right: "30px", bottom: "60px", }; let html5VideoPlayerEle = null; let html5MainVideoEle = null; let toggleStyleEle = null; let mouseMoveTimeoutId = null; const classNamesToCheckForHover = ["ytp-chrome-top", "ytp-chrome-bottom"]; const playIconContainerEle = document.createElement("div"); playIconContainerEle.innerHTML = playIconSVG; const playIconEle = playIconContainerEle.querySelector("svg"); Object.assign(playIconContainerEle.style, playIconContainerEleStyle); Object.assign(playIconEle.style, playIconEleStyle); const addToggleStyleEle = () => { const isHover = isAnyElementHovered(classNamesToCheckForHover); if (isHover) return; toggleStyleEle = GM_addStyle(toggleStyle); }; const addDefaultStyleEle = () => GM_addStyle(defaultStyle); const removeToggleStyleEle = () => { toggleStyleEle?.parentNode?.removeChild(toggleStyleEle); toggleStyleEle = null; }; const isAnyElementHovered = (classNames) => { for (let className of classNames) { let elements = document.getElementsByClassName(className); for (let element of elements) { if (element.matches(":hover")) { return true; } } } return false; }; const handleMouseMoveEvent = () => { clearTimeout(mouseMoveTimeoutId); if (toggleStyleEle) removeToggleStyleEle(); mouseMoveTimeoutId = setTimeout(addToggleStyleEle, 1000); }; const appendPlayIconContainerEle = () => html5VideoPlayerEle.appendChild(playIconContainerEle); const removePlayIconContainerEle = () => html5VideoPlayerEle.removeChild(playIconContainerEle); const initialHtml5MainVideoEleEvent = () => { html5MainVideoEle.addEventListener("play", () => removePlayIconContainerEle() ); html5MainVideoEle.addEventListener("pause", () => appendPlayIconContainerEle() ); }; const initializeElements = () => { html5VideoPlayerEle = document.querySelector(".html5-video-player"); html5MainVideoEle = document.querySelector(".html5-main-video"); if (!html5VideoPlayerEle || !html5MainVideoEle) return; initialHtml5MainVideoEleEvent(); clearInterval(initializeElementsIntervalId); }; let initializeElementsIntervalId = setInterval(initializeElements, 300); window.addEventListener("load", () => { addDefaultStyleEle(); }); window.addEventListener("mousemove", handleMouseMoveEvent); })();