Greasy Fork is available in English.

Threads.net Image Downloader

Add a download button to a specific div on Threads.net to download all images in the <picture> tag of the post.

  1. // ==UserScript==
  2. // @name Threads.net Image Downloader
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.6
  5. // @license MIT
  6. // @esversion 11
  7. // @description Add a download button to a specific div on Threads.net to download all images in the <picture> tag of the post.
  8. // @author StevenJon0826
  9. // @match https://www.threads.net/*
  10. // @grant GM_download
  11. // ==/UserScript==
  12. // ==UserScript==
  13. // @name Threads.net Image Downloader (Button in Specified Div)
  14. // @namespace http://tampermonkey.net/
  15. // @version 1.6
  16. // @license MIT
  17. // @esversion 11
  18. // @description Add a download button to a specific div on Threads.net to download all images in the <picture> tag of the post.
  19. // @author StevenJon0826
  20. // @match https://www.threads.net/*
  21. // @grant GM_download
  22. // ==/UserScript==
  23.  
  24. (function() {
  25. 'use strict';
  26.  
  27. function addButtonToElement(element) {
  28. // 檢查該元素是否已經存在按鈕,避免重複加入
  29. if (!element.querySelector('button.my-custom-button')) {
  30. // 建立按鈕
  31. const button = document.createElement('button');
  32. button.textContent = 'Download';
  33. button.classList.add('my-custom-button');
  34. button.style.position = 'relative';
  35. // 當按鈕被點擊時,往上找兩層並統計<picture>元素內的<img>數量
  36. button.addEventListener('click', function() {
  37. // 阻止事件的預設行為和冒泡
  38. event.preventDefault();
  39. event.stopPropagation();
  40.  
  41. // 往上找兩層 //x1s688f
  42. const grandparentElement = element.parentElement?.parentElement?.parentElement?.parentElement?.parentElement;
  43. if (grandparentElement) {
  44. // 在祖先層級中尋找所有的<picture>元素
  45. const pictures = grandparentElement.querySelectorAll('picture img');
  46. // 找到 class 包含 x1s688f 的 <span> 並取得其文字內容
  47. const spanElement = grandparentElement.querySelector('span[class*="x1s688f"]');
  48. let spanText;
  49. if (spanElement) {
  50. spanText = spanElement.textContent; // 取得文字內容
  51. }
  52. const timeElement = grandparentElement.querySelector('time'); // 假設只有一個time元素
  53. let formattedTime;
  54. if (timeElement) {
  55. const datetimeValue = timeElement.getAttribute('datetime'); // 取得datetime屬性
  56. const dateObject = new Date(datetimeValue); // 將datetime轉換為Date物件
  57.  
  58. // 格式化日期為YYYYMMDD_hhmmss
  59. const year = dateObject.getFullYear();
  60. const month = String(dateObject.getMonth() + 1).padStart(2, '0'); // 月份從0開始,所以加1
  61. const day = String(dateObject.getDate()).padStart(2, '0');
  62. const hours = String(dateObject.getHours()).padStart(2, '0');
  63. const minutes = String(dateObject.getMinutes()).padStart(2, '0');
  64. const seconds = String(dateObject.getSeconds()).padStart(2, '0');
  65.  
  66. formattedTime = `${year}${month}${day}_${hours}${minutes}${seconds}`;
  67. }
  68. pictures.forEach((img, index) => {
  69. const imageUrl = img.src;
  70. const filename = `Threads-${spanText}-${formattedTime}-${index + 1}.jpg`;
  71. GM_download(imageUrl, filename);
  72. });
  73.  
  74. // 找到 aria-label="讚" 的元素並模擬點擊
  75. const likeButton = grandparentElement.querySelector('[aria-label="讚"]');
  76. if (likeButton) {
  77. if (typeof likeButton.click === 'function') {
  78. likeButton.click(); // 如果元素有 click 方法,模擬點擊
  79. } else {
  80. // 如果該元素是SVG,則創建一個事件手動觸發
  81. const event = new MouseEvent('click', {
  82. bubbles: true,
  83. cancelable: true
  84. });
  85. likeButton.dispatchEvent(event); // 模擬點擊事件
  86. }
  87. console.log('Like button clicked');
  88. } else {
  89. console.log('No like button with aria-label "讚" found');
  90. }
  91.  
  92. } else {
  93. console.log('Could not find grandparent element');
  94. }
  95. });
  96. // 將按鈕加入到該元素中
  97. element.appendChild(button);
  98. }
  99. }
  100.  
  101. function scanForElements() {
  102. // 定期掃描符合條件的元素
  103. const elements = document.querySelectorAll('div[class*="x1fc57z9"]');
  104. elements.forEach(addButtonToElement);
  105. }
  106.  
  107. // 使用setInterval每隔一段時間檢查畫面上是否有符合條件的元素
  108. setInterval(scanForElements, 500); // 每秒檢查一次
  109. })();
  110.