YouTube Fullscreen Fix — Disable “More Videos” Grid + Preserve Controls

Removes the fullscreen recommendations grid & vignette; keeps scroll wheel volume. Prevents tick-4/7 vanish/jiggle on player controls without shifting layout. Restores V-key manual hide. Permanently hides interactive buttons (like, dislike, etc.) in fullscreen.

// ==UserScript==
// @name         YouTube Fullscreen Fix — Disable “More Videos” Grid + Preserve Controls
// @namespace    orangekite
// @version      1.3.5
// @description  Removes the fullscreen recommendations grid & vignette; keeps scroll wheel volume. Prevents tick-4/7 vanish/jiggle on player controls without shifting layout. Restores V-key manual hide. Permanently hides interactive buttons (like, dislike, etc.) in fullscreen.
// @match        https://www.youtube.com/*
// @run-at       document-start
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function () {
  'use strict';

  GM_addStyle(`
/* Fullscreen-scoped: match when either the player OR an ancestor is fullscreen */
.html5-video-player:fullscreen,
:fullscreen .html5-video-player {
  --ytp-grid-scroll-percentage: 0 !important;
  --ytp-grid-peek-height: 0px !important;
  --ytp-grid-peek-gradient: 0 !important;
  --ytp-controls-peek-height: 0px !important;
  --ytp-controls-peek-percent: 0 !important;
}

/* Hide the fullscreen recommendations grid and its moving parts */
.html5-video-player:fullscreen [class*="fullscreen-grid"],
.html5-video-player:fullscreen [class*="fullerscreen-grid"],
.html5-video-player:fullscreen [class*="grid-stills"],
.html5-video-player:fullscreen [class*="videowall-still"],
:fullscreen .html5-video-player [class*="fullscreen-grid"],
:fullscreen .html5-video-player [class*="fullerscreen-grid"],
:fullscreen .html5-video-player [class*="grid-stills"],
:fullscreen .html5-video-player [class*="videowall-still"] {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  height: 0 !important;
  max-height: 0 !important;
  overflow: hidden !important;
}

/* Hide the vignette/scrim/gradient behind the grid */
.html5-video-player:fullscreen [class*="grid-vignette"],
.html5-video-player:fullscreen [class*="grid-scrim"],
.html5-video-player:fullscreen [class*="gradient-bottom"],
:fullscreen .html5-video-player [class*="grid-vignette"],
:fullscreen .html5-video-player [class*="grid-scrim"],
:fullscreen .html5-video-player [class*="gradient-bottom"] {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* Hide “fullerscreen” education/teaser overlays */
.html5-video-player:fullscreen [class*="fullerscreen"],
.html5-video-player:fullscreen .ytp-fullerscreen-edu-panel,
.html5-video-player:fullscreen .ytp-cards-teaser,
.html5-video-player:fullscreen .ytp-cards-teaser-box,
:fullscreen .html5-video-player [class*="fullerscreen"],
:fullscreen .html5-video-player .ytp-fullerscreen-edu-panel,
:fullscreen .html5-video-player .ytp-cards-teaser,
:fullscreen .html5-video-player .ytp-cards-teaser-box {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* Safety net for lingering vignette/scrim overlays */
.html5-video-player:fullscreen [class*="vignette"],
.html5-video-player:fullscreen [class*="scrim"],
:fullscreen .html5-video-player [class*="vignette"],
:fullscreen .html5-video-player [class*="scrim"] {
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
}

/* --- Always show controls in fullscreen (no layout overrides) --- */
.html5-video-player:fullscreen .ytp-chrome-bottom,
:fullscreen .html5-video-player .ytp-chrome-bottom,
.html5-video-player:fullscreen .ytp-chrome-top,
:fullscreen .html5-video-player .ytp-chrome-top {
  opacity: 1 !important;
  transform: translateY(0) !important;
  transition: none !important;
}

/* --- Anti-vanish for tick 4 (no display/bottom changes here) --- */
.html5-video-player:fullscreen.ytp-autohide .ytp-chrome-bottom,
.html5-video-player:fullscreen.ytp-hide-controls .ytp-chrome-bottom,
:fullscreen .html5-video-player.ytp-autohide .ytp-chrome-bottom,
:fullscreen .html5-video-player.ytp-hide-controls .ytp-chrome-bottom,
.html5-video-player:fullscreen .ytp-chrome-bottom,
:fullscreen .html5-video-player .ytp-chrome-bottom {
  opacity: 1 !important;
  visibility: visible !important;
  transform: translateY(0) !important;
  pointer-events: auto !important;
}

/* Keep only the control rows/buttons visible; don't touch progress layers */
.html5-video-player:fullscreen .ytp-chrome-bottom :is(
  .ytp-left-controls,
  .ytp-right-controls,
  .ytp-chrome-controls,
  .ytp-volume-panel,
  .ytp-time-display,
  .ytp-subtitles-button,
  .ytp-settings-button,
  .ytp-fullscreen-button,
  .ytp-autonav-toggle-button
),
:fullscreen .html5-video-player .ytp-chrome-bottom :is(
  .ytp-left-controls,
  .ytp-right-controls,
  .ytp-chrome-controls,
  .ytp-volume-panel,
  .ytp-time-display,
  .ytp-subtitles-button,
  .ytp-settings-button,
  .ytp-fullscreen-button,
  .ytp-autonav-toggle-button
) {
  opacity: 1 !important;
  visibility: visible !important;
  transition: none !important;
}

/* Neutralize any “peek” transforms (class-based) */
.html5-video-player:fullscreen [class*="peek"],
:fullscreen .html5-video-player [class*="peek"] {
  transform: none !important;
  translate: 0 !important;
}

/* Stop tick-4 jiggle: anchor only the chrome container (not the progress bar) */
:is(.html5-video-player:fullscreen, :fullscreen .html5-video-player) .ytp-chrome-bottom {
  bottom: 0 !important;
  transform: translateY(0) !important;
  translate: 0 !important;
  margin-bottom: 0 !important;
}

/* If YouTube injects inline translateY on the chrome, zero it */
:is(.html5-video-player:fullscreen, :fullscreen .html5-video-player)
  .ytp-chrome-bottom[style*="translate"] {
  transform: translateY(0) !important;
}

/* -------- Permanently remove title + interactive overlay in fullscreen (expanded) -------- */
.html5-video-player:fullscreen :is(
  .ytp-title,
  .ytp-title-link,
  .ytp-title-text,
  .ytp-title-channel,
  .ytp-title-expanded,
  .ytp-chrome-top,
  .ytp-overlay-bottom-right,
  .branding-img-container.ytp-button
),
:fullscreen .html5-video-player :is(
  .ytp-title,
  .ytp-title-link,
  .ytp-title-text,
  .ytp-title-channel,
  .ytp-title-expanded,
  .ytp-chrome-top,
  .ytp-overlay-bottom-right,
  .branding-img-container.ytp-button
) {
  display: none !important;
  opacity: 0 !important;
  visibility: hidden !important;
  pointer-events: none !important;
  transform: none !important;
}
  `);

  // ---------------- Core JS helper: prevent tick-4 vanish without altering layout
  let manualHideActive = false; // shared flag used by both handlers

  const restoreChrome = () => {
    const player = document.querySelector('.html5-video-player.ytp-fullscreen');
    if (!player) return;

    const chrome = player.querySelector('.ytp-chrome-bottom');
    if (!chrome) return;

    if (manualHideActive) {
      // When user pressed V, don't force-show; let our V-handler control it.
      return;
    }

    // Cache the native display value once (whatever YouTube uses in this build)
    if (!chrome.dataset.nativeDisplay) {
      chrome.dataset.nativeDisplay = getComputedStyle(chrome).display || 'flex';
    }

    // Undo autohide flags YouTube flips on wheel peek
    player.classList.remove('ytp-autohide', 'ytp-hide-controls');

    // If they temporarily set display:none, restore the native value
    const disp = getComputedStyle(chrome).display;
    if (disp === 'none' || chrome.style.display === 'none') {
      chrome.style.display = chrome.dataset.nativeDisplay;
    }

    // Ensure visible (no layout overrides)
    chrome.style.opacity = '1';
    chrome.style.visibility = 'visible';
    chrome.style.transform = 'translateY(0)';
  };

  // Run on wheel-triggered "peek" and on fullscreen transitions
  window.addEventListener('wheel', restoreChrome, { passive: true });
  document.addEventListener('fullscreenchange', () => {
    manualHideActive = false;   // reset on FS boundary
    restoreChrome();
  }, { passive: true });

  // ---------------- V-key: restore manual hide with inline !important
  (() => {
    const playerSelector = '.html5-video-player.ytp-fullscreen';
    const chromeSelector = '.ytp-chrome-bottom';

    function applyManualHideStyles(chrome, hide) {
      if (hide) {
        chrome.style.setProperty('opacity', '0', 'important');
        chrome.style.setProperty('visibility', 'hidden', 'important');
        chrome.style.removeProperty('transform'); // allow YouTube's own state
      } else {
        chrome.style.removeProperty('opacity');
        chrome.style.removeProperty('visibility');
        // Immediately re-show to avoid residual fade
        restoreChrome();
      }
    }

    window.addEventListener('keydown', e => {
      if (e.key.toLowerCase() !== 'v') return;
      const player = document.querySelector(playerSelector);
      if (!player) return;
      const chrome = player.querySelector(chromeSelector);
      if (!chrome) return;

      manualHideActive = !manualHideActive;
      applyManualHideStyles(chrome, manualHideActive);
    }, true);

    // Keep behavior consistent if other events fire while hidden
    const syncIfNeeded = () => {
      if (!manualHideActive) return;
      const player = document.querySelector(playerSelector);
      const chrome = player?.querySelector(chromeSelector);
      if (chrome) applyManualHideStyles(chrome, true);
    };
    window.addEventListener('wheel', syncIfNeeded, { passive: true });
    window.addEventListener('keyup', syncIfNeeded, { passive: true });
  })();

})();