您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Download images from Twitter posts and pack them into a ZIP archive with metadata.
当前为
// ==UserScript== // @name Twitter Image Downloader // @namespace http://tampermonkey.net/ // @version 1.0 // @description Download images from Twitter posts and pack them into a ZIP archive with metadata. // @author Dramorian // @license MIT // @match https://twitter.com/* // @match https://x.com/* // @require https://cdnjs.cloudflare.com/ajax/libs/jszip/3.7.1/jszip.min.js // @require https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js // @grant none // ==/UserScript== (function() { 'use strict'; // Add a download button to the tweet actions bar function addDownloadButton(tweetElement) { // Check if button already exists if (tweetElement.querySelector('.download-images-btn')) return; const button = document.createElement('button'); button.innerText = 'Download Images'; button.className = 'download-images-btn'; button.style.marginLeft = '10px'; button.addEventListener('click', () => downloadImages(tweetElement)); const actionBar = tweetElement.querySelector('[role="group"]'); if (actionBar) { actionBar.appendChild(button); } } // Download images and metadata async function downloadImages(tweetElement) { const zip = new JSZip(); const tweetLinkElement = tweetElement.querySelector('a[href*="/status/"]'); const tweetLink = tweetLinkElement.href; const tweetParts = tweetLink.match(/https:\/\/(?:x\.com|twitter\.com)\/([^\/]+)\/status\/(\d+)/); const authorHandle = tweetParts[1]; const tweetId = tweetParts[2]; const authorComment = tweetElement.querySelector('div[lang]').innerText; const dateElement = tweetElement.querySelector('time'); const postDateTime = dateElement ? new Date(dateElement.getAttribute('datetime')) : new Date(); const imageElements = tweetElement.querySelectorAll('div.css-175oi2r a[href*="/photo/"]'); // Metadata starts with the link to the tweet, followed by the author comment, handle, date and time, and links to each image let metadata = `${tweetLink}\n${authorComment}\n@${authorHandle}\n${postDateTime.toLocaleString()}\n`; // Add images to the zip let imageIndex = 1; for (const imgElement of imageElements) { let imgUrl = imgElement.querySelector('img').src; imgUrl = imgUrl.replace(/(?<=name=)[^&]+/, 'orig'); const imgData = await fetch(imgUrl).then(res => res.blob()); const imageName = `${authorHandle}_${tweetId}_${imageIndex}.jpg`; zip.file(imageName, imgData); // Append each image link to the metadata metadata += `https://x.com${imgElement.getAttribute('href')}\n`; imageIndex++; } // Add metadata files zip.file('metadata.txt', metadata); zip.file(`${authorHandle}_${tweetId}.url`, `[InternetShortcut]\nURL=${tweetLink}`); // Generate the zip file and trigger the download const content = await zip.generateAsync({ type: 'blob' }); saveAs(content, `${authorHandle}_${tweetId}.zip`); } // Observe the DOM for new tweets and add the download button const observer = new MutationObserver(mutations => { for (const mutation of mutations) { for (const addedNode of mutation.addedNodes) { if (addedNode.nodeType === Node.ELEMENT_NODE) { const tweetElements = addedNode.querySelectorAll('article'); tweetElements.forEach(addDownloadButton); } } } }); observer.observe(document.body, { childList: true, subtree: true }); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址