怠惰聚圖&下載

自定義規則,透過CSS/XPath選擇器,定位圈選出要下載的DOM image對象,進行下載壓縮打包,也能聚集所有圖片到當前頁面裡。

От 08.04.2023. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

You will need to install an extension such as Tampermonkey to install this script.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name               怠惰聚圖&下載
// @name:zh-CN         怠惰聚图&下载
// @name:zh-TW         怠惰聚圖&下載
// @version            0.2
// @description        自定義規則,透過CSS/XPath選擇器,定位圈選出要下載的DOM image對象,進行下載壓縮打包,也能聚集所有圖片到當前頁面裡。
// @description:zh-CN  自定义规则,透过CSS/XPath选择器,定位圈选出要下载的DOM image对象,进行下载压缩打包,也能聚集所有图片到当前页面里。
// @description:zh-TW  自定義規則,透過CSS/XPath選擇器,定位圈選出要下載的DOM image對象,進行下載壓縮打包,也能聚集所有圖片到當前頁面裡。
// @author             tony0809
// @match              *://*/*
// @exclude            *hcaptcha*
// @exclude            *iframe*
// @exclude            *addthis*
// @exclude            *youtube*
// @exclude            *google*
// @icon               data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAtFBMVEVEREAAAABEREBEREAuuaIzqpkvr58yiHgzhnY6kYM7mYI4kog4s6A2tpo0r544ooo2nY40sJw0sp00rZg1sJw0sZ0zsp01sZw0sZw0rZk1sJw1sZw1rZk0sp00rpk1sp01sZs1rpk1rpk0sp01spw1sJ00rZo1rZk1rpo0r5k0sJw0sZ01r5o0sZw0rpk0sp01sZ01sJw1spw1r5k1sp01sZw0sZ01sZw1rpk1sp01sZw1r5pUzpTcAAAAOXRSTlMAAAUGCw8QERIUFxgbHB0hIieqq6yvtLa3vb/AwMHCxMXFxsfIyc3Oz+zt7vDx8fL4+Pn5+vr7/v7AEFI4AAABR0lEQVR42qWT11bDMAxApbhsmm5KKVD2KiUQwpD1///FkZcSmh4e8FOsex3LsgymPy6ISkRyA4FlWMRXomIyQOg/SbyKAmSOE2Ip02UOYxf/DILNjOOEWLnAEAqio0MMAzJjTAZh1p0SrYCIuu0cMZc9JbENXLa1NWGdI1nWeQuXGPzBTdzC8ws52UI5MwchrA/VTOuTEP9fFyTG7E+R9q8JLsbW1UHzU8HHrCuU1fyToDlB43xRqMUgfc+/KA77fZrWSH/47zPlzOcpJxG8u32r/OEg5SRCqO/WTeT3+5oTuP4LxrXnd5F7waZ+wM5c+NVeujMRrDYMYueE+VK5E5r3uzOb7TbvHH7f/1pP/L8nU9u38Nwyy8OZdjfwY+ZnmPinp28y3mglNeERDJYy/9A3GYVS+GMPMB+uyL67/qO68Mb8MurBD7foVTtvIbtnAAAAAElFTkSuQmCC
// @license            MIT
// @namespace          https://greasyfork.org/users/20361
// @grant              GM_xmlhttpRequest
// @grant              GM.xmlHttpRequest
// @grant              unsafeWindow
// @require            https://cdn.jsdelivr.net/npm/[email protected]/dist/jszip.min.js
// ==/UserScript==

