// ==UserScript==
// @name YouTube - 首页自适应
// @namespace http://tampermonkey.net/
// @version 1.4
// @description 实现YouTube首页自适应(5/4/3/2/1)布局
// @author Ferrari
// @match https://www.youtube.com/
// @grant GM_registerMenuCommand
// @grant GM_setValue
// @grant GM_getValue
// @run-at document-start
// @license MIT
// ==/UserScript==
(function() {
'use strict';
const CONFIG = {
MAX_ITEMS_PER_ROW: 5,
MIN_ITEMS_PER_ROW: 1,
ITEM_MIN_WIDTH: 260,
ITEM_PREFERRED_WIDTH: 300,
SIDEBAR_WIDTH_EXPANDED: 240,
SIDEBAR_WIDTH_COLLAPSED: 72,
GUTTER_SIZE: 16,
SIDE_PADDING: 24,
SHORTS_BLOCKED: 'yt-shorts-blocked'
};
let lastAppliedColumns = 0;
let stylesInitialized = false;
let lastWindowWidth = window.innerWidth;
let initialStylesApplied = false;
const getShortsHiddenState = () => {
const gmValue = GM_getValue('hideShortsFlag');
if (gmValue !== undefined) {
localStorage.setItem(CONFIG.SHORTS_BLOCKED, gmValue);
return gmValue;
}
return localStorage.getItem(CONFIG.SHORTS_BLOCKED) === 'true';
};
let hideShortsFlag = getShortsHiddenState();
GM_registerMenuCommand(hideShortsFlag ? '显示YouTube Shorts' : '隐藏YouTube Shorts', toggleShorts);
let shortsStyle = null;
function toggleShorts() {
hideShortsFlag = !hideShortsFlag;
GM_setValue('hideShortsFlag', hideShortsFlag);
localStorage.setItem(CONFIG.SHORTS_BLOCKED, hideShortsFlag);
const status = hideShortsFlag ? '已隐藏' : '已显示';
alert(`YouTube Shorts ${status},页面将刷新以应用更改`);
window.location.reload();
}
function applyShortsVisibility() {
if (!shortsStyle) {
shortsStyle = document.createElement('style');
shortsStyle.id = 'yt-shorts-visibility';
document.head.appendChild(shortsStyle);
}
if (hideShortsFlag) {
shortsStyle.textContent = `
ytd-rich-section-renderer,
ytd-reel-shelf-renderer,
ytd-shorts,
ytd-mini-guide-entry-renderer[endpoint*="shorts"],
ytd-guide-entry-renderer[endpoint*="shorts"] {
display: none !important;
}
`;
} else {
shortsStyle.textContent = '';
}
}
function adjustLoadingSkeletons(skeletonElements, columns) {
if (!skeletonElements.length) {
return;
}
skeletonElements.forEach((element, index) => {
if (!element) {
return;
}
try {
if (element.tagName === 'YTD-CONTINUATION-ITEM-RENDERER') {
element.style.width = '100%';
element.style.margin = '0';
element.style.padding = '0';
element.style.display = 'block';
element.style.overflow = 'hidden';
const spinner = element.querySelector('tp-yt-paper-spinner, yt-loading-icon');
if (spinner) {
spinner.style.margin = '16px auto';
spinner.style.display = 'block';
}
if (element.hasAttribute('elements-per-row') || element.parentElement?.tagName === 'YTD-RICH-GRID-RENDERER') {
element.setAttribute('elements-per-row', columns);
}
element.style.setProperty('--ytd-rich-grid-items-per-row', columns, 'important');
element.style.setProperty('--ytd-rich-grid-posts-per-row', columns, 'important');
const lastRow = document.querySelector('ytd-rich-grid-row:last-child');
if (lastRow) {
lastRow.style.marginBottom = '0';
element.style.marginTop = '0';
}
const contentsContainer = document.querySelector('ytd-rich-grid-renderer #contents');
if (contentsContainer) {
contentsContainer.style.padding = `0 ${CONFIG.GUTTER_SIZE/2}px`;
}
} else {
createSkeletonGrid(element, columns, 3);
if (element.hasAttribute('elements-per-row') || element.tagName === 'YTD-RICH-GRID-RENDERER') {
element.setAttribute('elements-per-row', columns);
}
const lastRow = document.querySelector('ytd-rich-grid-row:last-child');
if (lastRow) {
lastRow.style.marginBottom = '0';
element.style.marginTop = '0';
}
}
} catch (error) {
}
});
}
function createSkeletonGrid(container, columns, rows) {
if (!container) return;
try {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
container.style.display = 'grid';
container.style.gridTemplateColumns = `repeat(${columns}, 1fr)`;
container.style.gridTemplateRows = `repeat(${rows}, auto)`;
container.style.gap = `${CONFIG.GUTTER_SIZE}px`;
container.style.padding = `0 ${CONFIG.GUTTER_SIZE/2}px`;
container.style.width = '100%';
container.style.boxSizing = 'border-box';
container.style.setProperty('--ytd-rich-grid-items-per-row', columns, 'important');
container.style.setProperty('--ytd-rich-grid-posts-per-row', columns, 'important');
container.style.setProperty('--ytd-rich-grid-shorts-per-row', columns, 'important');
container.style.setProperty('--ytd-rich-grid-slim-items-per-row', columns, 'important');
if (
container.id === 'continuation-skeleton' ||
container.classList?.contains('rich-grid-skeleton-content') ||
container.classList?.contains('rich-shelf-videos') ||
container.id === 'skeleton'
) {
const totalItems = columns * rows;
for (let i = 0; i < totalItems; i++) {
const item = createSkeletonItem();
if (item) {
container.appendChild(item);
}
}
}
} catch (error) {
}
}
function createSkeletonItem() {
const item = document.createElement('div');
item.className = 'rich-shelf-video';
item.style.width = '100%';
item.style.margin = '0';
item.style.borderRadius = '12px';
item.style.overflow = 'hidden';
const thumbnail = document.createElement('div');
thumbnail.className = 'thumbnail-container';
thumbnail.style.width = '100%';
thumbnail.style.aspectRatio = '16/9';
thumbnail.style.backgroundColor = '#e0e0e0';
thumbnail.style.borderRadius = '12px';
thumbnail.style.marginBottom = '12px';
item.appendChild(thumbnail);
const details = document.createElement('div');
details.className = 'video-details-container';
details.style.width = '100%';
const titleLine = document.createElement('div');
titleLine.className = 'skeleton-line';
titleLine.style.height = '12px';
titleLine.style.width = '100%';
titleLine.style.backgroundColor = '#e0e0e0';
titleLine.style.borderRadius = '6px';
titleLine.style.marginBottom = '8px';
details.appendChild(titleLine);
const channelLine = document.createElement('div');
channelLine.className = 'skeleton-line';
channelLine.style.height = '12px';
channelLine.style.width = '60%';
channelLine.style.backgroundColor = '#e0e0e0';
channelLine.style.borderRadius = '6px';
channelLine.style.marginBottom = '8px';
details.appendChild(channelLine);
item.appendChild(details);
return item;
}
function adjustSkeletonItems(columns) {
const skeletonElements = document.querySelectorAll(
'#home-page-skeleton .rich-grid-skeleton-content, ' +
'#home-page-skeleton .rich-shelf-videos, ' +
'#search-page-skeleton .rich-shelf-videos, ' +
'ytd-browse[page-subtype="home"] #skeleton .rich-shelf-videos, ' +
'ytd-browse[page-subtype="home"] #skeleton .rich-grid-skeleton-content, ' +
'ytd-browse[page-subtype="subscriptions"] #skeleton .rich-shelf-videos, ' +
'ytd-browse[role="main"] #skeleton .rich-shelf-videos, ' +
'ytd-search #skeleton .rich-shelf-videos'
);
const loadingSkeletonElements = document.querySelectorAll(
'ytd-rich-grid-renderer #continuation-skeleton, ' +
'ytd-rich-grid-renderer .rich-grid-skeleton-content, ' +
'#contents ytd-continuation-item-renderer, ' +
'ytd-rich-grid-renderer [role="progressbar"], ' +
'ytd-browse[role="main"] #continuations, ' +
'ytd-browse .loading-skeleton'
);
if (skeletonElements.length > 0) {
skeletonElements.forEach((element) => {
createSkeletonGrid(element, columns, 3);
});
}
if (loadingSkeletonElements.length > 0) {
adjustLoadingSkeletons(loadingSkeletonElements, columns);
}
}
function adjustRegularSkeletons(skeletonElements, columns) {
skeletonElements.forEach(element => {
createSkeletonGrid(element, columns, 3);
});
}
function detectScrollLoading() {
let lastScrollY = window.scrollY;
let scrollTimer;
window.addEventListener('scroll', () => {
clearTimeout(scrollTimer);
const scrolledToBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 800;
if (scrolledToBottom) {
const loadingSkeletons = document.querySelectorAll(
'ytd-rich-grid-renderer #continuation-skeleton, ' +
'ytd-rich-grid-renderer .rich-grid-skeleton-content, ' +
'#contents ytd-continuation-item-renderer, ' +
'ytd-rich-grid-renderer [role="progressbar"], ' +
'ytd-browse[role="main"] #continuations, ' +
'ytd-browse .loading-skeleton'
);
if (loadingSkeletons.length > 0) {
const columns = calculateOptimalColumns();
adjustLoadingSkeletons(loadingSkeletons, columns);
styleLoadingAreas(columns);
}
}
scrollTimer = setTimeout(() => {
if (window.scrollY !== lastScrollY) {
lastScrollY = window.scrollY;
setTimeout(() => {
adjustLayout();
}, 300);
}
}, 200);
});
}
function styleLoadingAreas(columns) {
const loadingAreas = [
...document.querySelectorAll('#contents ytd-continuation-item-renderer'),
...document.querySelectorAll('ytd-rich-grid-renderer #continuation-skeleton'),
...document.querySelectorAll('ytd-rich-grid-renderer .rich-grid-skeleton-content')
];
if (loadingAreas.length === 0) return;
loadingAreas.forEach(area => {
area.style.width = '100%';
area.style.margin = '0';
area.style.padding = '0';
area.style.boxSizing = 'border-box';
area.style.setProperty('--ytd-rich-grid-items-per-row', columns, 'important');
area.style.setProperty('--ytd-rich-grid-posts-per-row', columns, 'important');
const lastRow = document.querySelector('ytd-rich-grid-row:last-child');
if (lastRow) {
lastRow.style.marginBottom = '0';
area.style.marginTop = '0';
}
const spinner = area.querySelector('tp-yt-paper-spinner, yt-loading-icon');
if (spinner) {
spinner.style.margin = '16px auto';
spinner.style.display = 'block';
}
});
const contentsContainer = document.querySelector('ytd-rich-grid-renderer #contents');
if (contentsContainer) {
contentsContainer.style.padding = `0 ${CONFIG.GUTTER_SIZE/2}px`;
}
}
function handleSkeletonPreload() {
const skeletonObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList' && mutation.addedNodes.length) {
const addedNodes = Array.from(mutation.addedNodes);
for (const node of addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (
node.id === 'skeleton' ||
node.querySelector?.('#skeleton') ||
node.classList?.contains('rich-grid-skeleton-content') ||
node.id === 'home-page-skeleton' ||
node.id === 'continuation-skeleton'
) {
const columns = calculateOptimalColumns();
createSkeletonGrid(node, columns, 3);
}
}
}
}
});
skeletonObserver.observe(document.body, {
childList: true,
subtree: true,
});
}
function earlyInterceptSkeleton() {
const originalCreateElement = document.createElement;
document.createElement = function(...args) {
const element = originalCreateElement.apply(document, args);
if (args[0].toLowerCase() === 'div') {
setTimeout(() => {
if (
element.id === 'skeleton' ||
element.id === 'home-page-skeleton' ||
element.id === 'continuation-skeleton' ||
element.classList?.contains('rich-grid-skeleton-content')
) {
const columns = calculateOptimalColumns();
createSkeletonGrid(element, columns, 3);
}
}, 0);
}
return element;
};
}
function injectInitialStyles() {
if (initialStylesApplied) return;
const columns = calculateOptimalColumns();
const initialStyle = document.createElement('style');
initialStyle.id = 'yt-grid-initial-styles';
initialStyle.textContent = `
ytd-rich-grid-renderer {
elements-per-row: ${columns} !important;
--ytd-rich-grid-items-per-row: ${columns} !important;
--ytd-rich-grid-posts-per-row: ${columns} !important;
--ytd-rich-grid-shorts-per-row: ${columns} !important;
--ytd-rich-grid-slim-items-per-row: ${columns} !important;
--ytd-rich-grid-game-cards-per-row: ${columns} !important;
--ytd-rich-grid-mini-game-cards-per-row: ${columns} !important;
--ytd-rich-grid-item-max-width: none !important;
--ytd-rich-grid-item-min-width: ${CONFIG.ITEM_MIN_WIDTH}px !important;
}
#home-page-skeleton .rich-shelf-videos,
#home-page-skeleton .rich-grid-skeleton-content,
#search-page-skeleton .rich-shelf-videos,
ytd-browse[page-subtype="home"] #skeleton,
ytd-browse[page-subtype="subscriptions"] #skeleton,
ytd-browse[role="main"] #skeleton,
ytd-search #skeleton,
ytd-rich-grid-renderer #continuation-skeleton,
ytd-rich-grid-renderer .rich-grid-skeleton-content {
display: grid !important;
grid-template-columns: repeat(${columns}, 1fr) !important;
grid-template-rows: repeat(3, auto) !important;
gap: ${CONFIG.GUTTER_SIZE}px !important;
width: 100% !important;
padding: 0 ${CONFIG.GUTTER_SIZE/2}px !important;
box-sizing: border-box !important;
margin-bottom: 16px !important;
--ytd-rich-grid-items-per-row: ${columns} !important;
--ytd-rich-grid-posts-per-row: ${columns} !important;
--ytd-rich-grid-shorts-per-row: ${columns} !important;
--ytd-rich-grid-slim-items-per-row: ${columns} !important;
}
ytd-rich-grid-renderer #continuation-skeleton,
ytd-rich-grid-renderer .rich-grid-skeleton-content {
margin-top: 0 !important;
padding-top: 0 !important;
border-top: none !important;
}
#home-page-skeleton .rich-shelf-video,
#search-page-skeleton .video-card,
ytd-browse[page-subtype="home"] #skeleton .rich-shelf-video,
ytd-browse[page-subtype="subscriptions"] #skeleton .rich-shelf-video,
ytd-browse[role="main"] #skeleton .rich-shelf-video,
ytd-search #skeleton .video-card,
ytd-rich-grid-renderer #continuation-skeleton .rich-shelf-video,
ytd-rich-grid-renderer .rich-grid-skeleton-content .rich-shelf-video {
width: 100% !important;
margin: 0 !important;
height: auto !important;
box-sizing: border-box !important;
border-radius: 12px !important;
overflow: hidden !important;
transition: opacity 0.3s ease !important;
}
.skeleton-line {
height: 12px !important;
background-color: #e0e0e0 !important;
border-radius: 6px !important;
margin-bottom: 8px !important;
}
#home-page-skeleton .thumbnail-container,
#home-page-skeleton .video-details-container,
#search-page-skeleton .thumbnail-container,
#search-page-skeleton .video-details-container,
ytd-browse #skeleton .thumbnail-container,
ytd-browse #skeleton .video-details-container,
ytd-search #skeleton .thumbnail-container,
ytd-search #skeleton .video-details-container,
ytd-rich-grid-renderer #continuation-skeleton .thumbnail-container,
ytd-rich-grid-renderer #continuation-skeleton .video-details-container,
ytd-rich-grid-renderer .rich-grid-skeleton-content .thumbnail-container,
ytd-rich-grid-renderer .rich-grid-skeleton-content .video-details-container {
width: 100% !important;
border-radius: 12px !important;
overflow: hidden !important;
}
ytd-rich-grid-row:last-of-type {
margin-bottom: 0 !important;
}
ytd-rich-grid-row {
--ytd-rich-grid-items-per-row: ${columns} !important;
--ytd-rich-grid-posts-per-row: ${columns} !important;
--ytd-rich-grid-shorts-per-row: ${columns} !important;
--ytd-rich-grid-slim-items-per-row: ${columns} !important;
}
`;
document.head.appendChild(initialStyle);
initialStylesApplied = true;
lastAppliedColumns = columns;
window.addEventListener('DOMContentLoaded', () => {
setTimeout(() => {
updateDOMAttributes(columns);
}, 0);
});
}
function calculateOptimalColumns() {
const windowWidth = window.innerWidth;
const contentWidth = getActualContentWidth();
const maxPossibleColumns = Math.floor(contentWidth / CONFIG.ITEM_MIN_WIDTH);
const preferredColumns = Math.floor(contentWidth / CONFIG.ITEM_PREFERRED_WIDTH);
let finalColumns;
if (contentWidth >= 1400) {
finalColumns = 5;
} else if (contentWidth >= 1100) {
finalColumns = 4;
} else if (contentWidth >= 800) {
finalColumns = 3;
} else if (contentWidth >= 500) {
finalColumns = 2;
} else {
finalColumns = 1;
}
finalColumns = Math.max(
CONFIG.MIN_ITEMS_PER_ROW,
Math.min(finalColumns, CONFIG.MAX_ITEMS_PER_ROW, maxPossibleColumns)
);
return finalColumns;
}
function getActualContentWidth() {
const contentContainer = document.querySelector(
'ytd-rich-grid-renderer #contents, ' +
'ytd-two-column-browse-results-renderer #primary, ' +
'.ytd-rich-grid-renderer'
);
if (contentContainer && contentContainer.clientWidth > 50) {
return contentContainer.clientWidth - (CONFIG.GUTTER_SIZE * 2);
}
const windowWidth = window.innerWidth;
let contentWidth = windowWidth;
const isMiniguideMode = document.documentElement.hasAttribute('miniguide');
const isSidebarCollapsed = document.documentElement.getAttribute('menu-expanded') === 'false';
if (windowWidth > 1000) {
if (isMiniguideMode || isSidebarCollapsed) {
contentWidth -= (CONFIG.SIDEBAR_WIDTH_COLLAPSED + CONFIG.SIDE_PADDING);
} else {
contentWidth -= (CONFIG.SIDEBAR_WIDTH_EXPANDED + CONFIG.SIDE_PADDING);
}
} else {
contentWidth -= (CONFIG.SIDEBAR_WIDTH_COLLAPSED + CONFIG.SIDE_PADDING/2);
}
contentWidth -= CONFIG.SIDE_PADDING;
return contentWidth;
}
function initializeStyles() {
if (stylesInitialized) return;
const baseStyle = document.createElement('style');
baseStyle.id = 'yt-grid-base-styles';
document.head.appendChild(baseStyle);
const dynamicStyle = document.createElement('style');
dynamicStyle.id = 'yt-grid-dynamic-styles';
document.head.appendChild(dynamicStyle);
stylesInitialized = true;
}
function applyGridLayout(columns) {
if (columns === lastAppliedColumns && lastAppliedColumns !== 0 && stylesInitialized) {
return;
}
if (!stylesInitialized) {
initializeStyles();
}
lastAppliedColumns = columns;
const baseStyle = document.getElementById('yt-grid-base-styles');
const dynamicStyle = document.getElementById('yt-grid-dynamic-styles');
if (baseStyle && !baseStyle.textContent) {
baseStyle.textContent = `
ytd-rich-item-renderer,
ytd-grid-renderer ytd-grid-video-renderer,
ytd-shelf-renderer,
ytd-expanded-shelf-contents-renderer {
transition: width 0.2s ease, padding 0.2s ease, opacity 0.3s ease !important;
}
ytd-thumbnail {
width: 100% !important;
margin: 0 !important;
}
ytd-rich-item-renderer #content,
ytd-rich-item-renderer #details,
ytd-rich-item-renderer #meta,
ytd-grid-video-renderer #content,
ytd-grid-video-renderer #details,
ytd-grid-video-renderer #meta {
width: 100% !important;
}
ytd-rich-grid-renderer[use-legacy-style-for-rich-grid],
ytd-rich-grid-row {
--ytd-rich-grid-items-per-row: ${columns} !important;
--ytd-rich-grid-posts-per-row: ${columns} !important;
--ytd-rich-grid-shorts-per-row: ${columns} !important;
--ytd-rich-grid-slim-items-per-row: ${columns} !important;
--ytd-rich-grid-game-cards-per-row: ${columns} !important;
--ytd-rich-grid-mini-game-cards-per-row: ${columns} !important;
--ytd-rich-grid-item-max-width: none !important;
--ytd-rich-grid-item-min-width: ${CONFIG.ITEM_MIN_WIDTH}px !important;
}
#home-page-skeleton .rich-shelf-videos,
#home-page-skeleton .rich-grid-skeleton-content,
#search-page-skeleton .rich-shelf-videos,
ytd-browse[page-subtype="home"] #skeleton .rich-shelf-videos,
ytd-browse[page-subtype="home"] #skeleton .rich-grid-skeleton-content,
ytd-browse[page-subtype="subscriptions"] #skeleton .rich-shelf-videos,
ytd-browse[role="main"] #skeleton .rich-shelf-videos,
ytd-search #skeleton .rich-shelf-videos,
ytd-rich-grid-renderer #continuation-skeleton,
ytd-rich-grid-renderer .rich-grid-skeleton-content {
display: grid !important;
gap: ${CONFIG.GUTTER_SIZE}px !important;
width: 100% !important;
padding: 0 ${CONFIG.GUTTER_SIZE/2}px !important;
box-sizing: border-box !important;
grid-template-columns: repeat(${columns}, 1fr) !important;
grid-template-rows: repeat(3, auto) !important;
}
ytd-continuation-item-renderer {
width: 100% !important;
padding: 0 !important;
margin: 0 !important;
display: block !important;
}
ytd-continuation-item-renderer yt-loading-icon,
ytd-continuation-item-renderer tp-yt-paper-spinner {
margin: 16px auto !important;
display: block !important;
}
ytd-rich-grid-renderer #contents {
padding: 0 ${CONFIG.GUTTER_SIZE/2}px !important;
}
`;
}
if (dynamicStyle) {
dynamicStyle.textContent = `
ytd-rich-grid-renderer,
ytd-rich-grid-row,
ytd-rich-section-renderer,
ytd-quad-section-renderer,
ytd-expanded-shelf-contents-renderer {
--ytd-rich-grid-items-per-row: ${columns} !important;
--ytd-rich-grid-posts-per-row: ${columns} !important;
--ytd-rich-grid-shorts-per-row: ${columns} !important;
--ytd-rich-grid-slim-items-per-row: ${columns} !important;
--ytd-rich-grid-game-cards-per-row: ${columns} !important;
--ytd-rich-grid-mini-game-cards-per-row: ${columns} !important;
}
ytd-rich-item-renderer,
ytd-grid-video-renderer,
ytd-compact-video-renderer,
ytd-grid-movie-renderer,
ytd-grid-playlist-renderer,
ytd-grid-channel-renderer {
width: calc(100% / ${columns}) !important;
max-width: none !important;
min-width: ${CONFIG.ITEM_MIN_WIDTH}px !important;
margin: 0 !important;
padding: 0 ${CONFIG.GUTTER_SIZE/2}px ${CONFIG.GUTTER_SIZE}px !important;
box-sizing: border-box !important;
}
ytd-rich-grid-row {
margin-bottom: ${CONFIG.GUTTER_SIZE}px !important;
}
ytd-rich-grid-renderer #continuation-skeleton,
ytd-rich-grid-renderer .rich-grid-skeleton-content {
grid-template-columns: repeat(${columns}, 1fr) !important;
grid-template-rows: repeat(3, auto) !important;
}
ytd-continuation-item-renderer {
margin-top: 0 !important;
padding-top: 0 !important;
border-top: none !important;
}
ytd-rich-grid-row:last-child {
margin-bottom: 0 !important;
}
`;
adjustSkeletonItems(columns);
}
updateDOMAttributes(columns);
}
function updateDOMAttributes(columns) {
const renderers = document.querySelectorAll('ytd-rich-grid-renderer');
renderers.forEach(renderer => {
renderer.setAttribute('elements-per-row', columns);
renderer.style.setProperty('--ytd-rich-grid-items-per-row', columns, 'important');
renderer.style.setProperty('--ytd-rich-grid-posts-per-row', columns, 'important');
renderer.style.setProperty('--ytd-rich-grid-shorts-per-row', columns, 'important');
renderer.style.setProperty('--ytd-rich-grid-slim-items-per-row', columns, 'important');
renderer.style.setProperty('--ytd-rich-grid-game-cards-per-row', columns, 'important');
renderer.style.setProperty('--ytd-rich-grid-mini-game-cards-per-row', columns, 'important');
renderer.style.setProperty('--ytd-rich-grid-item-max-width', 'none', 'important');
renderer.style.setProperty('--ytd-rich-grid-item-min-width', `${CONFIG.ITEM_MIN_WIDTH}px`, 'important');
});
const rows = document.querySelectorAll('ytd-rich-grid-row');
rows.forEach(row => {
row.style.setProperty('--ytd-rich-grid-items-per-row', columns, 'important');
row.style.setProperty('--ytd-rich-grid-posts-per-row', columns, 'important');
row.style.setProperty('--ytd-rich-grid-shorts-per-row', columns, 'important');
row.style.setProperty('--ytd-rich-grid-slim-items-per-row', columns, 'important');
});
const skeletons = document.querySelectorAll('#continuation-skeleton, .rich-grid-skeleton-content');
skeletons.forEach(skeleton => {
skeleton.style.setProperty('--ytd-rich-grid-items-per-row', columns, 'important');
skeleton.style.setProperty('--ytd-rich-grid-posts-per-row', columns, 'important');
});
}
function detectViewChanges() {
const targetNode = document.body;
const config = {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ['elements-per-row', 'style']
};
const observer = new MutationObserver((mutationsList) => {
for (const mutation of mutationsList) {
if (mutation.type === 'childList') {
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (node.tagName === 'YTD-RICH-GRID-RENDERER' ||
node.querySelector?.('ytd-rich-grid-renderer')) {
const columns = lastAppliedColumns || calculateOptimalColumns();
updateDOMAttributes(columns);
}
}
} else if (mutation.type === 'attributes') {
if (mutation.attributeName === 'elements-per-row' ||
mutation.attributeName === 'style') {
const target = mutation.target;
if (target.tagName === 'YTD-RICH-GRID-RENDERER') {
const columns = lastAppliedColumns || calculateOptimalColumns();
if (target.getAttribute('elements-per-row') != columns) {
setTimeout(() => {
updateDOMAttributes(columns);
adjustLayout();
}, 10);
}
}
}
}
}
});
observer.observe(targetNode, config);
}
function handleVideoLoading() {
const skeletonObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (
node.id === 'continuation-skeleton' ||
node.classList?.contains('rich-grid-skeleton-content')
) {
setTimeout(() => {
const columns = calculateOptimalColumns();
createSkeletonGrid(node, columns, 3);
updateDOMAttributes(columns);
const lastRow = document.querySelector('ytd-rich-grid-row:last-child');
if (lastRow) {
lastRow.style.marginBottom = '0';
node.style.marginTop = '0';
node.style.paddingTop = '0';
}
}, 0);
}
}
for (const node of mutation.removedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (
node.id === 'continuation-skeleton' ||
node.classList?.contains('rich-grid-skeleton-content')
) {
setTimeout(() => {
adjustLayout();
}, 50);
}
}
}
}
});
skeletonObserver.observe(document.documentElement, {
childList: true,
subtree: true
});
const contentObserver = new MutationObserver((mutations) => {
let newContentAdded = false;
for (const mutation of mutations) {
if (mutation.type === 'childList') {
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (node.tagName === 'YTD-RICH-ITEM-RENDERER' ||
node.tagName === 'YTD-RICH-GRID-ROW' ||
node.querySelector?.('ytd-rich-item-renderer')) {
newContentAdded = true;
break;
}
}
for (const node of mutation.removedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) continue;
if (node.id === 'continuation-skeleton' ||
node.classList?.contains('rich-grid-skeleton-content')) {
newContentAdded = true;
break;
}
}
}
if (newContentAdded) break;
}
if (newContentAdded) {
setTimeout(() => {
adjustLayout();
}, 100);
}
});
const contentContainer = document.querySelector('ytd-app');
if (contentContainer) {
contentObserver.observe(contentContainer, {
childList: true,
subtree: true
});
}
let scrollTimeout;
window.addEventListener('scroll', () => {
clearTimeout(scrollTimeout);
scrollTimeout = setTimeout(() => {
updateDOMAttributes(lastAppliedColumns || calculateOptimalColumns());
}, 150);
});
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
setTimeout(() => {
adjustLayout();
updateDOMAttributes(lastAppliedColumns || calculateOptimalColumns());
}, 300);
}
});
}
function adjustLayout() {
const columns = calculateOptimalColumns();
applyGridLayout(columns);
}
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(context, args), wait);
};
}
function initialize() {
injectInitialStyles();
handleSkeletonPreload();
handleVideoLoading();
applyShortsVisibility();
adjustLayout();
window.addEventListener('resize', debounce(() => {
if (window.innerWidth !== lastWindowWidth) {
lastWindowWidth = window.innerWidth;
adjustLayout();
}
}, 150));
detectViewChanges();
detectScrollLoading();
document.addEventListener('yt-navigate-finish', () => {
setTimeout(() => {
applyShortsVisibility();
adjustLayout();
}, 300);
});
const originalPushState = history.pushState;
history.pushState = function() {
originalPushState.apply(this, arguments);
setTimeout(() => {
applyShortsVisibility();
adjustLayout();
}, 300);
};
window.addEventListener('popstate', () => {
setTimeout(() => {
applyShortsVisibility();
adjustLayout();
}, 300);
});
setInterval(() => {
adjustLayout();
}, 2000);
}
earlyInterceptSkeleton();
injectInitialStyles();
applyShortsVisibility();
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initialize);
} else {
initialize();
}
})();