Youtube Scrollable Right Side Description

Moves and expands YouTube description on the right, making it scrollable and dynamically adjusting height to video.

当前为 2025-04-14 提交的版本,查看 最新版本

// ==UserScript==
// @name         Youtube Scrollable Right Side Description
// @description  Moves and expands YouTube description on the right, making it scrollable and dynamically adjusting height to video.
// @version      3.0
// @author       SH3LL
// @license      MIT
// @match        *://*.youtube.com/*
// @grant        none
// @run-at       document-end
// @namespace https://gf.qytechs.cn/users/762057
// ==/UserScript==

(function() {
    'use strict';

    let descriptionExpander;
    const moveEl = (parent, child) => parent?.prepend(child);
    const setElStyle = (el, styles) => el?.setAttribute('style', styles);
    const qSel = sel => document.querySelector(sel);
    const getElById = id => document.getElementById(id);

    const ownerObserver = new MutationObserver((mutationsList, observer) => {
        if (getElById('owner')) {
            observer.disconnect();
            console.log('"owner" found, executing.');
            executeScript();
        }
    });
    ownerObserver.observe(document.body, { childList: true, subtree: true });

    const updateDescHeight = height => {
        descriptionExpander && (descriptionExpander.style.maxHeight = `${height - 70}px`);
    };

    const videoHeightObserver = new MutationObserver(mutations => {
        for (const m of mutations) {
            if (m.type === 'attributes' && m.attributeName === 'style') {
                const heightMatch = m.target.style.height.match(/^(\d+)px$/);
                heightMatch && updateDescHeight(parseInt(heightMatch[1], 10));
            }
        }
    });

    const observeVideoHeight = () => {
        const videoContent = qSel('.ytp-iv-video-content');
        if (videoContent) {
            videoHeightObserver.observe(videoContent, { attributes: true, attributeFilter: ['style'] });
            const initialHeight = videoContent.style.height.match(/^(\d+)px$/);
            initialHeight && updateDescHeight(parseInt(initialHeight[1], 10));
        } else {
            console.warn('No .ytp-iv-video-content found.');
        }
    };

    function executeScript() {
        const related = qSel('#related');
        const bottomRow = getElById('bottom-row');
        const owner = getElById('owner');
        const below = qSel('#below');
        const infoContainer = getElById('info-container');
        descriptionExpander = getElById('description-inline-expander');
        const description = getElById('description');
        const descriptionInner = getElById('description-inner');
        const descStyle = `margin-left: 0; overflow: auto; max-width: 100%; font-size: 1.3rem; line-height: normal; width: auto; padding: 8px; border-bottom-width: 0; --yt-endpoint-text-decoration: underline; background-color: var(--yt-playlist-background-item)`;

        moveEl(related, bottomRow);
        owner && (moveEl(related, owner), setElStyle(owner, 'margin:0'));
        moveEl(below, infoContainer);
        setElStyle(infoContainer, 'color:white; font-size: 12px');

        if (descriptionExpander && description && descriptionInner) {
            setElStyle(descriptionExpander, descStyle);
            setElStyle(description, 'margin: 0');
            setElStyle(descriptionInner, 'margin: 0');
            descriptionExpander.setAttribute('is-expanded', '');
            observeVideoHeight();
        }

        const removalObserver = new MutationObserver(mutations => {
            const targets = ['expand', 'collapse', 'ytd-watch-info-text', 'snippet'];
            for (const m of mutations) {
                if (m.type === 'childList') {
                    targets.forEach(id => getElById(id)?.remove());
                    !targets.some(getElById) && (observer.disconnect(), console.log('Removal observer done.'));
                }
            }
        });

        const watchInfoFlex = qSel('ytd-watch-metadata > div');
        watchInfoFlex && removalObserver.observe(watchInfoFlex, { childList: true, subtree: true });
    }
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址