Greasy Fork

Greasy Fork is available in English.

聚合网页(美女图聚合展示演化而来)by SeLang

目标是聚合网页,省去翻页烦恼。有需要聚合的网址请反馈。 QQ群号:455809302,点击链接加入群【油猴脚本私人定制】:https://jq.qq.com/?_wv=1027&k=45p9bea

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         聚合网页(美女图聚合展示演化而来)by SeLang
// @namespace    http://cmsv1.findmd5.com/
// @version      0.09
// @description  目标是聚合网页,省去翻页烦恼。有需要聚合的网址请反馈。 QQ群号:455809302,点击链接加入群【油猴脚本私人定制】:https://jq.qq.com/?_wv=1027&k=45p9bea
// @author       selang
// @include      /https?\:\/\/*/
// @require      https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/ipfs/0.50.2/index.min.js
// @connect      *
// @grant        GM_download
// @grant        GM_openInTab
// @grant        GM_getTab
// @grant        GM_getTabs
// @grant        GM_saveTab
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        unsafeWindow
// ==/UserScript==

(async function () {
    if (window.top === window.self) {
        const NODE = await Ipfs.create(({repo: 'ipfs-monkey-aggregation'}));
        const RULE_CID_KEY = '聚合网页RULE_CID_KEY';
        const RULE_OFFICIAL_CID_KEY = '聚合网页OFFICIAL_RULE_CID_KEY';
        const AGGREGATION_TEMPLATE_HTML_KEY = "聚合网页OFFICIAL_AGGREGATION_TEMPLATE_HTML_KEY";
        const AGGREGATION_TEMPLATE_JS_KEY = "聚合网页OFFICIAL_AGGREGATION_TEMPLATE_JS_KEY";
        const AGGREGATION_TEMPLATE_CSS_KEY = "聚合网页OFFICIAL_AGGREGATION_TEMPLATE_CSS_KEY";
        const ENV_DEV_STATUS = 'DEV';
        const ENV_PRODUCT_STATUS = 'PRODUCT';
        const ENV_STATUS = ENV_PRODUCT_STATUS;

        //日志
        function log() {
            if (true) {
                console.log.apply(this, arguments);
            }
        };

        function err() {
            if (true) {
                console.error.apply(this, arguments);
            }
        }

        function priorityLog() {
            console.log.apply(this, arguments);
        }

        function getRuleCids() {
            let officialCIDValue = GM_getValue(RULE_OFFICIAL_CID_KEY);
            let value = GM_getValue(RULE_CID_KEY);
            if (value) {
                let parse = JSON.parse(value);
                if (officialCIDValue) {
                    return [officialCIDValue, ...parse];
                } else {
                    return parse;
                }
            }
            if (officialCIDValue) {
                return [officialCIDValue];
            } else {
                return [];
            }
        }

        function setRuleCids(key, value) {
            return GM_setValue(key, value);
        }

        function putCache(key, value) {
            return GM_setValue(key, value);
        }

        function getCache(key) {
            return GM_getValue(key);
        }

        const AsyncFunction = Object.getPrototypeOf(async function () {
        }).constructor;

        Array.prototype.distinct = function () {
            let arr = this;
            let result = [];
            let obj = {};

            for (let i of arr) {
                if (!obj[i]) {
                    result.push(i);
                    obj[i] = 1;
                }
            }
            return result;
        }

        const Alpha_Script = {
            sleep: function (time = 100) {
                return new Promise(resolve => {
                    setTimeout(function () {
                        resolve();
                    }, time);
                })
            },
            obtainHtmlAsync: function (options) {
                options = options || {};
                if (!options.url) {
                    throw new Error("参数不合法");
                }
                return new Promise(resolve => {
                    options.headers = {
                        ...Alpha_Script.parseHeaders("Accept:image/webp,image/*,*/*;q=0.8\n" +
                            "Accept-Encoding:gzip, deflate, sdch\n" +
                            "Accept-Language:zh-CN,zh;q=0.8\n" +
                            "Referer:" + window.location.href + "\n" +
                            `User-Agent:${window.navigator.userAgent}`
                        ), ...options.headers
                    };
                    options.method = options.method || 'GET';
                    let responseType = options.responseType;
                    switch (responseType) {
                        case "blob":
                            options.onload = options.onload || function (response) {
                                if (response && typeof response.status != "undefined") {
                                    let status = response.status;
                                    if (status >= 200 && status < 300) {
                                        resolve({status, response});
                                    } else if (status == 304) {
                                        resolve({status, response});
                                    }
                                }
                            }
                            break;
                        default:
                            options.onload = options.onload || function (response) {
                                if (response && typeof response.status != "undefined") {
                                    let status = response.status;
                                    if (status >= 200 && status < 300) {
                                        let html = response.responseText;
                                        resolve({status, response, html});
                                    } else if (status == 304) {
                                        resolve({status, response});
                                    }
                                }
                            }
                    }

                    GM_xmlhttpRequest(options);
                });
            },
            asyncPool: function (poolLimit, array, iteratorFn) {
                let i = 0;
                const ret = [];
                const executing = [];
                const enqueue = function () {
                    //Boundary processing, array is an empty array
                    if (i === array.length) {
                        return Promise.resolve();
                    }
                    //Initialize a promise every enqueue
                    const item = array[i];
                    const p = Promise.resolve(i).then((i) => iteratorFn(item, i, array));
                    i++;
                    //Put into promises array
                    ret.push(p);
                    //After the promise is executed, remove it from the executing array
                    const e = p.then(() => executing.splice(executing.indexOf(e), 1));
                    //Insert the executing number to indicate the executing promise
                    executing.push(e);
                    //Using promise.rece, whenever the number of promises in the executing array is less than poollimit, the new promise is instantiated and executed
                    let r = Promise.resolve();
                    if (executing.length >= poolLimit) {
                        r = Promise.race(executing);
                    }
                    //Recursion until array is traversed
                    return r.then(() => enqueue());
                };
                return enqueue().then(() => Promise.allSettled(ret));
            },
            obtainHtml: function (options) {
                options = options || {};
                if (!options.url || !options.method) {
                    throw new Error("参数不合法");
                }
                GM_xmlhttpRequest(options);
            },
            parseHeaders: function (headStr) {
                let o = {};
                let myregexp = /^([^:]+):(.*)$/img;
                let match = /^([^:]+):(.*)$/img.exec(headStr);
                while (match != null) {
                    o[match[1].trim()] = match[2].trim();
                    match = myregexp.exec(headStr);
                }
                return o;
            },
            //获取参数
            getParam: function (dest, name) {
                let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
                let r = dest.match(reg);
                if (r != null) return decodeURI(r[2]);
                return null;
            },
            isArray: function (value) {
                return Object.prototype.toString.apply(value) === '[object Array]';
            }
        };

        /**
         * 无变化则取缓存,有变化则缓存
         * @param cacheKey
         * @param options 数据结构里至少要有{url:'xx'}
         * @returns {Promise<*>}
         */
        async function obtainDataByUrl(cacheKey, options) {
            let ret = '';
            let cache = getCache(cacheKey);
            if (typeof cache != "undefined") {
                let {etag, html} = JSON.parse(cache);
                ret = html;
                if (typeof etag != 'undefined') {
                    let {status, html, response} = await Alpha_Script.obtainHtmlAsync({
                        ...options, headers: {
                            'If-None-Match': etag
                        }
                    });
                    if (status != 304) {
                        let etag = response.headers['etag'];
                        putCache(cacheKey, JSON.stringify({
                            etag, html
                        }))
                        ret = html;
                    }
                }
            } else {
                let {status, html, response} = await Alpha_Script.obtainHtmlAsync(options);
                let responseHeaders = Alpha_Script.parseHeaders(response.responseHeaders);
                let {etag} = responseHeaders;
                putCache(cacheKey, JSON.stringify({
                    etag, html
                }))
                ret = html;
            }
            return ret;
        };

        (function () {
            'use strict';
            priorityLog('欢迎进群:455809302交流。一起玩。');
            priorityLog('一起玩不论是不是技术人员都欢迎。只要有创意也欢迎加入。点击链接加入群【油猴脚本私人级别定制】:https://jq.qq.com/?_wv=1027&k=460soLy。');

            function validateUrl(url) {
                let validate = true;
                let lowerCaseUrl = url.toLowerCase();
                if (url.startsWith('#')) {
                    validate = false;
                } else if (lowerCaseUrl.startsWith('//')) {
                    url = `${window.location.protocol}${url}`;
                } else if (lowerCaseUrl.startsWith("/")) {
                    url = `${window.location.protocol}//${window.location.hostname}${url}`;
                } else if (lowerCaseUrl.startsWith('https://') || lowerCaseUrl.startsWith('http://')) {

                } else {
                    let prefixRegex = /(.*?\/)[^\/]*$/i;
                    let __matched = prefixRegex.exec(window.location.href);
                    if (__matched != null) {
                        url = `${__matched[1]}${url}`;
                    } else {
                        url = `${window.location.protocol}//${window.location.hostname}/${url}`;
                    }
                }

                return {validate, url};
            }

            async function parseNextPages(nextSelector = 'a:contains("下一页")') {
                let nextPages = [];
                let existNextPage = false;
                nextPages.push({
                    url: window.location.href,
                    html: $('html').prop("outerHTML")
                });
                let nextEs = $(nextSelector);
                log('解析下一页开始...');
                while (nextEs.length > 0) {
                    existNextPage = true;
                    let nextPageUrl = nextEs.attr('href');
                    let validateUrlResult = validateUrl(nextPageUrl);
                    if (!validateUrlResult.validate) {
                        break;
                    }
                    nextPageUrl = validateUrlResult.url;
                    log(nextPageUrl);
                    let {html} = await Alpha_Script.obtainHtmlAsync({url: nextPageUrl});
                    if (typeof html != "undefined") {
                        // console.log('nextPage Html==>', html);
                        let nextPageItem = {
                            url: nextPageUrl,
                            html
                        };
                        let duplicateNextPage = nextPages.filter(item => item.url == nextPageItem.url);
                        if (duplicateNextPage.length > 0) {
                            break
                        } else {
                            nextPages.push(nextPageItem);
                            let {$doc} = txt2Document(html);
                            nextEs = $doc.find(nextSelector);
                        }
                    } else {
                        console.log('nextPage 未获取到内容。nextPageUrl==>', nextPageUrl);
                        break;
                    }
                    // await Alpha_Script.sleep(1000);
                }
                log('解析下一页结束...');
                return {existNextPage, nextPages};
            }

            /**
             * 插件图片聚合例子
             * @param parseNextPages 解析下一页的公用方法
             * @param $  jquery
             * @param log 日志输出
             * @param Alpha_Script 公用对象
             * @returns {Promise<*[]>} 图片合集
             */
            async function example(parseNextPages, $, log, Alpha_Script) {
                //下一页css选择器
                let nextPageSelector = 'a:contains("下一页")';
                //要聚合的图片css选择器
                let imgSelector = 'img';
                let {existNextPage, nextPages} = await parseNextPages(nextPageSelector);
                if (existNextPage) {
                    nextPages.map(nextPage => {
                        let images = Array.from($($(nextPage.html)).find(imgSelector)).map(e => {
                            let src = e.src;
                            let dataOriginal = $(e).attr('data-original');
                            if (dataOriginal) {
                                src = dataOriginal;
                            }
                            return src;
                        });
                        nextPage.imgs = images;
                    });
                    let imgs = nextPages.flatMap(page => page.imgs);
                    return imgs;
                } else {
                    return [];
                }
            }

            /**
             * 校验cid是否符合rule
             * @param cid
             * @returns {Promise<{validate: boolean}|{date: *, parseRule: *, url: *, validate: boolean, desc: *}>}
             */
            async function parseRuleFromIPFS(cid) {
                const {date, desc, parseRule, url, pre, excludeWebsites} = (await NODE.dag.get(cid)).value;
                if (parseRule && url && desc && date) {
                    return {validate: true, date, desc, parseRule, url, pre, excludeWebsites};
                } else {
                    return {validate: false};
                }
            }

            /**
             * 获取cid下所有的规则
             * @param cid
             * @returns {Promise<[]>}
             */
            async function obtainRulesFromIPFS(cid) {
                let rules = [];
                let cids = [];
                while (true) {
                    try {
                        let rule = await parseRuleFromIPFS(cid);
                        if (rule.validate) {
                            rules.push(rule);
                            if (rule.pre) {
                                cid = rule.pre;
                                if (cids.includes(cid)) {
                                    err('闭环了');
                                    break;
                                } else {
                                    cids.push(cid);
                                }
                            } else {
                                break;
                            }
                        } else {
                            break;
                        }
                    } catch (e) {
                        err(e);
                        break;
                    }
                }
                return rules;
            }

            async function pluginExample() {
                //这里是一个插件的例子
                let cid = await NODE.dag.put(
                    {
                        url: '通用',
                        desc: '通用聚合',
                        parseRule: `return await (${example.toString()})(parseNextPages,$,log,Alpha_Script)`,
                        excludeWebsites: ['https://www.google.com.hk/search', 'http://greasyfork.icu/', 'https://xxxxx需要排除的网站'],
                        date: '2020年9月30日'
                    }
                );
                cid = await NODE.dag.put(
                    {
                        url: '这里可以写书写规则的网址',
                        desc: '第二个通用聚合',
                        parseRule: `return await (${example.toString()})(parseNextPages,$,log,Alpha_Script)`,
                        excludeWebsites: ['https://www.google.com.hk/search', 'http://greasyfork.icu/', 'https://xxxxx需要排除的网站'],
                        date: '2020年9月30日',
                        pre: cid.toString()
                    }
                );
                let cidStr = cid.toLocaleString();
                // cidStr = cid.toLocaleString();
                console.log('你的插件分享的地址为:', cidStr);
                return cidStr;
            }

            let isPageResLoadComplete = false;

            async function waitPageResLoadComplete() {
                for (; ;) {
                    if (isPageResLoadComplete) {
                        log('加载成功');
                        return;
                    } else {
                        await Alpha_Script.sleep(500);
                    }
                }
            }

            //热键
            function aggregationDisplaySwitchHotkeys() {
                $(document).keydown(function (e) {
                    if (e.ctrlKey && e.shiftKey) {
                        if (e.which == 76) {//L
                            log("触发快捷键");
                            aggregationDisplaySwitch();
                        }
                    }
                });
            }

            aggregationDisplaySwitchHotkeys();

            function aggregationDisplaySwitch() {
                let aggregationIFRAMEDisplayCss = $('#aggregationIFRAME').css('display');
                let aggregationIFRAMEDisplayCssCache = $('#aggregationIFRAME').attr('display-css-cache');
                if (aggregationIFRAMEDisplayCss != 'none') {
                    $('#aggregationIFRAME').css('display', 'none');

                    $('body').children().each(function (index, element) {
                        let displayCss = $(element).attr('display-css-cache');
                        if (element.id != 'aggregationIFRAME') {
                            $(element).css('display', displayCss);
                        }
                    });
                } else {
                    $('#aggregationIFRAME').css('display', aggregationIFRAMEDisplayCssCache);

                    $('body').children().each(function (index, element) {
                        if (element.id != 'aggregationIFRAME') {
                            $(element).css('display', 'none');
                        }
                    });
                }
            }

            window.addEventListener("message", async (event) => {
                let data = event.data;
                if (data.from == 'page') {
                    if (data.method == 'obtainHtmlAsync') {
                        let message = {result: '', from: 'monkey'};
                        try {
                            let {html} = await Alpha_Script.obtainHtmlAsync({url: data.url});
                            message.result = html;
                        } catch (e) {
                            message.error = e;
                        } finally {
                            event.ports[0].postMessage(message);
                        }
                    } else if (data.method == 'pageResLoadComplete') {
                        isPageResLoadComplete = true;
                        let message = {result: '', from: 'monkey'};
                        try {
                            let html = event.data;
                            log('html', html);
                            message.result = 'page收到::' + html;
                        } catch (e) {
                            message.error = e;
                        } finally {
                            event.ports[0].postMessage(message);
                        }
                    } else if (data.method == '聚合切换') {
                        aggregationDisplaySwitch();

                        let message = {result: '', from: 'monkey'};
                        try {
                            let html = event.data;
                            log('html', html);
                            message.result = 'page收到::' + html;
                        } catch (e) {
                            message.error = e;
                        } finally {
                            event.ports[0].postMessage(message);
                        }
                    }
                }
            }, false);

            function postMsg(msg) {
                return new Promise((res, rej) => {
                    const {port1, port2} = new MessageChannel();
                    port1.onmessage = ({data}) => {
                        if (data.from == 'page') {
                            port1.close();
                            if (data.error) {
                                rej(data);
                            } else {
                                res(data);
                            }
                        }
                    };
                    msg.from = 'monkey';
                    window.top.document.getElementById("aggregationIFRAME").contentWindow.postMessage(msg, window.location.origin, [port2]);
                });
            }

            function MIMEObjectURL(txt, contentType = "text/html; charset=UTF-8") {
                let txtBlob = new Blob([txt], {type: contentType});
                let txtBlobUrl = URL.createObjectURL(txtBlob);
                return txtBlobUrl;
            }

            function txt2Document(txt) {
                let parser = new DOMParser();
                let doc = parser.parseFromString(txt, "text/html");
                let $doc = $(doc);
                return {doc, $doc}
            }

            (async () => {
                // let cidStr = await pluginExample();
                await pluginExample();
                // 你自己写的或者他人分享的cidPath;
                let cidStr = "bafyreielhccxya5tbcqoqdfxfqcn7qukjed2jejnbeaffikxm7ssdano2i";
                setRuleCids(RULE_OFFICIAL_CID_KEY, cidStr);
                let ruleCids = getRuleCids();
                ruleCids.push(cidStr);
                let rules = [];
                for (const ruleCid of ruleCids) {
                    let rule = await obtainRulesFromIPFS(ruleCid);
                    rules = [...rules, ...rule];
                }
                log('当前规则总数:', rules.length);
                for (let rule of rules) {
                    log('当前执行规则>> %s 编写规则参考地址:%s\r\n 规则内容:%s', rule.desc, rule.url, rule.parseRule);
                    let excludeWebsites = rule.excludeWebsites;
                    if (Alpha_Script.isArray(excludeWebsites)) {
                        let findAnyOnes = excludeWebsites.filter(excludeWebsite => window.location.href.startsWith(excludeWebsite));
                        if (findAnyOnes.length > 0) {
                            log('当前规则被排除');
                            continue;
                        }
                    }
                    let ruleFunc = rule.parseRule;
                    let imgs = await (new AsyncFunction('parseNextPages', '$', 'log', 'Alpha_Script', ruleFunc))(parseNextPages, $, log, Alpha_Script);
                    imgs = imgs.distinct();
                    if (imgs.length > 0) {
                        log('规则找到图片');
                        let tempHost;
                        if (ENV_STATUS == ENV_DEV_STATUS) {
                            tempHost = 'http://127.0.0.1:8081';
                        } else {
                            tempHost = 'https://cmsv1.findmd5.com';
                        }
                        let aggregationTemplateHtml, aggregationTemplateCss, aggregationTemplateJs;
                        //国内IPFS不稳定,临时处理
                        if (true || ENV_STATUS == ENV_DEV_STATUS) {
                            aggregationTemplateHtml = await obtainDataByUrl(AGGREGATION_TEMPLATE_HTML_KEY, {url: `${tempHost}/static/imageAggregation/aggregationTemplate.html`});
                            aggregationTemplateCss = await obtainDataByUrl(AGGREGATION_TEMPLATE_CSS_KEY, {url: `${tempHost}/static/imageAggregation/css/aggregationTemplate.css`});
                            aggregationTemplateJs = await obtainDataByUrl(AGGREGATION_TEMPLATE_JS_KEY, {url: `${tempHost}/static/imageAggregation/js/aggregationTemplate.js`});
                        } else {
                            let aggregationTemplateHtmlCid, aggregationTemplateJsCid, aggregationTemplateCssCid;
                            aggregationTemplateHtmlCid = 'bafyreicncdsi25po7rij4oh355v7w7fjfu3da4ncpkxp2gwwoxucb5ulri';
                            aggregationTemplateJsCid = 'bafyreiblvxkpjinurhnxgwznsgmtap37vmd7l3cvbcqf3wul4ll2bb7fmy';
                            aggregationTemplateCssCid = 'bafyreihws6twoxkhqoc3klnm3lucsamss3bki4akrpnwexp6u5m5thzpva';
                            aggregationTemplateHtml = (await NODE.dag.get(aggregationTemplateHtmlCid)).value.data;
                            aggregationTemplateCss = (await NODE.dag.get(aggregationTemplateCssCid)).value.data;
                            aggregationTemplateJs = (await NODE.dag.get(aggregationTemplateJsCid)).value.data;
                        }


                        {
                            let cid = await NODE.dag.put(
                                {
                                    data: aggregationTemplateHtml,
                                    desc: 'aggregationTemplate.html',
                                }
                            );
                            log('aggregationTemplate.html cid: ', cid.toString());
                            cid = await NODE.dag.put(
                                {
                                    data: aggregationTemplateJs,
                                    desc: 'aggregationTemplate.js',
                                }
                            );
                            log('aggregationTemplate.js cid: ', cid.toString());
                            cid = await NODE.dag.put(
                                {
                                    data: aggregationTemplateCss,
                                    desc: 'aggregationTemplate.css',
                                }
                            );
                            log('aggregationTemplate.css cid: ', cid.toString());
                        }

                        if (ENV_STATUS == ENV_DEV_STATUS) {
                            console.log('aggregationTemplateHtml', aggregationTemplateHtml);
                            console.log('aggregationTemplateCss', aggregationTemplateCss);
                            console.log('aggregationTemplateJs', aggregationTemplateJs);
                        }


                        let aggregationTemplateCssBlobUrl = MIMEObjectURL(aggregationTemplateCss, 'text/css; charset=utf-8');
                        let aggregationTemplateJsBlobUrl = MIMEObjectURL(aggregationTemplateJs, 'application/javascript; charset=utf-8');

                        {
                            let {doc, $doc} = txt2Document(aggregationTemplateHtml);
                            $doc.find('head').append(`<link rel="stylesheet" href="${aggregationTemplateCssBlobUrl}"/>`);
                            $doc.find('body').append(`<script src="${aggregationTemplateJsBlobUrl}"></script>`);

                            let outerHTML = doc.querySelector('html').outerHTML;
                            aggregationTemplateHtml = outerHTML;
                        }
                        if (ENV_STATUS == ENV_DEV_STATUS) {
                            console.log('final aggregationTemplateHtml', aggregationTemplateHtml);
                        }

                        let aggregationTemplateHtmlBlobUrl = MIMEObjectURL(aggregationTemplateHtml);

                        $('body').append(`<iframe id="aggregationIFRAME" src="${aggregationTemplateHtmlBlobUrl}" frameborder="0" scrolling="no" width="100%"></iframe>`);
                        await waitPageResLoadComplete();

                        $('body').children().each(function (index, element) {
                            let displayCss = $(element).css('display');
                            $(element).attr('display-css-cache', displayCss);
                            if (element.id != 'aggregationIFRAME') {
                                $(element).css('display', 'none');
                            }
                        });

                        let promiseAllResult = await Alpha_Script.asyncPool(10, imgs, async function (src, i) {
                            let blob = await downloadImg2Blob(src);
                            let url = URL.createObjectURL(blob);
                            // $(`#c_${i}`).append(`<img src="${src}" onload="loadHidden(this)"/>`);
                            return {url, blob};
                        });
                        let imgBlobSrcs = promiseAllResult.filter(p => p.status == 'fulfilled').map(p => p.value);
                        await postMsg({method: 'images', result: imgBlobSrcs});
                        log('规则执行完毕');
                        break;
                        // await Alpha_Script.sleep(5000);
                    }
                }

                log('执行完毕');
            })();

            async function downloadImg2Blob(imgSrc) {
                let {response} = await Alpha_Script.obtainHtmlAsync({
                    url: imgSrc,
                    method: 'GET',
                    headers: {
                        "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
                        // "Accept-Encoding": "gzip, deflate, sdch",
                        // "Accept-Language": "zh-CN,zh;q=0.8",
                        "Referer": window.location.href,
                        "User-Agent": window.navigator.userAgent
                    },
                    responseType: 'blob'
                });
                let responseHeaders = Alpha_Script.parseHeaders(response.responseHeaders);
                let contentType = responseHeaders['content-type'];
                if (!contentType) {
                    contentType = "image/png";
                }
                let blob = new Blob([response.response], {type: contentType});
                return blob;
            }

            async function loadHidden(e) {
                let {height, width} = await imageWidth(e);
                if (!(height > 500 && width > 500)) {
                    e.style.display = 'none';
                }
            }

            function getImageWidth(url) {
                let img = new Image();
                img.src = url;
                return imageWidth(img);
            }

            function imageWidth(img) {
                return new Promise(resolve => {
                    // 如果图片被缓存,则直接返回缓存数据
                    if (img.complete) {
                        resolve(img);
                    } else {
                        // 完全加载完毕的事件
                        img.onload = function () {
                            resolve(img);
                        }
                    }

                });
            }

            GM_registerMenuCommand("规则列表", ruleListFunc, "R");

            function ruleListFunc() {
                let ruleCids = getRuleCids();
                let delBtn = '<button type="button" class=" btn-sm btn-warning">\n' +
                    '                删除\n' +
                    '            </button>';
                let inject = ruleCids.map(ruleCid => `<div><span>${ruleCid}</span><span>${delBtn}</span></div>`).join("<br/>");
                $('script').remove();
                $('head').append('<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootswatch/4.3.1/cerulean/bootstrap.min.css"/>');
                $('body').html(inject);
                $('body').append('<script src="https://cdn.staticfile.org/jquery/1.12.4/jquery.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>');
            }
        })();
    }
})
();