YouTube +

Tabview YouTube and Download

As of 2025-05-23. See the latest version.

// ==UserScript==
// @name            YouTube +
// @namespace       by
// @version         1.1
// @author          diorhc
// @description     Вкладки для информации, комментариев, видео, плейлиста и скачивание видео
// @description:en  Tabview YouTube and Download
// @match           https://www.youtube.com/watch*
// @icon            https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @license         MIT
// @grant           none
// ==/UserScript==

(function () {
    'use strict';

    let controls = null;

    function addButtons() {
            if (!controls) {
                    controls = document.querySelector('.ytp-right-controls');
            }

            if (!controls) {
                    return;
            }

            // Add screenshot button if not already added
            if (!document.querySelector('.ytp-screenshot-button')) {
                    addScreenshotButton();
            }

            // Add cobalt.tools button if not already added
            if (!document.querySelector('.ytp-cobalt-button')) {
                    addCobaltToolsButton();
            }
    }

    function addScreenshotButton() {
            const screenshotButton = document.createElement('button');
            screenshotButton.className = 'ytp-button ytp-screenshot-button';
            screenshotButton.setAttribute('title', 'Take screenshot');
            screenshotButton.style.position = 'relative';
            screenshotButton.style.bottom = '12px';
            screenshotButton.style.width = '44px';

            const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svgElement.setAttribute('viewBox', '0 0 487 487');
            svgElement.setAttribute('width', '24');
            svgElement.setAttribute('height', '24');
            svgElement.setAttribute('fill', '#ffffff');

            const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            pathElement.setAttribute('d', 'M308.1,277.95c0,35.7-28.9,64.6-64.6,64.6s-64.6-28.9-64.6-64.6s28.9-64.6,64.6-64.6S308.1,242.25,308.1,277.95z M440.3,116.05c25.8,0,46.7,20.9,46.7,46.7v122.4v103.8c0,27.5-22.3,49.8-49.8,49.8H49.8c-27.5,0-49.8-22.3-49.8-49.8v-103.9 v-122.3l0,0c0-25.8,20.9-46.7,46.7-46.7h93.4l4.4-18.6c6.7-28.8,32.4-49.2,62-49.2h74.1c29.6,0,55.3,20.4,62,49.2l4.3,18.6H440.3z M97.4,183.45c0-12.9-10.5-23.4-23.4-23.4c-13,0-23.5,10.5-23.5,23.4s10.5,23.4,23.4,23.4C86.9,206.95,97.4,196.45,97.4,183.45z M358.7,277.95c0-63.6-51.6-115.2-115.2-115.2s-115.2,51.6-115.2,115.2s51.6,115.2,115.2,115.2S358.7,341.55,358.7,277.95z');
            svgElement.appendChild(pathElement);
            screenshotButton.appendChild(svgElement);

            screenshotButton.addEventListener('click', () => {
                    const video = document.querySelector('video');
                    if (video) captureFrame(video);
            });

            controls.insertBefore(screenshotButton, controls.firstChild);
    }

    function addCobaltToolsButton() {
            const cobaltButton = document.createElement('button');
            cobaltButton.className = 'ytp-button ytp-cobalt-button';
            cobaltButton.setAttribute('title', 'Open in cobalt.tools');
            cobaltButton.style.position = 'relative';
            cobaltButton.style.bottom = '12px';
            cobaltButton.style.width = '44px';

            // Create SVG for cobalt.tools button
            const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            svgElement.setAttribute('viewBox', '0 0 24 24');
            svgElement.setAttribute('width', '24');
            svgElement.setAttribute('height', '24');
            svgElement.setAttribute('fill', '#ffffff');

            // Simple download icon for cobalt.tools
            const pathElement = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            pathElement.setAttribute('d', 'M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM17 13l-5 5-5-5h3V9h4v4h3z');
            svgElement.appendChild(pathElement);
            cobaltButton.appendChild(svgElement);

            cobaltButton.addEventListener('click', () => {
                    openInCobaltTools();
            });

            controls.insertBefore(cobaltButton, controls.firstChild);
    }

    function captureFrame(video) {
            const canvas = document.createElement('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            const videoTitle = document.title.replace(/\s-\sYouTube$/, '').trim();
            const filename = `${videoTitle}.png`;

            const link = document.createElement('a');
            link.href = canvas.toDataURL('image/png');
            link.download = filename;
            link.click();
    }

    function openInCobaltTools() {
            const videoUrl = window.location.href;
            const videoId = new URLSearchParams(window.location.search).get('v');

            if (videoId) {
                    // Copy the YouTube URL to clipboard
                    navigator.clipboard.writeText(videoUrl)
                        .then(() => {
                            // Create and show a brief notification
                            const notification = document.createElement('div');
                            notification.textContent = 'URL copied to clipboard';
                            notification.style.position = 'fixed';
                            notification.style.bottom = '70px';
                            notification.style.left = '50%';
                            notification.style.transform = 'translateX(-50%)';
                            notification.style.backgroundColor = 'rgba(0, 0, 0, 0.7)';
                            notification.style.color = 'white';
                            notification.style.padding = '10px 20px';
                            notification.style.borderRadius = '4px';
                            notification.style.zIndex = '9999';
                            document.body.appendChild(notification);
                            
                            // Remove the notification after 2 seconds
                            setTimeout(() => {
                                notification.style.opacity = '0';
                                notification.style.transition = 'opacity 0.5s';
                                setTimeout(() => notification.remove(), 500);
                            }, 2000);
                        });
                    
                    // Open in cobalt.tools
                    const cobaltUrl = `https://cobalt.tools/?url=https://www.youtube.com/watch?v=${videoId}`;
                    window.open(cobaltUrl, 'videoUrl');
            }
    }

    function handleFullscreenChange() {
            const buttons = document.querySelectorAll('.ytp-screenshot-button, .ytp-cobalt-button');
            const isFullscreen = document.fullscreenElement || document.webkitFullscreenElement;
            
            buttons.forEach(button => {
                    button.style.bottom = isFullscreen ? '15px' : '12px';
            });
    }

    function initialize() {
            document.addEventListener('yt-navigate-finish', () => {
                    if (window.location.href.includes('watch?v=')) {
                            addButtons();
                    }
            });

            document.addEventListener('fullscreenchange', handleFullscreenChange);

            // Initial setup
            if (window.location.href.includes('watch?v=')) {
                    addButtons();
            }
    }

    initialize();
})();
长期地址
遇到问题?请前往 GitHub 提 Issues,或加Q群1031348184

赞助商

Fishcpy

广告

Rainyun

一年攒够 12 元