🪄 YouTube UI Enhancer — Resize Thumbnails & Customize Layout

Get rid of oversized thumbnails, adjust rows, and clean up layout for a more streamlined YouTube experience.

بۇ قوليازمىنى قاچىلاش؟
ئاپتورنىڭ تەۋسىيەلىگەن قوليازمىسى

سىز بەلكىم 🔊 YouTube Volume Control on Scroll نى ياقتۇرۇشىڭىز مۇمكىن.

بۇ قوليازمىنى قاچىلاش
  1. // ==UserScript==
  2. // @name 🪄 YouTube UI Enhancer — Resize Thumbnails & Customize Layout
  3. // @namespace https://greatest.deepsurf.us/users/1461079
  4. // @version 2.0.1
  5. // @description Get rid of oversized thumbnails, adjust rows, and clean up layout for a more streamlined YouTube experience.
  6. // @author Michaelsoft
  7. // @match *://www.youtube.com/*
  8. // @grant GM_addStyle
  9. // @grant GM_getValue
  10. // @grant GM_setValue
  11. // @run-at document-end
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict';
  17.  
  18. // WARNING: Users should update their preferences through UI - values below will be overwritten every time the script is updated.
  19. const userSettings = {
  20. videosPerRow: 6, // Set how many videos per row (e.g., 4, 5, 6, etc.). Default value is 6.
  21. shortsPerRow: 12, // Set how many Shorts per row (e.g., 7, 8, 9, etc.). Default value is 12.
  22. disableShorts: false, // Set to true to completely hide the Shorts section. Default value is false.
  23. enableShowMoreFix: true, // Set to true to auto-expand Shorts ("Show More" fix). Default value is true.
  24. hideUIButton: false, // Set to true to hide the floating settings button. Default value is false.
  25. hideUIButtonShortcut: true, // Set to true to allow Alt+Shift+U shortcut to toggle button visibility. Default value is true.
  26. };
  27.  
  28. const settings = {};
  29. for (const key in userSettings) {
  30. settings[key] = GM_getValue(key, userSettings[key]);
  31. }
  32.  
  33. function saveSetting(key, value) {
  34. GM_setValue(key, value);
  35. settings[key] = value;
  36. applyCustomizations();
  37. }
  38.  
  39. function resetSettings() {
  40. for (const key in userSettings) {
  41. saveSetting(key, userSettings[key]);
  42. }
  43. enableShowMoreFix();
  44. }
  45.  
  46. let customStyle = null;
  47.  
  48. function applyCustomizations() {
  49. if (customStyle) customStyle.remove();
  50. customStyle = GM_addStyle(`
  51. ytd-rich-grid-renderer {
  52. --ytd-rich-grid-items-per-row: ${settings.videosPerRow} !important;
  53. --ytd-rich-grid-posts-per-row: ${settings.videosPerRow} !important;
  54. --ytd-rich-grid-slim-items-per-row: ${settings.shortsPerRow} !important;
  55. --ytd-rich-grid-game-cards-per-row: 7 !important;
  56. --ytd-rich-grid-gutter-margin: 0px !important;
  57. }
  58. ytd-rich-shelf-renderer {
  59. --ytd-rich-grid-items-per-row: ${settings.shortsPerRow} !important;
  60. }
  61. ${settings.disableShorts ? `
  62. ytd-rich-section-renderer.style-scope.ytd-rich-grid-renderer {
  63. display: none !important;
  64. }
  65. ` : ''}
  66. `);
  67. }
  68.  
  69. applyCustomizations();
  70.  
  71. let observer;
  72. function enableShowMoreFix() {
  73. if (observer) observer.disconnect();
  74. if (!settings.enableShowMoreFix) return;
  75.  
  76. observer = new MutationObserver(() => {
  77. document.querySelectorAll('ytd-rich-item-renderer[hidden]').forEach(el => {
  78. el.removeAttribute('hidden');
  79. });
  80. document.querySelectorAll('ytd-rich-shelf-renderer').forEach(el => {
  81. el.setAttribute('is-show-more-hidden', '');
  82. });
  83. });
  84.  
  85. observer.observe(document.documentElement, {
  86. childList: true,
  87. subtree: true
  88. });
  89. }
  90.  
  91. enableShowMoreFix();
  92.  
  93. function isDarkTheme() {
  94. const html = document.querySelector('html');
  95. return html && html.getAttribute('dark') !== null;
  96. }
  97.  
  98. let uiButton = null;
  99.  
  100. function createSettingsButton() {
  101. uiButton = document.createElement('div');
  102. uiButton.innerHTML = 'Customize Layout';
  103. uiButton.style.position = 'fixed';
  104. uiButton.style.bottom = '20px';
  105. uiButton.style.right = '20px';
  106. uiButton.style.zIndex = '9999';
  107. uiButton.style.padding = '10px 20px';
  108. uiButton.style.fontSize = '16px';
  109. uiButton.style.backgroundColor = '#065fd4';
  110. uiButton.style.color = '#fff';
  111. uiButton.style.borderRadius = '8px';
  112. uiButton.style.cursor = 'pointer';
  113. uiButton.style.boxShadow = '0 4px 12px rgba(0,0,0,0.4)';
  114. uiButton.style.opacity = '1';
  115. uiButton.style.transition = 'opacity 0.3s ease';
  116. uiButton.style.display = settings.hideUIButton ? 'none' : 'block'; // <--- important
  117.  
  118. uiButton.onclick = openSettingsMenu;
  119. document.body.appendChild(uiButton);
  120.  
  121. if (settings.hideUIButtonShortcut) {
  122. window.addEventListener('keydown', (e) => {
  123. if (e.altKey && e.shiftKey && e.key === 'U') {
  124. toggleUIButtonVisibility();
  125. }
  126. });
  127. }
  128. }
  129.  
  130. function toggleUIButtonVisibility() {
  131. if (uiButton) {
  132. if (uiButton.style.display === 'none') {
  133. uiButton.style.display = 'block';
  134. saveSetting('hideUIButton', false);
  135. } else {
  136. uiButton.style.display = 'none';
  137. saveSetting('hideUIButton', true);
  138. }
  139. }
  140. }
  141.  
  142. function openSettingsMenu() {
  143. const darkMode = isDarkTheme();
  144.  
  145. // Disable floating button while modal is open
  146. uiButton.style.pointerEvents = 'none';
  147. uiButton.style.opacity = '0.5';
  148.  
  149. const overlay = document.createElement('div');
  150. overlay.style.position = 'fixed';
  151. overlay.style.top = '0';
  152. overlay.style.left = '0';
  153. overlay.style.width = '100vw';
  154. overlay.style.height = '100vh';
  155. overlay.style.backgroundColor = 'rgba(0,0,0,0.7)';
  156. overlay.style.zIndex = '9998';
  157. overlay.onclick = () => {
  158. document.body.removeChild(overlay);
  159. uiButton.style.pointerEvents = 'auto';
  160. uiButton.style.opacity = '1';
  161. };
  162.  
  163. const menu = document.createElement('div');
  164. menu.style.position = 'fixed';
  165. menu.style.top = '50%';
  166. menu.style.left = '50%';
  167. menu.style.transform = 'translate(-50%, -50%)';
  168. menu.style.backgroundColor = darkMode ? '#222' : '#fff';
  169. menu.style.color = darkMode ? '#eee' : '#000';
  170. menu.style.padding = '20px 20px 20px 20px';
  171. menu.style.borderRadius = '12px';
  172. menu.style.boxShadow = '0 8px 24px rgba(0,0,0,0.6)';
  173. menu.style.width = '320px';
  174. menu.style.zIndex = '9999';
  175. menu.style.fontSize = '14px';
  176. menu.style.lineHeight = '1.5';
  177. menu.style.textAlign = 'left';
  178. menu.onclick = e => e.stopPropagation();
  179.  
  180. menu.innerHTML = `
  181. <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">
  182. <a href="https://greatest.deepsurf.us/en/scripts/533654-youtube-ui-enhancer-resize-thumbnails-modify-layout-more" target="_blank" style="text-decoration:none;color:inherit;font-size:20px;font-weight:bold;">
  183. 🪄 YouTube UI Enhancer
  184. </a>
  185. <button id="closeOverlay" style="background:none;border:none;color:${darkMode ? 'white' : 'black'};font-size:26px;line-height:1;cursor:pointer;padding:0;margin-left:10px;padding-bottom:5px;">×</button>
  186. </div>
  187. <label style="display:block; margin-bottom:10px;">Videos Per Row: <input id="videosPerRow" type="number" min="1" value="${settings.videosPerRow}" style="width:60px;"/></label>
  188. <label style="display:block; margin-bottom:20px;">Shorts Per Row: <input id="shortsPerRow" type="number" min="1" value="${settings.shortsPerRow}" style="width:60px;"/></label>
  189. <label style="display:block; margin-bottom:10px;">
  190. <input id="disableShorts" type="checkbox" ${settings.disableShorts ? 'checked' : ''} /> Hide Shorts Section
  191. </label>
  192. <label style="display:block; margin-bottom:20px;">
  193. <input id="enableShowMoreFix" type="checkbox" ${settings.enableShowMoreFix ? 'checked' : ''} /> Expand Shorts Automatically
  194. </label>
  195. <div style="margin-top:20px; margin-bottom:20px; border-top:1px solid ${darkMode ? 'white' : 'lightgrey'};"></div>
  196.  
  197. <label style="display:block; margin-bottom:20px;">
  198. <input id="hideUIButton" type="checkbox" ${settings.hideUIButton ? 'checked' : ''} /> Hide Script Button (Alt+Shift+U to Show)
  199. </label>
  200. <button id="saveSettingsBtn" style="padding:8px 14px;background:#065fd4;color:white;border:none;border-radius:8px;font-size:15px;font-weight:500;cursor:pointer;">Save Changes</button>
  201. <button id="resetSettingsBtn" style="margin-left:10px;padding:8px 14px;background:none;color:${darkMode ? 'white' : 'black'};border:1px solid lightgrey;border-radius:8px;font-size:15px;font-weight:500;cursor:pointer;">Reset to Default</button>
  202. `;
  203.  
  204. overlay.appendChild(menu);
  205. document.body.appendChild(overlay);
  206.  
  207. document.getElementById('closeOverlay').onclick = () => {
  208. document.body.removeChild(overlay);
  209. uiButton.style.pointerEvents = 'auto';
  210. uiButton.style.opacity = '1';
  211. };
  212.  
  213. document.getElementById('saveSettingsBtn').onclick = () => {
  214. const showMoreBefore = settings.enableShowMoreFix;
  215. saveSetting('videosPerRow', parseInt(document.getElementById('videosPerRow').value, 10));
  216. saveSetting('shortsPerRow', parseInt(document.getElementById('shortsPerRow').value, 10));
  217. saveSetting('disableShorts', document.getElementById('disableShorts').checked);
  218. saveSetting('enableShowMoreFix', document.getElementById('enableShowMoreFix').checked);
  219. saveSetting('hideUIButton', document.getElementById('hideUIButton').checked);
  220.  
  221. if (document.getElementById('hideUIButton').checked) {
  222. uiButton.style.display = 'none';
  223. } else {
  224. uiButton.style.display = 'block';
  225. }
  226.  
  227. if (showMoreBefore !== document.getElementById('enableShowMoreFix').checked) {
  228. location.reload();
  229. }
  230.  
  231. enableShowMoreFix();
  232. document.body.removeChild(overlay);
  233. uiButton.style.pointerEvents = 'auto';
  234. uiButton.style.opacity = '1';
  235. };
  236.  
  237. document.getElementById('resetSettingsBtn').onclick = () => {
  238. resetSettings();
  239. document.body.removeChild(overlay);
  240. uiButton.style.pointerEvents = 'auto';
  241. uiButton.style.opacity = '1';
  242. };
  243. }
  244.  
  245. createSettingsButton();
  246.  
  247. // Hide or show button when navigating to the home or subscriptions page
  248. function checkPageAndToggleUIButton() {
  249. const isHomeOrSubscriptions = window.location.pathname === '/' || window.location.pathname === '/feed/subscriptions';
  250. if (isHomeOrSubscriptions) {
  251. uiButton.style.display = settings.hideUIButton ? 'none' : 'block';
  252. } else {
  253. uiButton.style.display = 'none';
  254. }
  255. }
  256.  
  257. // Listen for page navigation changes and handle button visibility
  258. window.addEventListener('yt-navigate-finish', checkPageAndToggleUIButton);
  259. checkPageAndToggleUIButton();
  260. })();