Hide all YouTube player UI (buttons, spinner, shadows, ads, branding, related videos suggestions when the video ends) immediately and show them only on mouse hover.
// ==UserScript==
// @name YouTube Clean & Fast (Hide UI/Spinner)
// @namespace https://greasyfork.org/en/users/670188-hacker09?sort=daily_installs
// @version 4
// @description Hide all YouTube player UI (buttons, spinner, shadows, ads, branding, related videos suggestions when the video ends) immediately and show them only on mouse hover.
// @author hacker09
// @match *://www.youtube.com/embed/*
// @match *://www.youtube.com/watch*
// @icon https://www.youtube.com/s/desktop/03f86491/img/favicon.ico
// @run-at document-start
// @grant none
// ==/UserScript==
(function() {
'use strict';
const css = `
/* === MAIN UI HIDING (Opacity 0 when mouse is outside PLAYER) === */
/* 1. Top Controls */
body.tm-clean-ui .ytp-chrome-top,
/* 2. Bottom Controls */
body.tm-clean-ui .ytp-chrome-bottom,
/* 3. Shadows */
body.tm-clean-ui .ytp-gradient-top,
body.tm-clean-ui .ytp-gradient-bottom,
/* 4. Center Play Button */
body.tm-clean-ui .ytp-large-play-button,
/* 5. Spinner */
body.tm-clean-ui .ytp-spinner,
/* 6. Bezel */
body.tm-clean-ui .ytp-bezel-text-wrapper,
body.tm-clean-ui .ytp-bezel,
/* 7. Branding & Popups */
body.tm-clean-ui .ytp-watermark,
body.tm-clean-ui .ytp-upnext,
body.tm-clean-ui .ytp-pause-overlay-container,
body.tm-clean-ui .ytp-share-panel,
body.tm-clean-ui .ytp-storyboard-framepreview,
body.tm-clean-ui .ytp-cued-thumbnail-overlay,
/* 8. Top Alerts */
body.tm-clean-ui .ytp-caption-window-top,
/* 9. Suggested Ads */
body.tm-clean-ui .ytp-suggested-action,
body.tm-clean-ui .ytp-featured-product,
body.tm-clean-ui .ytp-ad-overlay-container,
body.tm-clean-ui .ytp-ad-overlay-slot,
body.tm-clean-ui .ytp-suggested-action-badge,
/* 10. Channel Branding */
body.tm-clean-ui .iv-branding,
body.tm-clean-ui .ytp-fullscreen-quick-actions,
/* 11. END SCREEN SUGGESTIONS */
body.tm-clean-ui .ytp-ce-element,
body.tm-clean-ui .ytp-ce-covering-overlay,
body.tm-clean-ui .ytp-ce-element-shadow,
body.tm-clean-ui .ytp-ce-video-title,
body.tm-clean-ui .ytp-ce-video-duration,
body.tm-clean-ui .ytp-ce-channel-title,
body.tm-clean-ui .ytp-ce-subscribe-container
{
opacity: 0 !important;
visibility: hidden !important;
display: none !important;
transition: opacity 0.1s ease-out !important;
}
/* === EXCEPTIONS (Always Visible) === */
body.tm-clean-ui .ytp-caption-window-bottom,
body.tm-clean-ui .html5-main-video {
opacity: 1 !important;
visibility: visible !important;
display: block !important;
}
/* === TRANSITIONS === */
.ytp-chrome-top,
.ytp-chrome-bottom,
.ytp-caption-window-top,
.ytp-ad-overlay-container,
.ytp-ce-element {
transition: opacity 0.1s ease-in !important;
}
`;
// Inject CSS immediately
const styleNode = document.createElement('style');
styleNode.type = 'text/css';
styleNode.appendChild(document.createTextNode(css));
(document.head || document.documentElement).appendChild(styleNode);
function startDelegate() {
if (!document.body) return;
// Default to hidden
document.body.classList.add('tm-clean-ui');
// Use a global mousemove listener to check where the mouse is
// This works even if the player is replaced or loaded late
document.addEventListener('mousemove', (e) => {
// Check if the hover target is inside the player container (#movie_player)
const isInsidePlayer = e.target.closest('#movie_player');
if (isInsidePlayer) {
// We are inside the player (including bottom bar) -> Show UI
if (document.body.classList.contains('tm-clean-ui')) {
document.body.classList.remove('tm-clean-ui');
}
} else {
// We are strictly outside the player -> Hide UI
if (!document.body.classList.contains('tm-clean-ui')) {
document.body.classList.add('tm-clean-ui');
}
}
}, true); // Capture phase to ensure we catch it
}
// Observer to trigger immediately when body is created (No 50ms timer)
if (document.body) {
startDelegate();
} else {
const observer = new MutationObserver((mutations, obs) => {
if (document.body) {
startDelegate();
obs.disconnect();
}
});
observer.observe(document.documentElement, { childList: true });
}
})();