// ==UserScript==
// @name 🪄 YouTube UI Enhancer — Resize Thumbnails & Customize Layout
// @namespace https://greasyfork.org/users/1461079
// @version 2.0.1
// @description Get rid of oversized thumbnails, adjust rows, and clean up layout for a more streamlined YouTube experience.
// @author Michaelsoft
// @match *://www.youtube.com/*
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @run-at document-end
// @license MIT
// ==/UserScript==
(function () {
'use strict';
// WARNING: Users should update their preferences through UI - values below will be overwritten every time the script is updated.
const userSettings = {
videosPerRow: 6, // Set how many videos per row (e.g., 4, 5, 6, etc.). Default value is 6.
shortsPerRow: 12, // Set how many Shorts per row (e.g., 7, 8, 9, etc.). Default value is 12.
disableShorts: false, // Set to true to completely hide the Shorts section. Default value is false.
enableShowMoreFix: true, // Set to true to auto-expand Shorts ("Show More" fix). Default value is true.
hideUIButton: false, // Set to true to hide the floating settings button. Default value is false.
hideUIButtonShortcut: true, // Set to true to allow Alt+Shift+U shortcut to toggle button visibility. Default value is true.
};
const settings = {};
for (const key in userSettings) {
settings[key] = GM_getValue(key, userSettings[key]);
}
function saveSetting(key, value) {
GM_setValue(key, value);
settings[key] = value;
applyCustomizations();
}
function resetSettings() {
for (const key in userSettings) {
saveSetting(key, userSettings[key]);
}
enableShowMoreFix();
}
let customStyle = null;
function applyCustomizations() {
if (customStyle) customStyle.remove();
customStyle = GM_addStyle(`
ytd-rich-grid-renderer {
--ytd-rich-grid-items-per-row: ${settings.videosPerRow} !important;
--ytd-rich-grid-posts-per-row: ${settings.videosPerRow} !important;
--ytd-rich-grid-slim-items-per-row: ${settings.shortsPerRow} !important;
--ytd-rich-grid-game-cards-per-row: 7 !important;
--ytd-rich-grid-gutter-margin: 0px !important;
}
ytd-rich-shelf-renderer {
--ytd-rich-grid-items-per-row: ${settings.shortsPerRow} !important;
}
${settings.disableShorts ? `
ytd-rich-section-renderer.style-scope.ytd-rich-grid-renderer {
display: none !important;
}
` : ''}
`);
}
applyCustomizations();
let observer;
function enableShowMoreFix() {
if (observer) observer.disconnect();
if (!settings.enableShowMoreFix) return;
observer = new MutationObserver(() => {
document.querySelectorAll('ytd-rich-item-renderer[hidden]').forEach(el => {
el.removeAttribute('hidden');
});
document.querySelectorAll('ytd-rich-shelf-renderer').forEach(el => {
el.setAttribute('is-show-more-hidden', '');
});
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
}
enableShowMoreFix();
function isDarkTheme() {
const html = document.querySelector('html');
return html && html.getAttribute('dark') !== null;
}
let uiButton = null;
function createSettingsButton() {
uiButton = document.createElement('div');
uiButton.innerHTML = 'Customize Layout';
uiButton.style.position = 'fixed';
uiButton.style.bottom = '20px';
uiButton.style.right = '20px';
uiButton.style.zIndex = '9999';
uiButton.style.padding = '10px 20px';
uiButton.style.fontSize = '16px';
uiButton.style.backgroundColor = '#065fd4';
uiButton.style.color = '#fff';
uiButton.style.borderRadius = '8px';
uiButton.style.cursor = 'pointer';
uiButton.style.boxShadow = '0 4px 12px rgba(0,0,0,0.4)';
uiButton.style.opacity = '1';
uiButton.style.transition = 'opacity 0.3s ease';
uiButton.style.display = settings.hideUIButton ? 'none' : 'block'; // <--- important
uiButton.onclick = openSettingsMenu;
document.body.appendChild(uiButton);
if (settings.hideUIButtonShortcut) {
window.addEventListener('keydown', (e) => {
if (e.altKey && e.shiftKey && e.key === 'U') {
toggleUIButtonVisibility();
}
});
}
}
function toggleUIButtonVisibility() {
if (uiButton) {
if (uiButton.style.display === 'none') {
uiButton.style.display = 'block';
saveSetting('hideUIButton', false);
} else {
uiButton.style.display = 'none';
saveSetting('hideUIButton', true);
}
}
}
function openSettingsMenu() {
const darkMode = isDarkTheme();
// Disable floating button while modal is open
uiButton.style.pointerEvents = 'none';
uiButton.style.opacity = '0.5';
const overlay = document.createElement('div');
overlay.style.position = 'fixed';
overlay.style.top = '0';
overlay.style.left = '0';
overlay.style.width = '100vw';
overlay.style.height = '100vh';
overlay.style.backgroundColor = 'rgba(0,0,0,0.7)';
overlay.style.zIndex = '9998';
overlay.onclick = () => {
document.body.removeChild(overlay);
uiButton.style.pointerEvents = 'auto';
uiButton.style.opacity = '1';
};
const menu = document.createElement('div');
menu.style.position = 'fixed';
menu.style.top = '50%';
menu.style.left = '50%';
menu.style.transform = 'translate(-50%, -50%)';
menu.style.backgroundColor = darkMode ? '#222' : '#fff';
menu.style.color = darkMode ? '#eee' : '#000';
menu.style.padding = '20px 20px 20px 20px';
menu.style.borderRadius = '12px';
menu.style.boxShadow = '0 8px 24px rgba(0,0,0,0.6)';
menu.style.width = '320px';
menu.style.zIndex = '9999';
menu.style.fontSize = '14px';
menu.style.lineHeight = '1.5';
menu.style.textAlign = 'left';
menu.onclick = e => e.stopPropagation();
menu.innerHTML = `
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:20px;">
<a href="https://greasyfork.org/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;">
🪄 YouTube UI Enhancer
</a>
<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>
</div>
<label style="display:block; margin-bottom:10px;">Videos Per Row: <input id="videosPerRow" type="number" min="1" value="${settings.videosPerRow}" style="width:60px;"/></label>
<label style="display:block; margin-bottom:20px;">Shorts Per Row: <input id="shortsPerRow" type="number" min="1" value="${settings.shortsPerRow}" style="width:60px;"/></label>
<label style="display:block; margin-bottom:10px;">
<input id="disableShorts" type="checkbox" ${settings.disableShorts ? 'checked' : ''} /> Hide Shorts Section
</label>
<label style="display:block; margin-bottom:20px;">
<input id="enableShowMoreFix" type="checkbox" ${settings.enableShowMoreFix ? 'checked' : ''} /> Expand Shorts Automatically
</label>
<div style="margin-top:20px; margin-bottom:20px; border-top:1px solid ${darkMode ? 'white' : 'lightgrey'};"></div>
<label style="display:block; margin-bottom:20px;">
<input id="hideUIButton" type="checkbox" ${settings.hideUIButton ? 'checked' : ''} /> Hide Script Button (Alt+Shift+U to Show)
</label>
<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>
<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>
`;
overlay.appendChild(menu);
document.body.appendChild(overlay);
document.getElementById('closeOverlay').onclick = () => {
document.body.removeChild(overlay);
uiButton.style.pointerEvents = 'auto';
uiButton.style.opacity = '1';
};
document.getElementById('saveSettingsBtn').onclick = () => {
const showMoreBefore = settings.enableShowMoreFix;
saveSetting('videosPerRow', parseInt(document.getElementById('videosPerRow').value, 10));
saveSetting('shortsPerRow', parseInt(document.getElementById('shortsPerRow').value, 10));
saveSetting('disableShorts', document.getElementById('disableShorts').checked);
saveSetting('enableShowMoreFix', document.getElementById('enableShowMoreFix').checked);
saveSetting('hideUIButton', document.getElementById('hideUIButton').checked);
if (document.getElementById('hideUIButton').checked) {
uiButton.style.display = 'none';
} else {
uiButton.style.display = 'block';
}
if (showMoreBefore !== document.getElementById('enableShowMoreFix').checked) {
location.reload();
}
enableShowMoreFix();
document.body.removeChild(overlay);
uiButton.style.pointerEvents = 'auto';
uiButton.style.opacity = '1';
};
document.getElementById('resetSettingsBtn').onclick = () => {
resetSettings();
document.body.removeChild(overlay);
uiButton.style.pointerEvents = 'auto';
uiButton.style.opacity = '1';
};
}
createSettingsButton();
// Hide or show button when navigating to the home or subscriptions page
function checkPageAndToggleUIButton() {
const isHomeOrSubscriptions = window.location.pathname === '/' || window.location.pathname === '/feed/subscriptions';
if (isHomeOrSubscriptions) {
uiButton.style.display = settings.hideUIButton ? 'none' : 'block';
} else {
uiButton.style.display = 'none';
}
}
// Listen for page navigation changes and handle button visibility
window.addEventListener('yt-navigate-finish', checkPageAndToggleUIButton);
checkPageAndToggleUIButton();
})();