(async () => {
    "use strict";
    const options = { //true 開啟,false 關閉
        enable: 0, //0為白名單模式根據自訂義規則啟用,1為全局啟用
        one: false, //單線程下載
        default: "img[src]" //預設CSS/Xpath選擇器/javascript代碼
        //default: "js;return [...document.images];"
    };
    const siteUrl = location.href;
    let siteData = {};
    let globalImgArray = [];
    let customTitle = null;
    //自定義站點規則
    const customData = [{
        name: "小黃書/8色人體攝影 xchina.co/8se.me",//按數字鍵1、Enter插入圖片,按0、Enter、Enter壓縮打包下載
        reg: /(xchina|8se)\.(co|me)\/photo\/id/, //網址正則匹配
        imgs: "js;let numP=fun.geT('div[target][title]').match(/\\d+/)[0];let max=Math.ceil(numP/18);return fun.getImg('img.cr_only',max,2,['_600x0','']);",
        insertImg: "//div[div[@class='photos']]", //清空元素內容把所有圖片插入到此元素
        customTitle: "let s=document.title.split('-');let title='';if(/未分/.test(s[1])){title+=s[0].trim()}else{title+=s[1].trim()+' - ';title+=s[0].trim()}return title;",
        css: "body{overflow:unset!important}.photos>div.item,.jquery-modal.blocker.current,.slider-ad,.article.ad,.pager>.tips,body>footer~*:not([id^='pv-']):not([class^='pv-']):not(.pagetual_tipsWords):not(.customPicDownloadMsg):not(#customPicDownload),.photoMask,.banner_ad{display: none!important;}",
        category: "nsfw2"
    }, {
        name: "Women Legs Gallery - www.nlegs.com", //專用下載腳本https://greasyfork.org/scripts/463123
        enable: 0, //0該站禁用
        reg: /www\.nlegs\.com\/girls\//,
        imgs: "img[src^=blob]",
        category: "nsfw1"
    }, {
        name: "Hit-x-Hot www.hitxhot.org",
        reg: /(www\.)?hitxhot\.(com|org)\/gallerys\/.+\.html/,
        imgs: "js;let max=fun.geT('h1').match(/\\d+$/)[0];return fun.getImg('.contentme img',max);",
        insertImg: ".contentme",
        customTitle: "return document.title.split('|')[0].slice(10).trim()",
        category: "nsfw2"
    }, {
        name: "秀人集 www.xiuren5.com",
        reg: /www\.xiuren\d+\.com\/\w+\/\d+\.html/i,
        imgs: "js;let max=fun.geT('.page a:last-child',2);return fun.getImg('.content>p img[alt]',max,3);",
        insertImg: "//div[p[img[@alt and @title]]]",
        customTitle: "return fun.geT('.item_title>h1');",
        category: "nsfw1"
    }, {
        name: "HotAsiaGirl hotgirl.asia 分頁模式",
        reg: /hotgirl\.asia\/.+\//,
        include: ".galeria_img",
        imgs: "js;if(fun.ge('.CustomPictureDownloadImage')){return [...fun.gae('.CustomPictureDownloadImage')]}else{return fun.getImgP('.galeria_img>img','.pagination a[href]')}",
        insertImg: ".main-content",
        customTitle: "return fun.geT('h3');",
        category: "nsfw2"
    }, {
        name: "HotAsiaGirl hotgirl.asia 幻燈片模式",
        reg: /hotgirl\.asia\/.+\//,
        include: "#carouselImageIndicators",
        imgs: "js;if(fun.ge('.CustomPictureDownloadImage')){return[...fun.gae('.CustomPictureDownloadImage')]}else{return[...fun.gae('#carouselImageIndicators img')]}",
        insertImg: ".main-content",
        customTitle: "return fun.geT('h3');",
        category: "nsfw2"
    }, {
        name: "MrCong.com",
        reg: /mrcong\.com\/.+\//,
        imgs: "js;let max=fun.geT('.page-link>*:last-child');return fun.getImg('.entry img[decoding]',max,4)",
        insertImg: "//p[img[@decoding]]",
        customTitle: "return fun.geT('h1');",
        category: "nsfw1"
    }, {
        name: "萌图社 www.446m.com",
        reg: /www\.\d+m\.com\/index\.php\/\w+\/\d+\.html/,
        imgs: ".post-item .img",
        customTitle: "return document.title.slice(0,-6)",
        category: "nsfw1"
    }, {
        name: "秀色女神 www.xsnvshen.co", //需搭配東方永頁機大圖規則
        reg: /www\.xsnvshen\.co\/album\/\d+/,
        imgs: ".longConWhite>img",
        customTitle: "return fun.geT('h1')",
        category: "nsfw1"
    }, {
        name: "Everia.club",
        reg: /everia\.club/,
        imgs: ".wp-block-image img",
        customTitle: "return fun.geT('h1')",
        category: "nsfw2"
    }, {
        name: "NongMo.Zone www.ilovexs.com",
        reg: /www\.ilovexs\.com\/post_id\/\d+\//,
        imgs: ".separator img",
        customTitle: "return fun.geT('h1')",
        category: "nsfw2"
    }, {
        name: "凸凹吧/撸女吧/女优吧/撸哥吧/欲女吧 www.tuao.one,www.63mm.cc,www.97mm.cc,www.luge8.co,luge8.co",
        reg: /(www\.)?(tuao8?|tumm|\d+mm|luge8?)\.[a-z]{2,3}\/(post|web)\//,
        imgs: "js;let max=fun.geT('.next-page',2);return fun.getImg('.entry img[title]',max);",
        customTitle: "return fun.geT('h1.title');",
        category: "nsfw2"
    }, {
        name: "Asian To Lick asiantolick.com",
        reg: /asiantolick\.com\/post/,
        imgs: "js;let arr=[];[...fun.gae('div[data-src]')].forEach(e=>{arr.push(e.dataset.src)});return arr;",
        insertImg: ".spotlight-group",
        customTitle: "return fun.geT('h1');",
        category: "nsfw2"
    }, {
        name: "goddess247.com",
        reg: /goddess247\.com\/.+\//,
        imgs: ".elementor-widget-container p img[alt]",
        customTitle: "return fun.title('-');",
        category: "nsfw1"
    }, {
        name: "www.4kup.net",
        reg: /www\.4kup\.net\/.+\.html/,
        imgs: "js;let arr=[];[...fun.gae('a.thumb-photo')].forEach(a=>{arr.push(a.href)});return arr;",
        insertImg: "#gallery",
        customTitle: "return fun.geT('h1');",
        next: ".next-page",
        category: "nsfw2"
    }, {
        name: "牛C网导航|就爱你导航 niuc2.com",
        reg: /niuc2\.com\/\d+\.html/,
        imgs: "js;let max=fun.geT('.page-nav>*:last-child',3);return fun.getImg(\"[class*='wp-image']\",max,5);",
        insertImg: "//p[a[img[@decoding]]]",
        customTitle: "return document.title.split('|')[0].trim()",
        css: ".post-apd{display: none!important;}",
        category: "nsfw2"
    }, {
        name: "H漫畫貼圖 - 7mmtv.sx",
        reg: /7mmtv\.sx\/.*hcomic/,
        imgs: "js;return Large_cgurl;",
        customTitle: "return fun.title('-');",
        category: "hcomic"
    }, {
        name: "嗨皮漫畫 m.happymh.com",
        reg: /m\.happymh\.com\/reads/,
        imgs: "js;let lps=location.pathname.split('/'),mangaCode=lps[2],id=lps[3],apiUrl=`https://m.happymh.com/v2.0/apis/manga/read?code=${mangaCode}&cid=${id}`;return fetch(apiUrl).then(res=>res.text()).then(res=>{let jsonData=JSON.parse(res);let srcs=jsonData.data.scans;let arr=[];for(let i in srcs){arr.push(srcs[i].url)}return arr});",
        customTitle: "let lps=location.pathname.split('/'),mangaCode=lps[2],id=lps[3],apiUrl=`https://m.happymh.com/v2.0/apis/manga/read?code=${mangaCode}&cid=${id}`;return fetch(apiUrl).then(res=>res.text()).then(res=>{let jsonData=JSON.parse(res);return jsonData.data.manga_name+' - '+jsonData.data.chapter_name});",
        insertImg: "//article[div[contains(@id,'imageLoader')]]",
        next: "//a[span[text()='下一話' or text()='下一话']]",
        category: "comic"
    }, {
        name: "COLAMANHUA www.colamanhua.com", //下載不了...Picviewer CE+可以
        enable: 0,
        reg: /www\.colamanhua\.com\/manga-.+\.html$/,
        imgs: ".mh_comicpic img[src^=blob]",
        one: true,
        category: "comic"
    }, {
        name: "8Comic無限動漫 www.comicabc.com",
        reg: /(a|www)\.(comicabc|twobili)\.com\/(ReadComic|online)/,
        imgs: "js;let code=[...document.scripts].find(s=>s.innerHTML.search(/ge\\(e\\)/)>-1).innerHTML;let cM=code.match(/ge\\([^.]+\\.src\\s?=\\s?([^;]+)/);let keyCode=cM[1];let arr=[];for(let i=1;i<=ps;i++){let r='('+i+')';let src='https:'+fun.run(keyCode.replace(/\\(pp?\\)/g,r));arr.push(src)}return arr;",
        customTitle: "let t=document.title.split(' ')[0];return`${t}-第${ch}集`;",
        next: "//button[text()='下一集']",
        category: "comic"
    }, {
        name: "8Comic無限動漫手機版 m.comicbus.com",
        reg: /8\.twobili\.com\/comic\/insurance/,
        imgs: "js;let arr=[];for(let i=1;i<=ps;i++){let imgSrc='https://img'+ss(c,4,2)+'.8comic.com/'+ss(c,6,1)+'/'+ti+'/'+ss(c,0,4)+'/'+nn([i])+'_'+ss(c,mm([i])+10,3,f)+'.jpg';arr.push(imgSrc)}return arr;",
        customTitle: "let t=document.title.split(' ')[0];let n=fun.geT('#chapter');return t+' - '+n;",
        next: "#nextvol",
        category: "comic"
    }, {
        name: "DM5/極速 分頁模式 www.dm5.com",
        reg: /(www|tel|en|cnc|hk|m)?\.?(dm5|1kkk)\.(com|cn)\/(m|ch|vol|other)[-_0-9]+\//,
        include: "#chapterpager",
        imgs: "js;let get=async()=>{if(!mkey){var mkey=''}let arr=[];for(let i=1;i<=DM5_IMAGE_COUNT;i++){fun.show(`獲取資料中(${i}/${DM5_IMAGE_COUNT})`);let apiUrl=location.origin+DM5_CURL+'chapterfun.ashx'+`?cid=${DM5_CID}&page=${i}&key=${mkey}&language=1>k=6&_cid=${DM5_CID}&_mid=${DM5_MID}&_dt=${DM5_VIEWSIGN_DT}&_sign=${DM5_VIEWSIGN}`,res=await fetch(apiUrl),resText=await res.text(),src=await fun.run(resText)[0];arr.push(src)}return arr};return get();",
        insertImg: "#cp_img",
        customTitle: "return fun.title('_', 2);",
        next: "//a[text()='下一章']",
        category: "comic"
    }, {
        name: "DM5/極速 條漫模式 https://www.dm5.com/manhua-moutianchengweimoshen/",
        reg: /(www|tel|en|cnc|hk|m)?\.?(dm5|1kkk)\.(com|cn)\/(m|ch|vol|other)[-_0-9]+\//,
        include: "#barChapter",
        imgs: "#barChapter>img",
        customTitle: "return fun.title('_', 2);",
        next: "//a[text()='下一章']",
        category: "comic"
    }, {
        name: "DM5/極速 手機版 m.dm5.com",
        reg: /(www|tel|en|cnc|hk|m)?\.?(dm5|1kkk)\.(com|cn)\/(m|ch|vol|other)[-_0-9]+\//,
        include: "//script[contains(text(),'newImgs')]",
        imgs: "js;return newImgs",
        insertImg: "#cp_img", //清空元素內容把所有圖片插入到此元素
        customTitle: "return fun.title('_', 2);",
        next: "//a[text()='下一章']",
        category: "comic"
    }];
    const fun = {
        ge: (e, d) => {
            if (/^\//.test(e)) {
                return (d || document).evaluate(e, (d || document), null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
            } else {
                return (d || document).querySelector(e);
            }
        },
        gae: (e, d) => {
            if (/^\//.test(e)) {
                let nodes = [];
                let results = (d || document).evaluate(e, (d || document), null, XPathResult.ANY_TYPE, null);
                let node;
                while (node = results.iterateNext()) {
                    nodes.push(node);
                }
                return nodes;
            } else {
                return (d || document).querySelectorAll(e);
            }
        },
        geT: (ele, mode = 1) => {
            if (mode == 1) {
                return fun.ge(ele).innerText;
            } else if (mode == 2) {
                return fun.ge(ele).previousElementSibling.innerText;
            } else if (mode == 3) {
                return fun.ge(ele).previousElementSibling.previousElementSibling.innerText;
            }
        },
        run: code => new Function("return " + code)(),
        html: str => new DOMParser().parseFromString(str, 'text/html'),
        title: (str, mode = 1) => {
            let s = document.title.split(str);
            if (mode == 1) {
                return s[0].replace(/,$/, '').trim();
            } else if (mode == 2) {
                return s[0] + str + s[1].replace(/,$/, '').trim();
            }
            return '參數錯誤';
        },
        show: text => {
            let msg = fun.ge(".customPicDownloadMsg");
            if (fun.ge(".customPicDownloadMsg[style]")) {
                msg.removeAttribute('style');
            }
            msg.innerText = text;
        },
        checkDataset: img => {
            if (img.tagName == "IMG" || img.tagName == "DIV") {
                const setArr = ["data-src", "data-original", "data-url", "data-thumb", "data-lazy-src", "data-lazyload", "data-lazyload-src"];
                //for (let i in setArr) {
                for (let i = 0; i < setArr.length; i++) {
                    let imgSrc = img.getAttribute(setArr[i]);
                    if (imgSrc) {
                        return {
                            ok: true,
                            src: imgSrc
                        };
                    }
                }
            }
            return {
                ok: false
            };
        },
        getImg: async (img, maxPage = 1, mode = 1, rText = [null, null]) => {
            fun.show("獲取元素中");
            let imgsArray = [];
            let html = url => fetch(url).then(res => res.text());
            let resArr = [];
            resArr.push(html(siteUrl));
            if (maxPage > 1) {
                for (let i = 2; i <= maxPage; i++) {
                    if (mode == 1) {
                        //.html => .html?page=2 第二頁
                        resArr.push(html(siteUrl + "?page=" + i));
                    } else if (mode == 2) {
                        //.html ==> /2.html 第二頁
                        resArr.push(html(siteUrl.slice(0, -5) + '/' + i + '.html'));
                    } else if (mode == 3) {
                        //.html ==> _1.html  第二頁
                        resArr.push(html(siteUrl.slice(0, -5) + '_' + (i -1) + '.html'));
                    } else if (mode == 4) {
                        //【/ ==> /2/】  第二頁
                        resArr.push(html(siteUrl.slice(0, -1) + '/' + i + '/'));
                    } else if (mode == 5) {
                        //.html ==> -2.html  第二頁
                        resArr.push(html(siteUrl.slice(0, -5) + '-' + i + '.html'));
                    }
                }
            }
            await Promise.all(resArr).then((htmls) => {
                for (let i = 0; i < htmls.length; i++) {
                    let doc = fun.html(htmls[i]);
                    let imgs = [...fun.gae(img, doc)];
                    for (let i = 0; i < imgs.length; i++) {
                        if (rText[0]) {
                            imgs[i].src = imgs[i].src.replace(rText[0], rText[1]);
                        }
                        imgsArray.push(imgs[i]);
                    }
                }
            });
            imgsArray = imgsArray.filter(i => i);
            //imgsArray = imgsArray.filter(i => i.tagName == "IMG");
            return imgsArray;
        },
        getImgP: async (img, paginationA, rText = [null, null] ) => {//從頁碼條抓鏈接
            fun.show("獲取元素中");
            let imgsArray = [];
            let html = url => fetch(url).then(res => res.text());
            let resArr = [];
            resArr.push(html(siteUrl));
            let links = fun.gae(paginationA);
            for (let i = 0; i < links.length; i++) {
                resArr.push(html(links[i].href));
            }
            await Promise.all(resArr).then((htmls) => {
                for (let i = 0; i < htmls.length; i++) {
                    let doc = fun.html(htmls[i]);
                    debug("getImgP DOM", doc);
                    let imgs = [...fun.gae(img, doc)];
                    for (let i = 0; i < imgs.length; i++) {
                        if (rText[0]) {
                            imgs[i].src = imgs[i].src.replace(rText[0], rText[1]);
                        }
                        imgsArray.push(imgs[i]);
                    }
                }
            });
            imgsArray = imgsArray.filter(i => i);
            return imgsArray;
        },
        insertImg: (imgsArray, ele) => {
            let srcArr = [];
            //for (let i in imgsArray) {
            for (let i = 0; i < imgsArray.length; i++) {
                let imgSrc;
                let check = fun.checkDataset(imgsArray[i]);
                if (imgsArray[i].tagName == 'IMG' && check.ok) {
                    srcArr.push(check.src);
                } else if (imgsArray[i].tagName == 'IMG') {
                    srcArr.push(imgsArray[i].src);
                } else if (/^http/.test(imgsArray[i])) {
                    srcArr.push(imgsArray[i]);
                } else {
                    debug("insertImg格式錯誤!", imgsArray[i]);
                    return;
                }
            }
            let fragment = new DocumentFragment();
            //for (let i in srcArr) {
            for (let i = 0; i < srcArr.length; i++) {
                let img = new Image();
                img.className = "CustomPictureDownloadImage";
                img.src = srcArr[i];
                fragment.appendChild(img);
            }
            let E = fun.ge(ele);
            if (E) {
                E.innerHTML = "";
                E.appendChild(fragment);
            } else {
                debug("用來定位插入的元素不存在");
            }
        },
        css: css => {
            let style = document.createElement("style");
            style.type = "text/css";
            style.id = "CustomPictureDownloadStyle";
            style.innerHTML = css;
            document.head.appendChild(style);
        }
    };
    const debug = (str, obj = "", title = "debug") => {
        console.log(
            `%c[Custom Picture Download] ${title}:`,
            'background-color: #C9FFC9;',
            str, obj
        );
    };
    let nsfw1Data = customData.filter(item => item.category == "nsfw1"); //列出寫真站
    let nsfw2Data = customData.filter(item => item.category == "nsfw2"); //列出老司機站
    let comicData = customData.filter(item => item.category == "comic"); //列出普漫站
    let hcomicData = customData.filter(item => item.category == "hcomic"); //列出H漫站
    let noneData = customData.filter(item => item.category == "none"); //列出未分類
    //for (let i in customData) {
    for (let i = 0; i < customData.length; i++) {
        if (customData[i].reg.test(siteUrl)) {
            options.enable = 1;
            if (customData[i].enable == 0) {
                options.enable = 0;
                debug("禁用");
                return;
            }
            if (customData[i].imgs) {
                options.default = customData[i].imgs;
                debug(`CSS/Xpath/JS選擇器:${options.default}`);
            }
            if (customData[i].one) {
                options.one = customData[i].one;
                debug("單線程下載");
            }
            let titleCode = customData[i].customTitle;
            if (titleCode) {
                customTitle = await new Function("fun", '"use strict";' + titleCode)(fun);
                debug(`自定義標題:${customTitle}`);
            }
            let include = customData[i].include;
            if (include) {
                if (!fun.ge(include)) {
                    options.enable = 0;
                    console.clear();
                    debug("頁面沒有包含必須元素,跳出本次循環繼續遍歷");
                    continue;
                }
            }
            let exclude = customData[i].exclude;
            if (exclude) {
                if (fun.ge(exclude)) {
                    options.enable = 0;
                    console.clear();
                    debug("頁面包含排除元素,跳出本次循環繼續遍歷");
                    continue;
                }
            }
            let next = customData[i].next;
            if (next) {
                document.addEventListener('keydown', (event) => {
                    let key = window.event ? event.keyCode : event.which;
                    if (key == 39) {
                        let n = fun.ge(next);
                        if (n) n.click();
                    }
                });
            }
            let css = customData[i].css;
            if (css) {
                fun.css(css);
            }
            siteData = customData[i];
            break;
        }
    }
    if (siteData.reg) {
        debug("列出寫真站", nsfw1Data);
        debug("列出老司機站", nsfw2Data);
        debug("列出普漫站", comicData);
        debug("列出H漫站", hcomicData);
        debug("列出未分類", noneData);
        debug("全局此站資料", siteData);
    }
    let promiseBlobArray = [];
    let downloadNum = 0;
    var _GM_xmlhttpRequest;
    if (typeof GM_xmlhttpRequest != "undefined") {
        _GM_xmlhttpRequest = GM_xmlhttpRequest;
    } else if (typeof GM != "undefined" && typeof GM.xmlHttpRequest != "undefined") {
        _GM_xmlhttpRequest = GM.xmlHttpRequest;
    }

    const ge = css => document.querySelector(css);
    const gae = css => document.querySelectorAll(css);
    const gx = xpath => document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
    const gax = xpath => {
        let nodes = [];
        let results = document.evaluate(xpath, document, null, XPathResult.ANY_TYPE, null);
        let node;
        while (node = results.iterateNext()) {
            nodes.push(node);
        }
        return nodes;
    };

    const getNum = (i) => {
        let n = parseInt(i) + 1;
        let picNum = n;
        if (i < 9) {
            picNum = "000" + n;
        } else if (i < 99) {
            picNum = "00" + n;
        } else if (i < 999) {
            picNum = "0" + n;
        }
        return picNum;
    };

    const showMsg = (text, time = 1000) => {
        ge(".customPicDownloadMsg").removeAttribute("style");
        ge(".customPicDownloadMsg").innerText = text;
        setTimeout(() => {
            ge(".customPicDownloadMsg").innerText = "none";
            ge(".customPicDownloadMsg").style = "display:none";
        }, time);
    };

    const checkDataset = (img) => {
        if (img.tagName == 'IMG') {
            const setArr = ["data-src", "data-original", "data-url", "data-thumb", "data-lazy-src", "data-lazyload", "data-lazyload-src"];
            //for (let i in setArr) {
            for (let i = 0; i < setArr.length; i++) {
                let imgSrc = img.getAttribute(setArr[i]);
                if (imgSrc) {
                    return {
                        ok: true,
                        src: imgSrc
                    };
                }
            }

        }
        return {
            ok: false
        };
    };

    const getData = (srcUrl, picNum, imgsNum) => {
        return new Promise((resolve) => {
            const getMsg = (text) => {
                downloadNum += 1;
                ge(".customPicDownloadMsg").innerText = `第${downloadNum}/${imgsNum}張下載${text}`;
            };
            _GM_xmlhttpRequest({
                method: "GET",
                url: srcUrl,
                responseType: "blob",
                headers: {
                    referer: location.origin + "/"
                },
                onload: (data) => {
                    let blob = data.response;
                    if (/^image/.test(blob.type)) {
                        resolve({
                            blob: blob,
                            picNum: picNum
                        });
                        getMsg("完成");
                    } else {
                        resolve({
                            error: "下載錯誤",
                            picNum: picNum,
                            src: srcUrl,
                            blob: blob
                        });
                        getMsg("錯誤");
                    }
                },
                onerror: (error) => {
                    resolve({
                        error: "下載錯誤",
                        picNum: picNum,
                        src: srcUrl
                    });
                    getMsg("錯誤");
                }
            });
        });
    };

    const imgZipDownload = async () => {
        if (/\d+/.test(ge(".customPicDownloadMsg").innerText)) {
            alert("下載&壓縮中請勿重複操作!");
            return;
        }
        let selector = await prompt("請輸入自訂CSS/Xpath選擇器:\n範例:img#TheImg OR //img[@id='TheImg']\n也能使用JS代碼自己生成的IMG元素陣列\n範例:js;return [...document.images];", options.default);
        let imgs;
        if (!selector || selector === "") {
            showMsg("已取消");
            return;
        } else if (selector.length < 3) {
            showMsg("字數小於3已取消");
            return;
        } else if (/^js;/.test(selector)) {
            imgs = await new Function("fun", '"use strict";' + selector.slice(3))(fun);
            debug("JSimgs:", imgs);
        } else if (/^\//.test(selector)) {
            imgs = [...gax(selector)];
        } else {
            imgs = [...gae(selector)];
        }
        imgs = imgs.filter(item => item); //去除空、無用、重複
        globalImgArray = imgs;
        let titleText = await prompt("請輸入自訂壓縮檔資料夾名稱", (customTitle || document.title));
        if (imgs[0] && titleText != null && titleText != "") {
            debug("imgZipDownload():", imgs);
            const imgsNum = imgs.length;
            let title = titleText;
            const zip = new JSZip();
            const zipFolder = zip.folder(`${title} [${imgsNum}P]`);
            ge(".customPicDownloadMsg").removeAttribute("style");
            ge(".customPicDownloadMsg").innerText = "0101010101...";
            //for (let i in imgs) {
            for (let i = 0; i < imgs.length; i++) {
                let n = parseInt(i) + 1;
                let picNum = getNum(i);
                let promiseBlob;
                let imgSrc;
                let check = fun.checkDataset(imgs[i]);
                if (imgs[i].tagName == 'IMG' && check.ok) {
                    imgSrc = check.src;
                } else if (imgs[i].tagName == 'IMG') {
                    imgSrc = imgs[i].src;
                } else if (/^http/.test(imgs[i])) {
                    imgSrc = imgs[i];
                } else {
                    debug("格式錯誤!", imgs[i]);
                    continue;
                }
                if (options.one) {
                    promiseBlob = await getData(imgSrc, picNum, imgsNum);
                } else {
                    promiseBlob = getData(imgSrc, picNum, imgsNum);
                }
                promiseBlobArray.push(promiseBlob);
            }
            debug("PromiseBlobArray:", promiseBlobArray);

            Promise.all(promiseBlobArray).then((data) => {
                debug("PromiseAllData:", data);
                let blobDataArray = data.filter(item => item.blob); //成功下載
                let errorDataArray = data.filter(item => item.error); //下載錯誤
                debug("NewDataArray:", blobDataArray);
                debug("ErrorDataArray:", errorDataArray);
                if (blobDataArray[0]) {
                    //for (let i in blobDataArray) {
                    for (let i = 0; i < blobDataArray.length; i++) {
                        let n = parseInt(i) + 1;
                        let ex = blobDataArray[i].blob.type.split("/")[1];
                        let fileName = `${blobDataArray[i].picNum}P.${ex}`;
                        //console.log(`第${n}/${blobDataArray.length}張,檔案名:${fileName},大小:${parseInt(blobDataArray[i].blob.size / 1024)} Kb`);
                        zipFolder.file(fileName, blobDataArray[i].blob, {
                            binary: true
                        });
                    }
                    zip.generateAsync({
                        type: "blob"
                    }, (metadata) => {
                        ge(".customPicDownloadMsg").innerText = "壓縮進度: " + metadata.percent.toFixed(2) + " %";
                    }).then(data => {
                        promiseBlobArray = [];
                        downloadNum = 0;
                        debug("ZIP壓縮檔數據:", data);
                        ge(".customPicDownloadMsg").innerText = "none";
                        ge(".customPicDownloadMsg").style = "display:none";
                        let a = document.createElement("a");
                        a.href = URL.createObjectURL(data);
                        a.download = `${title} [${imgsNum}P].zip`;
                        document.body.appendChild(a);
                        a.click();
                        a.remove();
                        URL.revokeObjectURL(data);
                    });
                } else {
                    promiseBlobArray = [];
                    downloadNum = 0;
                    showMsg("下載失敗數據為空...");
                }
            });
        } else {
            showMsg("無圖或壓縮檔名稱為null", 3000);
        }
    };

    const copyImgSrcText = async () => {
        let selector = await prompt("請輸入自訂CSS/Xpath選擇器:\n範例:img#TheImg OR //img[@id='TheImg']\n也能使用JS代碼自己生成的IMG元素陣列\n範例:js;return [...document.images];", options.default);
        let imgs;
        let imgSrcArray = [];
        if (!selector || selector === "") {
            showMsg("已取消");
            return;
        } else if (selector.length < 3) {
            showMsg("字數小於3已取消");
            return;
        } else if (/^js;/.test(selector)) {
            imgs = await new Function("fun", '"use strict";' + selector.slice(3))(fun);
            debug("JSimgs:", imgs);
        } else if (/^\//.test(selector)) {
            imgs = [...gax(selector)];
        } else {
            imgs = [...gae(selector)];
        }
        imgs = imgs.filter(item => item); //去除空、無用、重複
        if (siteData.insertImg) {
            debug("insertImg():", imgs);
        } else {
            debug("CopyImgSrcText():", imgs);
        }
        if (imgs[0]) {
            //for (let i in imgs) {
            for (let i = 0; i < imgs.length; i++) {
                let imgSrc;
                let check = fun.checkDataset(imgs[i]);
                if (imgs[i].tagName == 'IMG' && check.ok) {
                    imgSrc = check.src;
                } else if (imgs[i].tagName == 'IMG') {
                    imgSrc = imgs[i].src;
                } else if (/^http/.test(imgs[i])) {
                    imgSrcArray = [...imgs].filter(item => item);
                    break;
                } else {
                    debug("格式錯誤!", imgs[i]);
                    continue;
                }
                imgSrcArray.push(imgSrc);
            }
        } else {
            showMsg("沒有任何圖片元素...");
            return;
        }
        globalImgArray = imgSrcArray;
        if (siteData.insertImg) {
            fun.insertImg(globalImgArray, siteData.insertImg);
            showMsg("已插入全部圖片");
            return;
            /*
            let yes = confirm("已經插入所有圖片了,還要將網址複製到剪貼簿嗎?");
            if (!yes) {
                showMsg("已取消");
                return;
            }*/
        }
        imgSrcArray.push(customTitle || document.title);
        debug("imgSrcArray:", imgSrcArray);
        let str = imgSrcArray.join("\n");
        console.log(str);
        copyToClipboard(str);
        showMsg(`圖片網址已複製(${imgs.length})`);
        imgSrcArray = null;
    };

    const copyToClipboard = (textToCopy) => {
        if (navigator.clipboard && window.isSecureContext) {
            return navigator.clipboard.writeText(textToCopy);
        } else {
            let textArea = document.createElement("textarea");
            textArea.value = textToCopy;
            textArea.style.position = "absolute";
            textArea.style.opacity = 0;
            textArea.style.left = "-999999px";
            textArea.style.top = "-999999px";
            document.body.appendChild(textArea);
            textArea.focus();
            textArea.select();
            return new Promise((res, rej) => {
                document.execCommand('copy') ? res() : rej();
                textArea.remove();
            });
        }
    };
    const oneSwitch = () => {
        if (options.one) {
            options.one = false;
            showMsg("啟用多線程");
        } else {
            options.one = true;
            showMsg("啟用單線程");
        }
    };

    const addCustomPicDownloadButton = () => {
        let img = new Image();
        img.id = "customPicDownload";
        img.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACFlBMVEVEREAAAABEREBEREBUXnFTXXBTXG5VXXJUXHFUW28grV0grV0hrl4hrV0hq10iql0oomAhrV2BiZiAiJd/h5V+h5Uiq16OlaKNlKGMk5+Mkp+KkZ89p28nq2Hp9+/n9u3t8PHs7/Dg9Ojp7O3d8+bo7O3o6+zn6+3m6uzl6evX8OLV8OHi5ujh5efO7dze4uTe4ePb3+LY3eDX29/W2t7T19u35Mu25Mr01lqw4sbz1Vmv4sXA1NWs4cPw0lnv0lmp4MCk3r3ozVuh3buu0M6vz83kylugysefycadx8OexsOdxsOF0qZ6zp5pyJK1p2S0pmOsoGRWv4SLlKEmuZpBsnc5t3AmuJmQi2ont5kmtpcptJiOiWg0tWwytGorr5Yqr5YsrpUws2kqrJRNmpMusmcsqpIuqJMssWkqsWQqsGUnsGUzoI8lsGGAf2wkr2Ekr2BzfI0irl8hrl5ye4x9fGogrWAhrV03mIwgrF9xeoshq10gql8dp2ccp2cdpmkcnIUanIYcm4QRoIUTnoURn4QdmYM/h4QcmIMSnYMXmoMWmoIbloIclYJDgYIYl4EaloAek4IfkYFqbm0jjoBqbW0ni4ApiX9Hd35kanBjaXBhaG9MbnpOanhOaXhPaHdDbXZHanZGanRLZnZJZ3RSYnVMZXRPY3ROY3VSYXRQYnRTYHRVX3NUX3RSYHNUXnNTXXJTXXFME6frAAAAHnRSTlMAAAUGZ2dqeHh7lrzNzc7O3O/09PT19fn5+fn5/f4hZOrvAAAB1UlEQVR42oWTzYoTQRSFv6q6RqOoqBicTTCKK1cOURBGBV9AXCgu9Vl8FF/ApcshI4qKgrtBByZK0HSGmMxkMrF/qq6LTjptErGX5zu3uu65dY3TYCh9ag2UNPsfjnmpZW4MgBbaIy/6PCnxvL7gEQhJ7AruAqifcZ96EHDX67ngKgCJn/k3B6AC1O9Cj9ri/2mBsZIf9iLi0rMFDhhjbO6NsL9er+CQG3pYMT+XuGVmuH9SzPF7S/UONDfUHl44/6A24wfdpMgsSO6tP52ffxjF6cUT056MBdxf/cVRzP6PiQG8KhZMJedhewik0QT43RsBQUEwLufZx53Td85p7wCwEu+Fs6qAGBsA1aO3XUZbG/EAsAJJlM/MGgOoDltdYNTam3JIOlVmOaj2N/sAjHf9lGdBqwACmmi0FU/TOWxfEY483o/9tcuvJBXU+90PaZHf5NtVFzTL+N7bqD4GS9DRmzl3btJWk2WFIKradqX8LfudU3VKBuKd0vwc+HCjNDJhkJXfB6jq+wZJBSAT5MmKN1/la7sJ+jmsiyQrdkZo9N819FNnXcSZFTt1rGnXhl/G6a26IP/YOXczi5prQmFY3snbkzNSXGyBV+28p+nNF+vn2h97PvHD5SOHkgAAAABJRU5ErkJggg==";
        img.setAttribute("title", "左鍵:進行下載打包壓縮\n中鍵:切換單多線程\n右鍵:複製圖片網址和標題或插入所有圖片");
        img.oncontextmenu = () => false;
        img.addEventListener("click", () => {
            imgZipDownload();
        });
        img.addEventListener("mousedown", (event) => {
            if (event.button == 1) {
                event.preventDefault();
                oneSwitch();
            }
            if (event.button == 2) {
                copyImgSrcText();
            }
        });
        document.body.appendChild(img);
    };

    const addCustomPicDownloadMsg = () => {
        let div = document.createElement("div");
        div.className = "customPicDownloadMsg";
        div.style = "display:none";
        div.innerText = "none";
        document.body.appendChild(div);
    };

    const addGlobalStyle = css => {
        let style = document.createElement("style");
        style.type = "text/css";
        style.innerHTML = css;
        document.head.appendChild(style);
    };

    const css = `
#customPicDownload {
    width: 32px!important;
    height: 32px!important;
    position: fixed!important;
    bottom: 20px!important;
    left: 20px!important;
    z-index:2147483647;
    opacity: 0.8!important;
}
.customPicDownloadMsg {
    font-family: Arial,sans-serif!important;
    font-size: 26px;
    font-weight: bold;
    text-align: center;
    line-height: 50px;
    color: #ffffff;
    width: 280px;
    height: 50px;
    top: 30%;
    left: 50%;
    margin-left: -140px;
    background-color: #000;
    border: 1px solid #303030;
    border-radius: 10px;
    position: fixed;
    z-index:2147483647;
    opacity: 0.7;
}
.CustomPictureDownloadImage {
    width: auto !important;
    height: auto !important;
    max-width: 100% !important;
    display: block !important;
    margin: 0 auto !important
}
    `;

    if (options.enable == 1) {
        addCustomPicDownloadButton();
        addCustomPicDownloadMsg();
        addGlobalStyle(css);
        document.addEventListener('keydown', (e) => {
            switch (e.keyCode) {
                case 96: //數字鍵0
                    imgZipDownload();
                    break;
                case 97: //數字鍵1
                    copyImgSrcText();
                    break;
            }
        });
    }

})();