您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自定义规则,透过CSS/XPath选择器,定位圈选出要下载的DOM image对象,进行下载压缩打包,也能聚集所有图片到当前页面里。
当前为
// ==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; } }); } })();