// ==UserScript== // @name DDDD OCR WEB - 验证码自动识别 // @namespace https://github.com/MakotoArai-CN/ddddocr-webjs // @version 1.1.3-2026/2/9 02:21:17 // @author MakotoArai-CN // @description 自动检测并识别页面验证码,自动填充到输入框。首次使用需设置白名单,会自动下载约50MB模型文件以及20MB左右的ONNX推理运行时文件。 // @license MIT // @icon data:image/png;base64,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 // @match *://*/* // @require https://cdnjs.cloudflare.com/ajax/libs/onnxruntime-web/1.17.0/ort.min.js // @connect cdn.jsdelivr.net // @connect unpkg.com // @connect cdnjs.cloudflare.com // @connect fastly.jsdelivr.net // @connect registry.npmmirror.com // @connect raw.githubusercontent.com // @connect ghproxy.com // @connect ghfast.top // @connect mirror.ghproxy.com // @connect raw.kkgithub.com // @connect github.moeyy.xyz // @connect ghps.cc // @connect cors.isteed.cc // @connect raw.githubusercontents.com // @grant GM_getValue // @grant GM_notification // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant unsafeWindow // ==/UserScript== (function () { 'use strict'; class t{static extractImageFromElement(t){const e=document.createElement("canvas");e.width=t.naturalWidth||t.width,e.height=t.naturalHeight||t.height;const n=e.getContext("2d");n.fillStyle="#FFFFFF",n.fillRect(0,0,e.width,e.height),n.drawImage(t,0,0);const i=n.getImageData(0,0,e.width,e.height);return {data:this.toGrayscale(i.data),width:e.width,height:e.height}}static async loadImage(t){if("undefined"==typeof document)return this.loadImageInServiceWorker(t);if(t instanceof HTMLImageElement)return this.extractImageFromElement(t);const e=new Image;e.crossOrigin="anonymous",e.src="string"==typeof t?t:URL.createObjectURL(t),await new Promise((t,n)=>{e.onload=()=>t(),e.onerror=()=>n(new Error("图片加载失败")),setTimeout(()=>n(new Error("图片加载超时")),1e4);});const n=document.createElement("canvas");n.width=e.width,n.height=e.height;const i=n.getContext("2d");i.fillStyle="#FFFFFF",i.fillRect(0,0,e.width,e.height),i.drawImage(e,0,0);const o=i.getImageData(0,0,e.width,e.height),r=this.toGrayscale(o.data);return "string"!=typeof t&&URL.revokeObjectURL(e.src),{data:r,width:e.width,height:e.height}}static async loadImageInServiceWorker(t){let e;if("string"==typeof t)if(t.startsWith("data:")){const n=await fetch(t);e=await n.blob();}else {const n=await fetch(t);e=await n.blob();}else {if(!(t instanceof Blob))throw new Error("Service Worker 环境不支持 HTMLImageElement");e=t;}const n=await createImageBitmap(e),i=new OffscreenCanvas(n.width,n.height),o=i.getContext("2d");o.fillStyle="#FFFFFF",o.fillRect(0,0,i.width,i.height),o.drawImage(n,0,0);const r=o.getImageData(0,0,i.width,i.height),a=this.toGrayscale(r.data);return n.close(),{data:a,width:i.width,height:i.height}}static toGrayscale(t){const e=new Uint8ClampedArray(t.length/4);for(let n=0;n{if("undefined"!=typeof ort)return ort;if("undefined"!=typeof window&&window.ort)return window.ort;if("undefined"!=typeof globalThis&&globalThis.ort)return globalThis.ort;try{if("undefined"!=typeof unsafeWindow&&unsafeWindow.ort)return unsafeWindow.ort}catch(t){}return null};let e=t();if(e)return console.log("✅ ort 已存在"),e;console.log("⏳ 等待 ort 加载...");for(let n=0;n<100;n++)if(await new Promise(t=>setTimeout(t,100)),e=t(),e)return console.log("✅ ort 已就绪"),e;throw new Error("等待 ort 超时")}async recognize(e){this.initialized&&this.session||await this.init();const n=Date.now(),{data:i,width:o,height:r}=await t.loadImage(e),a=Math.floor(o*(64/r)),d=t.resize(i,o,r,a,64),s=t.normalize(d),c={input1:new this.ort.Tensor("float32",s,[1,1,64,a])},l=(await this.session.run(c)).output,u=this.decodeOutput(l);return console.log(`识别完成: ${u} (耗时: ${Date.now()-n}ms)`),{text:u}}decodeOutput(t){const e=this.convertToNumberArray(t.data),n=[];let i=-1;for(const o of e){if(o===i)continue;if(i=o,o<=0||o>=this.charsets.length)continue;const t=this.charsets[o];t&&n.push(t);}return n.join("")}convertToNumberArray(t){const e=[];for(let n=0;nt.startsWith("__reactProps$")||t.startsWith("__reactFiber$")||t.startsWith("__reactEventHandlers$"))){const e=t._valueTracker;e&&e.setValue("");}if((t.ngModel||t.getAttribute("ng-model")||t.getAttribute("[(ngModel)]"))&&(this.dispatchEvent(t,"input"),this.dispatchEvent(t,"blur")),Object.keys(t).find(t=>t.startsWith("__vue"))||t.hasAttribute("v-model")){const e=new CompositionEvent("compositionstart",{bubbles:true}),n=new CompositionEvent("compositionend",{bubbles:true,data:t.value});t.dispatchEvent(e),t.dispatchEvent(n);}}async simulateTyping(t,e){var n;for(const i of e){this.dispatchKeyEvent(t,"keydown",i);const e=null==(n=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value"))?void 0:n.set;e?e.call(t,t.value+i):t.value+=i;const o=new InputEvent("input",{bubbles:true,cancelable:true,inputType:"insertText",data:i});t.dispatchEvent(o),this.dispatchKeyEvent(t,"keyup",i),await this.delay(50+100*Math.random());}this.dispatchEvent(t,"change"),this.dispatchEvent(t,"blur");}dispatchEvent(t,e){t.dispatchEvent(new Event(e,{bubbles:true,cancelable:true}));}dispatchKeyEvent(t,e,n){t.dispatchEvent(new KeyboardEvent(e,{key:n,code:`Key${n.toUpperCase()}`,charCode:n.charCodeAt(0),keyCode:n.charCodeAt(0),bubbles:true,cancelable:true}));}delay(t){return new Promise(e=>setTimeout(e,t))}highlightInput(t){const e=t.style.border,n=t.style.boxShadow;t.style.border="2px solid #4CAF50",t.style.boxShadow="0 0 8px rgba(76, 175, 80, 0.5)",setTimeout(()=>{t.style.border=e,t.style.boxShadow=n;},2e3);}async submitForm(t){var e;const n=t.closest("form");if(n){const t=new Event("submit",{bubbles:true,cancelable:true});n.dispatchEvent(t)&&n.submit();}else {const n=((null==(e=t.parentElement)?void 0:e.parentElement)||document).querySelector('button[type="submit"], input[type="submit"], button:not([type])');n&&n.click();}}getLastFilledInput(){return this.lastFilledInput}}const i={MODEL_VERSION:"1.5.1",MODEL_REPO:"MakotoArai-CN/ddddocr-webjs",MODEL_BRANCH:"main",MODEL_PATH:"public/common.onnx",CHARSETS_PATH:"public/charsets.json",WASM_VERSION:"1.17.0",CACHE_DURATION:2592e6,CAPTCHA_KEYWORDS:["captcha","verify","code","vcode","authcode","验证码","checkcode","yzm","capimg","signCaptcha","imgcode","seccode","validcode","yanzhengma","validatecode","piccode","imgverify","codeimg","randcode","identify","kaptcha","verifycode","imgCaptcha","captchaImg","vcodeImg"],INPUT_KEYWORDS:["captcha","verify","code","vcode","authcode","验证码","checkcode","yzm","validatecode","validcode","seccode","imgcode","randcode","identify","kaptcha","answer","verifycode","captchaInput","vcodeInput"],AGREEMENT_KEYWORDS:["agree","agreement","accept","terms","policy","privacy","同意","协议","条款","隐私","用户协议","隐私政策","tos","consent","checkbox","check"],EXCLUDED_INPUT_TYPES:["password","email","tel","phone","mobile","hidden","submit","button","reset","file","image","checkbox","radio"],EXCLUDED_INPUT_NAMES:["username","user","account","email","phone","mobile","tel","password","pwd","pass","name","realname","nickname","search","query","q","keyword","address","city"],EXCLUDE_PATTERNS:["avatar","logo","icon","banner","ad","sponsor","background","bg","profile","user","photo","emoji","emoticon","sticker","gif","loading","spinner","placeholder"],MIN_CAPTCHA_WIDTH:50,MIN_CAPTCHA_HEIGHT:20,MAX_CAPTCHA_WIDTH:400,MAX_CAPTCHA_HEIGHT:150,AUTO_DETECT_INTERVAL:2e3,GITHUB_MIRRORS:["https://raw.githubusercontent.com","https://ghproxy.com/https://raw.githubusercontent.com","https://ghfast.top/https://raw.githubusercontent.com","https://mirror.ghproxy.com/https://raw.githubusercontent.com","https://raw.kkgithub.com","https://gh-proxy.org","https://hk.gh-proxy.org","https://cdn.gh-proxy.org","https://edgeone.gh-proxy.org","https://github.moeyy.xyz/https://raw.githubusercontent.com","https://ghps.cc/https://raw.githubusercontent.com","https://cors.isteed.cc/github.com/MakotoArai-CN/ddddocr-webjs/raw/main","https://raw.githubusercontents.com"],CDN_SOURCES:["https://cdn.jsdelivr.net","https://unpkg.com","https://cdnjs.cloudflare.com","https://fastly.jsdelivr.net","https://registry.npmmirror.com"]},o={debugMode:false,autoDetect:true,captchaSelector:"",inputSelector:"",submitSelector:"",agreementSelector:"",agreementSelectors:[],autoCheckAgreement:true,useLocalModel:false,localModelPath:"",localCharsetsPath:"",autoDownload:true,enableWhitelist:true,whitelist:[],useUploadedModel:false,useUploadedWasm:false,theme:"auto",typewriterEffect:true,autoCalculate:false,calculateOutputMode:"result",calculateRules:[],enableNotification:true},r=class{static setDebugMode(t){this.debugMode=t;}static isDebugMode(){return this.debugMode}static debug(...t){this.debugMode&&console.log(`${this.prefix} [DEBUG]`,...t);}static info(...t){this.debugMode&&console.info(`${this.prefix} [INFO]`,...t);}static warn(...t){console.warn(`${this.prefix} [WARN]`,...t);}static error(...t){console.error(`${this.prefix} [ERROR]`,...t);}static group(t){this.debugMode&&console.group(`${this.prefix} ${t}`);}static groupEnd(){this.debugMode&&console.groupEnd();}static table(t){this.debugMode&&console.table(t);}static time(t){this.debugMode&&console.time(`${this.prefix} ${t}`);}static timeEnd(t){this.debugMode&&console.timeEnd(`${this.prefix} ${t}`);}};r.debugMode=false,r.prefix="[DDDD OCR]";let a=r;const d=class{static parseExpression(t){const e=t.trim();let n=e;for(const r of this.NOISE_CHARS)n=n.split(r).join("");const i=[/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]?\s*\d*$/,/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]$/,/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)$/];for(const r of i){const t=n.match(r);if(t){const n=parseFloat(t[1]),i=t[2],o=parseFloat(t[3]);if(!isNaN(n)&&!isNaN(o))return {num1:n,operator:i,num2:o,originalText:e,cleanExpression:`${n}${this.normalizeOperator(i)}${o}`}}}const o=e.match(/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]\s*(\d+)$/);if(o){const t=parseFloat(o[1]),n=o[2],i=parseFloat(o[3]),r=parseFloat(o[4]);if(!isNaN(t)&&!isNaN(i)){const o=this.compute(t,n,i);if(null!==o&&Math.abs(o-r)>.001)return {num1:t,operator:n,num2:i,originalText:e,cleanExpression:`${t}${this.normalizeOperator(n)}${i}`}}}return null}static normalizeOperator(t){switch(t){case "x":case "X":case "*":return "×";case "/":return "÷";default:return t}}static compute(t,e,n){switch(e){case "+":return t+n;case "-":return t-n;case "*":case "×":case "x":case "X":return t*n;case "/":case "÷":return 0===n?null:t/n;default:return null}}static calculate(t){return this.compute(t.num1,t.operator,t.num2)}static formatResult(t){return Number.isInteger(t)?String(t):t.toFixed(2).replace(/\.?0+$/,"")}static formatEquation(t,e){const n=this.normalizeOperator(t.operator);return `${t.num1}${n}${t.num2}=${this.formatResult(e)}`}static matchesPattern(t,e,n){try{if("regex"===n)return new RegExp(e,"i").test(t);{const n="^"+e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$";return new RegExp(n,"i").test(t)}}catch{return false}}static getOutputModeForHostname(t,e,n){for(const i of e)if(i.enabled&&this.matchesPattern(t,i.pattern,i.matchType))return i.outputMode;return n}static shouldCalculateForHostname(t,e){if(!e||0===e.length)return true;const n=e.filter(t=>t.enabled);if(0===n.length)return true;for(const i of n)if(this.matchesPattern(t,i.pattern,i.matchType))return true;return false}static processResult(t,e,n){if(!e.autoCalculate)return t;if(e.rules&&e.rules.length>0&&!this.shouldCalculateForHostname(n,e.rules))return t;const i=this.parseExpression(t);if(!i)return t;const o=this.calculate(i);return null===o?t:"equation"===this.getOutputModeForHostname(n,e.rules,e.outputMode)?this.formatEquation(i,o):this.formatResult(o)}static isExpression(t){return null!==this.parseExpression(t)}};d.OPERATORS=["+","-","×","*","÷","/","x","X"],d.EQUALS_CHARS=["=","="],d.QUESTION_CHARS=["?","?","〇","o","O","0"],d.NOISE_CHARS=["?","?","〇"," ","\t","\n","\r"];let s=d;class c{constructor(){this.detectedCaptchas=[],this.processedElements=new WeakMap,this.checkedAgreements=new WeakSet;}scan(){return this.detectedCaptchas=[],a.time("CaptchaDetector.scan"),this.scanImages(),this.scanCanvas(),this.scanSvg(),this.scanBackgroundImages(),a.timeEnd("CaptchaDetector.scan"),a.debug("扫描结果:",this.detectedCaptchas.length,"个验证码"),this.detectedCaptchas}scanImages(){document.querySelectorAll("img").forEach((t,e)=>{if(this.isLikelyCaptcha(t)){const n=t.getBoundingClientRect(),i={id:`captcha-${e}`,type:"image",element:t,src:t.src,rect:n,confidence:this.calculateConfidence(t),inputElement:this.findRelatedInput(t),elementInfo:this.extractCaptchaInfo(t)};this.detectedCaptchas.push(i),a.debug("检测到图片验证码:",i.elementInfo);}});}scanCanvas(){document.querySelectorAll("canvas").forEach((t,e)=>{if(this.isLikelyCanvasCaptcha(t)){const n=t.getBoundingClientRect(),i={id:`captcha-canvas-${e}`,type:"canvas",element:t,rect:n,confidence:this.calculateConfidence(t),inputElement:this.findRelatedInput(t),elementInfo:this.extractCaptchaInfo(t)};this.detectedCaptchas.push(i),a.debug("检测到Canvas验证码:",i.elementInfo);}});}scanSvg(){document.querySelectorAll("svg").forEach((t,e)=>{if(this.isLikelySvgCaptcha(t)){const n=t.getBoundingClientRect(),i={id:`captcha-svg-${e}`,type:"svg",element:t,rect:n,confidence:this.calculateConfidence(t),inputElement:this.findRelatedInput(t),elementInfo:this.extractCaptchaInfo(t)};this.detectedCaptchas.push(i),a.debug("检测到SVG验证码:",i.elementInfo);}});}scanBackgroundImages(){document.querySelectorAll('div[style*="background"], span[style*="background"], td[style*="background"]').forEach((t,e)=>{const n=t;if(this.isLikelyBackgroundCaptcha(n)){const t=n.getBoundingClientRect(),i={id:`captcha-bg-${e}`,type:"background",element:n,src:n.style.backgroundImage||"",rect:t,confidence:this.calculateConfidence(n),inputElement:this.findRelatedInput(n),elementInfo:this.extractCaptchaInfo(n)};this.detectedCaptchas.push(i),a.debug("检测到背景图验证码:",i.elementInfo);}});}extractCaptchaInfo(t){var e,n;const i=t.getBoundingClientRect();return {tagName:t.tagName.toLowerCase(),id:t.id||null,className:(null==(n=null==(e=t.className)?void 0:e.toString)?void 0:n.call(e))||"",width:Math.round(i.width),height:Math.round(i.height),src:t.src}}extractInputInfo(t){return {tagName:t.tagName.toLowerCase(),id:t.id||null,name:t.name||null,className:t.className||"",placeholder:t.placeholder||null,type:t.type||"text"}}getEffectiveSize(t){const e=t.getBoundingClientRect();let n=e.width,i=e.height;return t instanceof HTMLImageElement&&(0===n&&t.naturalWidth>0&&(n=t.naturalWidth),0===i&&t.naturalHeight>0&&(i=t.naturalHeight),0===n&&(n=parseInt(t.getAttribute("width")||"0")||0),0===i&&(i=parseInt(t.getAttribute("height")||"0")||0)),{width:n,height:i}}isLikelyCaptcha(t){const{width:e,height:n}=this.getEffectiveSize(t);return !(!this.isCaptchaSize(e,n)||!this.isVisibleOrHasSize(t,e,n)||this.isExcludedImage(t)||!this.matchesKeywords(t)&&!this.srcContainsKeywords(t.src)&&!this.parentContainsKeywords(t)&&!this.hasNearbyInput(t)&&(!this.isDataUrlImage(t)||!this.isCaptchaSize(e,n)||!this.hasNearbyInput(t)&&!this.parentContainsKeywords(t)))}isDataUrlImage(t){return t.src&&(t.src.startsWith("data:image/")||t.src.startsWith("blob:"))?t.src:null}isVisibleOrHasSize(t,e,n){const i=window.getComputedStyle(t);return "none"!==i.display&&"hidden"!==i.visibility&&"0"!==i.opacity&&e>0&&n>0}getImageSrcForExclusionCheck(t){const e=(t.currentSrc||t.src||"").trim();if(!e)return "";if(e.startsWith("data:image/")||e.startsWith("blob:"))return "";try{const t=new URL(e,window.location.href);return (t.origin+t.pathname).toLowerCase()}catch{return e.slice(0,200).toLowerCase()}}isExcludedImage(t){var e,n;const o=this.getImageSrcForExclusionCheck(t),r=(t.alt||"").toLowerCase(),a=((null==(n=null==(e=t.className)?void 0:e.toString)?void 0:n.call(e))||"").toLowerCase(),d=(t.id||"").toLowerCase(),s=i.EXCLUDE_PATTERNS,c=`${o} ${r} ${a} ${d}`.trim();return s.some(t=>c.includes(t))}isLikelyCanvasCaptcha(t){const e=t.getBoundingClientRect();return !(!this.isCaptchaSize(e.width,e.height)||!this.isVisible(t)||!this.matchesKeywords(t)&&!this.parentContainsKeywords(t)&&!this.hasNearbyInput(t))}isLikelySvgCaptcha(t){const e=t.clientWidth||parseInt(t.getAttribute("width")||"0"),n=t.clientHeight||parseInt(t.getAttribute("height")||"0");return !(!this.isCaptchaSize(e,n)||!this.isVisible(t)||!this.matchesKeywords(t)&&!this.parentContainsKeywords(t)&&!this.hasNearbyInput(t))}isLikelyBackgroundCaptcha(t){const e=t.style.backgroundImage||"";if(!e||"none"===e)return false;const n=t.getBoundingClientRect();return !!this.isCaptchaSize(n.width,n.height)&&!!this.isVisible(t)&&(!!this.matchesKeywords(t)||!!this.parentContainsKeywords(t)||!!this.hasNearbyInput(t)||!!e.includes("data:image/")&&(this.hasNearbyInput(t)||this.parentContainsKeywords(t)))}isCaptchaSize(t,e){return t>=i.MIN_CAPTCHA_WIDTH&&t<=i.MAX_CAPTCHA_WIDTH&&e>=i.MIN_CAPTCHA_HEIGHT&&e<=i.MAX_CAPTCHA_HEIGHT}isVisible(t){const e=window.getComputedStyle(t),n=t.getBoundingClientRect();return "none"!==e.display&&"hidden"!==e.visibility&&"0"!==e.opacity&&n.width>0&&n.height>0}isFrameworkCheckbox(t){const e=["el-checkbox__original","ant-checkbox-input","ivu-checkbox-input","van-checkbox__input","weui-check","mdui-checkbox-input","mdc-checkbox__native-control"];for(const i of e)if(t.classList.contains(i))return true;const n=[".el-checkbox",".ant-checkbox",".ant-checkbox-wrapper",".ivu-checkbox",".ivu-checkbox-wrapper",".van-checkbox",".weui-check__label",".mdui-checkbox",".mdc-checkbox"];for(const i of n)if(t.closest(i))return true;return false}isCheckboxFunctional(t){if(t.disabled)return false;if(this.isFrameworkCheckbox(t)){const e=[t.closest(".el-checkbox"),t.closest(".ant-checkbox-wrapper"),t.closest(".ivu-checkbox-wrapper"),t.closest(".van-checkbox"),t.closest("label")];for(const t of e)if(t){const e=window.getComputedStyle(t);if("none"!==e.display&&"hidden"!==e.visibility)return true}let n=t.parentElement,i=0;for(;n&&i<5;){const t=window.getComputedStyle(n);if("none"===t.display)return false;if("hidden"===t.visibility)return false;n=n.parentElement,i++;}return true}if("none"===window.getComputedStyle(t).display)return false;let e=t.parentElement,n=0;for(;e&&n<5;){const t=window.getComputedStyle(e);if("none"===t.display||"hidden"===t.visibility)return false;e=e.parentElement,n++;}return true}findClickableTarget(t){const e=t.closest(".el-checkbox");if(e)return e.querySelector(".el-checkbox__inner")||e;const n=t.closest(".ant-checkbox-wrapper");if(n)return n.querySelector(".ant-checkbox-inner")||n;const i=t.closest(".ivu-checkbox-wrapper");if(i)return i.querySelector(".ivu-checkbox-inner")||i;const o=t.closest(".van-checkbox");return o?o.querySelector(".van-checkbox__icon")||o:t.closest("label")||null}matchesKeywords(t){var e,n;const o=((null==(n=null==(e=t.className)?void 0:e.toString)?void 0:n.call(e))||"").toLowerCase(),r=(t.id||"").toLowerCase();return i.CAPTCHA_KEYWORDS.some(t=>o.includes(t)||r.includes(t))}srcContainsKeywords(t){if(!t)return false;const e=t.toLowerCase();return i.CAPTCHA_KEYWORDS.some(t=>e.includes(t))}parentContainsKeywords(t){let e=t.parentElement,n=0;for(;e&&n<3;){if(this.matchesKeywords(e))return true;e=e.parentElement,n++;}return false}hasNearbyInput(t){return null!==this.findRelatedInput(t)}getInputLabelText(t){try{if(t.id){const e=document.querySelector(`label[for="${CSS.escape(t.id)}"]`);if(e)return (e.textContent||"").trim()}const e=t.closest("label");if(e)return (e.textContent||"").trim()}catch{}return ""}getInputSearchText(t){const e=[];return e.push(t.name||""),e.push(t.id||""),e.push(t.className||""),e.push(t.placeholder||""),e.push(t.getAttribute("aria-label")||""),e.push(t.getAttribute("data-label")||""),e.push(t.getAttribute("data-name")||""),e.push(this.getInputLabelText(t)),e.join(" ").toLowerCase()}isCaptchaInputByName(t){const e=this.getInputSearchText(t);return i.INPUT_KEYWORDS.some(t=>e.includes(t))}isExcludedInputByText(t){const e=this.getInputSearchText(t);return ["username","user","account","email","phone","mobile","tel","password","pwd","pass","search","query","keyword","用户名","账号","密码","手机","手机号","邮箱","搜索","查询","关键字"].some(t=>e.includes(t))}scoreInputCandidate(t,e,n){const i=this.calculateDistance(e,n);let o=0;const r=this.getInputSearchText(t);return this.isCaptchaInputByName(t)&&(o+=120),r.includes("验证码")&&(o+=140),r.includes("verify")&&(o+=80),r.includes("vcode")&&(o+=80),r.includes("authcode")&&(o+=80),r.includes("checkcode")&&(o+=80),r.includes("yzm")&&(o+=60),this.isExcludedInputByText(t)&&(o-=200),i-o}findClosestInputInContainer(t,e,n=Infinity){const i=t.querySelectorAll("input");let o=null,r=Infinity,a=Infinity;for(const d of i){const t=d;if(!this.isValidCaptchaInput(t))continue;const i=d.getBoundingClientRect(),s=this.calculateDistance(e,i);if(s>n)continue;const c=this.scoreInputCandidate(t,e,i);(cn.right&&e.left-n.right<220&&Math.abs(e.top-n.top)<90||e.top>n.bottom&&e.top-n.bottom<160&&Math.abs(e.left-n.left)<160||this.calculateDistance(n,e)<240))continue;const i=this.scoreInputCandidate(t,n,e);i{if(!this.isVisible(t))return;const{width:e,height:o}=this.getEffectiveSize(t);if(!this.isCaptchaSize(e,o))return;if(this.isExcludedImage(t))return;const r=t.getBoundingClientRect(),a=this.calculateDistance(n,r);i.push({element:t,distance:a,type:"image"});}),document.querySelectorAll("canvas").forEach(t=>{if(!this.isVisible(t))return;const e=t.getBoundingClientRect();if(!this.isCaptchaSize(e.width,e.height))return;const o=this.calculateDistance(n,e);i.push({element:t,distance:o,type:"canvas"});}),document.querySelectorAll("svg").forEach(t=>{if(!this.isVisible(t))return;const e=t.clientWidth||parseInt(t.getAttribute("width")||"0"),o=t.clientHeight||parseInt(t.getAttribute("height")||"0");if(!this.isCaptchaSize(e,o))return;const r=t.getBoundingClientRect(),a=this.calculateDistance(n,r);i.push({element:t,distance:a,type:"svg"});}),document.querySelectorAll('div[style*="background"], span[style*="background"]').forEach(t=>{const e=t;if(!this.isVisible(e))return;const o=e.style.backgroundImage||"";if(!o||"none"===o)return;const r=e.getBoundingClientRect();if(!this.isCaptchaSize(r.width,r.height))return;const a=this.calculateDistance(n,r);i.push({element:e,distance:a,type:"background"});}),i.sort((t,e)=>t.distance-e.distance);const o=i.slice(0,3);for(const r of o){const t=Math.max(0,100-Math.floor(r.distance/5));e.push({element:r.element,type:"captcha",confidence:t,selector:this.generateSelector(r.element)});}return a.debug("猜测的验证码元素:",e),e}guessRelatedInput(t){const e=[],n=t.getBoundingClientRect();a.debug("开始猜测关联的输入框, 验证码位置:",n);const i=[];document.querySelectorAll("input").forEach(t=>{const e=t;if(!this.isValidCaptchaInput(e))return;if(!this.isVisible(e))return;const o=e.getBoundingClientRect(),r=this.calculateDistance(n,o),a=this.isCaptchaInputByName(e),d=this.scoreInputCandidate(e,n,o);i.push({element:e,distance:r,hasKeyword:a,score:d});}),i.sort((t,e)=>t.score-e.score);const o=i.slice(0,3);for(const r of o){let t=Math.max(0,100-Math.floor(r.distance/5));r.hasKeyword&&(t=Math.min(100,t+20)),e.push({element:r.element,type:"input",confidence:t,selector:this.generateSelector(r.element)});}return a.debug("猜测的输入框元素:",e),e}guessAgreementCheckboxes(){const t=[];return document.querySelectorAll('input[type="checkbox"]').forEach(e=>{var n;const o=e;if(!this.isCheckboxFunctional(o))return;if(this.checkedAgreements.has(o))return;const r=[];r.push(o.name||""),r.push(o.id||""),r.push(o.className||""),r.push(o.getAttribute("data-type")||""),r.push(o.getAttribute("data-name")||""),r.push(o.getAttribute("aria-label")||""),r.push(o.getAttribute("data-v-inspector")||"");const a=o.id?document.querySelector(`label[for="${o.id}"]`):null;a&&(r.push(a.textContent||""),r.push(a.className||""));const d=o.closest("label");d&&(r.push(d.textContent||""),r.push(d.className||""));const s=[o.closest(".el-checkbox"),o.closest(".ant-checkbox-wrapper"),o.closest(".ivu-checkbox-wrapper"),o.closest(".van-checkbox"),o.closest('[class*="checkbox"]')];for(const t of s)t&&(r.push(t.textContent||""),r.push(t.className||""));let c=o.parentElement,l=0;for(;c&&l<6;){const t=c.tagName.toLowerCase();if(r.push(c.className||""),r.push(c.id||""),["label","div","span","p","li","td"].includes(t)){const t=c.children;for(let e=0;eh.includes(t))){const e=this.findClickableTarget(o);t.push({element:o,type:"agreement",confidence:80,selector:this.generateSelector(o),clickTarget:e||void 0});}}),a.debug("猜测的协议复选框:",t),t}findAgreementsBySelectors(t){const e=[];for(const i of t)if(i.trim())try{document.querySelectorAll(i).forEach(t=>{if(t instanceof HTMLInputElement&&"checkbox"===t.type&&!this.checkedAgreements.has(t)){const n=this.findClickableTarget(t);e.push({element:t,type:"agreement",confidence:100,selector:i,clickTarget:n||void 0});}});}catch(n){a.warn("无效的协议选择器:",i,n);}return e}markAgreementChecked(t){this.checkedAgreements.add(t);}calculateDistance(t,e){const n=t.left+t.width/2,i=t.top+t.height/2,o=e.left+e.width/2,r=e.top+e.height/2;return Math.sqrt(Math.pow(o-n,2)+Math.pow(r-i,2))}generateSelector(t){if(t.id)return "#"+t.id;const e=t.className;if(e){const n=e.toString().trim().split(/\s+/).filter(t=>t&&!t.includes(":"));if(n.length>0){const e=t.tagName.toLowerCase()+"."+n.join(".");if(1===document.querySelectorAll(e).length)return e}}const n=[];let i=t;for(;i&&i!==document.body&&n.length<5;){let t=i.tagName.toLowerCase();if(i.id){n.unshift("#"+i.id);break}const e=i.parentElement;if(e){const n=Array.from(e.children).filter(t=>t.tagName===i.tagName);n.length>1&&(t+=":nth-of-type("+(n.indexOf(i)+1)+")");}n.unshift(t),i=i.parentElement;}return n.join(" > ")}async captureImage(t){switch(t.type){case "image":return this.captureImgElement(t.element);case "canvas":return this.captureCanvasElement(t.element);case "svg":return this.captureSvgElement(t.element);case "background":return this.captureBackgroundElement(t.element)}}async captureBuffer(t){const e=await this.captureBlob(t);return await e.arrayBuffer()}async captureBlob(t){switch(t.type){case "image":return this.captureImgAsBlob(t.element);case "canvas":return this.captureCanvasAsBlob(t.element);case "svg":return this.captureSvgAsBlob(t.element);case "background":return this.captureBackgroundAsBlob(t.element)}}async captureImgElement(t){await this.waitForImageLoad(t);const e=document.createElement("canvas"),n=e.getContext("2d"),i=t.naturalWidth||t.width,o=t.naturalHeight||t.height;e.width=i,e.height=o,n.drawImage(t,0,0,i,o);try{return e.toDataURL("image/png")}catch{if(t.src.startsWith("data:"))return t.src;throw new Error("无法捕获跨域图片")}}async captureImgAsBlob(t){if(await this.waitForImageLoad(t),t.src&&!t.src.startsWith("data:")&&!t.src.startsWith("blob:"))try{const e=await fetch(t.src,{credentials:"include"});if(e.ok&&(e.headers.get("content-type")||"").includes("image/"))return await e.blob()}catch{}const e=document.createElement("canvas"),n=e.getContext("2d"),i=t.naturalWidth||t.width,o=t.naturalHeight||t.height;return e.width=i,e.height=o,n.fillStyle="#FFFFFF",n.fillRect(0,0,i,o),n.drawImage(t,0,0,i,o),await new Promise((t,n)=>{e.toBlob(e=>{e?t(e):n(new Error("图片转换失败"));},"image/png");})}async waitForImageLoad(t){var e;if(!(t.complete&&t.naturalWidth>0||(null==(e=t.src)?void 0:e.startsWith("data:"))&&t.naturalWidth>0))return new Promise((e,n)=>{const i=setTimeout(()=>n(new Error("图片加载超时")),5e3),o=()=>{a(),e();},r=()=>{a(),n(new Error("图片加载失败"));},a=()=>{clearTimeout(i),t.removeEventListener("load",o),t.removeEventListener("error",r);};t.addEventListener("load",o),t.addEventListener("error",r);})}captureCanvasElement(t){return t.toDataURL("image/png")}captureCanvasAsBlob(t){return new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("Canvas转换失败"));},"image/png");})}async captureSvgElement(t){const e=await this.captureSvgAsBlob(t);return await this.blobToDataURL(e)}async captureSvgAsBlob(t){const e=t.cloneNode(true),n=t.getBoundingClientRect();e.setAttribute("width",String(n.width)),e.setAttribute("height",String(n.height)),e.getAttribute("xmlns")||e.setAttribute("xmlns","http://www.w3.org/2000/svg");const i=(new XMLSerializer).serializeToString(e),o=new Blob([i],{type:"image/svg+xml"}),r=URL.createObjectURL(o);try{const t=await new Promise((t,e)=>{const n=new Image;n.onload=()=>t(n),n.onerror=()=>e(new Error("SVG转换失败")),n.src=r;}),e=document.createElement("canvas");e.width=Math.max(1,Math.round(n.width)),e.height=Math.max(1,Math.round(n.height));const i=e.getContext("2d");return i.fillStyle="#FFFFFF",i.fillRect(0,0,e.width,e.height),i.drawImage(t,0,0),await new Promise((t,n)=>{e.toBlob(e=>{e?t(e):n(new Error("SVG转换失败"));},"image/png");})}finally{URL.revokeObjectURL(r);}}async captureBackgroundElement(t){const e=await this.captureBackgroundAsBlob(t);return await this.blobToDataURL(e)}async captureBackgroundAsBlob(t){const e=(t.style.backgroundImage||window.getComputedStyle(t).backgroundImage||"").match(/url\(['"]?(.+?)['"]?\)/);if(!e)throw new Error("无法提取背景图URL");const n=e[1];if(n.startsWith("data:")){const t=await fetch(n);return await t.blob()}const i=new Image;i.crossOrigin="anonymous",i.src=n,await new Promise((t,e)=>{i.onload=()=>t(),i.onerror=()=>e(new Error("背景图加载失败")),setTimeout(()=>e(new Error("背景图加载超时")),5e3);});const o=document.createElement("canvas"),r=t.getBoundingClientRect();o.width=Math.max(1,Math.round(r.width)),o.height=Math.max(1,Math.round(r.height));const a=o.getContext("2d");return a.fillStyle="#FFFFFF",a.fillRect(0,0,o.width,o.height),a.drawImage(i,0,0,o.width,o.height),new Promise((t,e)=>{o.toBlob(n=>{n?t(n):e(new Error("背景图转换失败"));},"image/png");})}blobToDataURL(t){return new Promise((e,n)=>{const i=new FileReader;i.onload=()=>e(String(i.result)),i.onerror=()=>n(new Error("读取失败")),i.readAsDataURL(t);})}highlight(t){t.element.setAttribute("data-captcha-highlight","true");}unhighlight(t){t.element.removeAttribute("data-captcha-highlight");}highlightGuessed(t){t.setAttribute("data-captcha-guessed","true");}unhighlightGuessed(t){t.removeAttribute("data-captcha-guessed");}unhighlightAllGuessed(){document.querySelectorAll("[data-captcha-guessed]").forEach(t=>{t.removeAttribute("data-captcha-guessed");});}getDetectedCaptchas(){return this.detectedCaptchas}getMostLikelyCaptcha(){return 0===this.detectedCaptchas.length?null:this.detectedCaptchas.reduce((t,e)=>e.confidence>t.confidence?e:t)}hasElementChanged(t){const e=this.getElementHash(t),n=this.processedElements.get(t);return !n||e!==n}markElementProcessed(t){const e=this.getElementHash(t);this.processedElements.set(t,e);}getElementHash(t){if(t instanceof HTMLImageElement)return t.src+"_"+t.naturalWidth+"_"+t.naturalHeight;if(t instanceof HTMLCanvasElement)try{return t.toDataURL()}catch{return "canvas_"+Date.now()}else {if(t instanceof SVGElement)return t.outerHTML;if(t instanceof HTMLElement&&t.style.backgroundImage)return t.style.backgroundImage}return ""}}class l{constructor(){this.listeners=new Map;}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e);}off(t,e){var n;null==(n=this.listeners.get(t))||n.delete(e);}emit(t,e){var n;null==(n=this.listeners.get(t))||n.forEach(n=>{try{n(e);}catch(i){console.error(`Event handler error [${String(t)}]:`,i);}});}clear(){this.listeners.clear();}}const u="ddddocr_model_cache",h="ddddocr_uploaded_model";class p{constructor(){this.dbName="DdddOCRDB",this.storeName="modelStore",this.db=null;}async init(){return new Promise((t,e)=>{const n=indexedDB.open(this.dbName,2);n.onerror=()=>e(n.error),n.onsuccess=()=>{this.db=n.result,t();},n.onupgradeneeded=t=>{const e=t.target.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName);};})}async get(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(u);n.onerror=()=>e(n.error),n.onsuccess=()=>{const e=n.result;if(e)return Date.now()-e.timestamp>i.CACHE_DURATION||e.version!==i.MODEL_VERSION?(this.delete(),void t(null)):void t(e);t(null);};})}async set(t,e){this.db||await this.init();const n={model:t,charsets:e,timestamp:Date.now(),version:i.MODEL_VERSION};return new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,u);i.onerror=()=>e(i.error),i.onsuccess=()=>t();})}async delete(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(u);n.onerror=()=>e(n.error),n.onsuccess=()=>t();})}async getUploadedModel(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(h);n.onerror=()=>e(n.error),n.onsuccess=()=>t(n.result||null);})}async setUploadedModel(t,e){this.db||await this.init();const n={model:t,charsets:e,timestamp:Date.now(),version:"uploaded"};return new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,h);i.onerror=()=>e(i.error),i.onsuccess=()=>t();})}async deleteUploadedModel(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(h);n.onerror=()=>e(n.error),n.onsuccess=()=>t();})}}function m(t,e=3e4){return new Promise((n,i)=>{GM_xmlhttpRequest({method:"GET",url:t,responseType:"arraybuffer",timeout:e,headers:{"Cache-Control":"max-age=2592000"},onload:t=>{200===t.status?n(t.response):i(new Error(`HTTP ${t.status}`));},onerror:t=>i(t),ontimeout:()=>i(new Error("下载超时"))});})}function g(t,e=3e4){return new Promise((n,i)=>{GM_xmlhttpRequest({method:"GET",url:t,responseType:"json",timeout:e,headers:{"Cache-Control":"max-age=2592000"},onload:t=>{200===t.status?n(t.response):i(new Error(`HTTP ${t.status}`));},onerror:t=>i(t),ontimeout:()=>i(new Error("下载超时"))});})}function b(t,e){const n=t.replace(/\/+$/,""),o=e.replace(/^\/+/,"");if(n.includes("jsdelivr"))return `${n}/${i.MODEL_REPO}@${i.MODEL_BRANCH}/${o}`;const r=`/${i.MODEL_REPO}/`;return n.includes(r)?`${n}/${o}`:`${n}/${i.MODEL_REPO}/${i.MODEL_BRANCH}/${o}`}async function f(){const t=GM_getValue("ddddocr_config")||{},e=new p;if(t.useUploadedModel){const t=await e.getUploadedModel();if(t)return console.log("✅ 使用上传的模型"),{model:t.model,charsets:t.charsets}}if(false===t.autoDownload)throw new Error("自动下载已禁用,请上传模型文件或启用自动下载");const n=await e.get();if(n)return console.log("✅ 使用缓存的模型"),{model:n.model,charsets:n.charsets};console.log("📥 开始下载模型");let o=null,r=null;for(let d=0;dt.includes("jsdelivr")?`${t}/npm/onnxruntime-web@${i.WASM_VERSION}/dist/`:t.includes("unpkg")?`${t}/onnxruntime-web@${i.WASM_VERSION}/dist/`:t.includes("cdnjs")?`${t}/ajax/libs/onnxruntime-web/${i.WASM_VERSION}/`:t.includes("npmmirror")?`${t}/onnxruntime-web/${i.WASM_VERSION}/files/dist/`:`${t}/onnxruntime-web@${i.WASM_VERSION}/dist/`),w=["ort-wasm.wasm","ort-wasm-simd.wasm","ort-wasm-threaded.wasm","ort-wasm-simd-threaded.wasm"],y=new class{constructor(){this.dbName="WASMCacheDB",this.storeName="wasmStore",this.db=null,this.memoryCache=new Map;}async init(){if(!this.db)try{await this.openDatabase();}catch(t){if(!(t instanceof Error&&"VersionError"===t.name))throw t;await this.handleVersionError();}}openDatabase(){return new Promise((t,e)=>{const n=indexedDB.open(this.dbName,3);n.onerror=()=>{const t=n.error;e(t||new Error("数据库打开失败"));},n.onsuccess=()=>{this.db=n.result,this.db.onerror=t=>{console.warn("[WASMCache] 数据库错误:",t);},t();},n.onupgradeneeded=t=>{const e=t.target.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName);},n.onblocked=()=>{console.warn("[WASMCache] 数据库被阻塞");};})}async handleVersionError(){return console.warn("[WASMCache] 检测到数据库版本冲突,正在重建数据库..."),new Promise((t,e)=>{const n=indexedDB.deleteDatabase(this.dbName);n.onerror=()=>{e(new Error("无法删除旧数据库"));},n.onsuccess=()=>{console.log("[WASMCache] 旧数据库已删除,正在创建新数据库..."),this.openDatabase().then(t).catch(e);},n.onblocked=()=>{console.warn("[WASMCache] 删除数据库被阻塞"),setTimeout(()=>{this.openDatabase().then(t).catch(e);},100);};})}async get(t){return this.memoryCache.has(t)?this.memoryCache.get(t):(this.db||await this.init(),new Promise((e,n)=>{try{const o=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(t);o.onerror=()=>n(o.error),o.onsuccess=()=>{const n=o.result;if(n){if(Date.now()-n.timestamp>i.CACHE_DURATION||n.version!==i.WASM_VERSION)return this.delete(t).catch(()=>{}),void e(null);this.memoryCache.set(t,n.data),e(n.data);}else e(null);};}catch(o){n(o);}}))}async set(t,e){this.db||await this.init(),this.memoryCache.set(t,e);const n={data:e,timestamp:Date.now(),version:i.WASM_VERSION};return new Promise((e,i)=>{try{const o=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,t);o.onerror=()=>i(o.error),o.onsuccess=()=>e();}catch(o){i(o);}})}async delete(t){return this.memoryCache.delete(t),this.db||await this.init(),new Promise((e,n)=>{try{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(t);i.onerror=()=>n(i.error),i.onsuccess=()=>e();}catch(i){n(i);}})}async clear(){return this.memoryCache.clear(),this.db||await this.init(),new Promise((t,e)=>{try{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();n.onerror=()=>e(n.error),n.onsuccess=()=>t();}catch(n){e(n);}})}};async function x(t){for(let n=0;n{GM_xmlhttpRequest({method:"GET",url:i,responseType:"arraybuffer",timeout:3e4,headers:{Accept:"application/wasm","Cache-Control":"max-age=2592000"},onload:n=>{200===n.status?t(n.response):e(new Error(`HTTP ${n.status}`));},onerror:e,ontimeout:()=>e(new Error("下载超时"))});})}catch(e){if(n===v.length-1)throw new Error(`所有 WASM CDN 均下载失败: ${t}`)}}throw new Error(`下载 WASM 失败: ${t}`)}const E=class{static isMobile(){return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<=768}static injectStyles(){if(this.stylesInjected)return;const t=document.createElement("style");t.textContent="\n .ddddocr-dialog-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: ddddocr-fade-in 0.3s ease;\n padding: 16px;\n box-sizing: border-box;\n }\n\n .ddddocr-dialog {\n background: white;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(74, 144, 226, 0.25);\n max-width: 500px;\n width: 100%;\n max-height: 80vh;\n overflow: hidden;\n animation: ddddocr-scale-in 0.3s ease;\n display: flex;\n flex-direction: column;\n }\n\n .ddddocr-dialog.mobile {\n max-width: 100%;\n border-radius: 12px;\n }\n\n .ddddocr-dialog-header {\n background: #4A90E2;\n color: white;\n padding: 20px 24px;\n font-size: 18px;\n font-weight: 600;\n display: flex;\n align-items: center;\n gap: 10px;\n flex-shrink: 0;\n }\n\n .ddddocr-dialog.mobile .ddddocr-dialog-header {\n padding: 16px 20px;\n font-size: 16px;\n }\n\n .ddddocr-dialog-body {\n padding: 24px;\n max-height: calc(80vh - 140px);\n overflow-y: auto;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n flex: 1;\n -webkit-overflow-scrolling: touch;\n }\n\n .ddddocr-dialog.mobile .ddddocr-dialog-body {\n padding: 20px;\n }\n\n .ddddocr-dialog-body::-webkit-scrollbar {\n width: 6px;\n }\n\n .ddddocr-dialog-body::-webkit-scrollbar-track {\n background: #f1f5f9;\n border-radius: 3px;\n }\n\n .ddddocr-dialog-body::-webkit-scrollbar-thumb {\n background: #FFB6C1;\n border-radius: 3px;\n }\n\n .ddddocr-dialog-body::-webkit-scrollbar-thumb:hover {\n background: #FF69B4;\n }\n\n .ddddocr-dialog-content {\n color: #333;\n font-size: 14px;\n line-height: 1.6;\n white-space: pre-wrap;\n }\n\n .ddddocr-dialog.mobile .ddddocr-dialog-content {\n font-size: 15px;\n }\n\n .ddddocr-dialog-footer {\n padding: 16px 24px;\n border-top: 1px solid #f1f5f9;\n display: flex;\n justify-content: flex-end;\n gap: 12px;\n flex-shrink: 0;\n }\n\n .ddddocr-dialog.mobile .ddddocr-dialog-footer {\n padding: 16px 20px;\n flex-direction: column-reverse;\n }\n\n .ddddocr-dialog-button {\n padding: 10px 24px;\n border: none;\n border-radius: 8px;\n font-size: 14px;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.3s;\n -webkit-tap-highlight-color: transparent;\n }\n\n .ddddocr-dialog.mobile .ddddocr-dialog-button {\n padding: 14px 24px;\n font-size: 15px;\n width: 100%;\n }\n\n .ddddocr-dialog-button.primary {\n background: #4A90E2;\n color: white;\n }\n\n .ddddocr-dialog-button.primary:hover {\n transform: translateY(-2px);\n box-shadow: 0 6px 20px rgba(74, 144, 226, 0.35);\n }\n\n .ddddocr-dialog-button.primary:active {\n transform: translateY(0);\n }\n\n .ddddocr-dialog-button.secondary {\n background: #f1f5f9;\n color: #4A90E2;\n }\n\n .ddddocr-dialog-button.secondary:hover {\n background: #e2e8f0;\n }\n\n .ddddocr-dialog-button.secondary:active {\n background: #cbd5e1;\n }\n\n @keyframes ddddocr-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n\n @keyframes ddddocr-scale-in {\n from { opacity: 0; transform: scale(0.9); }\n to { opacity: 1; transform: scale(1); }\n }\n ",document.head.appendChild(t),this.stylesInjected=true;}static stopPropagation(t){t.stopPropagation();}static show(t){var e;this.injectStyles(),this.close();const n=document.createElement("div");n.className="ddddocr-dialog-overlay";const i=document.createElement("div");i.className="ddddocr-dialog",this.isMobile()&&i.classList.add("mobile"),i.innerHTML=`\n
${t.icon||"ℹ️"} ${t.title}
\n
\n
${t.content}
\n
\n \n `,n.appendChild(i),document.body.appendChild(n),this.container=n,i.addEventListener("mousedown",this.stopPropagation),i.addEventListener("mouseup",this.stopPropagation),i.addEventListener("click",this.stopPropagation),i.addEventListener("dblclick",this.stopPropagation),i.addEventListener("wheel",this.stopPropagation),i.addEventListener("keydown",this.stopPropagation),i.addEventListener("keyup",this.stopPropagation),i.addEventListener("keypress",this.stopPropagation),i.addEventListener("contextmenu",this.stopPropagation),i.addEventListener("touchstart",this.stopPropagation,{passive:true}),i.addEventListener("touchmove",this.stopPropagation,{passive:true}),i.addEventListener("touchend",this.stopPropagation),null==(e=i.querySelector(".ddddocr-dialog-button"))||e.addEventListener("click",()=>{var e;null==(e=t.onConfirm)||e.call(t),this.close();}),n.addEventListener("click",t=>{t.target===n&&this.close();});}static confirm(t){var e,n;this.injectStyles(),this.close();const i=document.createElement("div");i.className="ddddocr-dialog-overlay";const o=document.createElement("div");o.className="ddddocr-dialog",this.isMobile()&&o.classList.add("mobile"),o.innerHTML=`\n
${t.icon||"❓"} ${t.title}
\n
\n
${t.content}
\n
\n \n `,i.appendChild(o),document.body.appendChild(i),this.container=i,o.addEventListener("mousedown",this.stopPropagation),o.addEventListener("mouseup",this.stopPropagation),o.addEventListener("click",this.stopPropagation),o.addEventListener("dblclick",this.stopPropagation),o.addEventListener("wheel",this.stopPropagation),o.addEventListener("keydown",this.stopPropagation),o.addEventListener("keyup",this.stopPropagation),o.addEventListener("keypress",this.stopPropagation),o.addEventListener("contextmenu",this.stopPropagation),o.addEventListener("touchstart",this.stopPropagation,{passive:true}),o.addEventListener("touchmove",this.stopPropagation,{passive:true}),o.addEventListener("touchend",this.stopPropagation),null==(e=o.querySelector(".confirm-btn"))||e.addEventListener("click",()=>{var e;null==(e=t.onConfirm)||e.call(t),this.close();}),null==(n=o.querySelector(".cancel-btn"))||n.addEventListener("click",()=>{var e;null==(e=t.onCancel)||e.call(t),this.close();}),i.addEventListener("click",e=>{var n;e.target===i&&(null==(n=t.onCancel)||n.call(t),this.close());});}static close(){var t;null==(t=this.container)||t.remove(),this.container=null;}};E.container=null,E.stylesInjected=false;let C=E;const S="ddddocr_config_version",k="ddddocr_stats",I="ddddocr_site_rules",A=function(t,e,n){const i=()=>t(S)||1,r=t=>e(S,t);return {getConfig:()=>function(t,e,n){if(!t)return n(2),{...o};const i=e();let r={...o};for(const a of Object.keys(t)){const e=t[a];void 0!==e&&a in o&&(r[a]=e);}if(i<2&&t.agreementSelector&&(!r.agreementSelectors||0===r.agreementSelectors.length)){const e=t.agreementSelector.trim();e&&(r.agreementSelectors=[e]);}for(const a of Object.keys(o)) void 0===r[a]&&(r[a]=o[a]);return 2!==i&&n(2),r}(t(n),i,r),saveConfig(t){const i={...this.getConfig(),...t};e(n,i);},resetConfig(){e(n,o),r(2);}}}(t=>GM_getValue(t),(t,e)=>GM_setValue(t,e),"ddddocr_config");function R(){return A.getConfig()}function M(t){A.saveConfig(t);}function L(){return GM_getValue(I)||{}}function T(t,e){const n=L(),i=e.fullUrl||e.urlPattern||t,o=n[i]||{};n[i]={...o,...e,hostname:t,createdAt:o.createdAt||Date.now(),updatedAt:Date.now(),enabled:false!==e.enabled},GM_setValue(I,n);}function D(t){const e=L();delete e[t],GM_setValue(I,e);}const N=new class{constructor(t){this.dirty=false,this.saveTimer=null,this.storage=t,this.data=this.load();}load(){const t=this.storage.get(k);return t&&"object"==typeof t&&t.sites?t:{sites:{},total:0,updated:Date.now()}}scheduleSave(){this.saveTimer||(this.saveTimer=window.setTimeout(()=>{this.flush(),this.saveTimer=null;},5e3));}flush(){this.dirty&&(this.data.updated=Date.now(),this.storage.set(k,this.data),this.dirty=false);}record(t,e){this.data.sites[t]||(Object.keys(this.data.sites).length>=100&&this.pruneOldest(),this.data.sites[t]={count:0,lastTime:0,totalTime:0});const n=this.data.sites[t];n.count++,n.lastTime=Date.now(),n.totalTime+=e,this.data.total++,this.dirty=true,this.scheduleSave();}pruneOldest(){const t=Object.entries(this.data.sites);t.sort((t,e)=>t[1].lastTime-e[1].lastTime);const e=t.slice(0,10);for(const[n]of e)delete this.data.sites[n];}getStats(){return {...this.data}}getSiteStats(t){return this.data.sites[t]||null}getTopSites(t=10){return Object.entries(this.data.sites).map(([t,e])=>({hostname:t,stats:e})).sort((t,e)=>e.stats.count-t.stats.count).slice(0,t)}getAverageTime(t){if(t){const e=this.data.sites[t];return e&&e.count>0?Math.round(e.totalTime/e.count):0}if(0===this.data.total)return 0;const e=Object.values(this.data.sites).reduce((t,e)=>t+e.totalTime,0);return Math.round(e/this.data.total)}clear(){this.data={sites:{},total:0,updated:Date.now()},this.dirty=true,this.flush();}}({get:t=>GM_getValue(t),set:(t,e)=>GM_setValue(t,e)});function _(){const t=R();if(!t.enableWhitelist)return true;if(!t.whitelist||0===t.whitelist.length)return false;const e=window.location.hostname;return t.whitelist.some(t=>new RegExp("^"+t.replace(/\*/g,".*")+"$","i").test(e))}function $(){const t=R();if(t.enableWhitelist){if(!t.whitelist||0===t.whitelist.length)return false;if(!_())return false}return true}function P(){return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<=768}function H(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function O(t){return t?new Date(t).toLocaleDateString():"-"}class z{constructor(){this.container=null,this.overlay=null,this.isVisible=false,this.onConfigChange=()=>{},this.activeTab="general",this.currentEditRuleKey=null,this.createStyles(),this.handleResize=this.handleResize.bind(this);}handleResize(){this.container&&this.container.classList.toggle("mobile",P());}createStyles(){const t=document.createElement("style");t.id="ddddocr-settings-styles",t.textContent="\n.ddddocr-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n z-index: 2147483646;\n display: none;\n animation: ddddocr-fade 0.2s ease;\n -webkit-overflow-scrolling: touch;\n}\n.ddddocr-overlay.visible { display: block; }\n\n.ddddocr-modal {\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n width: 640px;\n max-width: 95vw;\n max-height: 85vh;\n background: #4A90E2;\n border-radius: 20px;\n z-index: 2147483647;\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n overflow: hidden;\n display: none;\n box-shadow: 0 25px 80px rgba(74, 144, 226, 0.35);\n}\n.ddddocr-modal.visible {\n display: block;\n animation: ddddocr-scale 0.3s ease;\n}\n.ddddocr-modal.mobile {\n width: 100%;\n max-width: 100%;\n height: 100%;\n max-height: 100%;\n top: 0;\n left: 0;\n transform: none;\n border-radius: 0;\n}\n\n@keyframes ddddocr-fade { from { opacity: 0; } to { opacity: 1; } }\n@keyframes ddddocr-scale {\n from { opacity: 0; transform: translate(-50%, -50%) scale(0.9); }\n to { opacity: 1; transform: translate(-50%, -50%) scale(1); }\n}\n.ddddocr-modal.mobile.visible {\n animation: ddddocr-slide-up 0.3s ease;\n}\n@keyframes ddddocr-slide-up {\n from { opacity: 0; transform: translateY(100%); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.ddddocr-header {\n background: rgba(255, 255, 255, 0.15);\n padding: 20px 24px;\n display: flex;\n justify-content: space-between;\n align-items: center;\n border-bottom: 1px solid rgba(255, 255, 255, 0.15);\n}\n.ddddocr-modal.mobile .ddddocr-header {\n padding: 16px;\n position: sticky;\n top: 0;\n z-index: 10;\n}\n\n.ddddocr-title {\n color: white;\n font-size: 20px;\n font-weight: 700;\n display: flex;\n align-items: center;\n gap: 10px;\n text-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);\n}\n.ddddocr-modal.mobile .ddddocr-title { font-size: 18px; }\n\n.ddddocr-close {\n width: 36px;\n height: 36px;\n min-width: 36px;\n min-height: 36px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.25);\n border: none;\n color: white;\n font-size: 24px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n -webkit-tap-highlight-color: transparent;\n}\n.ddddocr-close:hover { background: rgb(242, 0, 105); }\n.ddddocr-close:active { background: rgba(255, 255, 255, 0.5); }\n.ddddocr-modal.mobile .ddddocr-close { width: 44px; height: 44px; min-width: 44px; min-height: 44px; }\n\n.ddddocr-tabs {\n display: flex;\n background: rgba(255, 255, 255, 0.1);\n padding: 0 16px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: none;\n -ms-overflow-style: none;\n}\n.ddddocr-tabs::-webkit-scrollbar { display: none; }\n.ddddocr-modal.mobile .ddddocr-tabs { padding: 0 8px; position: sticky; top: 76px; z-index: 10; }\n\n.ddddocr-tab {\n padding: 14px 16px;\n color: rgba(255, 255, 255, 0.8);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n border: none;\n background: none;\n position: relative;\n transition: all 0.2s;\n white-space: nowrap;\n -webkit-tap-highlight-color: transparent;\n}\n.ddddocr-modal.mobile .ddddocr-tab { padding: 12px 14px; font-size: 14px; min-height: 48px; }\n.ddddocr-tab:hover { color: white; }\n.ddddocr-tab.active { color: white; }\n.ddddocr-tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: 30px;\n height: 3px;\n background: white;\n border-radius: 3px 3px 0 0;\n}\n\n.ddddocr-content {\n background: #f8fafc;\n padding: 24px;\n max-height: calc(85vh - 180px);\n overflow-y: auto;\n overflow-x: hidden;\n -webkit-overflow-scrolling: touch;\n}\n.ddddocr-modal.mobile .ddddocr-content {\n padding: 16px;\n max-height: none;\n height: calc(100% - 140px);\n padding-bottom: 100px;\n}\n.ddddocr-content::-webkit-scrollbar { width: 6px; }\n.ddddocr-content::-webkit-scrollbar-track { background: #f1f5f9; border-radius: 3px; }\n.ddddocr-content::-webkit-scrollbar-thumb { background: #FFB6C1; border-radius: 3px; }\n.ddddocr-content::-webkit-scrollbar-thumb:hover { background: #FF69B4; }\n\n.ddddocr-panel { display: none; }\n.ddddocr-panel.active { display: block; }\n\n.ddddocr-card {\n background: white;\n border-radius: 16px;\n padding: 20px;\n margin-bottom: 16px;\n box-shadow: 0 2px 12px rgba(74, 144, 226, 0.08);\n border: 1px solid rgba(74, 144, 226, 0.06);\n}\n.ddddocr-modal.mobile .ddddocr-card { padding: 16px; border-radius: 12px; }\n\n.ddddocr-card-title {\n font-size: 15px;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n}\n.ddddocr-card-title::before {\n content: '';\n width: 4px;\n height: 16px;\n background: #4A90E2;\n border-radius: 2px;\n}\n\n.ddddocr-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0;\n border-bottom: 1px solid #f1f5f9;\n gap: 12px;\n}\n.ddddocr-modal.mobile .ddddocr-row { padding: 16px 0; }\n.ddddocr-row:last-child { border-bottom: none; }\n\n.ddddocr-row-info { flex: 1; min-width: 0; }\n.ddddocr-row-label { font-size: 14px; color: #334155; font-weight: 500; }\n.ddddocr-modal.mobile .ddddocr-row-label { font-size: 15px; }\n.ddddocr-row-desc { font-size: 12px; color: #94a3b8; margin-top: 2px; }\n.ddddocr-modal.mobile .ddddocr-row-desc { font-size: 13px; }\n\n.ddddocr-switch {\n position: relative;\n width: 48px;\n height: 26px;\n min-width: 48px;\n background: #e2e8f0;\n border-radius: 13px;\n cursor: pointer;\n transition: background 0.3s;\n -webkit-tap-highlight-color: transparent;\n}\n.ddddocr-modal.mobile .ddddocr-switch { width: 56px; height: 32px; min-width: 56px; }\n.ddddocr-switch.on { background: #4A90E2; }\n.ddddocr-switch-knob {\n position: absolute;\n top: 3px;\n left: 3px;\n width: 20px;\n height: 20px;\n background: white;\n border-radius: 50%;\n transition: transform 0.3s;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n}\n.ddddocr-modal.mobile .ddddocr-switch-knob { width: 26px; height: 26px; }\n.ddddocr-switch.on .ddddocr-switch-knob { transform: translateX(22px); }\n.ddddocr-modal.mobile .ddddocr-switch.on .ddddocr-switch-knob { transform: translateX(24px); }\n\n.ddddocr-input {\n width: 100%;\n padding: 12px 14px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n font-size: 14px;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n}\n.ddddocr-modal.mobile .ddddocr-input { padding: 14px 16px; font-size: 16px; border-radius: 12px; }\n.ddddocr-input:focus { outline: none; border-color: #4A90E2; box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.15); }\n\n.ddddocr-select {\n width: 100%;\n padding: 12px 14px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n font-size: 14px;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n background: white;\n cursor: pointer;\n}\n.ddddocr-modal.mobile .ddddocr-select { padding: 14px 16px; font-size: 16px; border-radius: 12px; }\n.ddddocr-select:focus { outline: none; border-color: #4A90E2; }\n\n.ddddocr-textarea {\n width: 100%;\n padding: 12px 14px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n font-size: 13px;\n font-family: 'Monaco', 'Consolas', monospace;\n min-height: 100px;\n resize: vertical;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n}\n.ddddocr-modal.mobile .ddddocr-textarea { padding: 14px 16px; font-size: 14px; min-height: 120px; border-radius: 12px; }\n.ddddocr-textarea:focus { outline: none; border-color: #4A90E2; box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.15); }\n\n.ddddocr-file-zone {\n border: 2px dashed #d1e3f6;\n border-radius: 12px;\n padding: 24px;\n text-align: center;\n cursor: pointer;\n transition: all 0.2s;\n margin-top: 12px;\n background: rgba(74, 144, 226, 0.02);\n -webkit-tap-highlight-color: transparent;\n}\n.ddddocr-file-zone:hover { border-color: #4A90E2; background: rgba(74, 144, 226, 0.05); }\n.ddddocr-file-zone:active { background: rgba(74, 144, 226, 0.1); }\n.ddddocr-file-zone input { display: none; }\n.ddddocr-file-icon { font-size: 32px; margin-bottom: 8px; color: #4A90E2; }\n.ddddocr-file-text { font-size: 13px; color: #64748b; }\n.ddddocr-file-name { font-size: 12px; color: #4A90E2; margin-top: 8px; font-weight: 500; }\n\n.ddddocr-btn-group { display: flex; gap: 12px; margin-top: 16px; flex-wrap: wrap; }\n.ddddocr-btn {\n flex: 1;\n min-width: 100px;\n padding: 12px 20px;\n border: none;\n border-radius: 10px;\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n transition: all 0.2s;\n -webkit-tap-highlight-color: transparent;\n}\n.ddddocr-modal.mobile .ddddocr-btn { padding: 14px 20px; font-size: 15px; min-height: 48px; }\n.ddddocr-btn-primary { background: #4A90E2; color: white; }\n.ddddocr-btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(74, 144, 226, 0.35); }\n.ddddocr-btn-primary:active { transform: translateY(0); }\n.ddddocr-btn-secondary { background: #f1f5f9; color: #475569; }\n.ddddocr-btn-secondary:hover { background: #e2e8f0; }\n.ddddocr-btn-secondary:active { background: #cbd5e1; }\n.ddddocr-btn-danger { background: #fee2e2; color: #dc2626; }\n.ddddocr-btn-danger:hover { background: #fecaca; }\n.ddddocr-btn-danger:active { background: #fca5a5; }\n.ddddocr-btn-sm { padding: 8px 14px; font-size: 12px; flex: none;}\n.ddddocr-modal.mobile .ddddocr-btn-sm { padding: 10px 16px; font-size: 13px; min-height: 40px; }\n\n.ddddocr-hint {\n background: rgba(74, 144, 226, 0.08);\n border: 1px solid rgba(74, 144, 226, 0.15);\n border-radius: 10px;\n padding: 12px 14px;\n font-size: 12px;\n color: #64748b;\n margin-top: 12px;\n}\n.ddddocr-modal.mobile .ddddocr-hint { font-size: 13px; padding: 14px 16px; }\n\n.ddddocr-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: rgba(16, 185, 129, 0.15);\n color: #10b981;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n margin-bottom: 12px;\n border: 1px solid rgba(16, 185, 129, 0.3);\n}\n\n.ddddocr-rule-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #f8fafc;\n border-radius: 10px;\n margin-bottom: 8px;\n border: 1px solid rgba(74, 144, 226, 0.08);\n}\n.ddddocr-modal.mobile .ddddocr-rule-item { flex-wrap: wrap; padding: 14px; }\n.ddddocr-rule-item:last-child { margin-bottom: 0; }\n.ddddocr-rule-pattern { flex: 1; font-family: monospace; font-size: 13px; color: #334155; word-break: break-all; min-width: 0; }\n.ddddocr-rule-type { font-size: 11px; padding: 4px 8px; background: #e2e8f0; border-radius: 4px; color: #64748b; white-space: nowrap; }\n.ddddocr-rule-output { font-size: 11px; padding: 4px 8px; background: #dbeafe; border-radius: 4px; color: #4A90E2; white-space: nowrap; }\n.ddddocr-rule-delete {\n background: none;\n border: none;\n color: #ef4444;\n cursor: pointer;\n font-size: 16px;\n padding: 8px;\n min-width: 32px;\n min-height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n -webkit-tap-highlight-color: transparent;\n}\n.ddddocr-rule-edit {\n background: none;\n border: none;\n color: #4A90E2;\n cursor: pointer;\n font-size: 12px;\n padding: 8px;\n min-width: 32px;\n min-height: 32px;\n display: flex;\n align-items: center;\n justify-content: center;\n -webkit-tap-highlight-color: transparent;\n}\n\n.ddddocr-empty { text-align: center; padding: 24px; color: #94a3b8; font-size: 13px; }\n\n.ddddocr-add-rule { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }\n.ddddocr-add-rule input { flex: 2; min-width: 120px; }\n.ddddocr-add-rule select { flex: 1; min-width: 80px; }\n.ddddocr-modal.mobile .ddddocr-add-rule { flex-direction: column; }\n.ddddocr-modal.mobile .ddddocr-add-rule input,\n.ddddocr-modal.mobile .ddddocr-add-rule select { width: 100%; flex: none; }\n\n.ddddocr-save-float { display: none; }\n.ddddocr-modal.mobile .ddddocr-save-float {\n display: block;\n position: fixed;\n bottom: 0;\n left: 0;\n right: 0;\n padding: 16px;\n background: white;\n box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.1);\n z-index: 100;\n}\n.ddddocr-modal.mobile .ddddocr-save-float .ddddocr-btn { width: 100%; }\n.ddddocr-modal.mobile .ddddocr-tabs .ddddocr-btn { display: none; }\n\n/* 统计样式 */\n.ddddocr-stats-grid {\n display: grid;\n grid-template-columns: repeat(2, 1fr);\n gap: 12px;\n margin-bottom: 16px;\n}\n.ddddocr-modal.mobile .ddddocr-stats-grid { grid-template-columns: 1fr; }\n\n.ddddocr-stat-card {\n background: linear-gradient(135deg, #4A90E2 0%, #357ABD 100%);\n border-radius: 12px;\n padding: 16px;\n color: white;\n position: relative;\n overflow: hidden;\n}\n.ddddocr-stat-card::before {\n content: '';\n position: absolute;\n top: -50%;\n right: -50%;\n width: 100%;\n height: 100%;\n background: radial-gradient(circle, rgba(255,255,255,0.1) 0%, transparent 70%);\n pointer-events: none;\n}\n.ddddocr-stat-card.accent { background: linear-gradient(135deg, #FF69B4 0%, #FF1493 100%); }\n.ddddocr-stat-card.success { background: linear-gradient(135deg, #10b981 0%, #059669 100%); }\n.ddddocr-stat-card.warning { background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%); }\n\n.ddddocr-stat-label { font-size: 12px; opacity: 0.9; margin-bottom: 6px; }\n.ddddocr-stat-value { font-size: 28px; font-weight: 700; line-height: 1; }\n.ddddocr-stat-unit { font-size: 14px; font-weight: 400; opacity: 0.8; margin-left: 4px; }\n\n.ddddocr-rank-list { max-height: 400px; overflow-y: auto; }\n.ddddocr-rank-item {\n display: flex;\n align-items: center;\n padding: 14px 12px;\n background: #f8fafc;\n border-radius: 10px;\n margin-bottom: 8px;\n border: 1px solid rgba(74, 144, 226, 0.08);\n transition: all 0.2s;\n}\n.ddddocr-rank-item:hover { background: #f1f5f9; }\n.ddddocr-rank-item:last-child { margin-bottom: 0; }\n\n.ddddocr-rank-num {\n width: 28px;\n height: 28px;\n border-radius: 50%;\n background: #e2e8f0;\n color: #64748b;\n font-size: 12px;\n font-weight: 600;\n display: flex;\n align-items: center;\n justify-content: center;\n margin-right: 12px;\n flex-shrink: 0;\n}\n.ddddocr-rank-item:nth-child(1) .ddddocr-rank-num { background: linear-gradient(135deg, #fbbf24, #f59e0b); color: white; }\n.ddddocr-rank-item:nth-child(2) .ddddocr-rank-num { background: linear-gradient(135deg, #94a3b8, #64748b); color: white; }\n.ddddocr-rank-item:nth-child(3) .ddddocr-rank-num { background: linear-gradient(135deg, #cd7f32, #b8860b); color: white; }\n\n.ddddocr-rank-info { flex: 1; min-width: 0; }\n.ddddocr-rank-host { font-size: 14px; font-weight: 500; color: #334155; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.ddddocr-rank-meta { font-size: 12px; color: #94a3b8; margin-top: 4px; display: flex; gap: 12px; }\n.ddddocr-rank-count { font-size: 18px; font-weight: 700; color: #4A90E2; margin-left: 12px; flex-shrink: 0; }\n\n.ddddocr-progress-bar { height: 6px; background: #e2e8f0; border-radius: 3px; margin-top: 8px; overflow: hidden; }\n.ddddocr-progress-fill { height: 100%; background: linear-gradient(90deg, #4A90E2, #FF69B4); border-radius: 3px; transition: width 0.3s ease; }\n\n/* 站点规则样式 */\n.ddddocr-site-rule-item {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 14px;\n background: #f8fafc;\n border-radius: 10px;\n margin-bottom: 10px;\n border: 1px solid rgba(74, 144, 226, 0.08);\n}\n.ddddocr-site-rule-item:last-child { margin-bottom: 0; }\n.ddddocr-site-rule-info { flex: 1; min-width: 0; }\n.ddddocr-site-rule-key { font-size: 14px; font-weight: 500; color: #334155; word-break: break-all; margin-bottom: 4px; }\n.ddddocr-site-rule-selector { font-size: 12px; color: #64748b; font-family: monospace; word-break: break-all; }\n.ddddocr-site-rule-badge { font-size: 10px; padding: 2px 6px; background: #dbeafe; color: #4A90E2; border-radius: 4px; margin-top: 6px; display: inline-block; }\n.ddddocr-site-rule-actions { display: flex; gap: 4px; flex-shrink: 0; }\n\n.ddddocr-card-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 16px;\n}\n.ddddocr-card-header .ddddocr-card-title { margin-bottom: 0; }\n",document.getElementById("ddddocr-settings-styles")||document.head.appendChild(t);}async createContainer(){this.overlay=document.createElement("div"),this.overlay.className="ddddocr-overlay",this.container=document.createElement("div"),this.container.className="ddddocr-modal",P()&&this.container.classList.add("mobile");const t=R();let e=false,n=0;try{const t=new p,i=await t.getUploadedModel();i&&(e=!0,n=i.model.byteLength);}catch(d){console.warn("Failed to load uploaded model info:",d);}const i=this.renderCalculateRules(t.calculateRules||[]),o=this.renderSiteRules(),r=this.renderStats(),a=this.renderAgreementSelectors(t.agreementSelectors||[]);this.container.innerHTML=`\n
\n
DDDD OCR 设置
\n \n
\n
\n \n \n \n \n \n \n \n
\n
\n \x3c!-- 基本设置 --\x3e\n
\n
\n
检测与填充
\n ${this.renderSwitchRow("autoDetect","自动检测并填充","自动识别页面验证码并填充结果",t.autoDetect)}\n ${this.renderSwitchRow("typewriterEffect","打字机效果","模拟人工逐字输入,关闭则一次性填充",t.typewriterEffect)}\n ${this.renderSwitchRow("autoCheckAgreement","自动勾选协议","自动勾选用户协议、隐私政策等复选框",t.autoCheckAgreement)}\n ${this.renderSwitchRow("enableNotification","系统通知","识别完成后显示桌面通知提醒",t.enableNotification)}\n ${this.renderSwitchRow("debugMode","调试模式","在控制台输出详细日志",t.debugMode)}\n
\n
\n
自定义选择器
\n
验证码选择器
\n \n
输入框选择器
\n \n
留空则自动检测页面中的验证码元素
\n
协议复选框选择器
\n
${a}
\n
\n \n \n
\n
支持添加多个协议复选框选择器
\n
\n
\n\n \x3c!-- 网站规则 --\x3e\n
\n
\n
\n
已保存的规则
\n
\n \n \n
\n
\n
${o}
\n
\n \n
\n
添加规则
\n
主机名/URL
\n \n
验证码选择器
\n \n
输入框选择器
\n \n \n
\n
\n\n \x3c!-- 识别统计 --\x3e\n
\n ${r}\n
\n\n \x3c!-- 四则运算 --\x3e\n
\n
\n
四则运算识别
\n ${this.renderSwitchRow("autoCalculate","自动计算结果",'识别到 "3+5=?" 自动计算并填充',t.autoCalculate)}\n
\n
默认输出格式
\n \n
可为不同站点配置不同的输出格式
\n
\n
\n
\n
站点规则
\n
${i}
\n
\n \n \n \n \n
\n
\n 通配符: * 匹配任意字符,? 匹配单个字符
\n 正则: 使用标准正则表达式语法\n
\n
\n
\n\n \x3c!-- 模型管理 --\x3e\n
\n
\n
模型来源
\n ${e?`
[已上传] 本地模型 (${(n/1024/1024).toFixed(1)} MB)
`:""}\n ${this.renderSwitchRow("useUploadedModel","使用上传的模型","优先使用本地上传的模型文件",t.useUploadedModel)}\n ${this.renderSwitchRow("autoDownload","自动下载模型","首次使用时自动从网络下载模型",t.autoDownload)}\n
\n
\n
上传模型文件
\n
\n \n
[ONNX]
\n
点击上传 common.onnx
\n
\n
\n
\n \n
[JSON]
\n
点击上传 charsets.json
\n
\n
\n
\n \n \n
\n
\n
\n\n \x3c!-- 站点白名单 --\x3e\n
\n
\n
白名单设置
\n ${this.renderSwitchRow("enableWhitelist","启用站点白名单","仅在白名单站点启用脚本功能",t.enableWhitelist)}\n
\n \n
当前站点: ${window.location.hostname}
\n
\n
\n
\n
配置导入导出
\n
\n \n \n \n
\n
\n
\n
\n
\n \n
\n `,document.body.appendChild(this.overlay),document.body.appendChild(this.container),this.bindEvents(),window.addEventListener("resize",this.handleResize);}renderSwitchRow(t,e,n,i){return `\n
\n
\n
${e}
\n
${n}
\n
\n
\n
\n
\n
\n `}renderCalculateRules(t){return t&&0!==t.length?t.map((t,e)=>`\n
\n ${H(t.pattern)}\n ${"regex"===t.matchType?"正则":"通配符"}\n ${"result"===t.outputMode?"仅结果":"完整等式"}\n \n
\n `).join(""):'
暂无规则,将使用默认输出格式
'}renderSiteRules(){const t=L(),e=Object.keys(t);return 0===e.length?'
暂无保存的规则
':e.map(e=>{const n=t[e],i=e.length>35?e.substring(0,35)+"...":e,o=n.selector.length>40?n.selector.substring(0,40)+"...":n.selector;return `\n
\n
\n
${H(i)}
\n
${H(o)}
\n ${n.fullUrl?'
完整URL匹配
':""}\n
\n
\n \n \n
\n
\n `}).join("")}renderStats(){var t;const e=N.getStats(),n=Object.entries(e.sites||{}),i=n.reduce((t,[,e])=>t+e.totalTime,0),o=e.total>0?Math.round(i/e.total):0,r=e.updated?O(e.updated):"-";let a="";if(0===n.length)a='
暂无统计数据
';else {n.sort((t,e)=>e[1].count-t[1].count);const e=n.slice(0,15),i=(null==(t=e[0])?void 0:t[1].count)||1;a=e.map(([t,e],n)=>{const o=e.count>0?Math.round(e.totalTime/e.count):0,r=O(e.lastTime),a=Math.round(e.count/i*100);return `\n
\n
${n+1}
\n
\n
${H(t)}
\n
\n 平均 ${o}ms\n 最后: ${r}\n
\n
\n
\n
\n
\n
${e.count}
\n
\n `}).join("");}return `\n
\n
\n
总识别次数
\n
${e.total}
\n
\n
\n
统计站点数
\n
${n.length}
\n
\n
\n
平均识别耗时
\n
${o}ms
\n
\n
\n
最后更新
\n
${r}
\n
\n
\n
\n
\n
站点排行榜
\n \n
\n
${a}
\n
\n `}renderAgreementSelectors(t){return t&&0!==t.length?t.map((t,e)=>`\n
\n ${H(t)}\n \n
\n `).join(""):'
暂无协议选择器
'}stopPropagation(t){t.stopPropagation();}bindEvents(){var t,e,n,i,o,r,a,d,s,c,l,u,h,p;this.container&&this.overlay&&(["mousedown","mouseup","click","dblclick","wheel","keydown","keyup","keypress","contextmenu"].forEach(t=>this.container.addEventListener(t,this.stopPropagation)),this.container.addEventListener("touchstart",this.stopPropagation,{passive:true}),this.container.addEventListener("touchmove",this.stopPropagation,{passive:true}),this.container.addEventListener("touchend",this.stopPropagation),null==(t=this.container.querySelector(".ddddocr-close"))||t.addEventListener("click",()=>this.hide()),this.overlay.addEventListener("click",()=>this.hide()),this.container.querySelectorAll(".ddddocr-tab").forEach(t=>{t.addEventListener("click",()=>{const e=t.dataset.tab;e&&this.switchTab(e);});}),this.container.querySelectorAll(".ddddocr-switch").forEach(t=>{t.addEventListener("click",()=>{t.classList.toggle("on");const e=t.dataset.key;if("enableWhitelist"===e){const e=this.container.querySelector("#whitelistArea");e&&(e.style.display=t.classList.contains("on")?"block":"none");}if("autoCalculate"===e){const e=this.container.querySelector("#calculateOptionsArea"),n=this.container.querySelector("#calculateRulesCard"),i=t.classList.contains("on");e&&(e.style.display=i?"block":"none"),n&&(n.style.display=i?"block":"none");}});}),null==(e=this.container.querySelector("#addAgreementSelectorBtn"))||e.addEventListener("click",()=>this.addAgreementSelector()),this.bindAgreementSelectorDeleteEvents(),null==(n=this.container.querySelector("#addCalcRuleBtn"))||n.addEventListener("click",()=>this.addCalculateRule()),this.bindCalcRuleDeleteEvents(),null==(i=this.container.querySelector("#addSiteRuleBtn"))||i.addEventListener("click",()=>this.addSiteRule()),null==(o=this.container.querySelector("#saveEditRuleBtn"))||o.addEventListener("click",()=>this.saveEditRule()),null==(r=this.container.querySelector("#cancelEditRuleBtn"))||r.addEventListener("click",()=>this.cancelEditRule()),null==(a=this.container.querySelector("#exportRulesBtn"))||a.addEventListener("click",()=>this.exportSiteRules()),null==(d=this.container.querySelector("#importRulesBtn"))||d.addEventListener("click",()=>this.importSiteRules()),this.bindSiteRuleEvents(),null==(s=this.container.querySelector("#clearStatsBtn"))||s.addEventListener("click",()=>this.clearStats()),this.bindModelEvents(),null==(c=this.container.querySelector("#exportBtn"))||c.addEventListener("click",()=>this.exportConfig()),null==(l=this.container.querySelector("#importBtn"))||l.addEventListener("click",()=>this.importConfig()),null==(u=this.container.querySelector("#resetBtn"))||u.addEventListener("click",()=>this.resetConfig()),null==(h=this.container.querySelector("#saveBtn"))||h.addEventListener("click",()=>this.saveSettings()),null==(p=this.container.querySelector("#saveBtnFloat"))||p.addEventListener("click",()=>this.saveSettings()));}bindModelEvents(){var t,e,n,i,o,r,a,d,s,c;const l=null==(t=this.container)?void 0:t.querySelector("#modelZone"),u=null==(e=this.container)?void 0:e.querySelector("#modelFile"),h=null==(n=this.container)?void 0:n.querySelector("#modelName"),m=null==(i=this.container)?void 0:i.querySelector("#charsetsZone"),g=null==(o=this.container)?void 0:o.querySelector("#charsetsFile"),b=null==(r=this.container)?void 0:r.querySelector("#charsetsName");null==l||l.addEventListener("click",()=>null==u?void 0:u.click()),null==u||u.addEventListener("change",()=>{var t;(null==(t=u.files)?void 0:t[0])&&(h.textContent=`[OK] ${u.files[0].name}`);}),null==m||m.addEventListener("click",()=>null==g?void 0:g.click()),null==g||g.addEventListener("change",()=>{var t;(null==(t=g.files)?void 0:t[0])&&(b.textContent=`[OK] ${g.files[0].name}`);}),null==(d=null==(a=this.container)?void 0:a.querySelector("#uploadBtn"))||d.addEventListener("click",async()=>{var t,e;const n=null==(t=null==u?void 0:u.files)?void 0:t[0],i=null==(e=null==g?void 0:g.files)?void 0:e[0];if(n&&i)try{await async function(t,e){const n=await t.arrayBuffer(),i=await e.text(),o=JSON.parse(i),r=new p;await r.setUploadedModel(n,o),console.log("✅ 上传的模型已保存");}(n,i),M({useUploadedModel:!0}),C.show({title:"成功",content:"模型已保存,请刷新页面",icon:""});}catch(o){C.show({title:"错误",content:String(o),icon:""});}else C.show({title:"提示",content:"请选择模型文件和字符集文件",icon:""});}),null==(c=null==(s=this.container)?void 0:s.querySelector("#deleteModelBtn"))||c.addEventListener("click",()=>{C.confirm({title:"删除模型",content:"确定删除已上传的模型吗?",onConfirm:async()=>{await async function(){const t=new p;await t.deleteUploadedModel(),console.log("🗑️ 上传的模型已删除");}(),M({useUploadedModel:false}),C.show({title:"成功",content:"模型已删除",icon:""});}});});}bindAgreementSelectorDeleteEvents(){var t;null==(t=this.container)||t.querySelectorAll(".btn-delete-agreement").forEach(t=>{t.addEventListener("click",t=>{const e=parseInt(t.target.dataset.index||"0");this.deleteAgreementSelector(e);});});}bindCalcRuleDeleteEvents(){var t;null==(t=this.container)||t.querySelectorAll(".btn-delete-calc-rule").forEach(t=>{t.addEventListener("click",t=>{const e=parseInt(t.target.dataset.index||"0");this.deleteCalculateRule(e);});});}bindSiteRuleEvents(){var t,e;null==(t=this.container)||t.querySelectorAll(".btn-edit-site-rule").forEach(t=>{t.addEventListener("click",t=>{const e=t.target.dataset.key;e&&this.editSiteRule(e);});}),null==(e=this.container)||e.querySelectorAll(".btn-delete-site-rule").forEach(t=>{t.addEventListener("click",t=>{const e=t.target.dataset.key;e&&this.deleteSiteRuleUI(e);});});}addAgreementSelector(){var t,e;const n=null==(t=this.container)?void 0:t.querySelector("#newAgreementSelector"),i=null==n?void 0:n.value.trim();if(!i)return void C.show({title:"提示",content:"请输入选择器",icon:""});const o=R().agreementSelectors||[];if(o.includes(i))return void C.show({title:"提示",content:"选择器已存在",icon:""});o.push(i),M({agreementSelectors:o});const r=null==(e=this.container)?void 0:e.querySelector("#agreementSelectorsList");r&&(r.innerHTML=this.renderAgreementSelectors(o)),this.bindAgreementSelectorDeleteEvents(),n.value="";}deleteAgreementSelector(t){var e;const n=R().agreementSelectors||[];n.splice(t,1),M({agreementSelectors:n});const i=null==(e=this.container)?void 0:e.querySelector("#agreementSelectorsList");i&&(i.innerHTML=this.renderAgreementSelectors(n)),this.bindAgreementSelectorDeleteEvents();}addCalculateRule(){var t,e,n,i;const o=null==(t=this.container)?void 0:t.querySelector("#newCalcRulePattern"),r=null==(e=this.container)?void 0:e.querySelector("#newCalcRuleMatchType"),a=null==(n=this.container)?void 0:n.querySelector("#newCalcRuleOutputMode"),d=null==o?void 0:o.value.trim();if(!d)return void C.show({title:"提示",content:"请输入站点匹配规则",icon:""});const s=R().calculateRules||[];s.push({pattern:d,matchType:r.value,outputMode:a.value,enabled:true}),M({calculateRules:s});const c=null==(i=this.container)?void 0:i.querySelector("#calculateRulesList");c&&(c.innerHTML=this.renderCalculateRules(s)),this.bindCalcRuleDeleteEvents(),o.value="";}deleteCalculateRule(t){var e;const n=R().calculateRules||[];n.splice(t,1),M({calculateRules:n});const i=null==(e=this.container)?void 0:e.querySelector("#calculateRulesList");i&&(i.innerHTML=this.renderCalculateRules(n)),this.bindCalcRuleDeleteEvents();}addSiteRule(){var t,e,n;const i=null==(t=this.container)?void 0:t.querySelector("#newRuleHostname"),o=null==(e=this.container)?void 0:e.querySelector("#newRuleSelector"),r=null==(n=this.container)?void 0:n.querySelector("#newRuleInputSelector"),a=null==i?void 0:i.value.trim(),d=null==o?void 0:o.value.trim(),s=null==r?void 0:r.value.trim();a&&d?(T(a,{selector:d,inputSelector:s||void 0,enabled:true}),this.refreshSiteRulesList(),i.value="",o.value="",r.value=""):C.show({title:"提示",content:"请填写主机名和验证码选择器",icon:""});}editSiteRule(t){var e,n,i,o,r;const a=L()[t];if(!a)return;this.currentEditRuleKey=t;const d=null==(e=this.container)?void 0:e.querySelector("#editRuleCard"),s=null==(n=this.container)?void 0:n.querySelector("#editRuleKey"),c=null==(i=this.container)?void 0:i.querySelector("#editRuleOriginalKey"),l=null==(o=this.container)?void 0:o.querySelector("#editRuleSelector"),u=null==(r=this.container)?void 0:r.querySelector("#editRuleInput");d&&(d.style.display="block"),s&&(s.value=t),c&&(c.value=t),l&&(l.value=a.selector||""),u&&(u.value=a.inputSelector||"");}saveEditRule(){var t,e,n;const i=null==(t=this.container)?void 0:t.querySelector("#editRuleOriginalKey"),o=null==(e=this.container)?void 0:e.querySelector("#editRuleSelector"),r=null==(n=this.container)?void 0:n.querySelector("#editRuleInput"),a=null==i?void 0:i.value,d=null==o?void 0:o.value.trim(),s=null==r?void 0:r.value.trim();if(d){if(a){const t=L()[a];t&&(D(a),T(t.hostname,{...t,selector:d,inputSelector:s||void 0}));}this.cancelEditRule(),this.refreshSiteRulesList();}else C.show({title:"提示",content:"验证码选择器不能为空",icon:""});}cancelEditRule(){var t;this.currentEditRuleKey=null;const e=null==(t=this.container)?void 0:t.querySelector("#editRuleCard");e&&(e.style.display="none");}deleteSiteRuleUI(t){C.confirm({title:"删除规则",content:`确定删除规则 "${t}" 吗?`,onConfirm:()=>{D(t),this.refreshSiteRulesList();}});}refreshSiteRulesList(){var t;const e=null==(t=this.container)?void 0:t.querySelector("#siteRulesList");e&&(e.innerHTML=this.renderSiteRules()),this.bindSiteRuleEvents();}exportSiteRules(){const t=L(),e=Object.entries(t).map(([t,e])=>({hostname:e.hostname||t,selector:e.selector,inputSelector:e.inputSelector,fullUrl:e.fullUrl}));this.downloadJson(e,"ddddocr-rules.json");}importSiteRules(){const t=document.createElement("input");t.type="file",t.accept=".json",t.onchange=async t=>{var e;const n=null==(e=t.target.files)?void 0:e[0];if(n)try{const t=await n.text(),e=JSON.parse(t);if(!Array.isArray(e))throw new Error("格式错误");for(const n of e)n.hostname&&n.selector&&T(n.hostname,{selector:n.selector,inputSelector:n.inputSelector,fullUrl:n.fullUrl,enabled:!0});this.refreshSiteRulesList(),C.show({title:"成功",content:`已导入 ${e.length} 条规则`,icon:""});}catch{C.show({title:"错误",content:"规则文件格式错误",icon:""});}},t.click();}clearStats(){C.confirm({title:"清除统计",content:"确定要清除所有统计数据吗?",onConfirm:()=>{var t,e,n;N.clear();const i=null==(t=this.container)?void 0:t.querySelector('[data-panel="stats"]');i&&(i.innerHTML=this.renderStats()),null==(n=null==(e=this.container)?void 0:e.querySelector("#clearStatsBtn"))||n.addEventListener("click",()=>this.clearStats());}});}exportConfig(){const t=R();this.downloadJson(t,"ddddocr-config.json");}importConfig(){const t=document.createElement("input");t.type="file",t.accept=".json",t.onchange=async t=>{var e;const n=null==(e=t.target.files)?void 0:e[0];if(n)try{const t=await n.text();M(JSON.parse(t)),C.show({title:"成功",content:"配置已导入,请刷新页面",icon:""});}catch{C.show({title:"错误",content:"配置文件格式错误",icon:""});}},t.click();}resetConfig(){C.confirm({title:"重置设置",content:"确定重置所有设置吗?",onConfirm:()=>{GM_setValue("ddddocr_config",o),C.show({title:"成功",content:"设置已重置,请刷新页面",icon:""});}});}downloadJson(t,e){const n=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),i=URL.createObjectURL(n),o=document.createElement("a");o.href=i,o.download=e,o.click(),URL.revokeObjectURL(i);}switchTab(t){var e;if(this.container&&(this.activeTab=t,this.container.querySelectorAll(".ddddocr-tab").forEach(e=>{e.classList.toggle("active",e.dataset.tab===t);}),this.container.querySelectorAll(".ddddocr-panel").forEach(e=>{e.classList.toggle("active",e.dataset.panel===t);}),"stats"===t)){const t=this.container.querySelector('[data-panel="stats"]');t&&(t.innerHTML=this.renderStats()),null==(e=this.container.querySelector("#clearStatsBtn"))||e.addEventListener("click",()=>this.clearStats());}}saveSettings(){if(!this.container)return;const t={};this.container.querySelectorAll(".ddddocr-switch").forEach(e=>{const n=e.dataset.key;n&&(t[n]=e.classList.contains("on"));}),this.container.querySelectorAll("input[data-key]").forEach(e=>{const n=e.dataset.key;n&&(t[n]=e.value.trim());}),this.container.querySelectorAll("select[data-key]").forEach(e=>{const n=e.dataset.key;n&&(t[n]=e.value);}),this.container.querySelectorAll("textarea[data-key]").forEach(e=>{const n=e.dataset.key;if(n){const i=e.value;t[n]=i.split("\n").filter(t=>t.trim());}}),M(t),this.onConfigChange(R()),"undefined"!=typeof GM_notification&&GM_notification({title:"设置已保存",text:"配置已成功保存",timeout:2e3}),this.hide();}async show(){var t,e,n;this.container||await this.createContainer(),this.isVisible=true,null==(t=this.overlay)||t.classList.add("visible"),null==(e=this.container)||e.classList.add("visible"),P()&&(null==(n=this.container)||n.classList.add("mobile"),document.body.style.overflow="hidden");}hide(){var t,e;this.isVisible=false,null==(t=this.overlay)||t.classList.remove("visible"),null==(e=this.container)||e.classList.remove("visible"),document.body.style.overflow="",window.removeEventListener("resize",this.handleResize);}setOnConfigChange(t){this.onConfigChange=t;}}class B{constructor(){this.container=null,this.create();}create(){const t=document.createElement("style");t.textContent="\n .ddddocr-loading-indicator {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 4px;\n z-index: 2147483647;\n overflow: hidden;\n background: linear-gradient(90deg, #4A90E2 0%, #FF69B4 25%, #87CEEB 50%, #FF69B4 75%, #4A90E2 100%);\n background-size: 200% 100%;\n animation: ddddocr-wave 3s linear infinite;\n opacity: 0;\n transition: opacity 0.3s;\n }\n .ddddocr-loading-indicator.visible { opacity: 1; }\n @keyframes ddddocr-wave {\n 0% { background-position: 0% 50%; }\n 100% { background-position: 200% 50%; }\n }\n .ddddocr-loading-text {\n position: fixed;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n background: #4A90E2;\n color: white;\n padding: 6px 16px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n z-index: 2147483647;\n opacity: 0;\n transition: opacity 0.3s;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n }\n .ddddocr-loading-text.visible { opacity: 1; }\n ",document.head.appendChild(t),this.container=document.createElement("div"),this.container.className="ddddocr-loading-indicator",document.body.appendChild(this.container);const e=document.createElement("div");e.className="ddddocr-loading-text",e.id="ddddocr-loading-text",e.textContent="正在初始化 DDDD OCR...",document.body.appendChild(e);}show(t){if(!this.container)return;this.container.classList.add("visible");const e=document.getElementById("ddddocr-loading-text");e&&(t&&(e.textContent=t),e.classList.add("visible"));}updateText(t){const e=document.getElementById("ddddocr-loading-text");e&&(e.textContent=t);}hide(){if(!this.container)return;this.container.classList.remove("visible");const t=document.getElementById("ddddocr-loading-text");t&&t.classList.remove("visible"),setTimeout(()=>{var e;null==(e=this.container)||e.remove(),null==t||t.remove(),this.container=null;},300);}}class q{constructor(){this.engine=new e({getModel:f,wasmPaths:"https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.0/dist/"});}async init(){await async function(){try{await y.init();}catch(e){console.warn("[WASMCache] 初始化失败:",e);}(async function(){console.log("📦 开始预下载 WASM 文件"),await Promise.allSettled(w.map(async t=>{try{if(await y.get(t))return;const e=await x(t);await y.set(t,e);}catch(e){console.warn(`⚠️ ${t} 下载失败`,e);}}));})().catch(()=>{});const t=window.fetch;window.fetch=async function(n,i){const o="string"==typeof n?n:n instanceof URL?n.href:n.url,r=w.find(t=>o.includes(t));if(!r)return t.call(this,n,i);try{let t=await y.get(r);return t||(t=await x(r),y.set(r,t).catch(()=>{})),new Response(t,{status:200,headers:{"Content-Type":"application/wasm","Content-Length":String(t.byteLength)}})}catch(e){return t.call(this,n,i)}},console.log("✅ WASM 缓存已启用");}(),await this.engine.init();}async recognize(t){return this.engine.recognize(t)}}class F{constructor(t,e){this.observer=null,this.enabled=false,this.checkInterval=null,this.eventEmitter=null,this.autoFill=new n,this.initialScanDone=false,this.initialScanTimer=null,this.processingElements=new WeakSet,this.processedElements=new WeakMap,this.customCaptchaElement=null,this.customInputElement=null,this.ocr=t,this.detector=new c,this.eventEmitter=e||null;}start(){this.enabled||(this.enabled=true,a.info("启动验证码自动检测"),this.applyStoredSiteRule(),this.scheduleInitialDetect(),this.observer=new MutationObserver(t=>{let e=false;for(const n of t){if(n.addedNodes.forEach(t=>{t instanceof HTMLElement&&(this.checkElement(t),(t.matches('input[type="checkbox"]')||t.querySelector('input[type="checkbox"]'))&&(e=true));}),"attributes"===n.type){const t=n.target;t instanceof HTMLElement&&(t instanceof HTMLImageElement?"src"!==n.attributeName&&"data-src"!==n.attributeName||this.recheckImage(t):t instanceof HTMLCanvasElement?this.recheckCanvas(t):"style"===n.attributeName&&t.style.backgroundImage&&this.recheckDiv(t));}"childList"===n.type&&n.target instanceof SVGElement&&this.recheckSVG(n.target);}e&&setTimeout(()=>this.checkAgreementBoxes(),300);}),this.observer.observe(document.body,{childList:true,subtree:true,attributes:true,attributeFilter:["src","data-src","srcset","style","href"],characterData:true}),this.startIntervalCheck(),this.checkAgreementBoxes());}stop(){var t;this.enabled&&(this.enabled=false,a.info("停止验证码自动检测"),null==(t=this.observer)||t.disconnect(),this.observer=null,this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.initialScanTimer&&(clearTimeout(this.initialScanTimer),this.initialScanTimer=null));}isEnabled(){return this.enabled}applyStoredSiteRule(){const t=L(),e=window.location.href,n=window.location.hostname;let i=null;for(const o of Object.keys(t)){const r=t[o];if(r.enabled){if(r.fullUrl&&e===r.fullUrl){i=r;break}if(r.urlPattern&&e.startsWith(r.urlPattern)){i=r;break}r.hostname!==n||r.fullUrl||r.urlPattern||(i=r);}}if(i){const t=document.querySelector(i.selector);t&&(this.customCaptchaElement=t,i.inputSelector&&(this.customInputElement=document.querySelector(i.inputSelector)),a.info("应用站点规则:",i.selector));}}checkAgreementBoxes(){const t=R();if(!t.autoCheckAgreement)return;let e=[];t.agreementSelectors&&t.agreementSelectors.length>0&&(e=t.agreementSelectors);const n=this.detector.guessAgreementCheckboxes();for(const o of n){const t=o.element;if(t.checked)continue;const e=o.clickTarget;e?(e.click(),a.info("点击协议复选框容器")):(t.checked=true,t.dispatchEvent(new Event("change",{bubbles:true})),t.dispatchEvent(new Event("input",{bubbles:true})),a.info("直接勾选协议复选框")),this.detector.markAgreementChecked(t);}for(const o of e)if(o.trim())try{document.querySelectorAll(o).forEach(t=>{t instanceof HTMLInputElement&&"checkbox"===t.type&&!t.checked&&(t.checked=!0,t.dispatchEvent(new Event("change",{bubbles:!0})),t.dispatchEvent(new Event("input",{bubbles:!0})),a.info("通过选择器勾选协议:",o));});}catch(i){a.warn("无效的协议选择器:",o);}}scheduleInitialDetect(){this.initialScanDone||(this.detectExistingCaptchas(false),this.initialScanTimer=window.setTimeout(()=>{this.initialScanDone||this.detectExistingCaptchas(true);},3e3));}startIntervalCheck(){this.checkInterval=window.setInterval(()=>{const t=this.detector.scan();if(t&&0!==t.length)for(const e of t)if(this.hasElementChanged(e.element)){this.processDetectedCaptcha(e);break}},i.AUTO_DETECT_INTERVAL);}detectExistingCaptchas(t){a.debug("检测页面已存在的验证码"),document.querySelectorAll("img").forEach(e=>this.checkImage(e,t)),document.querySelectorAll("canvas").forEach(e=>this.checkCanvas(e,t)),document.querySelectorAll("svg").forEach(e=>this.checkSVG(e,t)),document.querySelectorAll('div[style*="background"]').forEach(e=>this.checkDiv(e,t)),t&&(this.initialScanDone=true);}checkElement(t){t instanceof HTMLImageElement&&this.checkImage(t,true),t instanceof HTMLCanvasElement&&this.checkCanvas(t,true),t instanceof SVGElement&&this.checkSVG(t,true),t.style.backgroundImage&&this.checkDiv(t,true),t.querySelectorAll("img").forEach(t=>this.checkImage(t,true)),t.querySelectorAll("canvas").forEach(t=>this.checkCanvas(t,true)),t.querySelectorAll("svg").forEach(t=>this.checkSVG(t,true));}async waitForImageLoad(t,e=5e3){return !!(t.complete&&t.naturalWidth>0)||new Promise(n=>{const i=setTimeout(()=>{a(),n(false);},e),o=()=>{a(),n(true);},r=()=>{a(),n(false);},a=()=>{clearTimeout(i),t.removeEventListener("load",o),t.removeEventListener("error",r);};t.addEventListener("load",o),t.addEventListener("error",r),t.complete&&t.naturalWidth>0&&(a(),n(true));})}async recheckImage(t){await this.waitForImageLoad(t)&&await this.checkImage(t,true);}async recheckCanvas(t){await new Promise(t=>requestAnimationFrame(t)),await this.checkCanvas(t,true);}async recheckSVG(t){await new Promise(t=>requestAnimationFrame(t)),await this.checkSVG(t,true);}async recheckDiv(t){await new Promise(t=>requestAnimationFrame(t)),await this.checkDiv(t,true);}async checkImage(t,e){var n;const i=R();if(i.captchaSelector){if(!t.matches(i.captchaSelector))return}else if(!this.isCaptchaImage(t))return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"img"}),!e)return;const o=this.findNearbyInput(t);o&&(o.value.trim()&&(o.value="",o.dispatchEvent(new Event("input",{bubbles:true}))),await this.waitForImageLoad(t)&&t.naturalWidth&&await this.recognizeAndFill(t,o));}async checkCanvas(t,e){var n;const i=R();if(i.captchaSelector){if(!t.matches(i.captchaSelector))return}else if(!this.isCaptchaCanvas(t))return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"canvas"}),!e)return;const o=this.findNearbyInput(t);if(!o)return;await new Promise(t=>requestAnimationFrame(t));const r=await new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("Canvas转换失败"));},"image/png");});await this.recognizeAndFillBlob(t,r,o);}async checkSVG(t,e){var n;const i=R();if(i.captchaSelector){if(!t.matches(i.captchaSelector))return}else if(!this.isCaptchaSVG(t))return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"svg"}),!e)return;const o=this.findNearbyInput(t);if(!o)return;const r=await this.svgToBlob(t);await this.recognizeAndFillBlob(t,r,o);}async checkDiv(t,e){var n;const i=R();if(i.captchaSelector){if(!t.matches(i.captchaSelector))return}else if(!this.isCaptchaDiv(t))return;const o=t.style.backgroundImage;if(!o)return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"div"}),!e)return;const r=this.findNearbyInput(t);if(!r)return;const a=o.match(/url\(['"]?(.+?)['"]?\)/);if(!a)return;const d=a[1],s=Date.now();let c="";if(d.startsWith("data:")){const t=await fetch(d),e=await t.blob();c=(await this.ocr.recognize(e)).text;}else c=(await this.ocr.recognize(d)).text;const l=Date.now()-s,u=this.processResult(c);await this.fillInput(r,u),this.markElementProcessed(t),N.record(window.location.hostname,l);}async svgToBlob(t){const e=(new XMLSerializer).serializeToString(t),n=new Blob([e],{type:"image/svg+xml;charset=utf-8"}),i=URL.createObjectURL(n),o=new Image;o.src=i,await new Promise((t,e)=>{o.onload=t,o.onerror=e,setTimeout(e,5e3);});const r=document.createElement("canvas");return r.width=t.clientWidth||150,r.height=t.clientHeight||50,r.getContext("2d").drawImage(o,0,0),URL.revokeObjectURL(i),new Promise((t,e)=>{r.toBlob(n=>{n?t(n):e(new Error("SVG转换失败"));},"image/png");})}async recognizeAndFill(t,e){var n,i,o;if(this.processingElements.has(t))return;this.processingElements.add(t);const r=Date.now();a.time("recognizeAndFill");try{null==(n=this.eventEmitter)||n.emit("recognize:start",{element:t});const o=await this.ocr.recognize(t),d=this.processResult(o.text);null==(i=this.eventEmitter)||i.emit("recognize:complete",{element:t,result:{text:d}}),await this.fillInput(e,d),this.markElementProcessed(t);const s=Date.now()-r;N.record(window.location.hostname,s),a.timeEnd("recognizeAndFill"),a.info("识别完成:",d);}catch(d){a.error("识别失败:",d),null==(o=this.eventEmitter)||o.emit("recognize:error",{element:t,error:d});}finally{this.processingElements.delete(t);}}async recognizeAndFillBlob(t,e,n){var i,o,r;if(this.processingElements.has(t))return;this.processingElements.add(t);const d=Date.now();try{null==(i=this.eventEmitter)||i.emit("recognize:start",{element:t});const r=await this.ocr.recognize(e),s=this.processResult(r.text);null==(o=this.eventEmitter)||o.emit("recognize:complete",{element:t,result:{text:s}}),await this.fillInput(n,s),this.markElementProcessed(t);const c=Date.now()-d;N.record(window.location.hostname,c),a.info("识别完成:",s);}catch(s){a.error("识别失败:",s),null==(r=this.eventEmitter)||r.emit("recognize:error",{element:t,error:s});}finally{this.processingElements.delete(t);}}processResult(t){const e=R();return e.autoCalculate?s.processResult(t,{autoCalculate:true,outputMode:e.calculateOutputMode,rules:e.calculateRules||[]},window.location.hostname):t}async fillInput(t,e){const n=R();await this.autoFill.fill(t,e,{simulate:true,autoSubmit:false,typewriterEffect:n.typewriterEffect}),n.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:"验证码已自动填充",text:`识别结果: ${e}`,timeout:3e3});}processDetectedCaptcha(t){const e=t.inputElement||this.detector.findRelatedInput(t.element);if(e)if("image"===t.type)this.recognizeAndFill(t.element,e);else if("canvas"===t.type){const n=t.element;n.toBlob(t=>{t&&this.recognizeAndFillBlob(n,t,e);},"image/png");}}isCaptchaImage(t){const e=t.naturalWidth||t.width,n=t.naturalHeight||t.height;if(ei.MAX_CAPTCHA_WIDTH||n>i.MAX_CAPTCHA_HEIGHT)return false;const o=(t.src+t.className+t.id+t.alt+(t.getAttribute("data-src")||"")).toLowerCase();return i.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}isCaptchaCanvas(t){const e=t.width,n=t.height;if(ei.MAX_CAPTCHA_WIDTH||n>i.MAX_CAPTCHA_HEIGHT)return false;const o=(t.className+t.id+(t.getAttribute("data-type")||"")).toLowerCase();return i.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}isCaptchaSVG(t){var e,n,o;const r=t.clientWidth||parseInt(t.getAttribute("width")||"0"),a=t.clientHeight||parseInt(t.getAttribute("height")||"0");if(ri.MAX_CAPTCHA_WIDTH||a>i.MAX_CAPTCHA_HEIGHT)return false;const d=(((null==(e=t.className)?void 0:e.baseVal)||"")+(t.id||"")).toLowerCase();if(i.CAPTCHA_KEYWORDS.some(t=>d.includes(t)))return true;let s=t.parentElement,c=0;for(;s&&c<3;){const t=(((null==(o=null==(n=s.className)?void 0:n.toString)?void 0:o.call(n))||"")+(s.id||"")).toLowerCase();if(i.CAPTCHA_KEYWORDS.some(e=>t.includes(e)))return true;s=s.parentElement,c++;}return null!==this.findNearbyInput(t)}isCaptchaDiv(t){const e=t.clientWidth,n=t.clientHeight;if(ei.MAX_CAPTCHA_WIDTH||n>i.MAX_CAPTCHA_HEIGHT)return false;const o=(t.className+t.id).toLowerCase();return i.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}findNearbyInput(t){const e=R();if(e.inputSelector){const t=document.querySelector(e.inputSelector);if(t instanceof HTMLInputElement)return t}return this.detector.findRelatedInput(t)}getElementHash(t){if(t instanceof HTMLImageElement)return t.src+"_"+t.naturalWidth+"_"+t.naturalHeight;if(t instanceof HTMLCanvasElement)try{return t.toDataURL()}catch{return "canvas_"+Date.now()}else {if(t instanceof SVGElement)return t.outerHTML;if(t instanceof HTMLElement&&t.style.backgroundImage)return t.style.backgroundImage}return ""}hasElementChanged(t){const e=this.getElementHash(t),n=this.processedElements.get(t);return !n||e!==n}markElementProcessed(t){const e=this.getElementHash(t);this.processedElements.set(t,e);}}class W{constructor(){this.loadingIndicator=null,this.initialized=false,this.menuCommandIds=new Map,this.eventEmitter=new l,this.ocr=new q,this.detector=new F(this.ocr,this.eventEmitter),this.settingsUI=new z,this.registerMenuCommands(),this.settingsUI.setOnConfigChange(t=>this.handleConfigChange(t));const t=R();a.setDebugMode(t.debugMode||false);}async init(){var t;if(!$())return void a.debug("当前站点不满足执行条件");if(this.initialized)return;const e=R();this.initialized=true,this.loadingIndicator=new B,a.info("DDDD OCR 启动");try{this.loadingIndicator.show("正在初始化 DDDD OCR"),this.loadingIndicator.updateText("正在加载模型文件"),await this.ocr.init(),a.info("OCR 已就绪"),this.loadingIndicator.updateText("DDDD OCR 已就绪"),e.autoDetect&&(this.detector.start(),a.info("自动检测已启动")),setTimeout(()=>{var t;return null==(t=this.loadingIndicator)?void 0:t.hide()},2e3),this.showNotification("DDDD OCR 已就绪",e.autoDetect?"自动检测已启用":"点击菜单启用自动检测"),this.refreshMenuCommands();}catch(n){a.error("初始化失败:",n),null==(t=this.loadingIndicator)||t.updateText("初始化失败: "+String(n)),setTimeout(()=>{var t;return null==(t=this.loadingIndicator)?void 0:t.hide()},3e3),this.showNotification("初始化失败",String(n),true);}}registerMenuCommands(){this.refreshMenuCommands();}refreshMenuCommands(){const t=GM_registerMenuCommand("打开设置",()=>this.settingsUI.show(),"s");this.menuCommandIds.set("settings",t);const e=GM_registerMenuCommand("清除缓存",async()=>{C.confirm({title:"清除缓存",content:"确定要清除所有缓存吗(包括模型和 WASM)?下次启动将重新下载。",confirmText:"确定清除",cancelText:"取消",onConfirm:async()=>{await async function(){const t=new p;await t.delete(),console.log("🗑️ 模型缓存已清除");}(),await async function(){await y.clear();}(),this.showNotification("缓存已清除","请刷新页面");}});},"d");this.menuCommandIds.set("cache",e);const n=GM_registerMenuCommand("查看状态",()=>this.showStatus(),"i");this.menuCommandIds.set("status",n);}showStatus(){var t,e,n;const i=R(),o=_(),r=L(),a=N.getStats(),d=`\n脚本状态: ${this.initialized?"已初始化":"未初始化"}\n当前站点: ${window.location.hostname}\n白名单状态: ${i.enableWhitelist?"已启用":"已禁用"}\n白名单数量: ${(null==(t=i.whitelist)?void 0:t.length)||0} 个站点\n当前站点匹配: ${o?"在白名单中":"不在白名单中"}\n自动检测: ${i.autoDetect?"已启用":"已禁用"}\n打字机效果: ${i.typewriterEffect?"已启用":"已禁用"}\n自动勾选协议: ${i.autoCheckAgreement?"已启用":"已禁用"}\n协议选择器数: ${(null==(e=i.agreementSelectors)?void 0:e.length)||0} 个\n自动计算: ${i.autoCalculate?"已启用":"已禁用"}\n计算输出: ${"result"===i.calculateOutputMode?"仅结果":"完整等式"}\n计算规则数: ${(null==(n=i.calculateRules)?void 0:n.length)||0} 条\n站点规则数: ${Object.keys(r).length} 条\n调试模式: ${i.debugMode?"已启用":"已禁用"}\n上传模型: ${i.useUploadedModel?"已启用":"未启用"}\n自动下载: ${i.autoDownload?"已启用":"已禁用"}\n总识别次数: ${a.total} 次`;C.show({title:"当前状态",content:d});}handleConfigChange(t){a.setDebugMode(t.debugMode||false),t.autoDetect&&!this.initialized&&this.init(),t.autoDetect?this.detector.start():this.detector.stop(),this.refreshMenuCommands();}showNotification(t,e,n=false){R().enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:t,text:e,timeout:n?5e3:3e3});}}function U(){const t=new W;$()?setTimeout(()=>t.init(),500):a.debug("DDDD OCR 不满足执行条件,仅注册菜单命令");}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",U):U(); })();