Greasy Fork is available in English.
解放眼睛和双手,自动识别并填入数字,字母(支持大小写),文字验证码。
// ==UserScript==// @name 网页通用验证码识别// @namespace http://tampermonkey.net/// @version 4.0// @description 解放眼睛和双手,自动识别并填入数字,字母(支持大小写),文字验证码。// @author 哈士奇// @include http://*// @include https://*// @license MIT// @grant unsafeWindow// @grant GM_addStyle// @grant GM_listValues// @grant GM_addValueChangeListener// @grant GM_removeValueChangeListener// @grant GM_setValue// @grant GM_getValue// @grant GM_deleteValue// @grant GM_log// @grant GM_getResourceText// @grant GM_getResourceURL// @grant GM_registerMenuCommand// @grant GM_unregisterMenuCommand// @grant GM_xmlhttpRequest// @grant GM_download// @grant GM_getTab// @grant GM_saveTab// @grant GM_getTabs// @grant GM_notification// @grant GM_setClipboard// @grant GM_info// @grant GM_xmlhttpRequest// @connect *// @require https://unpkg.com/[email protected]/dist/vue.js// @require https://unpkg.com/element-ui/lib/index.js// @resource elementUIcss https://unpkg.com/element-ui/lib/theme-chalk/index.css// @run-at document-end// ==/UserScript==(function () {// GM_setValue('tipsConfig',"")var elementUIcss = GM_getResourceText("elementUIcss");var routePrefix = 'http://1.95.154.26:7000'GM_addStyle(elementUIcss);function getStyle(el) {// 获取元素样式if (window.getComputedStyle) {return window.getComputedStyle(el, null);} else {return el.currentStyle;}}function init() {//简化各种api和初始化全局变量CUR_URL = window.location.href;DOMAIN = CUR_URL.split("//")[1].split("/")[0];SLIDE_STORE_KEY = "husky_" + "slidePath" + location.host;NORMAL_STORE_KEY = "husky_" + "normalPath" + location.host;selector = document.querySelector.bind(document);selectorAll = document.querySelectorAll.bind(document);getItem = localStorage.getItem.bind(localStorage);setItem = localStorage.setItem.bind(localStorage);}function getNumber(str) {return Number(str.split(".")[0].replace(/[^0-9]/gi, ""));}function isNumber(value) {if (!value && value !== 0) {return false;}value = Number(value);return typeof value === "number" && !isNaN(value);}function getEleTransform(el) {const style = window.getComputedStyle(el, null);var transform =style.getPropertyValue("-webkit-transform") ||style.getPropertyValue("-moz-transform") ||style.getPropertyValue("-ms-transform") ||style.getPropertyValue("-o-transform") ||style.getPropertyValue("transform") ||"null";return transform && transform.split(",")[4];}class Captcha {// 识别网页中的验证码constructor() {this.imgCache = [];this.inputTags = [];this.recommendPath = {};this.checkTimer = null;this.listenLoadSuccess = false;window.addEventListener("load", async () => {this.listenLoadSuccess = true;this.init();});setTimeout(() => {if (!this.listenLoadSuccess) {this.listenLoadSuccess = true;this.init();}}, 5000);}doCheckTask() {this.findCaptcha();// this.checkSlideCaptcha();}init() {if (blackListCheck()) {return;}this.manualLocateCaptcha();this.doCheckTask();const MutationObserver =window.MutationObserver ||window.WebKitMutationObserver ||window.MozMutationObserver;const body = document.body;const Observer = new MutationObserver((mutations, instance) => {if (blackListCheck()) {return;}for (let i = 0; i < mutations.length; i++) {const el = mutations[i].target;const tagName = mutations[i].target.tagName.toLowerCase();let checkList = [];checkList.push(el.getAttribute("id"));checkList.push(el.className);checkList.push(el.getAttribute("alt"));checkList.push(el.getAttribute("src"));checkList.push(el.getAttribute("name"));checkList = checkList.filter((item) => item);for (let x = 0; x < checkList.length; x++) {if (/.*(code|captcha|验证码|login|点击|verify|yzm|yanzhengma|滑块|拖动|拼图|yidun|slide).*/im.test(checkList[x].toString().toLowerCase()) ||tagName === "img" ||tagName === "iframe") {if (!this.checkTimer) {this.checkTimer = setTimeout(() => {this.doCheckTask();}, 0);} else {window.clearTimeout(this.checkTimer);this.checkTimer = setTimeout(() => {this.doCheckTask();}, 2000);}return;}}}});Observer.observe(body, {childList: true,subtree: true,attributes: true,});}dataURLtoFile(dataURL, filename = "captcha.jpg") {// base64转图片文件var arr = dataURL.split(","),mime =(arr[0].match(/:(.*?);/) && arr[0].match(/:(.*?);/)[1]) ||"image/png",bstr = atob(arr[1]),n = bstr.length,u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new File([u8arr], filename, { type: mime });}async getRecommendPath() {let requestUrl =routePrefix + "/cssPath?href=" +location.href.split("?")[0];try {GM_xmlhttpRequest({method: "get",url: requestUrl,onload: async (res) => {if (res.status === 200 && res.response) {let data = (res.response && JSON.parse(res.response)) || {};const { path, recommendTimes = 0 } = data;if (path && recommendTimes) {let inputSelector = path.split("$$")[0];let imgSelector = path.split("$$")[1];if (selector(inputSelector) &&selector(imgSelector) &&selector(imgSelector).getAttribute("src") &&selector(inputSelector).getAttribute("type") === "text") {let dataURL = await this.handleImg(selector(imgSelector));try {if (!this.hasRequest(dataURL, { record: true })) {let code = await this.request(this.dataURLtoFile(dataURL),this.cssPath(selector(inputSelector)) +"$$" +this.cssPath(selector(imgSelector)),selector(imgSelector).getAttribute("src"));if (code) {selector(inputSelector).value = code;if (typeof Vue !== "undefined") {new Vue().$message.success("获取验证码成功");}console.log("正在使用共享验证码功能获取验证码");} else {console.error("验证码为空,请检查图片是否正确");}}} catch (error) {console.log(error);// if (typeof Vue !== "undefined") {// new Vue().$message.error("获取验证码失败");// }}}}}},onerror: function (err) {console.log("推荐路径请求失败:" + err);},});} catch (error) {console.log(error);}}getCaptchaFeature(el) {// 获取验证码特征let checkList = [];checkList.push(el.getAttribute("id"));checkList.push(el.className);checkList.push(el.getAttribute("alt"));checkList.push(el.getAttribute("src"));checkList.push(el.getAttribute("name"));return checkList;}cssPath = (el) => {// 获取元素css pathif (!(el instanceof Element)) return;var path = [];while (el.nodeType === Node.ELEMENT_NODE) {var selector = el.nodeName.toLowerCase();if (el.id) {selector += "#" + el.id;path.unshift(selector);break;} else {var sib = el,nth = 1;while ((sib = sib.previousElementSibling)) {if (sib.nodeName.toLowerCase() == selector) nth++;}if (nth != 1) selector += ":nth-of-type(" + nth + ")";}path.unshift(selector);el = el.parentNode;}return path.join(" > ");};manualLocateCaptcha() {let imgs = [];let inputTags = [];let cssPathStore = {};let finish = false;this.vue = new Vue();this.isIframe = top !== self;var onTagClick = (e) => {let el = e.target;let tagName = el.tagName;if (tagName.toLowerCase() === "input") {let type = el.getAttribute("type");if (type && type !== "text") {this.vue.$message.error("提醒:当前点击输入框type=" + type + ",请选择文本输入框");} else {cssPathStore.input = this.cssPath(el);this.vue.$message.success("您已成功选择输入框");}} else {cssPathStore.img = this.cssPath(el);this.vue.$message.success("您已成功选择验证码图片");}if (cssPathStore.input && cssPathStore.img) {GM_setValue(NORMAL_STORE_KEY, JSON.stringify(cssPathStore));imgs.forEach((img) => {img && img.removeEventListener("click", onTagClick);}, false);inputTags.forEach((input) => {input.removeEventListener("click", onTagClick);}, false);setTimeout(() => {this.vue.$message.success("选择完毕,赶快试试吧");captchaInstance.doCheckTask();}, 3000);finish = true;}};var onMenuClick = (e) => {if (this.isIframe) {alert("当前脚本处于iframe中,暂不支持该操作,快让作者优化吧");return;}finish = false;cssPathStore = {};GM_deleteValue(NORMAL_STORE_KEY);this.vue.$alert("接下来请点击验证码图片和输入框", "操作提示", {confirmButtonText: "确定",callback: () => {setTimeout(() => {imgs.forEach((img) => {img && img.removeEventListener("click", onTagClick);}, false);inputTags.forEach((input) => {input.removeEventListener("click", onTagClick);}, false);if (!finish) {this.vue.$notify.success({title: "提示",message: "已退出手动选择验证码模式。",offset: 100,});}}, 20000);},});// alert("请点击验证码和输入框各一次。");imgs = [...selectorAll("img")];inputTags = [...selectorAll("input")];imgs.forEach((img) => {img.addEventListener("click", onTagClick);}, false);inputTags.forEach((input) => {input.addEventListener("click", onTagClick);}, false);};GM_registerMenuCommand("手动选择验证码和输入框", onMenuClick);}handleImg(img) {return new Promise((resolve, reject) => {try {// 图片没设置跨域,可采用图片转canvas转base64的方式let dataURL = null;const action = () => {let canvas = document.createElement("canvas");canvas.width = img.naturalWidth;canvas.height = img.naturalHeight;let ctx = canvas.getContext("2d");ctx.drawImage(img, 0, 0, img.naturalWidth, img.naturalHeight);dataURL = canvas.toDataURL("image/png");resolve(dataURL);};if (!img.src.includes(";base64,")) {img.onload = function () {action();};if (img.complete) {action();} else {img.onload = function () {action();};}} else {dataURL = img.src;resolve(dataURL);}} catch (error) {console.error("error:" + error);// 这块处理比较复杂,待优化// 图片设置跨域,重新请求图片内容后转base64,相当于替用户点击了“换一张图片”// if (this.times >= 1) {// return;// }// if (typeof Vue !== "undefined") {// new Vue().$notify.success({// title: "温馨提示",// message: "当前验证码结果可能和图片显示不一致,请放心提交。",// offset: 100,// });// }// this.times++;// GM_xmlhttpRequest({// method: "get",// url: img.src,// responseType: "blob",// onload: (res) => {// if (res.status === 200) {// let blob = res.response;// let fileReader = new FileReader();// fileReader.onloadend = (e) => {// let base64 = e.target.r###lt;// resolve(base64);// };// fileReader.readAsDataURL(blob);// } else {// console.log("图片转换blob失败");// console.log(res);// reject();// }// },// onerror: function(err) {// console.log("图片请求失败:" + err);// reject();// },// });}});}hasRequest(dataURL, config = {}) {let startIndex = config.type === "url" ? 0 : dataURL.length - 100;let imgClips = dataURL.slice(startIndex, dataURL.length);if (this.imgCache.includes(imgClips)) {return true;}if (config.record) {this.imgCache.push(imgClips);}return false;}request(file, path, src) {try {if (!file) {console.error("缺少file参数");return Promise.reject();}return new Promise((resolve, reject) => {let host = location.href;let href = location.href.split("?")[0].split("#")[0];if (self === top) {host = location.host;}let formData = new FormData();let detail = {// path,// src,// host,href,};formData.append("img", file);formData.append("detail", JSON.stringify(detail));let requestUrl = routePrefix + '/captcha';GM_xmlhttpRequest({method: "post",url: requestUrl,data: formData,onload: function (response) {let res = JSON.parse(response.response) || {};console.log({ res })if (response.status === 429) {let msg = res.msg || '获取验证码失败';let date = new Date().getDate();let tipsConfig = {date,times: 1,};let cache =GM_getValue("tipsConfig") &&JSON.parse(GM_getValue("tipsConfig"));if (cache && cache.times > 5) {} else {if (!cache) {GM_setValue("tipsConfig", JSON.stringify(tipsConfig));} else {cache.times = cache.times + 1;GM_setValue("tipsConfig", JSON.stringify(cache));}if (typeof Vue !== "undefined") {new Vue().$message.error(msg);}}console.error("获取验证码失败:", res);reject();} else {if (res.data.code) {resolve(res.data.code);} else {console.error("获取验证码失败,验证码为空:", response);reject();}}},onerror: function (err) {console.error(err);reject();},});});} catch (error) {console.log(error);}}async findCaptcha() {// 先读取用户手动设置的验证码配置let cache = GM_getValue(NORMAL_STORE_KEY);let captchaPath = cache && JSON.parse(cache);if (captchaPath &&captchaPath.input &&captchaPath.img &&selector(captchaPath.input) &&selector(captchaPath.img)) {let dataURL = await this.handleImg(selector(captchaPath.img));try {if (!this.hasRequest(dataURL, { record: true })) {let code = await this.request(this.dataURLtoFile(dataURL),this.cssPath(selector(captchaPath.input)) +"$$" +this.cssPath(selector(captchaPath.img)),selector(captchaPath.img).getAttribute("src"));if (code) {selector(captchaPath.input).value = code.trim();console.log("正在使用用户自定义验证码位置数据获取验证码");return;} else {console.error("验证码为空,请检查图片是否正确");}}} catch (error) {console.log(error);}return;}// 自动寻找验证码和输入框let captchaMap = [];let imgs = [...selectorAll("img")];imgs.forEach((img) => {let checkList = [...this.getCaptchaFeature(img),...this.getCaptchaFeature(img.parentNode),];checkList = checkList.filter((item) => item);let isInvalid =["#", "about:blank"].includes(img.getAttribute("src")) ||!img.getAttribute("src");for (let i = 0; i < checkList.length; i++) {if (/.*(code|captcha|验证码|login|点击|verify|yzm|yanzhengma).*/im.test(checkList[i].toLowerCase()) &&img.width > 30 &&img.width < 150 &&img.height < 80 &&!isInvalid) {captchaMap.push({ img: img, input: null });break;}}});captchaMap.forEach((item) => {let imgEle = item.img;let parentNode = imgEle.parentNode;for (let i = 0; i < 4; i++) {// 以当前可能是验证码的图片为基点,向上遍历四层查找可能的Input输入框if (!parentNode) {return;}let inputTags = [...parentNode.querySelectorAll("input")];if (inputTags.length) {let input = inputTags.pop();let type = input.getAttribute("type");while (type !== "text" && inputTags.length) {if (type === "password") {break;}input = inputTags.pop();type = input.getAttribute("type");}let inputWidth = getStyle(input).width.replace(/[^0-9]/gi, "");// let inputHeight = getStyle(input).height.replace(/[^0-9]/gi, "");if (!type || (type === "text" && inputWidth > 50)) {// 兼容各种奇葩情况item.input = input;break;}if (type === "password") {// 验证码一般在密码框后面,遍历到密码框了就大概率说明没有验证码break;}}parentNode = parentNode.parentNode;}});// console.log(captchaMap);if (!captchaMap.length) {const { path, recommendTimes } = this.recommendPath;if (path) {let inputSelector = path.split("$$")[0];let imgSelector = path.split("$$")[1];if (selector(inputSelector) && selector(imgSelector)) {let dataURL = await this.handleImg(selector(imgSelector));try {if (!this.hasRequest(dataURL, { record: true })) {selector(inputSelector).value = await this.request(this.dataURLtoFile(dataURL),path,item.img.getAttribute("src"));if (typeof Vue !== "undefined") {new Vue().$message.success("获取验证码成功");}}} catch (error) {console.log(error);// if (typeof Vue !== "undefined") {// new Vue().$message.error("获取验证码失败");// }}}}}captchaMap = captchaMap.filter((item) => item.input);captchaMap.forEach(async (item, index) => {let dataURL = await this.handleImg(item.img);try {if (!this.hasRequest(dataURL, { record: true })) {let code = await this.request(this.dataURLtoFile(dataURL),this.cssPath(item.input) + "$$" + this.cssPath(item.img),item.img.getAttribute("src"));if (code) {item.input.value = code;if (typeof Vue !== "undefined") {new Vue().$message.success("获取验证码成功");}console.log("正在使用自动寻找验证码功能获取验证码");} else {if (index === captchaMap.length - 1) {// this.getRecommendPath();}console.error("验证码为空,请检查图片是否正确");}}} catch (error) {if (index === captchaMap.length - 1) {// this.getRecommendPath();}console.log(error);// if (typeof Vue !== "undefined") {// new Vue().$message.error("获取验证码失败");// }}});}getImgViaBlob(url) {return new Promise((resolve, reject) => {try {GM_xmlhttpRequest({method: "get",url,responseType: "blob",onload: (res) => {if (res.status === 200) {let blob = res.response;let fileReader = new FileReader();fileReader.onloadend = (e) => {let base64 = e.target.r###lt;if (base64.length > 20) {resolve(base64);} else {alert("验证码助手:当前网站验证码图片禁止跨域访问,待作者优化。");handleClearMenuClick();reject("base64图片长度不够");throw "getImgViaBlob: base64图片长度不够";}};fileReader.readAsDataURL(blob);} else {console.log("图片转换blob失败");console.log(res);reject();}},onerror: function (err) {console.log("图片请求失败:" + err);reject();},});} catch (error) {console.log(error);reject();}});}elDisplay(el) {if (!el) {return false;}while (el) {if (!(el instanceof Element)) {return true;}if (getStyle(el).display === "none") {return false;}el = el.parentNode;}return true;}checkSlideCaptcha() {const check = async () => {const slideCache =(GM_getValue(SLIDE_STORE_KEY) &&JSON.parse(GM_getValue(SLIDE_STORE_KEY))) ||{};const { bgImg, targetImg, moveItem } = slideCache;if (bgImg &&targetImg &&moveItem &&selector(targetImg) &&selector(bgImg) &&selector(moveItem) &&this.elDisplay(selector(targetImg)) &&this.elDisplay(selector(bgImg)) &&this.elDisplay(selector(moveItem))) {const target_url =selector(targetImg).getAttribute("src") ||getStyle(selector(targetImg))["background-image"].split('"')[1];const bg_url =selector(bgImg).getAttribute("src") ||getStyle(selector(bgImg))["background-image"].split('"')[1];if (!this.hasRequest(target_url, { record: true, type: "url" })) {const target_base64 = await this.getImgViaBlob(target_url);const bg_base64 = await this.getImgViaBlob(bg_url);return new Promise(async (resolve, reject) => {let host = location.href;let href = location.href.split("?")[0].split("#")[0];if (self === top) {host = location.host;}let detail = {path: slideCache,host,href,};let formData = new FormData();let requestUrl = routePrefix + "/slideCaptcha";let targetWidth = getNumber(getStyle(selector(targetImg)).width);let bgWidth = getNumber(getStyle(selector(bgImg)).width);formData.append("target_img", this.dataURLtoFile(target_base64));formData.append("bg_img", this.dataURLtoFile(bg_base64));formData.append("targetWidth", targetWidth);formData.append("bgWidth", bgWidth);formData.append("detail", JSON.stringify(detail));GM_xmlhttpRequest({method: "post",url: requestUrl,data: formData,onload: (response) => {const data = JSON.parse(response.response);this.moveSideCaptcha(selector(targetImg),selector(moveItem),data.r###lt.target[0]);// resolve()},onerror: function (err) {console.error(err);reject();},});});}}};check();// const interval = 3000;// simulateInterval(check, interval);}moveSideCaptcha(targetImg, moveItem, distance) {if (distance === 0) {console.log("distance", distance);return;}var btn = moveItem;let target = targetImg;let varible = null;let targetLeft = Number(getStyle(target).left.replace("px", "")) || 0;let targetParentLeft =Number(getStyle(target.parentNode).left.replace("px", "")) || 0;let targetTransform = Number(getEleTransform(target)) || 0;let targetParentTransform =Number(getEleTransform(target.parentNode)) || 0;var mousedown = document.createEvent("MouseEvents");var rect = btn.getBoundingClientRect();var x = rect.x;var y = rect.y;mousedown.initMouseEvent("mousedown",true,true,document.defaultView,0,x,y,x,y,false,false,false,false,0,null);btn.dispatchEvent(mousedown);var dx = 0;var dy = 0;var interval = setInterval(function () {var mousemove = document.createEvent("MouseEvents");var _x = x + dx;var _y = y + dy;mousemove.initMouseEvent("mousemove",true,true,document.defaultView,0,_x,_y,_x,_y,false,false,false,false,0,null);btn.dispatchEvent(mousemove);btn.dispatchEvent(mousemove);let newTargetLeft =Number(getStyle(target).left.replace("px", "")) || 0;let newTargetParentLeft =Number(getStyle(target.parentNode).left.replace("px", "")) || 0;let newTargetTransform = Number(getEleTransform(target)) || 0;let newTargetParentTransform =Number(getEleTransform(target.parentNode)) || 0;if (newTargetLeft !== targetLeft) {varible = newTargetLeft;} else if (newTargetParentLeft !== targetParentLeft) {varible = newTargetParentLeft;} else if (newTargetTransform !== targetTransform) {varible = newTargetTransform;} else if (newTargetParentTransform != targetParentTransform) {varible = newTargetParentTransform;}if (varible >= distance) {clearInterval(interval);var mouseup = document.createEvent("MouseEvents");mouseup.initMouseEvent("mouseup",true,true,document.defaultView,0,_x,_y,_x,_y,false,false,false,false,0,null);setTimeout(() => {btn.dispatchEvent(mouseup);}, Math.ceil(Math.random() * 2000));} else {if (dx >= distance - 20) {dx += Math.ceil(Math.random() * 2);} else {dx += Math.ceil(Math.random() * 10);}let sign = Math.random() > 0.5 ? -1 : 1;dy += Math.ceil(Math.random() * 3 * sign);}}, 10);setTimeout(() => {clearInterval(interval);}, 10000);}}function getEleCssPath(el) {// 获取元素css pathif (!(el instanceof Element)) return;var path = [];while (el.nodeType === Node.ELEMENT_NODE) {var selector = el.nodeName.toLowerCase();if (el.id) {selector += "#" + el.id;path.unshift(selector);break;} else {var sib = el,nth = 1;while ((sib = sib.previousElementSibling)) {if (sib.nodeName.toLowerCase() == selector) nth++;}if (nth != 1) selector += ":nth-of-type(" + nth + ")";}path.unshift(selector);el = el.parentNode;}return path.join(" > ");}function handleSlideMenuClick({ isPostmessage } = {}) {if (top === self) {alert("请点击滑动验证码的大图片,小图片,滑块。");}this.vue = new Vue();this.isIframe = top !== self;GM_deleteValue(SLIDE_STORE_KEY);let imgs = [...selectorAll("img")];let divTags = [...selectorAll("div")];imgs.forEach((img) => {img.addEventListener("click", onSlideTagClick);}, false);divTags.forEach((input) => {input.addEventListener("click", onSlideTagClick);}, false);setTimeout(() => {imgs.forEach((img) => {img && img.removeEventListener("click", onSlideTagClick);}, false);divTags.forEach((input) => {input.removeEventListener("click", onSlideTagClick);}, false);}, 30000);if (!isPostmessage) {if (self === top) {const iframes = [...selectorAll("iframe")];iframes.forEach((iframe) => {iframe.contentWindow.postMessage({sign: "husky",action: "handleSlideMenuClick",},"*");});} else {window.postMessage({sign: "husky",action: "handleSlideMenuClick",},"*");}}}let noticeTimer = 0;function notice(msg) {if (noticeTimer) {clearTimeout(noticeTimer);} else {setTimeout(() => new Vue().$message.success(msg));}noticeTimer = setTimeout(() => new Vue().$message.success(msg), 1000);}var onSlideTagClick = (e) => {let el = e.target;let tagName = el.tagName.toLowerCase();let width = Number(getNumber(getStyle(el).width)) || 0;const vue = new Vue();let height = Number(getNumber(getStyle(el).height)) || 0;let position = getStyle(el).position;let pathCache =(GM_getValue(SLIDE_STORE_KEY) &&JSON.parse(GM_getValue(SLIDE_STORE_KEY))) ||{};if (tagName === "img") {if (width >= height && width > 150) {let newValue = { ...pathCache, bgImg: getEleCssPath(el) };GM_setValue(SLIDE_STORE_KEY, JSON.stringify(newValue));pathCache = newValue;notice("您已成功选择大图片");} else if (width < 100 && height >= width - 5) {let newValue = { ...pathCache, targetImg: getEleCssPath(el) };GM_setValue(SLIDE_STORE_KEY, JSON.stringify(newValue));pathCache = newValue;notice("您已成功选择小图片");}} else {let curEl = el;for (let i = 0; i < 3; i++) {if (!curEl || curEl === Window) {break;}position = getStyle(curEl).position;let bgUrl = getStyle(curEl)["backgroundImage"];width = Number(getNumber(getStyle(curEl).width)) || 0;height = Number(getNumber(getStyle(curEl).height)) || 0;if (position === "absolute" && width < 100 && height < 100) {let newValue = { ...pathCache, moveItem: getEleCssPath(curEl) };GM_setValue(SLIDE_STORE_KEY, JSON.stringify(newValue));pathCache = newValue;notice("您已成功选择滑块");break;}let reg = /url\("(.+)"\)/im;if (bgUrl && bgUrl.match(reg)) {if (width >= height && width > 150) {let newValue = { ...pathCache, bgImg: getEleCssPath(curEl) };GM_setValue(SLIDE_STORE_KEY, JSON.stringify(newValue));pathCache = newValue;notice("您已成功选择大图片");break;} else if (width < 100 && height >= width - 5) {let newValue = { ...pathCache, targetImg: getEleCssPath(curEl) };GM_setValue(SLIDE_STORE_KEY, JSON.stringify(newValue));pathCache = newValue;notice("您已成功选择小图片");break;}}curEl = curEl.parentNode;}curEl = el;const firstImg = curEl.querySelector("img");firstImg && onSlideTagClick({ target: firstImg });}const finish = Object.keys(pathCache).filter((item) => item).length == 3;if (finish) {let imgs = [...selectorAll("img")];let divTags = [...selectorAll("div")];imgs.forEach((img) => {img && img.removeEventListener("click", onSlideTagClick);}, false);divTags.forEach((div) => {div.removeEventListener("click", onSlideTagClick);}, false);setTimeout(() => {vue.$message.success("选择完毕,赶快试试吧");captchaInstance.doCheckTask();}, 3000);}};// GM_registerMenuCommand("手动定位滑动验证码", handleSlideMenuClick);function handleClearMenuClick() {GM_listValues().forEach((name) => {if (name.includes("husky")) {GM_deleteValue(name);}});}GM_registerMenuCommand("清空所有验证码配置", handleClearMenuClick);function cleanCurrentPage() {GM_deleteValue(SLIDE_STORE_KEY);GM_deleteValue(NORMAL_STORE_KEY);}GM_registerMenuCommand("清空当前页面验证码配置", cleanCurrentPage);let blackListMenuId = null;function blackListCheck() {let key = location.host + location.pathname + "_black";let data = GM_getValue(key) && JSON.parse(GM_getValue(key));if (blackListMenuId) {GM_unregisterMenuCommand(blackListMenuId);}if (data) {blackListMenuId = GM_registerMenuCommand("标记当前网站有验证码",labelWebsite);} else {blackListMenuId = GM_registerMenuCommand("标记当前网站没有验证码",labelWebsite);}return data;}function labelWebsite() {let key = location.host + location.pathname + "_black";let data = GM_getValue(key) && JSON.parse(GM_getValue(key));if (data) {GM_setValue(key, "false");} else {GM_setValue(key, "true");}notice("操作成功," + (data ? "已标记网站有验证码" : "已标记网站没有验证码"));if (data) {captchaInstance = captchaInstance || new Captcha();captchaInstance.init();}blackListCheck();}blackListCheck();var captchaInstance = null;function main() {window.addEventListener("DOMContentLoaded", function () {init();captchaInstance = new Captcha();});}const actions = {handleSlideMenuClick: handleSlideMenuClick,};window.addEventListener("message",(event) => {const { data = {} } = event || {};const { sign, action } = data;if (sign === "husky") {if (action && actions[action]) {actions[action]({ isPostmessage: true });}}},false);main();})();