Threads Video Downloader

Download photos and videos from Threads quickly and easily!

目前为 2025-02-13 提交的版本。查看 最新版本

// ==UserScript==
// @name         Threads Video Downloader
// @namespace    https://github.com/ManoloZocco/Threads-video-downloader-userscript
// @version      1.3.1
// @description  Download photos and videos from Threads quickly and easily!
// @author       P0L1T3 aka Manolo Zocco
// @match        https://*.threads.net/*
// @connect      *
// @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);

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址