Return YouTube Grid Layout

유튜브 홈/구독에서 보여지는 영상 갯수 제한을 원래대로 돌립니다 Force YouTube grid layout to show 1~6 videos per row responsively, and scale up thumbnails on wide screens

// ==UserScript==
// @name         Return YouTube Grid Layout
// @namespace    Return YouTube Grid Layout
// @version      1.2
// @description  유튜브 홈/구독에서 보여지는 영상 갯수 제한을 원래대로 돌립니다 Force YouTube grid layout to show 1~6 videos per row responsively, and scale up thumbnails on wide screens 
// @author       DOGJIP
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const STYLE_ID = 'custom-grid-style';

    function getItemsPerRow(width) {
        if (width >= 2000) return 6;
        if (width >= 1800) return 5;
        if (width >= 1500) return 4;
        if (width >= 1200) return 3;
        if (width >= 800) return 2;
        return 1;
    }

    function getItemWidth(width, itemsPerRow) {
        const containerWidth = width - 96;
        const totalMargin = 16 * (itemsPerRow - 1);
        const itemWidth = Math.floor((containerWidth - totalMargin) / itemsPerRow);

        const maxDefault = 300;
        const minDefault = 220;

        const maxW = Math.min(Math.max(itemWidth, maxDefault), 400);
        const minW = Math.min(Math.max(itemWidth - 20, minDefault), maxW - 10);

        return { maxW, minW };
    }

    function generateStyle(width) {
        const n = getItemsPerRow(width);
        const { maxW, minW } = getItemWidth(width, n);

        return `
            ytd-rich-grid-renderer {
                --ytd-rich-grid-item-max-width: ${maxW}px !important;
                --ytd-rich-grid-item-min-width: ${minW}px !important;
                --ytd-rich-grid-row-margin: 32px !important;
                --ytd-rich-grid-items-per-row: ${n} !important;
                --ytd-rich-grid-item-margin: 16px !important;
                --ytd-rich-grid-posts-per-row: 3 !important;
                --ytd-rich-grid-slim-items-per-row: ${n} !important;
                --ytd-rich-grid-game-cards-per-row: ${n} !important;
                --ytd-rich-grid-mini-game-cards-per-row: ${n} !important;
                --ytd-rich-grid-content-offset-top: 56px !important;
            }
        `;
    }

    function isExcludedPage(path) {
        return /^\/@[^\/]+\/(?:videos|streams)\/?$/.test(path);
    }

    function applyStyle() {
        if (isExcludedPage(location.pathname)) {
            const old = document.getElementById(STYLE_ID);
            if (old) old.remove();
            return;
        }

        const old = document.getElementById(STYLE_ID);
        if (old) old.remove();

        const styleEl = document.createElement('style');
        styleEl.id = STYLE_ID;
        styleEl.textContent = generateStyle(window.innerWidth);
        document.head.appendChild(styleEl);
    }

    window.addEventListener('load', () => setTimeout(applyStyle, 500));
    window.addEventListener('resize', () => setTimeout(applyStyle, 200));

    const observer = new MutationObserver(() => {
        applyStyle();
    });
    observer.observe(document.body, { childList: true, subtree: true });
})();