Threads Video Downloader

Download photos and videos from Threads quickly and easily!

当前为 2025-02-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Threads Video Downloader
  3. // @namespace https://github.com/ManoloZocco/Threads-video-downloader-userscript
  4. // @version 1.3
  5. // @description Download photos and videos from Threads quickly and easily!
  6. // @author P0L1T3 aka Manolo Zocco
  7. // @match https://*.threads.net/*
  8. // @connect threads.net
  9. // @connect www.threads.net
  10. // @grant GM_download
  11. // @grant GM_addStyle
  12. // @run-at document-end
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. (function() {
  17. 'use strict';
  18.  
  19. // Inserisce il CSS per il pulsante di download (da css/interface.css)
  20. GM_addStyle(`
  21. .dw {
  22. position: absolute;
  23. z-index: 5;
  24. width: 116px;
  25. height: 34px;
  26. border-radius: 8px;
  27. background: rgba(0, 0, 0, 0.6);
  28. box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  29. display: none;
  30. flex-direction: row;
  31. justify-content: space-around;
  32. align-items: center;
  33. cursor: pointer;
  34. margin: 7px;
  35. border: none;
  36. color: #FFF;
  37. font-size: 11px;
  38. font-weight: 600;
  39. text-transform: uppercase;
  40. line-height: 22px;
  41. letter-spacing: -0.42px;
  42. bottom: 7px;
  43. left: 7px;
  44. }
  45.  
  46. .dw .icon {
  47. background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M10 3v9' stroke='white' stroke-width='2' stroke-linecap='round'/%3E%3Cpath d='M6 10l4 4 4-4' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3Crect x='4' y='14' width='12' height='2' fill='white'/%3E%3C/svg%3E");
  48. width: 20px;
  49. height: 20px;
  50. margin-right: 5px;
  51. }
  52.  
  53. *:hover > .dw {
  54. display: flex;
  55. }
  56.  
  57. .dw:hover {
  58. background: rgba(0, 0, 0, 0.8);
  59. }
  60. `);
  61.  
  62. // Funzione di download basata su GM_download
  63. function downloadFile(url) {
  64. if (!url) return;
  65. let fileName = url.substring(url.lastIndexOf('/') + 1);
  66. if (!fileName) fileName = 'download';
  67. GM_download({
  68. url: url,
  69. name: fileName,
  70. onerror: function(err) {
  71. console.error('Download error:', err);
  72. }
  73. });
  74. }
  75.  
  76. // Oggetto che gestisce l'osservazione del DOM e l'iniezione dei pulsanti
  77. const downloader = {
  78. observeDom() {
  79. // Gestione dei video
  80. document.querySelectorAll("video").forEach((video) => {
  81. let container = downloader.findRoot(video);
  82. if (container && !container.querySelector(".dw")) {
  83. container.append(downloader.getBtn(video.currentSrc || video.src));
  84. }
  85. });
  86. // Gestione delle immagini
  87. document.querySelectorAll("img").forEach((img) => {
  88. if (img.width < 200 || img.height < 200) return;
  89. if (img.parentElement && img.parentElement.querySelector(".dw")) return;
  90. img.parentElement.prepend(downloader.getBtn(img.src));
  91. });
  92. },
  93. // Crea il pulsante di download
  94. getBtn(src) {
  95. const btn = document.createElement("button");
  96. btn.innerText = "Download";
  97. btn.className = "dw";
  98. const icon = document.createElement("span");
  99. icon.className = "icon";
  100. btn.appendChild(icon);
  101. btn.setAttribute("src", src);
  102. btn.addEventListener("click", downloader.dw);
  103. return btn;
  104. },
  105. // Risale la gerarchia DOM per trovare un container (div con data-visualcompletion)
  106. findRoot(element) {
  107. let parent = element.parentNode;
  108. if (!parent) return null;
  109. let found = parent.querySelector("div[data-visualcompletion]");
  110. return found || downloader.findRoot(parent);
  111. },
  112. // Gestore dell'evento click sul pulsante
  113. dw(event) {
  114. event.preventDefault();
  115. event.stopPropagation();
  116. let target = event.target.nodeName.toLowerCase() === "button" ? event.target : event.target.parentElement;
  117. let src = target.getAttribute("src");
  118. if (src) {
  119. downloadFile(src);
  120. }
  121. }
  122. };
  123.  
  124. // Avvia l'osservazione del DOM ad intervalli regolari
  125. setInterval(() => {
  126. downloader.observeDom();
  127. }, 500);
  128.  
  129. })();