YouTube - Proper Description

Forces the video description to live below the video with a reliable open/close toggle. Updated for modern YouTube DOM (no yt.msgs_ dependency).

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         YouTube - Proper Description
// @description  Forces the video description to live below the video with a reliable open/close toggle. Updated for modern YouTube DOM (no yt.msgs_ dependency).
// @namespace    http://tampermonkey.net/
// @icon         https://cdn-icons-png.flaticon.com/64/2504/2504965.png
// @supportURL   https://github.com/5tratz/Tampermonkey-Scripts/issues
// @version      0.0.6
// @author       5tratz
// @match        *://www.youtube.com/watch*
// @license      MIT
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function () {
  'use strict';

  function waitFor(selector) {
    return new Promise(resolve => {
      const el = document.querySelector(selector);
      if (el) return resolve(el);

      const mo = new MutationObserver(() => {
        const el = document.querySelector(selector);
        if (el) {
          mo.disconnect();
          resolve(el);
        }
      });
      mo.observe(document, { childList: true, subtree: true });
    });
  }

  function init() {
    waitFor('#meta ytd-video-secondary-info-renderer ytd-expander').then(expander => {
      if (expander.dataset.fixed) return;
      expander.dataset.fixed = '1';

      const more = expander.querySelector('tp-yt-paper-button#more');
      const less = expander.querySelector('tp-yt-paper-button#less');

      if (!more || !less) return;

      // Custom toggle
      const toggle = document.createElement('div');
      toggle.style.cursor = 'pointer';
      toggle.style.marginTop = '8px';
      toggle.style.fontWeight = '500';
      toggle.style.color = 'var(--yt-spec-text-primary)';
      toggle.textContent = expander.hasAttribute('collapsed')
        ? more.textContent.replace('...', '').trim() || 'Show more'
        : less.textContent.replace('...', '').trim() || 'Show less';

      expander.appendChild(toggle);

      function update() {
        toggle.textContent = expander.hasAttribute('collapsed')
          ? more.textContent.replace('...', '').trim() || 'Show more'
          : less.textContent.replace('...', '').trim() || 'Show less';
      }

      toggle.addEventListener('click', () => {
        if (expander.hasAttribute('collapsed')) {
          expander.removeAttribute('collapsed');
          more.setAttribute('hidden', '');
          less.removeAttribute('hidden');
        } else {
          expander.setAttribute('collapsed', '');
          less.setAttribute('hidden', '');
          more.removeAttribute('hidden');
        }
        update();
      });

      new MutationObserver(update).observe(expander, {
        attributes: true,
        attributeFilter: ['collapsed']
      });

      update();
    });
  }

  // Initial load
  init();

  // SPA navigation support
  let lastUrl = location.href;
  setInterval(() => {
    if (location.href !== lastUrl) {
      lastUrl = location.href;
      if (location.pathname === '/watch') {
        setTimeout(init, 500);
      }
    }
  }, 500);
})();