yt-dlp Video Command

Add yt-dlp copy command option to download videos

// ==UserScript==
// @name         yt-dlp Video Command
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  Add yt-dlp copy command option to download videos
// @author       tris
// @match        *://*/*
// @license      MIT
// @grant        GM_registerMenuCommand
// @grant        GM_setClipboard
// ==/UserScript==

(function() {
    'use strict';

    GM_registerMenuCommand("🔥 Copy yt-dlp Command", showDownloadPopup);

    function showDownloadPopup() {
        const existingPopup = document.getElementById('ytdlp-popup');
        if (existingPopup) {
            existingPopup.remove();
        }

        const popup = document.createElement('div');
        popup.id = 'ytdlp-popup';
        popup.innerHTML = `
            <div class="ytdlp-overlay">
                <div class="ytdlp-modal">
                    <div class="ytdlp-header">
                        <div class="ytdlp-header-content">
                            <h3>Copy command</h3>
                            <p>Generate yt-dlp download commands</p>
                        </div>
                        <button class="ytdlp-close">
                            <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
                                <line x1="18" y1="6" x2="6" y2="18"></line>
                                <line x1="6" y1="6" x2="18" y2="18"></line>
                            </svg>
                        </button>
                    </div>

                    <div class="ytdlp-content">
                        <div class="ytdlp-field">
                            <label for="video-url">Video URL</label>
                            <input type="text" id="video-url" placeholder="Paste your video URL here..." value="">
                            <div class="ytdlp-hint">Supports YouTube, Twitch, TikTok, and 1000+ sites</div>
                        </div>

                        <div class="ytdlp-field-row">
                            <div class="ytdlp-field">
                                <label for="quality-select">Quality</label>
                                <select id="quality-select">
                                    <option value="best">Best Quality</option>
                                    <option value="worst">Worst Quality</option>
                                    <option value="best[height<=720]">720p or lower</option>
                                    <option value="best[height<=480]">480p or lower</option>
                                    <option value="best[height<=360]">360p or lower</option>
                                    <option value="bestvideo+bestaudio">Best Video + Best Audio</option>
                                    <option value="bestaudio">Audio Only</option>
                                </select>
                            </div>

                            <div class="ytdlp-field">
                                <label for="output-format">Format</label>
                                <select id="output-format">
                                    <option value="mp4">MP4</option>
                                    <option value="mkv">MKV</option>
                                    <option value="webm">WebM</option>
                                    <option value="avi">AVI</option>
                                    <option value="mp3">MP3 (Audio)</option>
                                    <option value="m4a">M4A (Audio)</option>
                                </select>
                            </div>
                        </div>

                        <div class="ytdlp-field">
                            <label for="output-path">Output Directory <span class="ytdlp-optional">(optional)</span></label>
                            <input type="text" id="output-path" placeholder="e.g., ~/Downloads/Videos">
                        </div>

                        <button class="ytdlp-generate-btn" id="copy-command">
                            Generate Command
                        </button>

                        <div class="ytdlp-output" id="command-output" style="display: none;">
                            <div class="ytdlp-output-header">
                                <span>Generated Command</span>
                                <button class="ytdlp-copy-btn" id="copy-again-btn">Copy</button>
                            </div>
                            <div class="ytdlp-code-block">
                                <code id="command-text"></code>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        `;

        const style = document.createElement('style');
        style.textContent = `
            .ytdlp-overlay {
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.6);
                display: flex;
                justify-content: center;
                align-items: center;
                z-index: 10001;
                animation: ytdlp-fadeIn 0.15s ease-out;
            }

            @keyframes ytdlp-fadeIn {
                from { opacity: 0; }
                to { opacity: 1; }
            }

            @keyframes ytdlp-slideIn {
                from {
                    opacity: 0;
                    transform: scale(0.96) translateY(8px);
                }
                to {
                    opacity: 1;
                    transform: scale(1) translateY(0);
                }
            }

            .ytdlp-modal {
                background: #1a1a1a;
                border: 1px solid #333;
                border-radius: 12px;
                width: 90%;
                max-width: 480px;
                max-height: 90vh;
                overflow: hidden;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                animation: ytdlp-slideIn 0.2s ease-out;
                color: #e5e5e5;
            }

            .ytdlp-header {
                padding: 20px 20px 16px 20px;
                border-bottom: 1px solid #333;
                display: flex;
                justify-content: space-between;
                align-items: flex-start;
            }

            .ytdlp-header-content h3 {
                margin: 0 0 4px 0;
                font-size: 18px;
                font-weight: 600;
                color: #f5f5f5;
                line-height: 1.2;
            }

            .ytdlp-header-content p {
                margin: 0;
                font-size: 14px;
                color: #a3a3a3;
                font-weight: 400;
            }

            .ytdlp-close {
                background: none;
                border: none;
                color: #a3a3a3;
                cursor: pointer;
                padding: 4px;
                border-radius: 6px;
                transition: all 0.15s ease;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            .ytdlp-close:hover {
                background: #2a2a2a;
                color: #e5e5e5;
            }

            .ytdlp-content {
                padding: 20px;
            }

            .ytdlp-field {
                margin-bottom: 20px;
            }

            .ytdlp-field-row {
                display: flex;
                gap: 16px;
                margin-bottom: 20px;
            }

            .ytdlp-field-row .ytdlp-field {
                flex: 1;
                margin-bottom: 0;
            }

            .ytdlp-field label {
                display: block;
                margin-bottom: 6px;
                font-size: 14px;
                font-weight: 500;
                color: #e5e5e5;
            }

            .ytdlp-optional {
                color: #737373;
                font-weight: 400;
                font-size: 14px;
            }

            .ytdlp-field input,
            .ytdlp-field select {
                width: 100%;
                padding: 10px 12px;
                border: 1px solid #404040;
                border-radius: 8px;
                background: #262626;
                color: #e5e5e5;
                font-size: 14px;
                font-family: inherit;
                box-sizing: border-box;
                transition: border-color 0.15s ease;
            }

            .ytdlp-field input:focus,
            .ytdlp-field select:focus {
                outline: none;
                border-color: #d97706;
            }

            .ytdlp-field input::placeholder {
                color: #737373;
            }

            .ytdlp-hint {
                font-size: 13px;
                color: #737373;
                margin-top: 6px;
            }

            .ytdlp-generate-btn {
                width: 100%;
                padding: 12px;
                background: #d97706;
                color: white;
                border: none;
                border-radius: 8px;
                font-size: 14px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.15s ease;
                font-family: inherit;
                margin-bottom: 20px;
            }

            .ytdlp-generate-btn:hover {
                background: #b45309;
            }

            .ytdlp-generate-btn:active {
                transform: translateY(1px);
            }

            .ytdlp-output {
                animation: ytdlp-slideDown 0.2s ease-out;
            }

            @keyframes ytdlp-slideDown {
                from {
                    opacity: 0;
                    transform: translateY(-8px);
                }
                to {
                    opacity: 1;
                    transform: translateY(0);
                }
            }

            .ytdlp-output-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 8px;
            }

            .ytdlp-output-header span {
                font-size: 14px;
                font-weight: 500;
                color: #e5e5e5;
            }

            .ytdlp-copy-btn {
                background: #404040;
                color: #e5e5e5;
                border: none;
                padding: 6px 12px;
                border-radius: 6px;
                font-size: 13px;
                cursor: pointer;
                transition: all 0.15s ease;
                font-family: inherit;
            }

            .ytdlp-copy-btn:hover {
                background: #525252;
            }

            .ytdlp-code-block {
                background: #0f0f0f;
                border: 1px solid #333;
                border-radius: 8px;
                padding: 12px;
            }

            .ytdlp-code-block code {
                display: block;
                color: #22c55e;
                font-family: 'Courier New', monospace;
                font-size: 13px;
                line-height: 1.4;
                word-break: break-all;
                white-space: pre-wrap;
                cursor: pointer;
            }

            .ytdlp-code-block:hover {
                background: #171717;
            }

            .ytdlp-notification {
                position: fixed;
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                background: #0f0f0f;
                border: 1px solid #333;
                color: #e5e5e5;
                padding: 10px 16px;
                border-radius: 8px;
                font-family: inherit;
                font-size: 14px;
                z-index: 10002;
                animation: ytdlp-notificationSlide 0.2s ease-out;
            }

            .ytdlp-notification.error {
                background: #450a0a;
                border-color: #dc2626;
                color: #fecaca;
            }

            @keyframes ytdlp-notificationSlide {
                from {
                    opacity: 0;
                    transform: translateX(-50%) translateY(-10px);
                }
                to {
                    opacity: 1;
                    transform: translateX(-50%) translateY(0);
                }
            }

            @media (max-width: 640px) {
                .ytdlp-modal {
                    width: 95%;
                    margin: 16px;
                }

                .ytdlp-field-row {
                    flex-direction: column;
                    gap: 20px;
                }

                .ytdlp-field-row .ytdlp-field {
                    margin-bottom: 0;
                }
            }
        `;

        popup.appendChild(style);
        document.body.appendChild(popup);

        const closeBtn = popup.querySelector('.ytdlp-close');
        const overlay = popup.querySelector('.ytdlp-overlay');
        const copyBtn = popup.querySelector('#copy-command');
        const copyAgainBtn = popup.querySelector('#copy-again-btn');

        closeBtn.addEventListener('click', () => popup.remove());
        overlay.addEventListener('click', (e) => {
            if (e.target === overlay) popup.remove();
        });

        copyBtn.addEventListener('click', generateAndCopyCommand);
        copyAgainBtn.addEventListener('click', () => {
            const commandText = document.getElementById('command-text').textContent;
            if (commandText) {
                copyToClipboard(commandText);
                showNotification('Command copied to clipboard!');
            }
        });

        const commandCode = popup.querySelector('#command-text');
        commandCode.addEventListener('click', () => {
            if (commandCode.textContent) {
                copyToClipboard(commandCode.textContent);
                showNotification('Command copied to clipboard!');
            }
        });

        const urlInput = popup.querySelector('#video-url');
        urlInput.focus();
    }

    function generateAndCopyCommand() {
        const url = document.getElementById('video-url').value.trim();
        const quality = document.getElementById('quality-select').value;
        const format = document.getElementById('output-format').value;
        const outputPath = document.getElementById('output-path').value.trim();

        if (!url) {
            showNotification('Please enter a video URL', 'error');
            return;
        }

        let command = 'yt-dlp';

        if (quality !== 'best') {
            command += ` -f "${quality}"`;
        }

        if (['mp3', 'm4a'].includes(format)) {
            command += ` --extract-audio --audio-format ${format}`;
        } else if (format !== 'mp4') {
            command += ` --merge-output-format ${format}`;
        }

        if (outputPath) {
            command += ` -o "${outputPath}/%(title)s.%(ext)s"`;
        }

        command += ` "${url}"`;

        const commandOutput = document.getElementById('command-output');
        const commandText = document.getElementById('command-text');
        commandText.textContent = command;
        commandOutput.style.display = 'block';

        copyToClipboard(command);
        showNotification('yt-dlp command copied to clipboard!');
    }

    function copyToClipboard(text) {
        if (typeof GM_setClipboard !== 'undefined') {
            GM_setClipboard(text);
            return;
        }

        if (navigator.clipboard) {
            navigator.clipboard.writeText(text).catch(() => {
                fallbackCopy(text);
            });
        } else {
            fallbackCopy(text);
        }
    }

    function fallbackCopy(text) {
        const textArea = document.createElement('textarea');
        textArea.value = text;
        textArea.style.position = 'fixed';
        textArea.style.opacity = '0';
        document.body.appendChild(textArea);
        textArea.select();
        document.execCommand('copy');
        document.body.removeChild(textArea);
    }

    function showNotification(message, type = 'success') {
        const existingNotifications = document.querySelectorAll('.ytdlp-notification');
        existingNotifications.forEach(notification => notification.remove());

        const notification = document.createElement('div');
        notification.textContent = message;
        notification.className = `ytdlp-notification ${type === 'error' ? 'error' : ''}`;

        document.body.appendChild(notification);

        setTimeout(() => {
            notification.style.opacity = '0';
            notification.style.transform = 'translateX(-50%) translateY(-10px)';
            notification.style.transition = 'all 0.2s ease-out';
            setTimeout(() => notification.remove(), 200);
        }, 3000);
    }
})();

QingJ © 2025

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