Changes the YouTube homepage to show you 5 videos per row and removing the weird left padding.
// ==UserScript==
// @name YouTube: 5 Videos Per Row
// @namespace http://tampermonkey.net/
// @version 1.0.1
// @license MIT
// @description Changes the YouTube homepage to show you 5 videos per row and removing the weird left padding.
// @author Lemustache
// @match https://www.youtube.com/*
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Desired number of videos per row
const videosPerRow = 5;
// Style ID
const styleId = `youtube-${videosPerRow}-videos-per-row-updated`;
// Debugging function
function debugLog(message) {
console.log(`[YouTube Layout Fix]: ${message}`);
}
// Error reporting
function reportError(message, error) {
console.error(`[YouTube Layout Fix - ERROR]: ${message}`);
if (error) {
console.error(error);
}
}
// Apply the layout fix
function applyLayoutFix(videosPerRow) {
try {
debugLog(`Applying layout fix for ${videosPerRow} videos per row...`);
// Remove existing style
const existingStyle = document.getElementById(styleId);
if (existingStyle) {
existingStyle.remove();
debugLog('Removed existing style.');
}
const videoWidthPercentage = (100 / videosPerRow);
const gap = 12;
const adjustedWidth = `calc(${videoWidthPercentage}% - ${gap}px)`;
const style = document.createElement('style');
style.id = styleId;
// More Specific and Robust CSS - Focus on Core Layout First
style.textContent = `
/* 1. Target the Rich Grid Renderer Directly */
#contents.ytd-rich-grid-renderer {
display: flex !important; /* Essential for flexbox layout */
flex-wrap: wrap !important; /* Allow items to wrap to the next line */
gap: ${gap}px !important; /* Space between videos */
width: 100% !important; /* Ensure it takes full width */
margin: 0 !important; /* Reset any default margins */
padding: 0 !important; /* Reset any default padding */
}
/* 2. Target the Individual Video Items */
ytd-rich-item-renderer {
flex: 0 0 ${adjustedWidth} !important; /* Flex basis: important for width */
max-width: ${adjustedWidth} !important; /* Maximum width */
margin-bottom: ${gap}px !important; /* Consistent bottom margin */
padding: 0 !important; /* Reset padding */
box-sizing: border-box !important; /* Include padding/border in width */
}
/*3. Address the is-in-first-column issue*/
ytd-rich-item-renderer[is-in-first-column] {
margin-left: 0 !important; /* Reset margin for first column items */
}
/*4. Thumbnail Styling: Ensure the thumbnail fills its container*/
ytd-rich-item-renderer #thumbnail {
width: 100% !important;
height: auto !important; /* Maintain aspect ratio */
display: block !important; /* Remove any inline spacing */
}
ytd-rich-item-renderer #thumbnail img {
width: 100% !important;
height: auto !important;
object-fit: cover !important; /* Prevent distortion */
}
/* 5. Important! Reset default styles that YouTube might be applying */
ytd-rich-item-renderer {
margin: 0 !important;
padding: 0 !important;
border: 0 !important;
outline: 0 !important;
}
/* 6. VERY SPECIFIC OVERRIDE */
#contents.ytd-rich-grid-renderer > ytd-rich-item-renderer[is-in-first-column] {
margin-left: 0 !important;
}
`;
document.head.appendChild(style);
debugLog(`Applied style for ${videosPerRow} videos per row.`);
} catch (error) {
reportError("Error applying layout fix:", error);
}
}
// Initialize the script
function initialize() {
try {
applyLayoutFix(videosPerRow);
debugLog('Initial layout fix applied.');
// Apply layout fix on navigation
window.addEventListener('yt-navigate-finish', () => {
try {
applyLayoutFix(videosPerRow);
debugLog('Layout fix applied on navigation.');
} catch (error) {
reportError("Error applying layout fix on navigation:", error);
}
});
// Apply layout fix on window resize (handle responsive changes)
window.addEventListener('resize', () => {
try {
applyLayoutFix(videosPerRow);
debugLog('Layout fix applied on window resize.');
} catch (error) {
reportError("Error applying layout fix on window resize:", error);
}
});
} catch (error) {
reportError("Error during initialization:", error);
}
}
// Set up MutationObserver
const observer = new MutationObserver(() => {
try {
applyLayoutFix(videosPerRow);
debugLog('Layout fix applied due to mutation.');
} catch (error) {
reportError("Error applying layout fix during mutation:", error);
}
});
// Start observing
try {
observer.observe(document.body, {
childList: true,
subtree: true
});
debugLog('MutationObserver started.');
} catch (error) {
reportError("Error setting up MutationObserver:", error);
}
// Initialize on load
window.addEventListener('load', () => {
try {
initialize();
debugLog('Page loaded, initialization complete.');
} catch (error) {
reportError("Error during window load:", error);
}
});
// Attempt immediate initialization
if (document.readyState === "complete" || document.readyState === "interactive") {
try {
initialize();
debugLog('Page already loaded, immediate initialization.');
} catch (error) {
reportError("Error during immediate initialization:", error);
}
}
})();