// ==UserScript== // @name 🔥🔥嗅探网站图片,一键下载(支持贴吧,豆瓣)🔥🔥 // @namespace https://www.softrr.cn/ // @version 1.1.1 // @author hackhase // @description 嗅探网站的图片,支持一键下载里面的图片,包括360图书馆,百度贴吧,豆瓣高清图片批量下载,后续再增加图源 // @license MIT // @icon http://pubimage.360doc.com/index7/nlogo.jpg // @match *://www.360doc.com/content/* // @match *://tieba.baidu.com/* // @match *://*.douban.com/photos/* // @match *://movie.douban.com/subject/* // @require https://cdn.jsdelivr.net/npm/vue@3.3.11/dist/vue.global.prod.js // @require data:application/javascript,%3Bwindow.Vue%3DVue%3B // @require https://cdn.jsdelivr.net/npm/element-plus@2.5.5/dist/index.full.min.js // @resource element-plus/dist/index.css https://cdn.jsdelivr.net/npm/element-plus@2.5.5/dist/index.css // @connect www.softrr.cn // @connect tieba.baidu.com // @connect tiebapic.baidu.com // @connect tb2.bdstatic.com // @connect * // @connect www.douban.com // @connect movie.douban.com // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_xmlhttpRequest // @grant unsafeWindow // @noframes // @downloadURL none // ==/UserScript== (t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const e=document.createElement("style");e.textContent=t,document.head.append(e)})(" :root{font-family:Inter,Avenir,Helvetica,Arial,sans-serif;font-size:16px;line-height:24px;font-weight:400;color-scheme:light dark;color:#ffffffde;background-color:#242424;font-synthesis:none;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-text-size-adjust:100%}a{font-weight:500;color:#646cff;text-decoration:inherit}a:hover{color:#535bf2}body{margin:0;place-items:center;min-width:320px;min-height:100vh}h1{font-size:3.2em;line-height:1.1}button{border-radius:8px;border:1px solid transparent;padding:.6em 1.2em;font-size:1em;font-weight:500;font-family:inherit;background-color:#1a1a1a;cursor:pointer;transition:border-color .25s}button:hover{border-color:#646cff}button:focus,button:focus-visible{outline:4px auto -webkit-focus-ring-color}.card{padding:2em}@media (prefers-color-scheme: light){:root{color:#213547;background-color:#fff}a:hover{color:#747bff}button{background-color:#f9f9f9}}.modal-wrapper[data-v-eb552d62]{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#00000080;margin-top:0;display:flex;justify-content:center;align-items:center;z-index:999}.modal[data-v-eb552d62]{background-color:#fff;padding:20px;border-radius:5px}.header[data-v-eb552d62]{display:flex;justify-content:space-between;align-items:center;margin-bottom:10px}.header h2[data-v-eb552d62]{margin:0;font-size:20px;font-weight:700}.header button[data-v-eb552d62]{border:none;background-color:transparent;font-size:20px;cursor:pointer}.content[data-v-eb552d62]{max-height:400px;overflow:auto;font-size:16px;display:flex;justify-content:space-between}.content .produce[data-v-eb552d62]{flex:60%}.content .produce p[data-v-eb552d62]{margin-top:15px}.content .produce .ipt[data-v-eb552d62]{margin-top:15px;height:30px;border-radius:5px;padding-left:10px}.content .img[data-v-eb552d62]{flex:35%;height:180px;display:flex;align-items:center;justify-content:center}.content .img img[data-v-eb552d62]{width:180px}input[data-v-eb552d62]::-webkit-input-placeholder{color:#aab2bd;font-size:14px;padding-left:5px}.copy[data-v-a5b45cdd]{width:200px;position:fixed;right:10px;top:80px}.copy .down[data-v-a5b45cdd]{display:flex;align-items:center;justify-content:center;flex-wrap:wrap;width:80px;height:80px;border-radius:50%;font-size:14px;color:#fff;background-color:red!important;cursor:pointer}.copy .down[data-v-a5b45cdd]:hover{background-color:#00ff48!important} "); (async function (vue, elementPlus) { 'use strict'; var _GM_xmlhttpRequest = /* @__PURE__ */ (() => typeof GM_xmlhttpRequest != "undefined" ? GM_xmlhttpRequest : void 0)(); var _unsafeWindow = /* @__PURE__ */ (() => typeof unsafeWindow != "undefined" ? unsafeWindow : void 0)(); const _export_sfc = (sfc, props) => { const target = sfc.__vccOpts || sfc; for (const [key, val] of props) { target[key] = val; } return target; }; const _withScopeId$1 = (n) => (vue.pushScopeId("data-v-eb552d62"), n = n(), vue.popScopeId(), n); const _hoisted_1$1 = { class: "modal" }; const _hoisted_2$1 = { class: "header" }; const _hoisted_3 = { class: "content" }; const _hoisted_4 = { class: "produce" }; const _hoisted_5 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("p", null, "1、扫描右侧公众号,点击关注!", -1)); const _hoisted_6 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("p", null, "2、在软件爬取者后台回复:验证码", -1)); const _hoisted_7 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("p", null, "3、在下方输入框输入获取的验证码后回车", -1)); const _hoisted_8 = /* @__PURE__ */ _withScopeId$1(() => /* @__PURE__ */ vue.createElementVNode("div", { class: "img" }, [ /* @__PURE__ */ vue.createElementVNode("img", { src: "https://www.softrr.cn/assets/pqz-daa4b840.jpg", alt: "" }) ], -1)); const _sfc_main$1 = { __name: "Model", props: { title: { type: String, required: true }, code: { type: Number } }, setup(__props, { expose: __expose }) { const props = __props; const visible = vue.ref(false); const openModal = () => { visible.value = true; }; const closeModal = () => { visible.value = false; }; __expose({ visible, openModal, closeModal }); const codeValue = vue.ref(); const enterCode = () => { if (codeValue.value == props.code) { localStorage.setItem("code", codeValue.value); visible.value = false; alert("验证成功,请再次点击解析!"); codeValue.value = ""; } else { alert("验证码错误,请重新输入!"); codeValue.value = ""; } }; return (_ctx, _cache) => { return vue.withDirectives((vue.openBlock(), vue.createElementBlock("div", { class: "modal-wrapper", onClick: vue.withModifiers(closeModal, ["self"]) }, [ vue.createElementVNode("div", _hoisted_1$1, [ vue.createElementVNode("div", _hoisted_2$1, [ vue.createElementVNode("h2", null, vue.toDisplayString(__props.title), 1), vue.createElementVNode("button", { onClick: closeModal }, "X") ]), vue.createElementVNode("div", _hoisted_3, [ vue.createElementVNode("div", _hoisted_4, [ _hoisted_5, _hoisted_6, _hoisted_7, vue.withDirectives(vue.createElementVNode("input", { class: "ipt", type: "text", "onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => codeValue.value = $event), onKeydown: vue.withKeys(enterCode, ["enter"]), placeholder: "请输入验证码后按回车" }, null, 544), [ [vue.vModelText, codeValue.value] ]) ]), _hoisted_8 ]) ]) ], 512)), [ [vue.vShow, visible.value] ]); }; } }; const Model = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["__scopeId", "data-v-eb552d62"]]); const importScript = (src) => { return new Promise((resolve, reject) => { const script = document.createElement("script"); script.src = src; script.addEventListener("load", () => { var _a; resolve(); (_a = script.parentElement) == null ? void 0 : _a.removeChild(script); }); script.addEventListener("error", (e) => { var _a; reject(e); (_a = script.parentElement) == null ? void 0 : _a.removeChild(script); }); document.body.appendChild(script); }); }; await( importScript( "https://cdn.jsdelivr.net/npm/jszip@3.10.1/dist/jszip.min.js" )); const JSZip = _unsafeWindow == null ? void 0 : _unsafeWindow.JSZip; const getFile = (url) => { return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "GET", url, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/537.36" }, responseType: "blob", onload: function(res) { resolve(res.response); } }); }); }; const getFileDoc = (url) => { return new Promise((resolve, reject) => { let xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", url, true); xmlhttp.responseType = "blob"; xmlhttp.onload = function() { if (this.status == 200) { resolve(this.response); } else { reject(this.status); } }; xmlhttp.send(); }); }; const downFile = async (arrList) => { const zip = new JSZip(); const promises = []; await arrList.forEach((item) => { if (item.src.includes("360doc")) { const promise = getFileDoc(item.src).then((data) => { const lst = item.src.split("."); const fileType = lst[lst.length - 1].includes("?") ? lst[lst.length - 1].split("?")[0] : lst[lst.length - 1]; zip.file(Date.now() + "." + fileType, data, { binary: true }); }); promises.push(promise); } else if (item.src.includes("tieba")) { const promise = getFile(item.src).then((data) => { const lst = item.src.split("."); const fileType = lst[lst.length - 1].includes("?") ? lst[lst.length - 1].split("?")[0] : lst[lst.length - 1]; zip.file(Date.now() + "." + fileType, data, { binary: true }); }); promises.push(promise); } else if (item.src.includes("douban")) { if (item.src.includes("photo/m")) { item.src = item.src.replace("photo/m", "photo/l"); } if (item.src.includes("photo/sqxs")) { item.src = item.src.replace("photo/sqxs", "photo/l"); } const promise = getFile(item.src).then((data) => { const lst = item.src.split("."); const fileType = lst[lst.length - 1]; zip.file(Date.now() + "." + fileType, data, { binary: true }); }); promises.push(promise); } }); Promise.all(promises).then(() => { zip.generateAsync({ type: "blob" }).then((content) => { downLoad(content, "图片下载", "zip"); }); }); }; const downLoad = (blob, name, type) => { if (!blob || !type) return; const url = window.URL || window.webkitURL || window.moxURL; const downloadHref = url.createObjectURL(blob); const link = document.createElement("a"); link.href = downloadHref; link.download = `${name || "导出文件"}.${type}`; document.body.appendChild(link); link.click(); document.body.removeChild(link); url.revokeObjectURL(downloadHref); }; const _withScopeId = (n) => (vue.pushScopeId("data-v-a5b45cdd"), n = n(), vue.popScopeId(), n); const _hoisted_1 = { class: "copy", ref: "btnGroupRef" }; const _hoisted_2 = /* @__PURE__ */ _withScopeId(() => /* @__PURE__ */ vue.createElementVNode("br", null, null, -1)); const _sfc_main = { __name: "App", setup(__props) { const imgList = vue.ref([]); let url = window.location.href; const getImageList = () => { if (url.includes("360doc")) { var a_left = document.querySelector(".a_left"); a_left.style.zIndex = 0; imgList.value = document.querySelector("#artContent").querySelectorAll("img"); } if (url.includes("tieba")) { var card_head = document.querySelector(".head_main") || document.querySelector("#container"); card_head.style.zIndex = 0; imgList.value = document.querySelector("#pb_content").querySelectorAll("img"); } if (url.includes("douban")) { if (url.includes("photos/album")) { console.log(1); imgList.value = document.querySelector(".photolst").querySelectorAll("img"); } if (url.includes("subject")) { imgList.value = document.querySelector(".article").querySelectorAll("img"); } } }; const code = vue.ref(); const getCode = () => { return new Promise((resolve, reject) => { _GM_xmlhttpRequest({ method: "GET", url: `https://www.softrr.cn/crawler/getCode`, headers: { Referer: "https://www.softrr.cn/", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.5735.289 Safari/537.36" }, onload: function(res) { code.value = JSON.parse(res.response).data[0].code; resolve(code.value); } }); }); }; const title = vue.ref("为了减少端口压力,防止滥用,采取必要的验证手段。"); const model = vue.ref(""); const locoCode = vue.ref(); const onImage = async () => { locoCode.value = localStorage.getItem("code"); code.value = await getCode(); if (locoCode.value == code.value) { downLoad2(); } else { model.value.openModal(); } }; const downLoad2 = () => { let list = []; getImageList(); imgList.value.forEach((item) => { if (item.src.includes("default")) return; if (url.includes("tieba") && !item.src.includes("gss0")) { if (item.src.includes("?")) { list.push(item); } } if (url.includes("360doc")) { list.push(item); } if (url.includes("douban")) { list.push(item); } }); if (list.length === 0) { elementPlus.ElMessage({ type: "info", message: "请至少选择一个文件下载" }); return; } downFile(list); }; return (_ctx, _cache) => { return vue.openBlock(), vue.createElementBlock("div", _hoisted_1, [ vue.createElementVNode("a", { onClick: onImage, class: "down" }, [ vue.createTextVNode("图片"), _hoisted_2, vue.createTextVNode("下载") ]), vue.createVNode(Model, { title: title.value, code: code.value, ref_key: "model", ref: model }, null, 8, ["title", "code"]) ], 512); }; } }; const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-a5b45cdd"]]); const cssLoader = (e) => { const t = GM_getResourceText(e); return GM_addStyle(t), t; }; cssLoader("element-plus/dist/index.css"); vue.createApp(App).mount( (() => { const app = document.createElement("div"); document.body.append(app); return app; })() ); })(Vue, ElementPlus);