Youtube - More elements per row (Videos, Shorts & Posts)

4/26/2025, 12:18:33 PM

질문, 리뷰하거나, 이 스크립트를 신고하세요.
// ==UserScript==
// @name        Youtube - More elements per row (Videos, Shorts & Posts)
// @namespace   Violentmonkey Scripts
// @match       https://www.youtube.com/*
// @grant       none
// @license     MIT
// @run-at      document-start
// @version     1.0
// @author      -
// @description 4/26/2025, 12:18:33 PM
// ==/UserScript==

// Videos
let maxNumOfColumns = 15;
let minColumnWidth = 200;

// Shorts
let maxNumOfColumns2 = 12;
let minColumnWidth2 = 150;

// Posts
let maxNumOfColumns3 = 6;
let minColumnWidth3 = 326;


function calcNumOfElements(type) {
    if (!pm) pm = document.getElementById('page-manager');

    if (type == 'video') {
        for (let i = maxNumOfColumns; i > 0; i--) {
            if ((pm?.clientWidth - 32) / i >= minColumnWidth) {
                document.documentElement.style.setProperty('--videosPerRow', i);
                return i;
            }
        }
    } else if (type == 'short') {
        for (let i = maxNumOfColumns2; i > 0; i--) {
            if ((pm?.clientWidth - 32) / i >= minColumnWidth2) return i;
        }
    } else {
        for (let i = maxNumOfColumns3; i > 0; i--) {
            if ((pm?.clientWidth - 32) / i >= minColumnWidth3) return i;
        }
    }
}

let pm, hasRun, hasRun2;
const origObjDefineProp = Object.defineProperty;
Object.defineProperty = function() {
    if (!hasRun && arguments[0]?.refreshGridLayout) {
        hasRun = 1;
        let rgl = arguments[0].refreshGridLayout;

        arguments[0].refreshGridLayout = function() {
            origObjDefineProp(this, 'elementsPerRow', {
                get: function() {
                    return calcNumOfElements('video') || 1;
                },
                set: function(x) {
                    elementsPerRow = x;
                },
                configurable: true
            });

            origObjDefineProp(this, 'slimItemsPerRow', {
                get: function() {
                    return calcNumOfElements('short') || 1;
                },
                set: function(x) {
                    slimItemsPerRow = x;
                },
                configurable: true
            });

            return rgl.apply(this, arguments);
        }
    }

    if (!hasRun2 && arguments[0]?.refreshGridLayoutNew) {
        hasRun2 = 1;
        let rglNew = arguments[0].refreshGridLayoutNew;

        arguments[0].refreshGridLayoutNew = function() {
            origObjDefineProp(this, 'elementsPerRow', {
                get: function() {
                    let type;
                    if (this.isShortsShelf?.() || this.isGameCardShelf?.() || this.isMiniGameCardShelf?.()) type = 'short';
                    else if (this.isPostShelfRenderer?.()) type = 'post';
                    else type = 'video';

                    return calcNumOfElements(type) || 1;
                },
                set: function(x) {
                    elementsPerRow = x;
                },
                configurable: true
            });

            return rglNew.apply(this, arguments);
        }
    }

    return origObjDefineProp.apply(this, arguments);
}

const sheet = new CSSStyleSheet();
document.adoptedStyleSheets = [sheet];
sheet.replaceSync(`
ytd-rich-grid-media[mini-mode] {
  max-width: initial;
}

ytd-two-column-browse-results-renderer[page-subtype=channels]:has(ytd-rich-grid-renderer:not([is-shorts-grid])) {
  width: calc(100% - 32px) !important;
  max-width: calc(var(--videosPerRow) * (var(--ytd-rich-grid-item-max-width) + var(--ytd-rich-grid-item-margin))) !important;
}

#home-page-skeleton .rich-grid-media-skeleton {
  min-width: ${minColumnWidth - 16}px !important;
  flex-basis: ${minColumnWidth - 16}px !important;
}
`);