Greasy Fork is available in English.
Twitter 视频下载
// ==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");
});
})();