Greasy Fork

Greasy Fork is available in English.

批量保存Telegram用户头像

提取blob URL 中的 UUID 作为文件名批量下载头像,默认保存格式为jpg

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         批量保存Telegram用户头像
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  提取blob URL 中的 UUID 作为文件名批量下载头像,默认保存格式为jpg
// @author       GR:PM
// @license      MIT
// @match        https://web.telegram.org/k/*
// @grant        none
// ==/UserScript==

(function () {
    "use strict";

    // 创建控制按钮
    function createUI() {
        const container = document.createElement("div");
        container.style.cssText =
            "position:fixed; bottom:20px; right:20px; z-index:9999; display:flex; flex-direction:column; gap:10px;";

        const autoBtn = document.createElement("button");
        autoBtn.innerText = "⚡ 自动加载并下载全部头像";
        styleButton(autoBtn, "#ff8c00");

        autoBtn.onclick = startAutoProcess;

        container.appendChild(autoBtn);
        document.body.appendChild(container);
    }

    function styleButton(btn, color) {
        btn.style.cssText = `
            padding: 12px 20px;
            background-color: ${color};
            color: white;
            border: none;
            border-radius: 8px;
            cursor: pointer;
            box-shadow: 0 4px 12px rgba(0,0,0,0.2);
            font-weight: bold;
            transition: transform 0.2s;
        `;
        btn.onmouseover = () => (btn.style.transform = "scale(1.05)");
        btn.onmouseout = () => (btn.style.transform = "scale(1)");
    }

    // 等待函数
    const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

    // 核心流程:自动翻页 -> 等待加载 -> 下载
    async function startAutoProcess() {
        console.log("开始自动执行...");

        let nextButton = document.querySelector(".profile-avatars-arrow-next");

        // 1. 循环点击“下一步”直到按钮消失或不可点击
        while (
            nextButton &&
            getComputedStyle(nextButton).display !== "none" &&
            getComputedStyle(nextButton).visibility !== "hidden"
        ) {
            nextButton.click();
            // 稍微等待动画和加载,300ms 是一个比较稳妥的值
            await sleep(300);

            // 重新获取按钮状态
            nextButton = document.querySelector(".profile-avatars-arrow-next");

            // 检查是否还有未加载的 hide 元素
            const hiddenAvatars = document.querySelectorAll(
                ".profile-avatars-avatar.hide",
            );
            if (hiddenAvatars.length === 0) break;
        }

        console.log("翻页完成,等待最终资源同步...");
        await sleep(1000); // 给 Blob 生成留一点最后的时间

        // 2. 执行下载
        downloadAll();
    }

    function downloadAll() {
        const avatarImages = document.querySelectorAll(
            ".profile-avatars-avatars .avatar-photo",
        );

        if (avatarImages.length === 0) {
            alert("未找到可下载的头像图片。");
            return;
        }

        console.log(`准备下载 ${avatarImages.length} 张头像...`);

        avatarImages.forEach((img, index) => {
            const src = img.src;
            if (!src || !src.startsWith("blob:")) return;

            const uuid = src.split("/").pop();
            const fileName = `${uuid}.jpg`;

            const link = document.createElement("a");
            link.href = src;
            link.download = fileName;

            // 批量下载间隔,防止浏览器崩溃
            setTimeout(() => {
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                console.log(
                    `[${index + 1}/${avatarImages.length}] 已保存: ${fileName}`,
                );
            }, index * 200);
        });

        console.log(`完成。`)
    }

    createUI();
})();