讓 YouTube 的推薦影片變回4個一行

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

目前为 2025-05-11 提交的版本。查看 最新版本

// ==UserScript==
// @name         讓 YouTube 的推薦影片變回4個一行
// @name:en      Change YouTube's recommended videos back to 4 rows
// @namespace    http://tampermonkey.net/
// @version      2025-05-11 1.5
// @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 IronIndex = 0
    let VideoCount = 0
    const rowBtnCount = 4
    let lastPath = ""
    // let settime
    new MutationObserver(() => {

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


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


        // checkStructure(cnt)

        //確保頁面渲染完成
        document.settime = setInterval(() => {
            checkStructure(cnt)
        }, 500);

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




})();


function checkStructure(cnt) {
    let cntBtns = cnt.children

    //第8位沒有 isSet 判斷結構改變
    if (cnt.children[8].dataset.isSet !== "true") {
        document.VideoCount = 0
    }

    if (cnt.children.length === document.VideoCount) {
        console.log(`${cnt.children.length} : ${document.VideoCount}`)
        return;
    }

    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
        }


        console.log("觸發")
        //移動節點
        moveElement()
        // clearInterval(document.settime)
    }
}



//取得目前推薦類別序號
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() {
    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"
    }
}