Greasy Fork

Greasy Fork is available in English.

Twitter/X 视频下载助手

Twitter 视频下载

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Twitter/X 视频下载助手
// @namespace    http://tampermonkey.net/
// @version      2.6.0
// @description  Twitter 视频下载
// @author       Gemini Modified
// @license      MIT
// @match        https://x.com/*
// @match        https://twitter.com/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js
// @grant        GM_download
// ==/UserScript==

(function() {
    "use strict";

    $("head").append(`
        <style>
            #Orb {
                width: 38px; height: 38px; border-radius: 50%;
                background: radial-gradient(circle, #fff 0%, #1D9BF0 28%, #1A8CD8 70%, transparent 100%);
                border: 3px solid #fff;
                box-shadow: 0 0 18px rgba(29, 155, 240, 0.8), inset 0 0 12px rgba(29, 155, 240, 0.5);
                cursor: pointer; display: flex; align-items: center; justify-content: center;
                transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
                z-index: 1000000; backdrop-filter: blur(4px);
            }
            #Orb:hover { filter: brightness(1.1); transform: scale(1.05); }
            #VideoList::-webkit-scrollbar { display: none; }
            #RefreshList {
                background: #1D9BF0; border: none; color: white; padding: 4px 12px;
                border-radius: 8px; cursor: pointer; font-size: 12px; font-weight: bold;
            }
        </style>
    `);

    $("body").append(`
        <div id='MyUrls' style='position:fixed; top:20px; right:20px; z-index:999999; display:flex; flex-direction:column; align-items:flex-end;'>
            <div id='Orb'>
                <svg viewBox="0 0 24 24" fill="none" style="width: 58%; height: 58%; filter: drop-shadow(0 0 2px rgba(255,255,255,0.8));">
                    <path d="M12 3V16M12 16L7 11M12 16L17 11" stroke="#ffffff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
                    <path d="M5 21H19" stroke="#ffffff" stroke-width="3.5" stroke-linecap="round" stroke-linejoin="round"/>
                </svg>
            </div>
            <div id='VideoList' style='display:none; width:280px; max-height:80vh; background:rgba(255,255,255,0.98); backdrop-filter:blur(15px); border:2.5px solid #1D9BF0; padding:12px; border-radius:14px; box-shadow:0 15px 45px rgba(0,0,0,0.2); margin-top:15px; overflow-y:auto;'>
                <div style='display:flex; justify-content:space-between; align-items:center; margin-bottom:12px; border-bottom:2px solid #EFF3F4; padding-bottom:10px;'>
                    <b style="color:#0F1419; font-size:15px;">视频下载列表</b>
                    <button id='RefreshList'>刷新</button>
                </div>
                <div id="ListContent"></div>
            </div>
        </div>
    `);

    function resetSniffer() {
        $("#ListContent").empty();
        console.log("Twitter下载助手:已自动重置嗅探环境");
    }

    let lastUrl = location.href;
    new MutationObserver(() => {
        const currentUrl = location.href;
        if (currentUrl !== lastUrl) {
            lastUrl = currentUrl;
            resetSniffer(); 
        }
    }).observe(document, { subtree: true, childList: true });

    $("#Orb").click(() => $("#VideoList").fadeToggle(200));
    $("#RefreshList").click((e) => { e.stopPropagation(); resetSniffer(); });

    (function(open) {
        XMLHttpRequest.prototype.open = function() {
            this.addEventListener("load", function() {
                try {
                    if (this.responseText && (this.responseURL.includes("/TweetDetail") || this.responseURL.includes("/UserBy"))) {
                        findTwitterVideos(JSON.parse(this.responseText));
                    }
                } catch(e) {}
            });
            open.apply(this, arguments);
        };
    })(XMLHttpRequest.prototype.open);

    function findTwitterVideos(obj) {
        if (!obj || typeof obj !== 'object') return;
        if (obj.variants && Array.isArray(obj.variants)) {
            const mp4s = obj.variants.filter(v => v.content_type === 'video/mp4');
            if (mp4s.length > 0) {
                mp4s.sort((a, b) => (b.bitrate || 0) - (a.bitrate || 0));
                addToList(mp4s[0].url);
            }
        }
        for (let key in obj) findTwitterVideos(obj[key]);
    }

    function addToList(url) {
        if ($(`input[value='${url}']`).length > 0) return;
        $("#ListContent").append(`
            <div style='background:#F7F9F9; padding:12px; margin-bottom:10px; border-radius:10px; border:1px solid #CFD9DE;'>
                <input class='downUrl' value='${url}' style='width:100%; font-size:11px; margin-bottom:8px; background:transparent; border:none; color:#1D9BF0; font-weight:600;' readonly>
                <button class='SaveBtn' style='width:100%; background:#1D9BF0; color:white; border:none; padding:8px; cursor:pointer; border-radius:999px; font-weight:bold;'>下载视频</button>
            </div>
        `);
    }

    $(document).on("click", ".SaveBtn", function() {
        const url = $(this).prev(".downUrl").val();
        GM_download(url, "twitter_video_" + Date.now() + ".mp4");
    });
})();