您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Download photos and videos from Threads quickly and easily!
当前为
- // ==UserScript==
- // @name Threads Video Downloader
- // @namespace https://github.com/ManoloZocco/Threads-video-downloader-userscript
- // @version 1.3
- // @description Download photos and videos from Threads quickly and easily!
- // @author P0L1T3 aka Manolo Zocco
- // @match https://*.threads.net/*
- // @connect threads.net
- // @connect www.threads.net
- // @grant GM_download
- // @grant GM_addStyle
- // @run-at document-end
- // @license MIT
- // ==/UserScript==
- (function() {
- 'use strict';
- // Inserisce il CSS per il pulsante di download (da css/interface.css)
- GM_addStyle(`
- .dw {
- position: absolute;
- z-index: 5;
- width: 116px;
- height: 34px;
- border-radius: 8px;
- background: rgba(0, 0, 0, 0.6);
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
- display: none;
- flex-direction: row;
- justify-content: space-around;
- align-items: center;
- cursor: pointer;
- margin: 7px;
- border: none;
- color: #FFF;
- font-size: 11px;
- font-weight: 600;
- text-transform: uppercase;
- line-height: 22px;
- letter-spacing: -0.42px;
- bottom: 7px;
- left: 7px;
- }
- .dw .icon {
- 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");
- width: 20px;
- height: 20px;
- margin-right: 5px;
- }
- *:hover > .dw {
- display: flex;
- }
- .dw:hover {
- background: rgba(0, 0, 0, 0.8);
- }
- `);
- // Funzione di download basata su GM_download
- function downloadFile(url) {
- if (!url) return;
- let fileName = url.substring(url.lastIndexOf('/') + 1);
- if (!fileName) fileName = 'download';
- GM_download({
- url: url,
- name: fileName,
- onerror: function(err) {
- console.error('Download error:', err);
- }
- });
- }
- // Oggetto che gestisce l'osservazione del DOM e l'iniezione dei pulsanti
- const downloader = {
- observeDom() {
- // Gestione dei video
- document.querySelectorAll("video").forEach((video) => {
- let container = downloader.findRoot(video);
- if (container && !container.querySelector(".dw")) {
- container.append(downloader.getBtn(video.currentSrc || video.src));
- }
- });
- // Gestione delle immagini
- document.querySelectorAll("img").forEach((img) => {
- if (img.width < 200 || img.height < 200) return;
- if (img.parentElement && img.parentElement.querySelector(".dw")) return;
- img.parentElement.prepend(downloader.getBtn(img.src));
- });
- },
- // Crea il pulsante di download
- getBtn(src) {
- const btn = document.createElement("button");
- btn.innerText = "Download";
- btn.className = "dw";
- const icon = document.createElement("span");
- icon.className = "icon";
- btn.appendChild(icon);
- btn.setAttribute("src", src);
- btn.addEventListener("click", downloader.dw);
- return btn;
- },
- // Risale la gerarchia DOM per trovare un container (div con data-visualcompletion)
- findRoot(element) {
- let parent = element.parentNode;
- if (!parent) return null;
- let found = parent.querySelector("div[data-visualcompletion]");
- return found || downloader.findRoot(parent);
- },
- // Gestore dell'evento click sul pulsante
- dw(event) {
- event.preventDefault();
- event.stopPropagation();
- let target = event.target.nodeName.toLowerCase() === "button" ? event.target : event.target.parentElement;
- let src = target.getAttribute("src");
- if (src) {
- downloadFile(src);
- }
- }
- };
- // Avvia l'osservazione del DOM ad intervalli regolari
- setInterval(() => {
- downloader.observeDom();
- }, 500);
- })();