您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a button to the YouTube player to display the video description without conflicts, with a reliable download, Plain Text formatting, Close the button
// ==UserScript== // @name YouTube Embed Video Description // @namespace GPT // @version 1.0.8 // @description Adds a button to the YouTube player to display the video description without conflicts, with a reliable download, Plain Text formatting, Close the button // @description:ru Добавляет кнопку в плеер YouTube для отображения описания видео без конфликтов, с надёжной загрузкой, plain text форматирование, с кнопкой закрыть // @author Wizzergod // @icon https://www.google.com/s2/favicons?sz=64&domain=youtube.com // @match *://www.youtube.com/embed/* // @match *://www.youtube.com/watch?v=* // @grant GM_addStyle // @grant GM_getResourceURL // @grant GM_xmlhttpRequest // @resource icon https://images.icon-icons.com/3361/PNG/512/communication_information_aid_disclaimer_customer_service_about_guide_help_info_icon_210836.png // @run-at document-body // @license MIT // ==/UserScript== (function () { 'use strict'; const lang = navigator.language.startsWith('ru') ? 'ru' : 'en'; const i18n = { ru: { title: 'Показать описание видео', loading: 'Загрузка описания...', notFound: 'Видео не найдено.', error: 'Ошибка загрузки описания.', close: '✖', }, en: { title: 'Show video description', loading: 'Loading description...', notFound: 'Video not found.', error: 'Error loading description.', close: '✖', } }; const t = i18n[lang]; const iconURL = GM_getResourceURL('icon'); GM_addStyle(` #wizzergod-yt-desc-btn { background-image: url(${iconURL}); background-size: 26px 26px; background-repeat: no-repeat; background-position: center; width: 36px; height: 36px; cursor: pointer; border: none; background-color: parent; display: inline-flex; align-items: center; justify-content: center; ition: form 0.3s ease; z-index: 99999; margin: 0 8px; } #wizzergod-yt-desc-btn:hover { form: scale(1.15); } #wizzergod-yt-desc-btn:active { form: scale(0.9); background-color: rgba(255, 255, 255, 0.1); } #wizzergod-yt-desc-modal { position: fixed; top: 15vh; left: 10vw; width: 80vw; height: 50vh; background: rgba(17,17,17,0.95); color: white; padding: 20px; border-radius: 12px; z-index: 2147483647; display: none; flex-direction: column; resize: both; overflow: auto; box-shadow: 0 0 20px rgba(0,0,0,0.8); font-family: Arial, sans-serif; backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.1); } #wizzergod-yt-desc-modal.show { display: flex; } #wizzergod-yt-desc-modal .close-btn { align-self: flex-end; font-size: 24px; cursor: pointer; padding: 5px 10px; user-select: none; } #wizzergod-yt-desc-modal .content { white-space: pre-wrap; word-break: break-word; font-size: 14px; line-height: 1.4; flex-grow: 1; overflow-y: auto; text-align: center; margin-top: 10px; } `); function createButton() { const btn = document.createElement('button'); btn.id = 'wizzergod-yt-desc-btn'; btn.className = 'ytp-button'; btn.title = t.title; btn.setAttribute('aria-label', t.title); btn.onclick = () => { toggleModal(); }; return btn; } function createModal() { const modal = document.createElement('div'); modal.id = 'wizzergod-yt-desc-modal'; const close = document.createElement('div'); close.className = 'close-btn'; close.textContent = t.close; close.onclick = () => modal.classList.remove('show'); const content = document.createElement('div'); content.className = 'content'; content.textContent = t.loading; modal.appendChild(close); modal.appendChild(content); document.body.appendChild(modal); return modal; } async function fetchDescription(videoId, modal) { try { const res = await fetch(`https://www.youtube.com/watch?v=${videoId}`, { cache: 'no-store' }); const text = await res.text(); const match = text.match(/"shortDescription":"(.*?)"/); const desc = match ? JSON.parse('"' + match[1] + '"') : t.notFound; const content = modal.querySelector('.content'); content.textContent = desc; } catch (e) { const content = modal.querySelector('.content'); content.textContent = t.error; } } function toggleModal() { let modal = document.getElementById('wizzergod-yt-desc-modal'); if (!modal) modal = createModal(); modal.classList.add('show'); const content = modal.querySelector('.content'); content.textContent = t.loading; const videoId = location.href.match(/embed\/([^?&]+)/)?.[1] || location.href.match(/[?&]v=([^?&]+)/)?.[1]; if (videoId) { fetchDescription(videoId, modal); } else { content.textContent = t.notFound; } } function addButtonWhenReady() { const controlBarSelector = '.ytp-right-controls'; const controls = document.querySelector(controlBarSelector); if (!controls) { setTimeout(addButtonWhenReady, 300); return; } if (document.getElementById('wizzergod-yt-desc-btn')) return; const btn = createButton(); controls.insertBefore(btn, controls.firstChild); } const observer = new MutationObserver(() => { addButtonWhenReady(); }); observer.observe(document.body, { childList: true, subtree: true, }); addButtonWhenReady(); })();