Home: collapse guide, 5 videos per row, hide Shorts. Watch: hide recommendations sidebar and center the player/content. Adds a topbar theme switcher that triggers YouTube's official Appearance modes.
// ==UserScript==
// @name YouTube Layout Plus
// @namespace https://qazwsx123.uk/
// @version 0.1.4
// @description Home: collapse guide, 5 videos per row, hide Shorts. Watch: hide recommendations sidebar and center the player/content. Adds a topbar theme switcher that triggers YouTube's official Appearance modes.
// @author Codex
// @match https://www.youtube.com/*
// @run-at document-idle
// @grant none
// ==/UserScript==
(function () {
'use strict';
const STYLE_ID = 'tm-youtube-layout-plus-style';
const THEME_SWITCHER_ID = 'tm-youtube-layout-plus-theme-switcher';
const THEME_BUSY_CLASS = 'tm-youtube-layout-plus-theme-busy';
const THEME_MODE_STORAGE_KEY = 'tm-youtube-layout-plus-theme-mode';
const THEME_MODES = [
{ mode: 'auto', label: 'Auto', signal: 'TOGGLE_DARK_THEME_DEVICE' },
{ mode: 'light', label: 'Light', signal: 'TOGGLE_DARK_THEME_OFF' },
{ mode: 'dark', label: 'Dark', signal: 'TOGGLE_DARK_THEME_ON' },
];
let currentUrl = location.href;
let applyTimer = null;
let bodyObserver = null;
let routeTimer = null;
let lastAutoCollapsedHomeUrl = '';
let currentThemeMode = loadStoredThemeMode();
let themeSwitchInFlight = false;
function isHomePage() {
return location.pathname === '/';
}
function isWatchPage() {
return location.pathname === '/watch';
}
function ensureStyle() {
if (document.getElementById(STYLE_ID)) return;
const style = document.createElement('style');
style.id = STYLE_ID;
style.textContent = `
html.tm-youtube-layout-plus-home {
--tm-guide-collapsed-width: 72px;
--tm-chip-strip-bg: linear-gradient(180deg, rgba(237, 240, 243, 0.98) 0%, rgba(227, 231, 236, 0.96) 100%);
--tm-chip-active-bg: linear-gradient(180deg, #fcfcfd 0%, #f3f5f8 100%);
--tm-chip-text: #444950;
--tm-chip-text-active: #1f2328;
--tm-chip-separator: rgba(60, 64, 67, 0.14);
--tm-chip-strip-border: rgba(255, 255, 255, 0.42);
--tm-chip-strip-shadow-top: rgba(255, 255, 255, 0.38);
--tm-chip-strip-shadow-bottom: rgba(0, 0, 0, 0.04);
--tm-chip-hover-bg: rgba(255, 255, 255, 0.34);
--tm-chip-active-shadow-top: rgba(255, 255, 255, 0.42);
--tm-chip-active-shadow-mid: rgba(60, 64, 67, 0.16);
--tm-chip-active-shadow-ring: rgba(60, 64, 67, 0.08);
--tm-chip-arrow-bg: rgba(255, 255, 255, 0.55);
--tm-chip-arrow-shadow-top: rgba(255, 255, 255, 0.35);
--tm-chip-arrow-shadow-mid: rgba(60, 64, 67, 0.1);
}
html[dark].tm-youtube-layout-plus-home {
--tm-chip-strip-bg: linear-gradient(180deg, rgba(43, 45, 49, 0.98) 0%, rgba(31, 33, 36, 0.98) 100%);
--tm-chip-active-bg: linear-gradient(180deg, rgba(71, 74, 80, 0.98) 0%, rgba(56, 58, 63, 0.98) 100%);
--tm-chip-text: rgba(231, 234, 237, 0.9);
--tm-chip-text-active: #ffffff;
--tm-chip-separator: rgba(255, 255, 255, 0.12);
--tm-chip-strip-border: rgba(255, 255, 255, 0.08);
--tm-chip-strip-shadow-top: rgba(255, 255, 255, 0.06);
--tm-chip-strip-shadow-bottom: rgba(0, 0, 0, 0.45);
--tm-chip-hover-bg: rgba(255, 255, 255, 0.08);
--tm-chip-active-shadow-top: rgba(255, 255, 255, 0.08);
--tm-chip-active-shadow-mid: rgba(0, 0, 0, 0.32);
--tm-chip-active-shadow-ring: rgba(255, 255, 255, 0.08);
--tm-chip-arrow-bg: rgba(255, 255, 255, 0.08);
--tm-chip-arrow-shadow-top: rgba(255, 255, 255, 0.06);
--tm-chip-arrow-shadow-mid: rgba(0, 0, 0, 0.28);
}
html.${THEME_BUSY_CLASS} ytd-popup-container tp-yt-iron-dropdown {
visibility: hidden !important;
}
#${THEME_SWITCHER_ID} {
position: relative;
display: flex;
align-items: center;
gap: 0;
margin-left: 12px;
padding: 4px 6px;
border: 1px solid var(--yt-spec-10-percent-layer, rgba(0, 0, 0, 0.12));
border-radius: 20px;
background: var(--yt-spec-badge-chip-background, rgba(0, 0, 0, 0.05));
}
#${THEME_SWITCHER_ID} .tm-theme-switch-track {
display: inline-flex;
align-items: center;
gap: 4px;
}
#${THEME_SWITCHER_ID} .tm-theme-switch-option {
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 52px;
height: 28px;
padding: 0 10px;
border: 0;
border-radius: 14px;
background: transparent;
color: var(--yt-spec-text-primary, #0f0f0f);
cursor: pointer;
font: 600 12px/1 Roboto, Arial, sans-serif;
transition: background 140ms ease, color 140ms ease, box-shadow 140ms ease;
}
#${THEME_SWITCHER_ID} .tm-theme-switch-option:hover {
background: var(--yt-spec-badge-chip-background-hover, rgba(0, 0, 0, 0.08));
}
#${THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"] {
background: var(--yt-spec-brand-background-solid, rgba(15, 15, 15, 0.92));
color: var(--yt-spec-static-brand-white, #fff);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
}
html[dark] #${THEME_SWITCHER_ID} {
border-color: rgba(255, 255, 255, 0.14);
background: rgba(255, 255, 255, 0.04);
}
html[dark] #${THEME_SWITCHER_ID} .tm-theme-switch-option {
color: rgba(255, 255, 255, 0.92);
}
html[dark] #${THEME_SWITCHER_ID} .tm-theme-switch-option[data-active="true"] {
background: rgba(255, 255, 255, 0.14);
color: #fff;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
}
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-feed-filter-chip-bar-renderer,
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) #chips-wrapper {
left: var(--tm-guide-collapsed-width) !important;
width: calc(100vw - var(--tm-guide-collapsed-width)) !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer {
padding: 8px 14px 12px !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-wrapper,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips {
align-items: center !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #chips-content {
padding: 4px 8px !important;
margin-top: 12px !important;
border: 1px solid var(--tm-chip-strip-border) !important;
border-radius: 22px !important;
background: var(--tm-chip-strip-bg) !important;
box-shadow: inset 0 1px 0 var(--tm-chip-strip-shadow-top), inset 0 -1px 0 var(--tm-chip-strip-shadow-bottom) !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer {
position: relative !important;
margin: 0 !important;
padding: 0 2px !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer + yt-chip-cloud-chip-renderer::before {
content: '' !important;
position: absolute !important;
left: -1px !important;
top: 9px !important;
bottom: 9px !important;
width: 1px !important;
border-radius: 999px !important;
background: var(--tm-chip-separator) !important;
pointer-events: none !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer button.ytChipShapeButtonReset {
border-radius: 18px !important;
overflow: visible !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip {
position: relative !important;
min-height: 38px !important;
padding: 0 22px !important;
border: 0 !important;
border-radius: 18px !important;
background: transparent !important;
box-shadow: none !important;
color: var(--tm-chip-text) !important;
font-weight: 600 !important;
letter-spacing: -0.01em !important;
transition:
background 140ms ease,
box-shadow 140ms ease,
color 140ms ease,
transform 140ms ease !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip > div {
font-size: 15px !important;
line-height: 36px !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer:hover .ytChipShapeChip,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer button:focus-visible .ytChipShapeChip {
background: var(--tm-chip-hover-bg) !important;
color: var(--tm-chip-text-active) !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected] .ytChipShapeChip,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .ytChipShapeChip.ytChipShapeActive {
background: var(--tm-chip-active-bg) !important;
box-shadow:
0 1px 0 var(--tm-chip-active-shadow-top) inset,
0 1px 2px var(--tm-chip-active-shadow-mid),
0 0 0 1px var(--tm-chip-active-shadow-ring) !important;
color: var(--tm-chip-text-active) !important;
transform: translateY(-1px) !important;
z-index: 1 !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected]::before,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer[selected] + yt-chip-cloud-chip-renderer::before {
opacity: 0 !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer yt-touch-feedback-shape,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .yt-spec-touch-feedback-shape__stroke,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer yt-chip-cloud-chip-renderer .yt-spec-touch-feedback-shape__fill {
border-radius: 18px !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #right-arrow.ytd-feed-filter-chip-bar-renderer,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #left-arrow.ytd-feed-filter-chip-bar-renderer {
margin-top: 0 !important;
}
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #right-arrow button,
html.tm-youtube-layout-plus-home ytd-feed-filter-chip-bar-renderer #left-arrow button {
border: 0 !important;
border-radius: 18px !important;
background: var(--tm-chip-arrow-bg) !important;
box-shadow: inset 0 1px 0 var(--tm-chip-arrow-shadow-top), 0 1px 2px var(--tm-chip-arrow-shadow-mid) !important;
}
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-page-manager {
margin-left: var(--tm-guide-collapsed-width) !important;
width: calc(100% - var(--tm-guide-collapsed-width)) !important;
}
html.tm-youtube-layout-plus-home ytd-browse {
overflow: visible !important;
}
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-two-column-browse-results-renderer,
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) ytd-rich-grid-renderer,
html.tm-youtube-layout-plus-home ytd-app[mini-guide-visible]:not([guide-persistent-and-visible]) #contents.ytd-rich-grid-renderer {
margin-left: 0 !important;
width: auto !important;
}
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer {
padding-top: 10px !important;
padding-left: 14px !important;
padding-right: 12px !important;
box-sizing: border-box !important;
}
html.tm-youtube-layout-plus-home ytd-rich-grid-renderer {
--ytd-rich-grid-items-per-row: 5 !important;
--ytd-rich-grid-posts-per-row: 5 !important;
}
html.tm-youtube-layout-plus-home ytd-rich-item-renderer,
html.tm-youtube-layout-plus-home ytd-rich-grid-row,
html.tm-youtube-layout-plus-home ytd-rich-grid-media,
html.tm-youtube-layout-plus-home #contents.ytd-rich-grid-renderer > * {
max-width: none !important;
}
html.tm-youtube-layout-plus-home ytd-rich-item-renderer {
margin-left: 0 !important;
margin-right: 10px !important;
}
html.tm-youtube-layout-plus-home ytd-rich-section-renderer,
html.tm-youtube-layout-plus-home ytd-rich-shelf-renderer,
html.tm-youtube-layout-plus-home ytd-reel-shelf-renderer {
display: none !important;
}
html.tm-youtube-layout-plus-watch ytd-watch-flexy #secondary,
html.tm-youtube-layout-plus-watch ytd-watch-flexy #related,
html.tm-youtube-layout-plus-watch ytd-watch-flexy #secondary-inner,
html.tm-youtube-layout-plus-watch ytd-watch-next-secondary-results-renderer {
display: none !important;
}
html.tm-youtube-layout-plus-watch ytd-watch-flexy[is-two-columns_] #primary {
max-width: none !important;
width: min(1400px, calc(100vw - 48px)) !important;
margin: 0 auto !important;
}
html.tm-youtube-layout-plus-watch ytd-watch-flexy[is-two-columns_] #columns {
display: block !important;
}
html.tm-youtube-layout-plus-watch ytd-watch-flexy[is-two-columns_] #primary-inner,
html.tm-youtube-layout-plus-watch ytd-watch-flexy[is-two-columns_] #above-the-fold,
html.tm-youtube-layout-plus-watch ytd-watch-flexy[is-two-columns_] #below {
max-width: none !important;
}
`;
document.head.appendChild(style);
}
function collapseGuide() {
const app = document.querySelector('ytd-app');
if (app) {
app.removeAttribute('guide-persistent-and-visible');
app.setAttribute('mini-guide-visible', '');
}
const drawer = document.querySelector('tp-yt-app-drawer#guide');
if (drawer) {
drawer.removeAttribute('opened');
drawer.style.width = '';
drawer.style.minWidth = '';
drawer.style.visibility = '';
}
const guideRenderer = document.querySelector('ytd-guide-renderer');
if (guideRenderer) {
guideRenderer.style.display = '';
guideRenderer.style.width = '';
guideRenderer.style.minWidth = '';
}
}
function applyHomeLayout() {
const richGrid = document.querySelector('ytd-rich-grid-renderer');
if (!richGrid) return;
document.documentElement.classList.add('tm-youtube-layout-plus-home');
if (lastAutoCollapsedHomeUrl !== location.href) {
collapseGuide();
lastAutoCollapsedHomeUrl = location.href;
}
}
function applyWatchLayout() {
const watchFlexy = document.querySelector('ytd-watch-flexy');
if (!watchFlexy) return;
document.documentElement.classList.add('tm-youtube-layout-plus-watch');
}
function clearModeClasses() {
document.documentElement.classList.remove(
'tm-youtube-layout-plus-home',
'tm-youtube-layout-plus-watch'
);
}
function delay(ms) {
return new Promise((resolve) => {
window.setTimeout(resolve, ms);
});
}
function loadStoredThemeMode() {
try {
const mode = window.localStorage.getItem(THEME_MODE_STORAGE_KEY);
return THEME_MODES.some((item) => item.mode === mode) ? mode : null;
} catch {
return null;
}
}
function persistThemeMode(mode) {
try {
if (THEME_MODES.some((item) => item.mode === mode)) {
window.localStorage.setItem(THEME_MODE_STORAGE_KEY, mode);
} else {
window.localStorage.removeItem(THEME_MODE_STORAGE_KEY);
}
} catch {
// Ignore storage failures.
}
}
async function waitFor(getValue, timeout = 2000) {
const startedAt = Date.now();
while (Date.now() - startedAt < timeout) {
const value = getValue();
if (value) return value;
await delay(50);
}
return null;
}
function getThemeSignal(mode) {
return THEME_MODES.find((item) => item.mode === mode)?.signal || null;
}
function getThemeOptionSignal(option) {
return option?.data?.serviceEndpoint?.signalServiceEndpoint?.actions?.[0]?.signalAction?.signal || null;
}
function isVisibleElement(element) {
if (!element) return false;
const rect = element.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
}
function getOfficialThemeOptions(options = {}) {
const { visibleOnly = false } = options;
return Array.from(document.querySelectorAll('ytd-compact-link-renderer')).filter(
(option) => THEME_MODES.some((mode) => getThemeOptionSignal(option) === mode.signal)
&& (!visibleOnly || isVisibleElement(option))
);
}
function getOfficialThemeOption(mode, options = {}) {
const signal = getThemeSignal(mode);
return getOfficialThemeOptions(options).find((option) => getThemeOptionSignal(option) === signal) || null;
}
function detectThemeModeFromOptions() {
const selectedOption = getOfficialThemeOptions({ visibleOnly: true }).find(
(option) => option?.data?.icon?.iconType === 'CHECK'
);
if (!selectedOption) return null;
return THEME_MODES.find((mode) => mode.signal === getThemeOptionSignal(selectedOption))?.mode || null;
}
function findAccountMenuButton() {
return Array.from(document.querySelectorAll('button')).find((button) => {
const label = button.getAttribute('aria-label') || button.textContent || '';
return /Account menu/i.test(label);
}) || null;
}
function findAppearanceMenuEntry() {
return Array.from(document.querySelectorAll('ytd-toggle-theme-compact-link-renderer')).find(
(entry) => isVisibleElement(entry)
) || null;
}
function closeOfficialThemeMenus() {
document.dispatchEvent(
new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true })
);
document.dispatchEvent(
new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true })
);
const openPopup = Array.from(document.querySelectorAll('tp-yt-iron-dropdown')).find((popup) => {
const rect = popup.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
});
if (openPopup) {
findAccountMenuButton()?.click();
}
}
async function ensureOfficialThemeOptionsLoaded() {
const cachedOption = getOfficialThemeOptions({ visibleOnly: true })[0];
if (cachedOption) return true;
closeOfficialThemeMenus();
await delay(80);
let appearanceEntry = findAppearanceMenuEntry();
if (!appearanceEntry) {
const accountMenuButton = findAccountMenuButton();
if (!accountMenuButton) return false;
accountMenuButton.click();
appearanceEntry = await waitFor(findAppearanceMenuEntry, 2000);
}
if (!appearanceEntry) return false;
appearanceEntry.click();
return !!(await waitFor(() => getOfficialThemeOptions({ visibleOnly: true })[0], 2000));
}
function updateThemeSwitcherUI() {
const switcher = document.getElementById(THEME_SWITCHER_ID);
if (!switcher) return;
const inferredMode = detectThemeModeFromOptions();
if (inferredMode) {
currentThemeMode = inferredMode;
persistThemeMode(inferredMode);
} else if (!currentThemeMode) {
currentThemeMode = loadStoredThemeMode();
}
const activeMode = currentThemeMode || (document.documentElement.hasAttribute('dark') ? 'dark' : 'light');
const optionButtons = switcher.querySelectorAll('.tm-theme-switch-option[data-mode]');
for (const button of optionButtons) {
const isActive = button.dataset.mode === activeMode;
button.dataset.active = String(isActive);
button.setAttribute('aria-pressed', String(isActive));
button.disabled = themeSwitchInFlight;
}
}
async function setThemeMode(mode) {
if (themeSwitchInFlight) return;
themeSwitchInFlight = true;
document.documentElement.classList.add(THEME_BUSY_CLASS);
try {
updateThemeSwitcherUI();
const loaded = await ensureOfficialThemeOptionsLoaded();
if (!loaded) return;
const option = getOfficialThemeOption(mode, { visibleOnly: true });
if (!option) return;
option.click();
currentThemeMode = mode;
persistThemeMode(mode);
await waitFor(
() => !getOfficialThemeOptions({ visibleOnly: true })[0] || detectThemeModeFromOptions() === mode,
1500
);
updateThemeSwitcherUI();
} finally {
closeOfficialThemeMenus();
themeSwitchInFlight = false;
document.documentElement.classList.remove(THEME_BUSY_CLASS);
updateThemeSwitcherUI();
}
}
function ensureThemeSwitcher() {
const logoRenderer = document.querySelector('ytd-topbar-logo-renderer');
if (!logoRenderer) return;
let switcher = document.getElementById(THEME_SWITCHER_ID);
if (!switcher) {
const track = document.createElement('div');
track.className = 'tm-theme-switch-track';
track.setAttribute('role', 'group');
track.setAttribute('aria-label', 'Theme switcher');
switcher = document.createElement('div');
switcher.id = THEME_SWITCHER_ID;
for (const item of THEME_MODES) {
const optionButton = document.createElement('button');
optionButton.type = 'button';
optionButton.className = 'tm-theme-switch-option';
optionButton.dataset.mode = item.mode;
optionButton.dataset.active = 'false';
optionButton.textContent = item.label;
optionButton.setAttribute('aria-pressed', 'false');
optionButton.addEventListener('click', async (event) => {
event.preventDefault();
event.stopPropagation();
await setThemeMode(item.mode);
});
track.appendChild(optionButton);
}
switcher.append(track);
logoRenderer.insertAdjacentElement('afterend', switcher);
} else if (switcher.previousElementSibling !== logoRenderer) {
logoRenderer.insertAdjacentElement('afterend', switcher);
}
updateThemeSwitcherUI();
}
function applyLayout() {
ensureStyle();
clearModeClasses();
try {
ensureThemeSwitcher();
} catch (error) {
console.error('YouTube Layout Plus theme switcher failed:', error);
}
if (isHomePage()) {
applyHomeLayout();
return;
}
if (isWatchPage()) {
applyWatchLayout();
}
}
function scheduleApply() {
clearTimeout(applyTimer);
applyTimer = window.setTimeout(applyLayout, 120);
}
function startObservers() {
if (bodyObserver) return;
bodyObserver = new MutationObserver(() => {
scheduleApply();
});
bodyObserver.observe(document.body, {
childList: true,
subtree: true,
});
}
function watchRoute() {
if (routeTimer) return;
routeTimer = window.setInterval(() => {
if (location.href === currentUrl) return;
currentUrl = location.href;
if (!isHomePage()) {
lastAutoCollapsedHomeUrl = '';
}
scheduleApply();
}, 500);
}
function init() {
ensureStyle();
scheduleApply();
startObservers();
watchRoute();
}
init();
})();