Greasy Fork

Greasy Fork is available in English.

🎃 YouTube 下载按钮(直链 y2mate / yt-dlp 友好)

在 YouTube 视频页面添加下载按钮(支持 y2mate、prounlimited、ddownload 等多个后端,可自行修改)

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         🎃 YouTube 下载按钮(直链 y2mate / yt-dlp 友好)
// @namespace    https://github.com/ddgksf2013
// @version      2025.12.4
// @description  在 YouTube 视频页面添加下载按钮(支持 y2mate、prounlimited、ddownload 等多个后端,可自行修改)
// @author       现代重构版
// @match        *://*.youtube.com/watch*
// @match        *://*.youtube.com/shorts/*
// @grant        none
// @run-at       document-end
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // ======== 可自行修改的下载站点(任选其一或增加更多)========
    const DOWNLOAD_SITES = [
        // { name: "y2mate", url: id => `https://y2mate.com.cn/zh/youtube/${id}` },
        // { name: "y2mate(新版)", url: id => `https://yt5s.io/youtube/${id}` },
        { name: "prounlimited", url: id => `https://prounlimited.me/zh/youtube-downloader/${id}` },       // 目前最快最稳
        { name: "ddownload",   url: id => `https://ddownload.me/video/${id}` },
        { name: "cobalt",      url: id => `https://cobalt.tools/?v=${id}` }, // 需要自行部署或用公开实例
    ];
    // ===================================================

    const BUTTON_TEXT = "⚡ 下载 MP4/MP3";

    function getVideoId() {
        const url = new URL(location.href);
        return url.searchParams.get('v') || location.pathname.split('/').pop();
    }

    function createButton() {
        const btn = document.createElement('button');
        btn.textContent = BUTTON_TEXT;
        btn.style.cssText = `
            background: #ff0000 !important;
            color: #fff !important;
            border: none !important;
            padding: 8px 16px !important;
            margin: 0 8px 8px 0 !important;
            border-radius: 18px !important;
            font-weight: 600 !important;
            font-size: 14px !important;
            cursor: pointer !important;
            box-shadow: 0 1px 6px rgba(0,0,0,0.25) !important;
            transition: all 0.2s !important;
        `;
        btn.onmouseover = () => btn.style.opacity = '0.85';
        btn.onmouseout  = () => btn.style.opacity = '1';

        // 点击后弹出小菜单,支持多个站点
        btn.onclick = () => {
            const vid = getVideoId();
            if (!vid) return;

            if (DOWNLOAD_SITES.length === 1) {
                open(DOWNLOAD_SITES[0].url(vid), '_blank');
                return;
            }

            // 多站点时弹出简易菜单
            alert(`请选择下载站点(视频 ID: ${vid}):\n\n` +
                DOWNLOAD_SITES.map((s, i) => `${i+1}. ${s.name}\n→ ${s.url(vid)}`).join('\n') +
                '\n\n手动复制链接后打开即可');
        };

        return btn;
    }

    function insertButton() {
        const vid = getVideoId();
        if (!vid) return;

        // 方式1:放在视频标题下方(最显眼)
        const titleContainer = document.querySelector('ytd-watch-metadata #title') ||
                              document.querySelector('h1.ytd-watch-metadata');
        if (titleContainer && !document.getElementById('my-ytdownload-btn')) {
            const container = document.createElement('div');
            container.id = 'my-ytdownload-container';
            container.style.marginTop = '8px';
            container.appendChild(createButton());
            titleContainer.parentNode.appendChild(container);
            return;
        }

        // 方式2:放在订阅按钮旁边(新版 YouTube 常用位置)
        const subscribeButton = document.querySelector('ytd-subscribe-button-renderer');
        if (subscribeButton && !document.getElementById('my-ytdownload-btn')) {
            const btn = createButton();
            btn.id = 'my-ytdownload-btn';
            subscribeButton.parentNode.insertBefore(btn, subscribeButton.nextSibling);
        }
    }

    // 监听 YouTube SPA 路由变化(新版 YouTube 是单页应用)
    let lastUrl = location.href;
    new MutationObserver(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            setTimeout(insertButton, 1500);
        }
    }).observe(document, { subtree: true, childList: true });

    // 初始加载
    setTimeout(insertButton, 2000);
    insertButton();
})();