YouTube Smaller Thumbnails

Adds 3 additional thumbnails per row

Mint 2025.04.22.. Lásd a legutóbbi verzió

// ==UserScript==
// @name         YouTube Smaller Thumbnails
// @namespace    http://greasyfork.org
// @version      0.0.2
// @description  Adds 3 additional thumbnails per row
// @author       you
// @license      MIT
// @match        *://www.youtube.com/*
// @match        *://youtube.com/*
// @run-at       document-start
// @grant        none
// ==/UserScript==
(function() {
    'use strict';
    const DELTA = 3; // Amount of columns to add.
    const MAX_COLUMNS = 6; // Maximum amount of columns.

    function getTargetValue(currentValue) {
        let newValue = currentValue + DELTA;

        if (newValue > MAX_COLUMNS) {
            newValue = MAX_COLUMNS;
        }

        return newValue;
    }

    function modifyGridStyle(gridElement) {
        const currentStyle = gridElement.getAttribute('style');
        if (!currentStyle) return;

        const itemsPerRowMatch = currentStyle.match(/--ytd-rich-grid-items-per-row:\s*(\d+)/);
        if (!itemsPerRowMatch) return;

        const currentValue = parseInt(itemsPerRowMatch[1], 10);

        if (isNaN(currentValue)) {
            return;
        }

        const newValue = getTargetValue(currentValue);

        if (currentValue === newValue) {
            return;
        }

        const newStyle = currentStyle.replace(
            /--ytd-rich-grid-items-per-row:\s*\d+/,
            `--ytd-rich-grid-items-per-row: ${newValue}`
        );

        gridElement.setAttribute('style', newStyle);
        console.log(`[YouTube Smaller Thumbnails] Modified grid items per row: ${currentValue} -> ${newValue}`);
    }

    function modifyItemsPerRow(itemElement) {
        const currentValue = parseInt(itemElement.getAttribute('items-per-row'), 10);

        if (isNaN(currentValue)) {
            return;
        }

        const newValue = getTargetValue(currentValue)

        if (currentValue === newValue) {
            return;
        }

        itemElement.setAttribute('items-per-row', newValue);
        console.log(`[YouTube Smaller Thumbnails] Modified item renderer items per row: ${currentValue} -> ${newValue}`);
    }

    function processExistingElements() {
        document.querySelectorAll('ytd-rich-grid-renderer').forEach(gridElement => {
            modifyGridStyle(gridElement);
        });

        document.querySelectorAll('ytd-rich-item-renderer').forEach(itemElement => {
            modifyItemsPerRow(itemElement);
        });
    }

    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.addedNodes && mutation.addedNodes.length > 0) {
                mutation.addedNodes.forEach((node) => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.tagName === 'YTD-RICH-GRID-RENDERER') {
                            modifyGridStyle(node);
                        }
                        if (node.tagName === 'YTD-RICH-ITEM-RENDERER') {
                            modifyItemsPerRow(node);
                        }

                        node.querySelectorAll('ytd-rich-grid-renderer').forEach(gridElement => {
                            modifyGridStyle(gridElement);
                        });
                        node.querySelectorAll('ytd-rich-item-renderer').forEach(itemElement => {
                            modifyItemsPerRow(itemElement);
                        });
                    }
                });
            }

            if (mutation.type === 'attributes') {
                const target = mutation.target;

                if (target.tagName === 'YTD-RICH-GRID-RENDERER' && mutation.attributeName === 'style') {
                    modifyGridStyle(target);
                }
                if (target.tagName === 'YTD-RICH-ITEM-RENDERER' && mutation.attributeName === 'items-per-row') {
                    modifyItemsPerRow(target);
                }
            }
        });
    });

    function startObserver() {
        processExistingElements();
        observer.observe(document.documentElement, {
            childList: true,
            subtree: true,
            attributes: true,
            attributeFilter: ['style', 'items-per-row']
        });

        console.log('[YouTube Smaller Thumbnails] Observer started');
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', startObserver);
    } else {
        startObserver();
    }

    setInterval(processExistingElements, 3000);
})();