QQ群相册批量下载

自动点击QQ群相册的下载功能,实现所有的群相册的批量下载

// ==UserScript==
// @name         QQ群相册批量下载
// @namespace    http://lvshuncai.com
// @homepage     https://github.com/ShunCai/QQ-Group-Albums-Downloader
// @version      1.1
// @description  自动点击QQ群相册的下载功能,实现所有的群相册的批量下载
// @author       芷炫
// @match        https://h5.qzone.qq.com/groupphoto/index?inqq=*&groupId=*
// @match        https://h5.qzone.qq.com/groupphoto/album?inqq=*&groupId=*
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    // 获取查询参数
    var getQueryString = function(name) {
        let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
        let r = window.location.search.substring(1).match(reg);
        if (r != null) {
            return decodeURI(r[2]);
        };
        return null;
    }

    // 延迟函数
    var delay = milliseconds => new Promise(resolve => {
        setTimeout(resolve, milliseconds);
    });

    // 上传相片按钮
    let $uploadBtn = document.querySelector('#js_pic_upload_btn,#js-header-upload')
    if (!$uploadBtn) {
        return;
    }

    // 替换文件名称的特殊字符
    const replaceFileName = name => {
        return name.replace(/'|#|~|&| |!|\\|\/|:|\?|"|<|>|\*|\|/g, "_");
    }

    // 下载文件
    const download = async(downloadBtn, albums) => {
        for (let i = 0; i < albums.length; i++) {
            const ablum = albums[i];
            // 创建A标签
            const downLink = document.createElement('a');
            downLink.download = replaceFileName(ablum.title) + '.zip';
            downLink.href = ablum.downloadUrl.replace('http:', 'https:');
            downLink.style.display = 'none';
            document.body.append(downLink);

            // 模拟点击
            downLink.click();

            // Chrome requires the timeout
            await delay(1000);

            // 移除A标签
            downLink.remove();

            downloadBtn.innerText = '已下载' + (i + 1) + '/' + albums.length;
        }
    }

    // 迅雷下载
    const invokeThunder = async albums => {
        // 迅雷下载任务
        const thunderTask = [];
        for (const album of albums) {
            thunderTask.push({
                name: replaceFileName(album.title) + '.zip',
                url: album.downloadUrl
            })
        }

        // 迅雷下载信息
        const thunderInfo = {
            taskGroupName: 'QQ群相册_' + getQueryString('groupId'),
            hideYunPan: '0',
            referer: 'https://h5.qzone.qq.com/',
            tasks: thunderTask
        }

        await copyToClipboard('thunderx://' + JSON.stringify(thunderInfo));
    }

    // 复制文本到剪切板
    const copyToClipboard = async text => {
        // 创建text area
        let textArea = document.createElement("textarea");
        textArea.value = text;
        // 使text area不在viewport,同时设置不可见
        textArea.style.position = "absolute";
        textArea.style.opacity = 0;
        textArea.style.left = "-999999px";
        textArea.style.top = "-999999px";
        document.body.appendChild(textArea);
        textArea.focus();
        textArea.select();

        // 执行复制命令并移除文本框
        let res = document.execCommand('copy');
        if (res) {

            // Chrome requires the timeout
            await delay(1000);

            textArea.remove();
        }
    }

    // 复制相册下载地址
    const copyAlbumUrls = async albums => {
        const urls = [];
        for (const album of albums) {
            urls.push(album.downloadUrl);
        }
        await copyToClipboard(urls.join('\n'));
    }

    // 获取下载URL
    var getDownloadUrl = async album => {
        // 请求地址参数
        const urlParmas = new URLSearchParams();
        urlParmas.append('g_tk', PSY.user.token());
        urlParmas.append('qzonetoken', window.g_qzonetoken);
        // 请求实体参数
        const bodyParmas = new URLSearchParams();
        bodyParmas.append('uin', PSY.user.getLoginUin());
        bodyParmas.append('hostUin', -1);
        bodyParmas.append('inCharset', 'utf-8');
        bodyParmas.append('outCharset', 'utf-8');
        bodyParmas.append('refer', 'refer');
        bodyParmas.append('source', 'qzone');
        bodyParmas.append('platform', 'qzone');
        bodyParmas.append('format', 'json');
        bodyParmas.append('appid', 422);
        bodyParmas.append('selectMode', 1);
        bodyParmas.append('albumid', album.id);
        bodyParmas.append('hostid', getQueryString('groupId'));
        bodyParmas.append('albumName', album.title);
        const response = await fetch('https://h5.qzone.qq.com/proxy/domain/app.photo.qq.com/cgi-bin/app/cgi_arch_photo_v2?' + urlParmas.toString(), {
            method: 'POST',
            body: bodyParmas
        });
        return await response.json();
    }

    // 相册每页条目数
    const ALBUMNS_PAGE_SIZE = 1000;

    // 获取相册信息
    const getAlbumInfo = async(page) => {
        const parmas = new URLSearchParams();
        parmas.append('g_tk', PSY.user.token());
        parmas.append('qzonetoken', window.g_qzonetoken);
        parmas.append('qunId', getQueryString('groupId'));
        parmas.append('uin', PSY.user.getLoginUin());
        parmas.append('start', page * ALBUMNS_PAGE_SIZE);
        parmas.append('num', ALBUMNS_PAGE_SIZE);
        parmas.append('format', 'json');
        parmas.append('inCharset', 'utf-8');
        parmas.append('outCharset', 'utf-8');
        parmas.append('platform', 'qzone');
        parmas.append('source', 'qzone');
        parmas.append('cmd', 'qunGetAlbumList');
        const response = await fetch('https://h5.qzone.qq.com/proxy/domain/u.photo.qzone.qq.com/cgi-bin/upp/qun_list_album_v2?' + parmas.toString());
        return await response.json();
    }

    // 获取相册信息
    const getAlbumList = async() => {
        window.albums = [];

        // 获取第一页相册 
        const albumInfo = await getAlbumInfo(0);
        window.albums.push(...albumInfo.data.album || []);

        // 相册个数
        const total = albumInfo.data.total;
        if (total > ALBUMNS_PAGE_SIZE) {
            for (let page = 1; page * ALBUMNS_PAGE_SIZE < total; page++) {
                const pageAlbumInfo = await getAlbumInfo(page);
                window.albums.push(...pageAlbumInfo.data.album || []);
                await delay(1500);
            }
        }

        return window.albums;
    }

    // 获取相册下载链接
    const getDownloadLinks = async albums => {
        for (const album of albums) {

            // 获取相册下载地址
            const downloadInfo = await getDownloadUrl(album);
            album.downloadUrl = downloadInfo.data.downloadUrl;

            // 延迟
            await delay(1000);
        }
    }

    // 批量下载
    const $downloadBtn = document.createElement('a');
    $downloadBtn.innerText = '批量下载';
    $downloadBtn.setAttribute('class', 'mod-btn-upload');
    $downloadBtn.setAttribute('title', '直接通过浏览器自身下载全部相册,相册过多时,下载容易出错,建议自行复制链接到第三方工具下载');
    $downloadBtn.style.cssText = "background-color: #dd905b;border-color: #dd905b;margin-left: 10px;";
    $downloadBtn.addEventListener("click", async function() {

        // 获取相册列表
        if (!window.albums) {
            this.innerText = '正在读取相册下载链接...';
            window.albums = await getAlbumList();
            await getDownloadLinks(window.albums);
        }

        this.innerText = '正在下载';

        // 浏览器下载
        await download(this, albums);

        this.innerText = '下载完成';

        setTimeout(() => {
            this.innerText = '批量下载';
        }, 3000);
    })
    $uploadBtn.parentElement.appendChild($downloadBtn);

    // 迅雷下载
    const $thunderBtn = document.createElement('a');
    $thunderBtn.innerText = '迅雷下载';
    $thunderBtn.setAttribute('title', '需先安装迅雷,并打开迅雷,以及打开剪切板监听,或直接复制链接到迅雷下载');
    $thunderBtn.setAttribute('class', 'mod-btn-upload');
    $thunderBtn.style.cssText = "background-color: #5b63dd;border-color: #5b63dd;margin-left: 10px;";
    $thunderBtn.addEventListener("click", async function() {

        // 获取相册列表
        if (!window.albums) {
            this.innerText = '正在读取相册下载链接...';
            window.albums = await getAlbumList();
            await getDownloadLinks(window.albums);
        }

        this.innerText = '正在触发迅雷';

        // 迅雷下载
        await invokeThunder(albums);

        this.innerText = '已触发,若未下载,请打开迅雷后重试';

        setTimeout(() => {
            this.innerText = '迅雷下载';
        }, 3000);
    })
    $uploadBtn.parentElement.appendChild($thunderBtn);

    // 复制链接
    const $copyLinks = document.createElement('a');
    $copyLinks.innerText = '复制链接';
    $copyLinks.setAttribute('title', '复制下载链接到剪切板,可以自行到迅雷、IDM等第三方工具下载,建议尽快下载,避免存在有效期');
    $copyLinks.setAttribute('class', 'mod-btn-upload');
    $copyLinks.style.cssText = "background-color: #5bdd6b;border-color: #5bdd6b;margin-left: 10px;";
    $copyLinks.addEventListener("click", async function() {

        // 获取相册列表
        if (!window.albums) {
            this.innerText = '正在读取相册下载链接...';
            window.albums = await getAlbumList();
            await getDownloadLinks(window.albums);
        }

        this.innerText = '正在复制';

        // 复制到剪切板
        await copyAlbumUrls(albums);

        this.innerText = '复制完成';

        setTimeout(() => {
            this.innerText = '复制链接';
        }, 3000);
    })
    $uploadBtn.parentElement.appendChild($copyLinks);

})();

QingJ © 2025

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