YouTube - Auto Expand Subscriptions

Automatically expands the "Show more" button in YouTube's subscription sidebar, keeping your subscriptions list fully expanded.

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         YouTube - Auto Expand Subscriptions
// @namespace    http://tampermonkey.net/
// @version      0.3
// @description  Automatically expands the "Show more" button in YouTube's subscription sidebar, keeping your subscriptions list fully expanded.
// @author       sharmanhall
// @match        https://www.youtube.com/*
// @grant        none
// @run-at       document-idle
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @license      MIT
// @copyright    2024, sharmanhall
// @supportURL   https://github.com/sharmanhall/youtube-auto-expand/issues
// @homepageURL  https://github.com/sharmanhall/youtube-auto-expand
// ==/UserScript==

(function() {
    'use strict';

    const DEBUG = true;
    function log(...args) {
        if (DEBUG) console.log('[YT-Auto-Expand]', ...args);
    }

    function findShowMoreButton() {
        log('Starting button search...');
        // Try various selectors
        const buttonSelectors = [
            'ytd-guide-collapsible-entry-renderer ytd-guide-entry-renderer#expander-item',
            '#items ytd-guide-collapsible-entry-renderer #expander-item',
            '#items ytd-guide-section-renderer ytd-guide-collapsible-entry-renderer'
        ];

        for (const selector of buttonSelectors) {
            const element = document.querySelector(selector);
            if (element) {
                const endpoint = element.querySelector('a#endpoint');
                if (endpoint) {
                    const paperItem = endpoint.querySelector('tp-yt-paper-item');
                    if (paperItem && element.textContent.trim().includes('Show more')) {
                        log('Found Show more button');
                        return endpoint;
                    }
                }
            }
        }
        return null;
    }

    function expandSubscriptions() {
        const button = findShowMoreButton();
        if (button) {
            log('Clicking button...');
            button.click();
            return true;
        }
        return false;
    }

    // Function to handle retries with delay
    function attemptExpansionWithRetry(retriesLeft = 10) {
        if (retriesLeft <= 0) {
            log('Max retries reached');
            return;
        }

        if (!expandSubscriptions()) {
            setTimeout(() => {
                attemptExpansionWithRetry(retriesLeft - 1);
            }, 1000);
        }
    }

    // Wait specifically for the guide section to be ready
    function waitForGuide() {
        log('Setting up guide observer');
        
        // First try to find the guide container
        const guideContainer = document.querySelector('tp-yt-app-drawer');
        if (!guideContainer) {
            // If no container yet, watch for it
            const bodyObserver = new MutationObserver((mutations, obs) => {
                const container = document.querySelector('tp-yt-app-drawer');
                if (container) {
                    obs.disconnect();
                    observeGuide(container);
                }
            });
            
            bodyObserver.observe(document.body, {
                childList: true,
                subtree: true
            });
        } else {
            observeGuide(guideContainer);
        }
    }

    function observeGuide(container) {
        log('Guide container found, watching for changes');
        
        // Only watch the guide container for changes
        const observer = new MutationObserver((mutations) => {
            // Only proceed if we see the section renderer
            if (document.querySelector('ytd-guide-section-renderer')) {
                // Check if button exists and isn't already clicked
                const button = findShowMoreButton();
                if (button && button.textContent.includes('Show more')) {
                    attemptExpansionWithRetry();
                }
            }
        });

        observer.observe(container, {
            childList: true,
            subtree: true,
            attributes: false, // Don't watch for attribute changes
            characterData: false // Don't watch for text changes
        });
        
        // Make initial attempt
        attemptExpansionWithRetry();
    }

    // Start observing as soon as possible
    waitForGuide();
    
    // Also try when the window loads
    window.addEventListener('load', () => {
        log('Window loaded, making attempt...');
        attemptExpansionWithRetry();
    });

})();