// ==UserScript== // @name Threads.net Image Downloader // @namespace http://tampermonkey.net/ // @version 1.6 // @license MIT // @esversion 11 // @description Add a download button to a specific div on Threads.net to download all images in the tag of the post. // @author StevenJon0826 // @match https://www.threads.net/* // @grant GM_download // @downloadURL https://update.greasyfork.icu/scripts/508541/Threadsnet%20Image%20Downloader.user.js // @updateURL https://update.greasyfork.icu/scripts/508541/Threadsnet%20Image%20Downloader.meta.js // ==/UserScript== // ==UserScript== // @name Threads.net Image Downloader (Button in Specified Div) // @namespace http://tampermonkey.net/ // @version 1.6 // @license MIT // @esversion 11 // @description Add a download button to a specific div on Threads.net to download all images in the tag of the post. // @author StevenJon0826 // @match https://www.threads.net/* // @grant GM_download // ==/UserScript== (function() { 'use strict'; function addButtonToElement(element) { // 檢查該元素是否已經存在按鈕,避免重複加入 if (!element.querySelector('button.my-custom-button')) { // 建立按鈕 const button = document.createElement('button'); button.textContent = 'Download'; button.classList.add('my-custom-button'); button.style.position = 'relative'; // 當按鈕被點擊時,往上找兩層並統計元素內的數量 button.addEventListener('click', function() { // 阻止事件的預設行為和冒泡 event.preventDefault(); event.stopPropagation(); // 往上找兩層 //x1s688f const grandparentElement = element.parentElement?.parentElement?.parentElement?.parentElement?.parentElement; if (grandparentElement) { // 在祖先層級中尋找所有的元素 const pictures = grandparentElement.querySelectorAll('picture img'); // 找到 class 包含 x1s688f 的 並取得其文字內容 const spanElement = grandparentElement.querySelector('span[class*="x1s688f"]'); let spanText; if (spanElement) { spanText = spanElement.textContent; // 取得文字內容 } const timeElement = grandparentElement.querySelector('time'); // 假設只有一個time元素 let formattedTime; if (timeElement) { const datetimeValue = timeElement.getAttribute('datetime'); // 取得datetime屬性 const dateObject = new Date(datetimeValue); // 將datetime轉換為Date物件 // 格式化日期為YYYYMMDD_hhmmss const year = dateObject.getFullYear(); const month = String(dateObject.getMonth() + 1).padStart(2, '0'); // 月份從0開始,所以加1 const day = String(dateObject.getDate()).padStart(2, '0'); const hours = String(dateObject.getHours()).padStart(2, '0'); const minutes = String(dateObject.getMinutes()).padStart(2, '0'); const seconds = String(dateObject.getSeconds()).padStart(2, '0'); formattedTime = `${year}${month}${day}_${hours}${minutes}${seconds}`; } pictures.forEach((img, index) => { const imageUrl = img.src; const filename = `Threads-${spanText}-${formattedTime}-${index + 1}.jpg`; GM_download(imageUrl, filename); }); // 找到 aria-label="讚" 的元素並模擬點擊 const likeButton = grandparentElement.querySelector('[aria-label="讚"]'); if (likeButton) { if (typeof likeButton.click === 'function') { likeButton.click(); // 如果元素有 click 方法,模擬點擊 } else { // 如果該元素是SVG,則創建一個事件手動觸發 const event = new MouseEvent('click', { bubbles: true, cancelable: true }); likeButton.dispatchEvent(event); // 模擬點擊事件 } console.log('Like button clicked'); } else { console.log('No like button with aria-label "讚" found'); } } else { console.log('Could not find grandparent element'); } }); // 將按鈕加入到該元素中 element.appendChild(button); } } function scanForElements() { // 定期掃描符合條件的元素 const elements = document.querySelectorAll('div[class*="x1fc57z9"]'); elements.forEach(addButtonToElement); } // 使用setInterval每隔一段時間檢查畫面上是否有符合條件的元素 setInterval(scanForElements, 500); // 每秒檢查一次 })();