Greasy Fork is available in English.

QQ空间相册下载神器

批量下载小姐姐空间高清大图照片佳选插件~自动命名快速汲取dalao灵感~(bug反馈联系 snomiao@gmail.com ) 注:使用 chrome 的用户也可以考虑 QQ空间导出助手 插件

// ==UserScript==
// @name         QQ空间相册下载神器
// @name:zh      [雪星实验室] QQ空间相册下载神器
// @namespace    https://userscript.snomiao.com/
// @version      0.4.0
// @description  批量下载小姐姐空间高清大图照片佳选插件~自动命名快速汲取dalao灵感~(bug反馈联系 snomiao@gmail.com )  注:使用 chrome 的用户也可以考虑 QQ空间导出助手 插件
// @author       snomiao@gmail.com
// @match        *://user.qzone.qq.com/*
// @match        *://*.photo.store.qq.com/*
// @match        *://*.qpic.cn/*
// @grant        none
// ==/UserScript==
//
// 注:使用 chrome 用户也可以考虑 QQ空间导出助手
// https://chrome.google.com/webstore/detail/qq%E7%A9%BA%E9%97%B4%E5%AF%BC%E5%87%BA%E5%8A%A9%E6%89%8B/aofadimegphfgllgjblddapiaojbglhf
//
// 更新:(20210228) 0.4.0 修复史前照片下载
// 更新:(20200518) 0.3.0 还是弹吧……(因为 IFRAME 没法监控状态可能会漏照片、用 xhr 和 fetch 会有跨域问题)
// 更新:(20200501) 0.2.0 改进下载逻辑,不再弹出窗口
//
(() => {
    var 下载 = (url, filename = '') => {
        var a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = filename;
        document.body.appendChild(a);
        a.click();
        a.remove();
    };
    var 响应被下载 = () => {
        var m = decodeURI(location.hash).match(/(?<=#下载-).*/);
        if (!m) return null;
        var filename = m[0];
        下载(location.href, filename);
        (opener || parent).postMessage(
            '下载完成-' + location.href,
            'https://user.qzone.qq.com'
        );
        window.close();
    };
    var 智能下载 = (url, filename = '') => {
        var 当页域名 = location.hostname;
        var 同源 = !!url.match(':/' + 当页域名 + '/');
        if (同源) return 下载(url, filename);
        if ('打开新页面') {
            // 或打开新页面
            var src = url + '#下载-' + encodeURI(filename);
            window.open(src, '_BLANK');
            return;
        }
        if ('使用IFRAME下载') {
            // 否则使用 iframe // iframe会漏照片……闲了再调试好了。。
            window.addEventListener(
                'message',
                (e) => {
                    var m = e.data && e.data.match(/(?<=下载完成-)(.*)/);
                    if (!m) return;
                    let url = m[0];
                    // console.debug("删除iframe",e.origin, url);
                    // e.origin ignore
                    [...document.querySelectorAll('iframe')]
                        .filter((e) => e.src == url)
                        .forEach((e) => {
                            // console.debug("删除了iframe",e.src, e);
                            e.remove();
                        });
                },
                false
            );
            document.body.appendChild(
                新元素('<iframe style="visibility: hidden"></iframe>', {
                    src: url + '#下载-' + encodeURI(filename),
                })
            );
        }
    };
    /* 一些常见源地址类型
    photogz.photo.store.qq.com
    http://b${数字}.photo.store.qq.com/psu // 比较早期的
    */
    var 高清地址を取 = (src) => {
        if (src.match(/\/\/b\d+\.photo\.store\.qq\.com\//)) {
            return src
                .replace('http:', 'https:')
                .replace(/\/\/.*?\//, '//r.photo.store.qq.com/')
                .replace(/null&.*$/, '')
                .replace(/\/(?:m|b)(\/|$)/, '/b$1') //高清(一些早期照片没有原图)
                .replace(/&(?:w|h)=\d+/, '');
        } else {
            return src
                .replace('http:', 'https:')
                .replace(/\/\/.*?\//, '//r.photo.store.qq.com/')
                .replace(/null&.*$/, '')
                .replace(/\/(?:m|b)(\/|$)/, '/r$1') //原图
                .replace(/&(?:w|h)=\d+/, '');
        }
    };

    var 试取内容 = (e) => e?.textContent?.trim() || '';
    var 照片列を取 = () => {
        var 相册名 = 试取内容(document.querySelector('.j-pl-albuminfo-title'));
        return [...document.querySelectorAll('.j-pl-photoitem,.j-box-img')].map(
            (e, i) => ({
                src: e.querySelector('.j-pl-photoitem-img,.j-img').src,
                url: 高清地址を取(
                    e.querySelector('.j-pl-photoitem-img,.j-img').src
                ),
                filename:
                    (
                        相册名 +
                        '-' +
                        // (1 + i) + '-' +
                        试取内容(
                            e.querySelector('.j-pl-photoitem-title,span[title]')
                        ) +
                        '-' +
                        试取内容(
                            e.querySelector('.j-pl-photoitem-desc,j-photo-desc')
                        )
                    )
                        .replace(/\/|\?|\*|\:|\||\\|\<|\>|\r|\n/, '_')
                        .substr(0, 50) + '.jpg',
            })
        );
    };
    var 下载当页 = (globalThis.下载当页 = () => {
        const 试取列 = 照片列を取();
        const 列有效 = 试取列.every(({ src }) => src);
        if (列有效)
            return 照片列を取().forEach(({ url, filename }) =>
                智能下载(url, filename)
            );
        // 自动滚动重试
        window.parent.scrollBy(0, window.innerHeight);
        window.scrollBy(0, window.innerHeight);
        setTimeout(下载当页, 200);
    });
    // UI
    var 新元素 = (innerHTML, attributes = {}) => {
        var e = document.createElement('div');
        e.innerHTML = innerHTML;
        return Object.assign(e.children[0], attributes);
    };
    var 生成下载界面 = () => {
        // “更多”按钮前插入一个按钮
        var 下载按钮 = 新元素('<div></div>', {
            className: 'photo-op-item photos-download',
            innerHTML:
                '<a class="c-tx2 bg3 bor gb-btn-nor" href="javascript:globalThis.下载当页()">下载当页</a>',
            title: '请滚动到底以确保当前页面所有照片都已加载',
            //onclick: 下载当页,
        });
        [
            ...document.querySelectorAll('.photo-op-item.photos-download'),
        ].forEach((e) => e.remove());
        var 更多按钮 = document.querySelector('.photo-op-item.j-pl-moreop');
        更多按钮 && 更多按钮.parentNode.insertBefore(下载按钮, 更多按钮);
    };

    // 被下载
    if (
        location.host.match(/.*\.photo\.store\.qq\.com/) ||
        location.host.match(/.*\.qpic\.cn/)
    )
        响应被下载();

    // 相册页面
    if (location.hostname == 'user.qzone.qq.com')
        window.addEventListener('load', 生成下载界面, false), 生成下载界面();
})();