您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add download button for posts with images/videos on Threads.net
// ==UserScript== // @name Threads.net Media Downloader // @namespace https://www.youtube.com/channel/UC26YHf9ASpeu68az2xRKn1w // @version 05-01-2025 // @description Add download button for posts with images/videos on Threads.net // @author Kinnena, ICHx // @match https://www.threads.net/* // @match https://www.threads.com/* // // @icon https://cdn-icons-png.flaticon.com/512/12105/12105338.png // @grant GM_download // @license MIT // ==/UserScript== (function() { 'use strict'; function addButtonToElement(element) { if (element.querySelector('button.my-custom-button')) return; const postContainer = element.closest('div[role="article"]') || element.parentElement?.parentElement?.parentElement?.parentElement?.parentElement; if (!postContainer) return; const hasMedia = postContainer.querySelector('picture img, video'); if (!hasMedia) return; const button = document.createElement('button'); button.textContent = 'Download'; button.className = 'my-custom-button'; Object.assign(button.style, { position: 'relative', background: '#0095f6', color: 'white', border: 'none', borderRadius: '4px', padding: '6px 12px', margin: '4px', cursor: 'pointer' }); button.addEventListener('click', function(event) { event.preventDefault(); event.stopPropagation(); // Get post metadata const spanElement = postContainer.querySelector('span[class*="x1s688f"]'); const timeElement = postContainer.querySelector('time'); const spanText = (spanElement?.textContent || 'unknown').replace(/[^\w]/g, '_').substring(0, 30); const datetime = timeElement?.getAttribute('datetime'); // Format timestamp let formattedTime = ''; if (datetime) { const date = new Date(datetime); formattedTime = [ date.getFullYear(), String(date.getMonth() + 1).padStart(2, '0'), String(date.getDate()).padStart(2, '0'), '_', String(date.getHours()).padStart(2, '0'), String(date.getMinutes()).padStart(2, '0'), String(date.getSeconds()).padStart(2, '0') ].join(''); } // Collect media const mediaElements = [ ...postContainer.querySelectorAll('picture img'), ...postContainer.querySelectorAll('video') ]; mediaElements.forEach((media, index) => { let url, type; if (media.tagName === 'IMG') { url = media.src; type = 'image'; } else { url = media.src || media.querySelector('source')?.src; type = 'video'; } if (url) { const extension = getFileExtension(url) || (type === 'image' ? 'jpg' : 'mp4'); const filename = `Threads_${spanText}_${formattedTime}_${index + 1}.${extension}`; GM_download({ url: url, name: filename, onerror: (e) => console.error('Download error:', e) }); } }); // Auto-like functionality const likeButton = postContainer.querySelector('[aria-label="讚"]'); if (likeButton) { likeButton.click(); } }); element.appendChild(button); } function getFileExtension(url) { try { const cleanUrl = url.split(/[?#]/)[0]; return cleanUrl.split('.').pop().toLowerCase(); } catch { return null; } } function scanForButtons() { document.querySelectorAll('div[class*="x1fc57z9"]').forEach(addButtonToElement); } // Initial check scanForButtons(); // Periodic check for new posts setInterval(scanForButtons, 1000); })();