Change YouTube's recommended videos back to 4 rows

這個腳本會將YouTube的推薦影片從三個一排,變回四個一排

目前為 2025-05-11 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Change YouTube's recommended videos back to 4 rows
// @name:en      ra45388791
// @namespace    http://tampermonkey.net/
// @version      2025-05-11 1.2
// @description  這個腳本會將YouTube的推薦影片從三個一排,變回四個一排
// @description:en This script will change YouTube's recommended videos from three in a row to four in a row
// @author       bahamutID:ra45388791
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=wayne-blog.com
// @grant        none
// ==/UserScript==

(function () {
    'use strict';
    // let lastUrl = location.href;
    let IronIndex = 0
    let VideoCount = 0
    const rowBtnCount = 4

    new MutationObserver(() => {

        if (location.pathname !== "/") { return; }
        let cnt = document.querySelector("#contents");
        const activeIronIndex = getIronIndex()
        //狀態檢查
        //是否渲染過
        if (cnt.dataset.isActiveScript === "true") {
            //是否變更過推薦類別
            if (IronIndex === activeIronIndex) {
                //影片數量是否不同
                if (cnt.children.length === VideoCount) {
                    return;
                }
            }
        }


        //設定狀態
        cnt.dataset.isActiveScript = "true"
        IronIndex = activeIronIndex
        cnt.style = `--ytd-rich-grid-items-per-row: ${rowBtnCount};`
        let cntBtns = cnt.children

        //確保頁面渲染完成
        const settime = setInterval(() => {
            if (cntBtns.length > 4) {
                let count = cnt.children.length
                //影片數量變更時重新定位
                if (document.VideoCount !== count) {
                    for (let btn of cntBtns) {
                        if (btn.dataset.isSet === "true") {
                            btn.dataset.isSet = ""
                        }
                    }
                    document.VideoCount = count
                }

                //移動節點
                moveElement()
                clearInterval(settime)
                return;
            }
        }, 500);

    }).observe(document, {
        childList: true,
        subtree: true
    });




})();


//取得目前推薦類別序號
function getIronIndex() {
    const irons = document.querySelectorAll("#chips > yt-chip-cloud-chip-renderer")

    for (let i = 0; i < irons.length; i++) {
        const haveClass = irons[i].classList.contains("iron-selected")
        if (haveClass) {
            return i + 1
        }
    }
    return 0
}

function moveElement(elementName, interval) {
    let cnt = document.querySelector("#contents").children;
    let count = 0   //待移動節點數量
    if (cnt.length < 9) { return }

    //把節點移到最後
    for (let i = 0; i < cnt.length; i++) {
        const e = cnt[i];
        if (e.tagName === "YTD-RICH-SECTION-RENDERER") {
            if (e.dataset.isSet !== "true") {       //已定位不允許再移動
                e.parentNode.insertBefore(e, cnt[cnt.length - 1])
                count++
            }
        }
    }

    //移動節點
    let setIndex = 0
    for (let i = 0; i < count; i++) {
        let index
        //紀錄需要移動的節點
        for (let j = setIndex; j < cnt.length; j++) {
            const e = cnt[j];
            if (e.tagName === "YTD-RICH-SECTION-RENDERER") {
                if (e.dataset.isSet !== "true") {   //已定位不允許再移動
                    index = j
                    break;
                }
            }
        }

        //以8個為一組
        setIndex += 8 + i

        const targetIndex = cnt[index]
        //將 targetIndex 移動到 setIndex 之前
        cnt[0].parentNode.insertBefore(targetIndex, cnt[setIndex])
        //該節點狀態設為已定位
        targetIndex.dataset.isSet = "true"
    }
}