// ==UserScript== // @name DDDD OCR WEB - 验证码自动识别 // @namespace https://github.com/MakotoArai-CN/ddddocr-webjs // @version 1.1.2-2026/2/6 02:32:52 // @author MakotoArai-CN // @description 自动检测并识别页面验证码,自动填充到输入框。首次使用需设置白名单,会自动下载约50MB模型文件以及20MB左右的ONNX推理运行时文件。 // @license MIT // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAAAgY0hSTQAAeiYAAICEAAD6AAAAgOgAAHUwAADqYAAAOpgAABdwnLpRPAAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAADsOAAA7DgBcSvKOAAAC9BJREFUaN7tmVuMVdd5gL912Xufy5zLMMNgYMYQAyFAiUceHNtNgxTTVJYfUtNUeemF8VtvlhXJUvPQRn2oVKV5qCo/uKkqxaiWqrZq7RIlkl2rkWIpRBgBBlHIYOxyGRgGmJkz57r3Xpc+nDPMnDlzAZPGrdRfWtLRWWuvtb7/tv+1Nvy/fLoiHnaC8fFxAAX0AcUlc3rvfUUIUfPeu6NHj/7vAThy5AhCiCywDzgIPAk8BgwBsjPMAbeAS8AJ4MfARSB+/fXXf/EA4+PjCCHw3g8Ch4EXgKedc/3OOeGcY6EJIRBCIKVESolSygsh7gA/Af4V+L6UcjZJEt54443/eYCOm2SAQ8A3vfdPG2N0mqYYY3DO4b1feYEOiNaaMAxRSiVCiPeAv+hYJX0Yi6wL0Nn8EPCn3vvxNE374jjGWrvqplddTAiUUkRRRBAEc0KIvwG+Dcx9UohVATobB9gN/LUx5tdarZZI03T12ZYDiZWnF0IQBAGZTMYqpd4CvgFc+yQQarWO0dHRhc3/bZIkhxqNhrDWrrBpB3iEDlHZEipTQEZ5RBCBs+AM4HtgrLUYY6SUcq9Saifw49HR0eqZM2ce3gJL3OZoHMfPNZvNXnfxDqQmGnyM3KNjZDZ9Dl3chFBBu9smmOptWlMXaFw5SXz34zaMkN0bEIJcLkcYhv8ghPh9733lQSzRA9DJNpH3/jtxHP9Rs9kUvZv3RJs+S2nf82QfHUNmilgPzoHrDJUCpAQlwDUrNK+dpnL+B8TTEz3LdiBsGIZ/CXwLMPcL0eVCL7744sKEz6Vp+ufNZjPq3rxHSE1xz1cY/NLvEWzeS0JEK4XEgHFgO804SG27eZ0hs3E7+UfHcEmDZOZKx/UWQay1Umu9Ryl1HLgyMjLCxMTEgwGMjo4ipRy01r7aaDR2Oee6NSU15dHfoPzkb2F0kWbS2eAaycj7RRgZ5ugb+TwSiG/9rOtB7z3OuZzWekgp9f1sNpvcTzzo7sU8zrnDcRz/ck/Aek9h9yEKo1+jRYY0hQ05eGYEBnKwGoMA7jTgp9dgpgFWZyiMfg3brDB/4e0uKxhjSJLkkJTyV4E378eF7gGMj48ThmGmXq9/NUmS7uzkHdGm3RSf+DotMhgLoYLf3AdPj9zPMjBchNdPQWIBlaH4xNeJ71wmnr7UFdhxHGe01r9eKpWOjY+P2/VioSslJEmyL03Tp1dyneK+57GZQawFPBQi2Dlwf5uH9thC1H7WWLCZQQp7nwPZ5QQ450jT9Nlms7njgSwQxzFKqYPGmMHl2g837kRveaKtvQUosWj8Wsvw1slbVJsG0fnX4ylkNS8c2ERfRiPofhUkFqKRLxANvt3OTEusYIzZmqbpU977daNYQtt9tm/frowxTy7XPkB2ZAwblVZ19Gbi+dHFKj88W+GH5+ba7WyFH12s0kxWeciDDUtkR57o6bLWSmPMF06fPr20IljbArdu3eozxuxYnvOFjtBDn7uX31fUgtb0b96BKXpkR8vOQ39eILVe9TnrQQ/tQegIbxdLFO89xpjdBw8ejJrNZrwugLUWa23ROTfUrSWPjPogP8TadZtAqACpF91EehCKNcV7EPkhZNSHrc90+Zi1drBer+e99+sDtFotAOGckz0jpMbJcM2yVUnoz3ZQxOLm+rPtvrXEybAnkDtW6DfG5IUQM+sCJEmyppa8X7vuLkbwB0+138DLwYrR+lZYybree+I4Zj3RC4MBL4ToiWDvUrxZeyIpoJxZd62VAUyMd70lurW2Uq1WG/cFUKlUEELUCoXCjJRy+71eIXCtGun8FKp/eNUs5JxntmFwyyJdSkF/TiPlKvYTkM5P4Vo1xLJy23t/t1KpNNc7NGmA69evE8dx/fHHH78ipezOazYmmTpP5tEDq04y2zB8+9hl7laTexvx3jNQCPnjr+5goC9YRf2QTJ0HG4Psjnjn3KWTJ082+/v71wSQAJcvX+a1115L0jQ93aMkIWhdPdHJEqvsQ0iawUbq4SNdrRlsxItVoliArc/QunpiJe3bVqv1/ksvveRnZ2fXBwA4evQotVrtJ865ue6FJG7uKo0r73e9SZcaVghFtjhArjxErryx04bIFgcQS3Lpcmeof3wcN3e155AD2Gw2y7Fjx+6V+OsCnDp1iitXrpw1xpxZPkhJqJ8/Rjo/DaKdKustw+RMC4DJmRa1lmkbyLeboF1iLB1Tb5m2EgSIxjTJz36AWsGqUsqwXC7/2bPPPvs8sObb+J56ZmdnqVarreHh4U2ZTObLS+GEkJjabeLaHLmRMYQOSFLLhY+u89HUPO+er1AVJeQyP+4a858VqpSQSiFMg6GPvsuIOcd8HJCa3vO/EKKotT4IXNJaT+zfv58PPvhgdQCAw4cP+4mJidkNGzY8o5Ta0jVQKVq3P8RaS2bzHmQQMVuNuXh9jjgoE+VLK2hSLY5RJaK+EsI0KF1+nUduvclnNmcp5QJuVRyp7YboXNuUtNZf9N5PbN269dKOHTtYfsjpApiYmGBmZqa6YcMGk8/nvyyECJdoBKUE9etnSWszRBt3kSlvIlMYIMoWVr1CCTN9ZIoDRH0lfO0WGyZeZePUmwwWFAJHuU9RzAVMz/seS3Qgylrrg7Va7aIQ4sPR0dEuiC4A7z3ee/PKK6/cHhoaGg7DcD9Lco8QEqUkzakLNK6dBiEJio8gw+xiHIrFJiSdd8k81YvvcuPdv6Jv5qfs2hISBqp9ArSG/j5FX05xe57VIEpa62eEECeFENeWAqxWIejh4eGx/fv3fycMwy8t73TOEbeapMYRDO4kt/0pMlt+iaC4GaHbtYM3Men8FK0b52h8fJz07kfgHVrB2Gdgz1Zxb3EhJGEmz/W5gBMfGppJr0GjKCKbzb4lpfwd731t4aS2VonTt3Pnzl/ZtWvXt8IwfGalAcYYkriFMQavQmRUQHQKM+9SXFxD2KR9Lxpl0FqTpoY0aTC23fdABJk8k3MBJy5bmrHvgchms61MJvPbwL8sAKxV8CYzMzMz1toPy+XyVq31tuXAUkqCMCQIQ7QUSBejFppPCQNNJpMljCKkbPuYUhKEYvKuIZCeweLiGa7HnWz3gs45rbU2xWLx3/bu3evPnDnDOhU7rbm5ublarXa+v78/CoLgsaWBvRgb7UtbrXVXU0r1vGW7IGYMgeqF2FDQZEPFzVnfVal67xFCSCHEP3vv6/cDANCs1WpzU1NTF6IomshmsxuVUptYdiHwoLIAcf1uL4S3hkyouHpXkiyzgve+JYT4e2tt5dy5c/cFABCnaTp/8+bNyUql8n4URZe11l4pVRZCZGDda3rrvU+FEF0nl+XutLEoOpcFnkrD8l93Ndb11EmzxpjvpWk6f/HiRTT3Lw3g2vT09Pz09PRkLpf7923btu0YHBx8PJvN7tNaD0spB4UQwYKmnHN30jS9Uq/Xz3rv08HBwT+UUm5dOmkQaCDHqSsNjPM8NiSIU8+Zq5Zm4ntKcefcdKVSqS2U2Z/0I58CcrQ/6uWVUvl8Pp8rFosFrdun+DRN0/n5+Wq9Xq875+qAGxsb+8qWLVv+REo5vHzCNDXErQaRdlgHToRks7meTNRsNl995513vlEqlWylUnn4r5S0zxRRp0kWi04BWCDuNIBHDhw48MLmzZu/uRKEtZY0NQgpCIOgJwFYaydv3Ljxu0eOHPmPl19++Z4mH1YckAJN2m7WXPK71enr1KjUb9y4caNQKNzq6+sbE0IUlk608C1Nr5y9bLVa/bvjx4//43vvvdda+FL08wB4EPFA/ebNmzcLhcLNfD7/eSll6T6eM/V6/Z/OnTv3aqPRmEzT9F5y/UUDdEFEUfRxLpcra623wMoJxTk3WalUvnf27Nnv3rlzZ4K2Re/JzyMGPqkoYFO5XN62e/fuL5bL5UNBEHxWCJEDvHNuutlsvj85Ofn2xMTEOe/9Ndpu2SWfJgC0g74PGAzDsH9gYGBDFEWR997Pz8/Pz83NzXjvZ4C7wIqXV582wFKQHO1MtiCOtsYTVv9+8n9f/hszVLRFCfSpmgAAACV0RVh0ZGF0ZTpjcmVhdGUAMjAxOC0wMy0yM1QyMDo0MDo1NCswMTowMMg8IW4AAAAldEVYdGRhdGU6bW9kaWZ5ADIwMTgtMDMtMjNUMjA6NDA6NTQrMDE6MDC5YZnSAAAARnRFWHRzb2Z0d2FyZQBJbWFnZU1hZ2ljayA2LjcuOC05IDIwMTYtMDYtMTYgUTE2IGh0dHA6Ly93d3cuaW1hZ2VtYWdpY2sub3Jn5r80tgAAABh0RVh0VGh1bWI6OkRvY3VtZW50OjpQYWdlcwAxp/+7LwAAABh0RVh0VGh1bWI6OkltYWdlOjpoZWlnaHQANTEywNBQUQAAABd0RVh0VGh1bWI6OkltYWdlOjpXaWR0aAA1MTIcfAPcAAAAGXRFWHRUaHVtYjo6TWltZXR5cGUAaW1hZ2UvcG5nP7JWTgAAABd0RVh0VGh1bWI6Ok1UaW1lADE1MjE4MzQwNTSBWxDZAAAAE3RFWHRUaHVtYjo6U2l6ZQAzMC44S0JCwEbzfwAAAD90RVh0VGh1bWI6OlVSSQBmaWxlOi8vLi91cGxvYWRzLzU2L2F1czRHbDAvMTM4MS9vY3JmZWVkZXJfOTQ0MjMucG5nsES2aAAAAABJRU5ErkJggg== // @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 ImageProcessor{static extractImageFromElement(e){const t=document.createElement("canvas");t.width=e.naturalWidth||e.width,t.height=e.naturalHeight||e.height;const n=t.getContext("2d");n.fillStyle="#FFFFFF",n.fillRect(0,0,t.width,t.height),n.drawImage(e,0,0);const i=n.getImageData(0,0,t.width,t.height);return {data:this.toGrayscale(i.data),width:t.width,height:t.height}}static async loadImage(e){if("undefined"==typeof document)return this.loadImageInServiceWorker(e);if(e instanceof HTMLImageElement)return this.extractImageFromElement(e);const t=new Image;t.crossOrigin="anonymous",t.src="string"==typeof e?e:URL.createObjectURL(e),await new Promise((e,n)=>{t.onload=()=>e(),t.onerror=()=>n(new Error("图片加载失败")),setTimeout(()=>n(new Error("图片加载超时")),1e4);});const n=document.createElement("canvas");n.width=t.width,n.height=t.height;const i=n.getContext("2d");i.fillStyle="#FFFFFF",i.fillRect(0,0,t.width,t.height),i.drawImage(t,0,0);const o=i.getImageData(0,0,t.width,t.height),d=this.toGrayscale(o.data);return "string"!=typeof e&&URL.revokeObjectURL(t.src),{data:d,width:t.width,height:t.height}}static async loadImageInServiceWorker(e){let t;if("string"==typeof e)if(e.startsWith("data:")){const n=await fetch(e);t=await n.blob();}else {const n=await fetch(e);t=await n.blob();}else {if(!(e instanceof Blob))throw new Error("Service Worker 环境不支持 HTMLImageElement");t=e;}const n=await createImageBitmap(t),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 d=o.getImageData(0,0,i.width,i.height),a=this.toGrayscale(d.data);return n.close(),{data:a,width:i.width,height:i.height}}static toGrayscale(e){const t=new Uint8ClampedArray(e.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(e){}return null};let e=getOrtInstance();if(e)return e;for(let t=0;t<100;t++)if(await new Promise(e=>setTimeout(e,100)),e=getOrtInstance(),e)return e;throw new Error("等待 ort 超时")}async recognize(e){this.initialized&&this.session||await this.init();const{data:t,width:n,height:i}=await ImageProcessor.loadImage(e),o=Math.floor(n*(64/i)),d=ImageProcessor.resize(t,n,i,o,64),a=ImageProcessor.normalize(d),r={input1:new this.ort.Tensor("float32",a,[1,1,64,o])},s=(await this.session.run(r)).output;return {text:this.decodeOutput(s)}}decodeOutput(e){const t=this.convertToNumberArray(e.data),n=[];let i="";for(const o of t){if(o<=0||o>=this.charsets.length)continue;const e=this.charsets[o];e&&e!==i&&(n.push(e),i=e);}return n.join("")}convertToNumberArray(e){const t=[];for(let n=0;ne.startsWith("__reactProps$")||e.startsWith("__reactFiber$")||e.startsWith("__reactEventHandlers$"))){const t=e._valueTracker;t&&t.setValue("");}if((e.ngModel||e.getAttribute("ng-model")||e.getAttribute("[(ngModel)]"))&&(this.dispatchEvent(e,"input"),this.dispatchEvent(e,"blur")),Object.keys(e).find(e=>e.startsWith("__vue"))||e.hasAttribute("v-model")){const t=new CompositionEvent("compositionstart",{bubbles:true}),n=new CompositionEvent("compositionend",{bubbles:true,data:e.value});e.dispatchEvent(t),e.dispatchEvent(n);}}async simulateTyping(e,t){var n;for(const i of t){this.dispatchKeyEvent(e,"keydown",i);const t=null==(n=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value"))?void 0:n.set;t?t.call(e,e.value+i):e.value+=i;const o=new InputEvent("input",{bubbles:true,cancelable:true,inputType:"insertText",data:i});e.dispatchEvent(o),this.dispatchKeyEvent(e,"keyup",i),await this.delay(50+100*Math.random());}this.dispatchEvent(e,"change"),this.dispatchEvent(e,"blur");}dispatchEvent(e,t){e.dispatchEvent(new Event(t,{bubbles:true,cancelable:true}));}dispatchKeyEvent(e,t,n){e.dispatchEvent(new KeyboardEvent(t,{key:n,code:`Key${n.toUpperCase()}`,charCode:n.charCodeAt(0),keyCode:n.charCodeAt(0),bubbles:true,cancelable:true}));}delay(e){return new Promise(t=>setTimeout(t,e))}highlightInput(e){const t=e.style.border,n=e.style.boxShadow;e.style.border="2px solid #4CAF50",e.style.boxShadow="0 0 8px rgba(76, 175, 80, 0.5)",setTimeout(()=>{e.style.border=t,e.style.boxShadow=n;},2e3);}async submitForm(e){var t;const n=e.closest("form");if(n){const e=new Event("submit",{bubbles:true,cancelable:true});n.dispatchEvent(e)&&n.submit();}else {const n=((null==(t=e.parentElement)?void 0:t.parentElement)||document).querySelector('button[type="submit"], input[type="submit"], button:not([type])');n&&n.click();}}getLastFilledInput(){return this.lastFilledInput}}const e={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"],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"]},t={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},n=class{static setDebugMode(e){this.debugMode=e;}static isDebugMode(){return this.debugMode}static debug(...e){this.debugMode;}static info(...e){this.debugMode;}static warn(...e){}static error(...e){}static group(e){this.debugMode;}static groupEnd(){this.debugMode;}static table(e){this.debugMode;}static time(e){this.debugMode;}static timeEnd(e){this.debugMode;}};n.debugMode=false,n.prefix="[DDDD OCR]";let i=n;const o=class{static parseExpression(e){const t=e.trim();let n=t;for(const d of this.NOISE_CHARS)n=n.split(d).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 d of i){const e=n.match(d);if(e){const n=parseFloat(e[1]),i=e[2],o=parseFloat(e[3]);if(!isNaN(n)&&!isNaN(o))return {num1:n,operator:i,num2:o,originalText:t,cleanExpression:`${n}${this.normalizeOperator(i)}${o}`}}}const o=t.match(/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]\s*(\d+)$/);if(o){const e=parseFloat(o[1]),n=o[2],i=parseFloat(o[3]),d=parseFloat(o[4]);if(!isNaN(e)&&!isNaN(i)){const o=this.compute(e,n,i);if(null!==o&&Math.abs(o-d)>.001)return {num1:e,operator:n,num2:i,originalText:t,cleanExpression:`${e}${this.normalizeOperator(n)}${i}`}}}return null}static normalizeOperator(e){switch(e){case "x":case "X":case "*":return "×";case "/":return "÷";default:return e}}static compute(e,t,n){switch(t){case "+":return e+n;case "-":return e-n;case "*":case "×":case "x":case "X":return e*n;case "/":case "÷":return 0===n?null:e/n;default:return null}}static calculate(e){return this.compute(e.num1,e.operator,e.num2)}static formatResult(e){return Number.isInteger(e)?String(e):e.toFixed(2).replace(/\.?0+$/,"")}static formatEquation(e,t){const n=this.normalizeOperator(e.operator);return `${e.num1}${n}${e.num2}=${this.formatResult(t)}`}static matchesPattern(e,t,n){try{if("regex"===n)return new RegExp(t,"i").test(e);{const n="^"+t.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$";return new RegExp(n,"i").test(e)}}catch{return false}}static getOutputModeForHostname(e,t,n){for(const i of t)if(i.enabled&&this.matchesPattern(e,i.pattern,i.matchType))return i.outputMode;return n}static shouldCalculateForHostname(e,t){if(!t||0===t.length)return true;const n=t.filter(e=>e.enabled);if(0===n.length)return true;for(const i of n)if(this.matchesPattern(e,i.pattern,i.matchType))return true;return false}static processResult(e,t,n){if(!t.autoCalculate)return e;if(t.rules&&t.rules.length>0&&!this.shouldCalculateForHostname(n,t.rules))return e;const i=this.parseExpression(e);if(!i)return e;const o=this.calculate(i);return null===o?e:"equation"===this.getOutputModeForHostname(n,t.rules,t.outputMode)?this.formatEquation(i,o):this.formatResult(o)}static isExpression(e){return null!==this.parseExpression(e)}};o.OPERATORS=["+","-","×","*","÷","/","x","X"],o.EQUALS_CHARS=["=","="],o.QUESTION_CHARS=["?","?","〇","o","O","0"],o.NOISE_CHARS=["?","?","〇"," ","\t","\n","\r"];let d=o;class CaptchaDetector{constructor(){this.detectedCaptchas=[],this.processedElements=new WeakMap,this.checkedAgreements=new WeakSet;}scan(){return this.detectedCaptchas=[],i.time("CaptchaDetector.scan"),this.scanImages(),this.scanCanvas(),this.scanSvg(),i.timeEnd("CaptchaDetector.scan"),i.debug("扫描结果:",this.detectedCaptchas.length,"个验证码"),this.detectedCaptchas}scanImages(){document.querySelectorAll("img").forEach((e,t)=>{if(this.isLikelyCaptcha(e)){const n=e.getBoundingClientRect(),o={id:`captcha-${t}`,type:"image",element:e,src:e.src,rect:n,confidence:this.calculateConfidence(e),inputElement:this.findRelatedInput(e),elementInfo:this.extractCaptchaInfo(e)};this.detectedCaptchas.push(o),i.debug("检测到图片验证码:",o.elementInfo);}});}scanCanvas(){document.querySelectorAll("canvas").forEach((e,t)=>{if(this.isLikelyCanvasCaptcha(e)){const n=e.getBoundingClientRect(),o={id:`captcha-canvas-${t}`,type:"canvas",element:e,rect:n,confidence:this.calculateConfidence(e),inputElement:this.findRelatedInput(e),elementInfo:this.extractCaptchaInfo(e)};this.detectedCaptchas.push(o),i.debug("检测到Canvas验证码:",o.elementInfo);}});}scanSvg(){document.querySelectorAll("svg").forEach((e,t)=>{if(this.isLikelySvgCaptcha(e)){const n=e.getBoundingClientRect(),o={id:`captcha-svg-${t}`,type:"svg",element:e,rect:n,confidence:this.calculateConfidence(e),inputElement:this.findRelatedInput(e),elementInfo:this.extractCaptchaInfo(e)};this.detectedCaptchas.push(o),i.debug("检测到SVG验证码:",o.elementInfo);}});}extractCaptchaInfo(e){var t,n;const i=e.getBoundingClientRect();return {tagName:e.tagName.toLowerCase(),id:e.id||null,className:(null==(n=null==(t=e.className)?void 0:t.toString)?void 0:n.call(t))||"",width:Math.round(i.width),height:Math.round(i.height),src:e.src}}extractInputInfo(e){return {tagName:e.tagName.toLowerCase(),id:e.id||null,name:e.name||null,className:e.className||"",placeholder:e.placeholder||null,type:e.type||"text"}}isLikelyCaptcha(e){const t=e.getBoundingClientRect();return !(!this.isCaptchaSize(t.width,t.height)||!this.isVisible(e)||this.isExcludedImage(e)||!this.matchesKeywords(e)&&!this.srcContainsKeywords(e.src)&&!this.parentContainsKeywords(e)&&!this.hasNearbyInput(e))}isExcludedImage(e){var t,n;const i=e.src.toLowerCase()+(e.alt||"").toLowerCase()+((null==(n=null==(t=e.className)?void 0:t.toString)?void 0:n.call(t))||"").toLowerCase();return ["avatar","logo","icon","banner","ad","sponsor","background","bg","profile","user","photo","emoji","emoticon","sticker","gif","loading","spinner","placeholder"].some(e=>i.includes(e))}isLikelyCanvasCaptcha(e){const t=e.getBoundingClientRect();return !(!this.isCaptchaSize(t.width,t.height)||!this.isVisible(e)||!this.matchesKeywords(e)&&!this.parentContainsKeywords(e)&&!this.hasNearbyInput(e))}isLikelySvgCaptcha(e){const t=e.clientWidth||parseInt(e.getAttribute("width")||"0"),n=e.clientHeight||parseInt(e.getAttribute("height")||"0");return !(!this.isCaptchaSize(t,n)||!this.isVisible(e)||!this.matchesKeywords(e)&&!this.parentContainsKeywords(e)&&!this.hasNearbyInput(e))}isCaptchaSize(t,n){return t>=e.MIN_CAPTCHA_WIDTH&&t<=e.MAX_CAPTCHA_WIDTH&&n>=e.MIN_CAPTCHA_HEIGHT&&n<=e.MAX_CAPTCHA_HEIGHT}isVisible(e){const t=window.getComputedStyle(e),n=e.getBoundingClientRect();return "none"!==t.display&&"hidden"!==t.visibility&&"0"!==t.opacity&&n.width>0&&n.height>0}isFrameworkCheckbox(e){const t=["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 t)if(e.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(e.closest(i))return true;return false}isCheckboxFunctional(e){if(e.disabled)return false;if(this.isFrameworkCheckbox(e)){const t=[e.closest(".el-checkbox"),e.closest(".ant-checkbox-wrapper"),e.closest(".ivu-checkbox-wrapper"),e.closest(".van-checkbox"),e.closest("label")];for(const e of t)if(e){const t=window.getComputedStyle(e);if("none"!==t.display&&"hidden"!==t.visibility)return true}let n=e.parentElement,i=0;for(;n&&i<5;){const e=window.getComputedStyle(n);if("none"===e.display)return false;if("hidden"===e.visibility)return false;n=n.parentElement,i++;}return true}if("none"===window.getComputedStyle(e).display)return false;let t=e.parentElement,n=0;for(;t&&n<5;){const e=window.getComputedStyle(t);if("none"===e.display||"hidden"===e.visibility)return false;t=t.parentElement,n++;}return true}findClickableTarget(e){const t=e.closest(".el-checkbox");if(t)return t.querySelector(".el-checkbox__inner")||t;const n=e.closest(".ant-checkbox-wrapper");if(n)return n.querySelector(".ant-checkbox-inner")||n;const i=e.closest(".ivu-checkbox-wrapper");if(i)return i.querySelector(".ivu-checkbox-inner")||i;const o=e.closest(".van-checkbox");return o?o.querySelector(".van-checkbox__icon")||o:e.closest("label")||null}matchesKeywords(t){var n,i;const o=((null==(i=null==(n=t.className)?void 0:n.toString)?void 0:i.call(n))||"").toLowerCase(),d=(t.id||"").toLowerCase();return e.CAPTCHA_KEYWORDS.some(e=>o.includes(e)||d.includes(e))}srcContainsKeywords(t){if(!t)return false;const n=t.toLowerCase();return e.CAPTCHA_KEYWORDS.some(e=>n.includes(e))}parentContainsKeywords(e){let t=e.parentElement,n=0;for(;t&&n<3;){if(this.matchesKeywords(t))return true;t=t.parentElement,n++;}return false}hasNearbyInput(e){return null!==this.findRelatedInput(e)}findClosestInputInContainer(e,t,n=Infinity){const i=e.querySelectorAll('input[type="text"], input:not([type])');let o=null,d=Infinity,a=false;for(const r of i){const e=r;if(!this.isValidCaptchaInput(e))continue;const i=r.getBoundingClientRect(),s=this.calculateDistance(t,i);if(s>n)continue;const c=this.isCaptchaInputByName(e);(st.right&&e.left-t.right<150&&Math.abs(e.top-t.top)<50)return a;if(e.top>t.bottom&&e.top-t.bottom<100&&Math.abs(e.left-t.left)<100)return a}return null}findCaptchaInput(e){const t=e.querySelectorAll('input[type="text"], input:not([type])');for(const n of t){const e=n;if(this.isValidCaptchaInput(e)&&this.isCaptchaInputByName(e))return e}return null}isValidCaptchaInput(t){const n=(t.type||"text").toLowerCase();if(e.EXCLUDED_INPUT_TYPES.includes(n))return false;const i=(t.name||"").toLowerCase(),o=(t.id||"").toLowerCase();for(const d of e.EXCLUDED_INPUT_NAMES)if(i===d||o===d)return false;return !!this.isVisible(t)}isCaptchaInputByName(t){const n=(t.name+t.id+t.className+t.placeholder).toLowerCase();return e.INPUT_KEYWORDS.some(e=>n.includes(e))}calculateConfidence(e){let t=0;this.matchesKeywords(e)&&(t+=30),e.src&&this.srcContainsKeywords(e.src)&&(t+=20),this.parentContainsKeywords(e)&&(t+=15),this.findRelatedInput(e)&&(t+=25);const n=e.getBoundingClientRect();return this.isCaptchaSize(n.width,n.height)&&(t+=10),Math.min(t,100)}guessRelatedCaptcha(e){const t=[],n=e.getBoundingClientRect();i.debug("开始猜测关联的验证码元素, 输入框位置:",n);const o=[];document.querySelectorAll("img").forEach(e=>{if(!this.isVisible(e))return;const t=e.getBoundingClientRect();if(!this.isCaptchaSize(t.width,t.height))return;if(this.isExcludedImage(e))return;const i=this.calculateDistance(n,t);o.push({element:e,distance:i,type:"image"});}),document.querySelectorAll("canvas").forEach(e=>{if(!this.isVisible(e))return;const t=e.getBoundingClientRect();if(!this.isCaptchaSize(t.width,t.height))return;const i=this.calculateDistance(n,t);o.push({element:e,distance:i,type:"canvas"});}),document.querySelectorAll("svg").forEach(e=>{if(!this.isVisible(e))return;const t=e.clientWidth||parseInt(e.getAttribute("width")||"0"),i=e.clientHeight||parseInt(e.getAttribute("height")||"0");if(!this.isCaptchaSize(t,i))return;const d=e.getBoundingClientRect(),a=this.calculateDistance(n,d);o.push({element:e,distance:a,type:"svg"});}),o.sort((e,t)=>e.distance-t.distance);const d=o.slice(0,3);for(const i of d){const e=Math.max(0,100-Math.floor(i.distance/5));t.push({element:i.element,type:"captcha",confidence:e,selector:this.generateSelector(i.element)});}return i.debug("猜测的验证码元素:",t),t}guessRelatedInput(e){const t=[],n=e.getBoundingClientRect();i.debug("开始猜测关联的输入框, 验证码位置:",n);const o=[];document.querySelectorAll("input").forEach(e=>{const t=e;if(!this.isValidCaptchaInput(t))return;if(!this.isVisible(t))return;const i=t.getBoundingClientRect(),d=this.calculateDistance(n,i),a=this.isCaptchaInputByName(t);o.push({element:t,distance:d,hasKeyword:a});}),o.sort((e,t)=>e.hasKeyword&&!t.hasKeyword?-1:!e.hasKeyword&&t.hasKeyword?1:e.distance-t.distance);const d=o.slice(0,3);for(const i of d){let e=Math.max(0,100-Math.floor(i.distance/5));i.hasKeyword&&(e=Math.min(100,e+20)),t.push({element:i.element,type:"input",confidence:e,selector:this.generateSelector(i.element)});}return i.debug("猜测的输入框元素:",t),t}guessAgreementCheckboxes(){const t=[];return document.querySelectorAll('input[type="checkbox"]').forEach(n=>{var i;const o=n;if(!this.isCheckboxFunctional(o))return;if(this.checkedAgreements.has(o))return;const d=[];d.push(o.name||""),d.push(o.id||""),d.push(o.className||""),d.push(o.getAttribute("data-type")||""),d.push(o.getAttribute("data-name")||""),d.push(o.getAttribute("aria-label")||""),d.push(o.getAttribute("data-v-inspector")||"");const a=o.id?document.querySelector(`label[for="${o.id}"]`):null;a&&(d.push(a.textContent||""),d.push(a.className||""));const r=o.closest("label");r&&(d.push(r.textContent||""),d.push(r.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 e of s)e&&(d.push(e.textContent||""),d.push(e.className||""));let c=o.parentElement,l=0;for(;c&&l<6;){const e=c.tagName.toLowerCase();if(d.push(c.className||""),d.push(c.id||""),["label","div","span","p","li","td"].includes(e)){const e=c.children;for(let t=0;tu.includes(e))){const e=this.findClickableTarget(o);t.push({element:o,type:"agreement",confidence:80,selector:this.generateSelector(o),clickTarget:e||void 0});}}),i.debug("猜测的协议复选框:",t),t}findAgreementsBySelectors(e){const t=[];for(const o of e)if(o.trim())try{document.querySelectorAll(o).forEach(e=>{if(e instanceof HTMLInputElement&&"checkbox"===e.type&&!this.checkedAgreements.has(e)){const n=this.findClickableTarget(e);t.push({element:e,type:"agreement",confidence:100,selector:o,clickTarget:n||void 0});}});}catch(n){}return t}markAgreementChecked(e){this.checkedAgreements.add(e);}calculateDistance(e,t){const n=e.left+e.width/2,i=e.top+e.height/2,o=t.left+t.width/2,d=t.top+t.height/2;return Math.sqrt(Math.pow(o-n,2)+Math.pow(d-i,2))}generateSelector(e){if(e.id)return "#"+e.id;const t=e.className;if(t){const n=t.toString().trim().split(/\s+/).filter(e=>e&&!e.includes(":"));if(n.length>0){const t=e.tagName.toLowerCase()+"."+n.join(".");if(1===document.querySelectorAll(t).length)return t}}const n=[];let i=e;for(;i&&i!==document.body&&n.length<5;){let e=i.tagName.toLowerCase();if(i.id){n.unshift("#"+i.id);break}const t=i.parentElement;if(t){const n=Array.from(t.children).filter(e=>e.tagName===i.tagName);n.length>1&&(e+=":nth-of-type("+(n.indexOf(i)+1)+")");}n.unshift(e),i=i.parentElement;}return n.join(" > ")}async captureImage(e){switch(e.type){case "image":return this.captureImgElement(e.element);case "canvas":return this.captureCanvasElement(e.element);case "svg":return this.captureSvgElement(e.element)}}async captureBuffer(e){const t=await this.captureBlob(e);return await t.arrayBuffer()}async captureBlob(e){switch(e.type){case "image":return this.captureImgAsBlob(e.element);case "canvas":return this.captureCanvasAsBlob(e.element);case "svg":return this.captureSvgAsBlob(e.element)}}async captureImgElement(e){await this.waitForImageLoad(e);const t=document.createElement("canvas"),n=t.getContext("2d"),i=e.naturalWidth||e.width,o=e.naturalHeight||e.height;t.width=i,t.height=o,n.drawImage(e,0,0,i,o);try{return t.toDataURL("image/png")}catch{if(e.src.startsWith("data:"))return e.src;throw new Error("无法捕获跨域图片")}}async captureImgAsBlob(e){if(await this.waitForImageLoad(e),e.src&&!e.src.startsWith("data:")&&!e.src.startsWith("blob:"))try{const t=await fetch(e.src,{credentials:"include"});if(t.ok&&(t.headers.get("content-type")||"").includes("image/"))return await t.blob()}catch{}const t=document.createElement("canvas"),n=t.getContext("2d"),i=e.naturalWidth||e.width,o=e.naturalHeight||e.height;return t.width=i,t.height=o,n.fillStyle="#FFFFFF",n.fillRect(0,0,i,o),n.drawImage(e,0,0,i,o),await new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("图片转换失败"));},"image/png");})}async waitForImageLoad(e){var t;if(!(e.complete&&e.naturalWidth>0||(null==(t=e.src)?void 0:t.startsWith("data:"))&&e.naturalWidth>0))return new Promise((t,n)=>{const i=setTimeout(()=>n(new Error("图片加载超时")),5e3),onLoad=()=>{cleanup(),t();},onError=()=>{cleanup(),n(new Error("图片加载失败"));},cleanup=()=>{clearTimeout(i),e.removeEventListener("load",onLoad),e.removeEventListener("error",onError);};e.addEventListener("load",onLoad),e.addEventListener("error",onError);})}captureCanvasElement(e){return e.toDataURL("image/png")}captureCanvasAsBlob(e){return new Promise((t,n)=>{e.toBlob(e=>{e?t(e):n(new Error("Canvas转换失败"));},"image/png");})}async captureSvgElement(e){const t=await this.captureSvgAsBlob(e);return await this.blobToDataURL(t)}async captureSvgAsBlob(e){const t=e.cloneNode(true),n=e.getBoundingClientRect();t.setAttribute("width",String(n.width)),t.setAttribute("height",String(n.height));const i=(new XMLSerializer).serializeToString(t),o=new Blob([i],{type:"image/svg+xml"}),d=URL.createObjectURL(o);try{const e=await new Promise((e,t)=>{const n=new Image;n.onload=()=>e(n),n.onerror=()=>t(new Error("SVG转换失败")),n.src=d;}),t=document.createElement("canvas");t.width=Math.max(1,Math.round(n.width)),t.height=Math.max(1,Math.round(n.height));const i=t.getContext("2d");return i.fillStyle="#FFFFFF",i.fillRect(0,0,t.width,t.height),i.drawImage(e,0,0),await new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("SVG转换失败"));},"image/png");})}finally{URL.revokeObjectURL(d);}}blobToDataURL(e){return new Promise((t,n)=>{const i=new FileReader;i.onload=()=>t(String(i.result)),i.onerror=()=>n(new Error("读取失败")),i.readAsDataURL(e);})}highlight(e){e.element.setAttribute("data-captcha-highlight","true");}unhighlight(e){e.element.removeAttribute("data-captcha-highlight");}highlightGuessed(e){e.setAttribute("data-captcha-guessed","true");}unhighlightGuessed(e){e.removeAttribute("data-captcha-guessed");}unhighlightAllGuessed(){document.querySelectorAll("[data-captcha-guessed]").forEach(e=>{e.removeAttribute("data-captcha-guessed");});}getDetectedCaptchas(){return this.detectedCaptchas}getMostLikelyCaptcha(){return 0===this.detectedCaptchas.length?null:this.detectedCaptchas.reduce((e,t)=>t.confidence>e.confidence?t:e)}hasElementChanged(e){const t=this.getElementHash(e),n=this.processedElements.get(e);return !n||t!==n}markElementProcessed(e){const t=this.getElementHash(e);this.processedElements.set(e,t);}getElementHash(e){if(e instanceof HTMLImageElement)return e.src+"_"+e.naturalWidth+"_"+e.naturalHeight;if(e instanceof HTMLCanvasElement)try{return e.toDataURL()}catch{return "canvas_"+Date.now()}else {if(e instanceof SVGElement)return e.outerHTML;if(e instanceof HTMLElement&&e.style.backgroundImage)return e.style.backgroundImage}return ""}}class EventEmitter{constructor(){this.listeners=new Map;}on(e,t){this.listeners.has(e)||this.listeners.set(e,new Set),this.listeners.get(e).add(t);}off(e,t){var n;null==(n=this.listeners.get(e))||n.delete(t);}emit(e,t){var n;null==(n=this.listeners.get(e))||n.forEach(e=>{try{e(t);}catch(n){}});}clear(){this.listeners.clear();}}const a="ddddocr_model_cache",r="ddddocr_uploaded_model";class ModelCache{constructor(){this.dbName="DdddOCRDB",this.storeName="modelStore",this.db=null;}async init(){return new Promise((e,t)=>{const n=indexedDB.open(this.dbName,2);n.onerror=()=>t(n.error),n.onsuccess=()=>{this.db=n.result,e();},n.onupgradeneeded=e=>{const t=e.target.result;t.objectStoreNames.contains(this.storeName)||t.createObjectStore(this.storeName);};})}async get(){return this.db||await this.init(),new Promise((t,n)=>{const i=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(a);i.onerror=()=>n(i.error),i.onsuccess=()=>{const n=i.result;if(n)return Date.now()-n.timestamp>e.CACHE_DURATION||n.version!==e.MODEL_VERSION?(this.delete(),void t(null)):void t(n);t(null);};})}async set(t,n){this.db||await this.init();const i={model:t,charsets:n,timestamp:Date.now(),version:e.MODEL_VERSION};return new Promise((e,t)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(i,a);n.onerror=()=>t(n.error),n.onsuccess=()=>e();})}async delete(){return this.db||await this.init(),new Promise((e,t)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(a);n.onerror=()=>t(n.error),n.onsuccess=()=>e();})}async getUploadedModel(){return this.db||await this.init(),new Promise((e,t)=>{const n=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(r);n.onerror=()=>t(n.error),n.onsuccess=()=>e(n.result||null);})}async setUploadedModel(e,t){this.db||await this.init();const n={model:e,charsets:t,timestamp:Date.now(),version:"uploaded"};return new Promise((e,t)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,r);i.onerror=()=>t(i.error),i.onsuccess=()=>e();})}async deleteUploadedModel(){return this.db||await this.init(),new Promise((e,t)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(r);n.onerror=()=>t(n.error),n.onsuccess=()=>e();})}}function downloadFile(e,t=3e4){return new Promise((n,i)=>{GM_xmlhttpRequest({method:"GET",url:e,responseType:"arraybuffer",timeout:t,headers:{"Cache-Control":"max-age=2592000"},onload:e=>{200===e.status?n(e.response):i(new Error(`HTTP ${e.status}`));},onerror:e=>i(e),ontimeout:()=>i(new Error("下载超时"))});})}function downloadJSON(e,t=3e4){return new Promise((n,i)=>{GM_xmlhttpRequest({method:"GET",url:e,responseType:"json",timeout:t,headers:{"Cache-Control":"max-age=2592000"},onload:e=>{200===e.status?n(e.response):i(new Error(`HTTP ${e.status}`));},onerror:e=>i(e),ontimeout:()=>i(new Error("下载超时"))});})}function buildURL(t,n){const i=t.replace(/\/+$/,""),o=n.replace(/^\/+/,"");if(i.includes("jsdelivr"))return `${i}/${e.MODEL_REPO}@${e.MODEL_BRANCH}/${o}`;const d=`/${e.MODEL_REPO}/`;return i.includes(d)?`${i}/${o}`:`${i}/${e.MODEL_REPO}/${e.MODEL_BRANCH}/${o}`}async function loadModel(){const t=GM_getValue("ddddocr_config")||{},n=new ModelCache;if(t.useUploadedModel){const e=await n.getUploadedModel();if(e)return {model:e.model,charsets:e.charsets}}if(false===t.autoDownload)throw new Error("自动下载已禁用,请上传模型文件或启用自动下载");const i=await n.get();if(i)return {model:i.model,charsets:i.charsets};let o=null,d=null;for(let r=0;rt.includes("jsdelivr")?`${t}/npm/onnxruntime-web@${e.WASM_VERSION}/dist/`:t.includes("unpkg")?`${t}/onnxruntime-web@${e.WASM_VERSION}/dist/`:t.includes("cdnjs")?`${t}/ajax/libs/onnxruntime-web/${e.WASM_VERSION}/`:t.includes("npmmirror")?`${t}/onnxruntime-web/${e.WASM_VERSION}/files/dist/`:`${t}/onnxruntime-web@${e.WASM_VERSION}/dist/`),c=["ort-wasm.wasm","ort-wasm-simd.wasm","ort-wasm-threaded.wasm","ort-wasm-simd-threaded.wasm"],l=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(e){if(!(e instanceof Error&&"VersionError"===e.name))throw e;await this.handleVersionError();}}openDatabase(){return new Promise((e,t)=>{const n=indexedDB.open(this.dbName,3);n.onerror=()=>{const e=n.error;t(e||new Error("数据库打开失败"));},n.onsuccess=()=>{this.db=n.result,this.db.onerror=e=>{},e();},n.onupgradeneeded=e=>{const t=e.target.result;t.objectStoreNames.contains(this.storeName)||t.createObjectStore(this.storeName);},n.onblocked=()=>{};})}async handleVersionError(){return new Promise((e,t)=>{const n=indexedDB.deleteDatabase(this.dbName);n.onerror=()=>{t(new Error("无法删除旧数据库"));},n.onsuccess=()=>{this.openDatabase().then(e).catch(t);},n.onblocked=()=>{setTimeout(()=>{this.openDatabase().then(e).catch(t);},100);};})}async get(t){return this.memoryCache.has(t)?this.memoryCache.get(t):(this.db||await this.init(),new Promise((n,i)=>{try{const o=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(t);o.onerror=()=>i(o.error),o.onsuccess=()=>{const i=o.result;if(i){if(Date.now()-i.timestamp>e.CACHE_DURATION||i.version!==e.WASM_VERSION)return this.delete(t).catch(()=>{}),void n(null);this.memoryCache.set(t,i.data),n(i.data);}else n(null);};}catch(o){i(o);}}))}async set(t,n){this.db||await this.init(),this.memoryCache.set(t,n);const i={data:n,timestamp:Date.now(),version:e.WASM_VERSION};return new Promise((e,n)=>{try{const o=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(i,t);o.onerror=()=>n(o.error),o.onsuccess=()=>e();}catch(o){n(o);}})}async delete(e){return this.memoryCache.delete(e),this.db||await this.init(),new Promise((t,n)=>{try{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(e);i.onerror=()=>n(i.error),i.onsuccess=()=>t();}catch(i){n(i);}})}async clear(){return this.memoryCache.clear(),this.db||await this.init(),new Promise((e,t)=>{try{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();n.onerror=()=>t(n.error),n.onsuccess=()=>e();}catch(n){t(n);}})}};async function downloadWASM(e){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?e(n.response):t(new Error(`HTTP ${n.status}`));},onerror:t,ontimeout:()=>t(new Error("下载超时"))});})}catch(t){if(n===s.length-1)throw new Error(`所有 WASM CDN 均下载失败: ${e}`)}}throw new Error(`下载 WASM 失败: ${e}`)}const h=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 e=document.createElement("style");e.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(e),this.stylesInjected=true;}static stopPropagation(e){e.stopPropagation();}static show(e){var t;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
${e.icon||"ℹ️"} ${e.title}
\n
\n
${e.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==(t=i.querySelector(".ddddocr-dialog-button"))||t.addEventListener("click",()=>{var t;null==(t=e.onConfirm)||t.call(e),this.close();}),n.addEventListener("click",e=>{e.target===n&&this.close();});}static confirm(e){var t,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
${e.icon||"❓"} ${e.title}
\n
\n
${e.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==(t=o.querySelector(".confirm-btn"))||t.addEventListener("click",()=>{var t;null==(t=e.onConfirm)||t.call(e),this.close();}),null==(n=o.querySelector(".cancel-btn"))||n.addEventListener("click",()=>{var t;null==(t=e.onCancel)||t.call(e),this.close();}),i.addEventListener("click",t=>{var n;t.target===i&&(null==(n=e.onCancel)||n.call(e),this.close());});}static close(){var e;null==(e=this.container)||e.remove(),this.container=null;}};h.container=null,h.stylesInjected=false;let u=h;const p="ddddocr_config_version",m="ddddocr_stats",g="ddddocr_site_rules",b=function(e,n,i){const getVersion=()=>e(p)||1,setVersion=e=>n(p,e);return {getConfig:()=>function(e,n,i){if(!e)return i(2),{...t};const o=n();let d={...t};for(const a of Object.keys(e)){const n=e[a];void 0!==n&&a in t&&(d[a]=n);}if(o<2&&e.agreementSelector&&(!d.agreementSelectors||0===d.agreementSelectors.length)){const t=e.agreementSelector.trim();t&&(d.agreementSelectors=[t]);}for(const a of Object.keys(t)) void 0===d[a]&&(d[a]=t[a]);return 2!==o&&i(2),d}(e(i),getVersion,setVersion),saveConfig(e){const t={...this.getConfig(),...e};n(i,t);},resetConfig(){n(i,t),setVersion(2);}}}(e=>GM_getValue(e),(e,t)=>GM_setValue(e,t),"ddddocr_config");function getConfig(){return b.getConfig()}function saveConfig(e){b.saveConfig(e);}function getSiteRules(){return GM_getValue(g)||{}}function saveSiteRule(e,t){const n=getSiteRules(),i=t.fullUrl||t.urlPattern||e,o=n[i]||{};n[i]={...o,...t,hostname:e,createdAt:o.createdAt||Date.now(),updatedAt:Date.now(),enabled:false!==t.enabled},GM_setValue(g,n);}function deleteSiteRule(e){const t=getSiteRules();delete t[e],GM_setValue(g,t);}const f=new class{constructor(e){this.dirty=false,this.saveTimer=null,this.storage=e,this.data=this.load();}load(){const e=this.storage.get(m);return e&&"object"==typeof e&&e.sites?e:{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(m,this.data),this.dirty=false);}record(e,t){this.data.sites[e]||(Object.keys(this.data.sites).length>=100&&this.pruneOldest(),this.data.sites[e]={count:0,lastTime:0,totalTime:0});const n=this.data.sites[e];n.count++,n.lastTime=Date.now(),n.totalTime+=t,this.data.total++,this.dirty=true,this.scheduleSave();}pruneOldest(){const e=Object.entries(this.data.sites);e.sort((e,t)=>e[1].lastTime-t[1].lastTime);const t=e.slice(0,10);for(const[n]of t)delete this.data.sites[n];}getStats(){return {...this.data}}getSiteStats(e){return this.data.sites[e]||null}getTopSites(e=10){return Object.entries(this.data.sites).map(([e,t])=>({hostname:e,stats:t})).sort((e,t)=>t.stats.count-e.stats.count).slice(0,e)}getAverageTime(e){if(e){const t=this.data.sites[e];return t&&t.count>0?Math.round(t.totalTime/t.count):0}if(0===this.data.total)return 0;const t=Object.values(this.data.sites).reduce((e,t)=>e+t.totalTime,0);return Math.round(t/this.data.total)}clear(){this.data={sites:{},total:0,updated:Date.now()},this.dirty=true,this.flush();}}({get:e=>GM_getValue(e),set:(e,t)=>GM_setValue(e,t)});function isWhitelisted(){const e=getConfig();if(!e.enableWhitelist)return true;if(!e.whitelist||0===e.whitelist.length)return false;const t=window.location.hostname;return e.whitelist.some(e=>new RegExp("^"+e.replace(/\*/g,".*")+"$","i").test(t))}function shouldExecuteScript(){const e=getConfig();if(e.enableWhitelist){if(!e.whitelist||0===e.whitelist.length)return false;if(!isWhitelisted())return false}return true}function isMobile(){return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<=768}function escapeHtml(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function formatTime(e){return e?new Date(e).toLocaleDateString():"-"}class SettingsUI{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",isMobile());}createStyles(){const e=document.createElement("style");e.id="ddddocr-settings-styles",e.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(e);}async createContainer(){this.overlay=document.createElement("div"),this.overlay.className="ddddocr-overlay",this.container=document.createElement("div"),this.container.className="ddddocr-modal",isMobile()&&this.container.classList.add("mobile");const e=getConfig();let t=false,n=0;try{const e=new ModelCache,i=await e.getUploadedModel();i&&(t=!0,n=i.model.byteLength);}catch(r){}const i=this.renderCalculateRules(e.calculateRules||[]),o=this.renderSiteRules(),d=this.renderStats(),a=this.renderAgreementSelectors(e.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","自动检测并填充","自动识别页面验证码并填充结果",e.autoDetect)}\n ${this.renderSwitchRow("typewriterEffect","打字机效果","模拟人工逐字输入,关闭则一次性填充",e.typewriterEffect)}\n ${this.renderSwitchRow("autoCheckAgreement","自动勾选协议","自动勾选用户协议、隐私政策等复选框",e.autoCheckAgreement)}\n ${this.renderSwitchRow("enableNotification","系统通知","识别完成后显示桌面通知提醒",e.enableNotification)}\n ${this.renderSwitchRow("debugMode","调试模式","在控制台输出详细日志",e.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 ${d}\n
\n\n \x3c!-- 四则运算 --\x3e\n
\n
\n
四则运算识别
\n ${this.renderSwitchRow("autoCalculate","自动计算结果",'识别到 "3+5=?" 自动计算并填充',e.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 ${t?`
[已上传] 本地模型 (${(n/1024/1024).toFixed(1)} MB)
`:""}\n ${this.renderSwitchRow("useUploadedModel","使用上传的模型","优先使用本地上传的模型文件",e.useUploadedModel)}\n ${this.renderSwitchRow("autoDownload","自动下载模型","首次使用时自动从网络下载模型",e.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","启用站点白名单","仅在白名单站点启用脚本功能",e.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(e,t,n,i){return `\n
\n
\n
${t}
\n
${n}
\n
\n
\n
\n
\n
\n `}renderCalculateRules(e){return e&&0!==e.length?e.map((e,t)=>`\n
\n ${escapeHtml(e.pattern)}\n ${"regex"===e.matchType?"正则":"通配符"}\n ${"result"===e.outputMode?"仅结果":"完整等式"}\n \n
\n `).join(""):'
暂无规则,将使用默认输出格式
'}renderSiteRules(){const e=getSiteRules(),t=Object.keys(e);return 0===t.length?'
暂无保存的规则
':t.map(t=>{const n=e[t],i=t.length>35?t.substring(0,35)+"...":t,o=n.selector.length>40?n.selector.substring(0,40)+"...":n.selector;return `\n
\n
\n
${escapeHtml(i)}
\n
${escapeHtml(o)}
\n ${n.fullUrl?'
完整URL匹配
':""}\n
\n
\n \n \n
\n
\n `}).join("")}renderStats(){var e;const t=f.getStats(),n=Object.entries(t.sites||{}),i=n.reduce((e,[,t])=>e+t.totalTime,0),o=t.total>0?Math.round(i/t.total):0,d=t.updated?formatTime(t.updated):"-";let a="";if(0===n.length)a='
暂无统计数据
';else {n.sort((e,t)=>t[1].count-e[1].count);const t=n.slice(0,15),i=(null==(e=t[0])?void 0:e[1].count)||1;a=t.map(([e,t],n)=>{const o=t.count>0?Math.round(t.totalTime/t.count):0,d=formatTime(t.lastTime),a=Math.round(t.count/i*100);return `\n
\n
${n+1}
\n
\n
${escapeHtml(e)}
\n
\n 平均 ${o}ms\n 最后: ${d}\n
\n
\n
\n
\n
\n
${t.count}
\n
\n `}).join("");}return `\n
\n
\n
总识别次数
\n
${t.total}
\n
\n
\n
统计站点数
\n
${n.length}
\n
\n
\n
平均识别耗时
\n
${o}ms
\n
\n
\n
最后更新
\n
${d}
\n
\n
\n
\n
\n
站点排行榜
\n \n
\n
${a}
\n
\n `}renderAgreementSelectors(e){return e&&0!==e.length?e.map((e,t)=>`\n
\n ${escapeHtml(e)}\n \n
\n `).join(""):'
暂无协议选择器
'}stopPropagation(e){e.stopPropagation();}bindEvents(){var e,t,n,i,o,d,a,r,s,c,l,h,u,p;this.container&&this.overlay&&(["mousedown","mouseup","click","dblclick","wheel","keydown","keyup","keypress","contextmenu"].forEach(e=>this.container.addEventListener(e,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==(e=this.container.querySelector(".ddddocr-close"))||e.addEventListener("click",()=>this.hide()),this.overlay.addEventListener("click",()=>this.hide()),this.container.querySelectorAll(".ddddocr-tab").forEach(e=>{e.addEventListener("click",()=>{const t=e.dataset.tab;t&&this.switchTab(t);});}),this.container.querySelectorAll(".ddddocr-switch").forEach(e=>{e.addEventListener("click",()=>{e.classList.toggle("on");const t=e.dataset.key;if("enableWhitelist"===t){const t=this.container.querySelector("#whitelistArea");t&&(t.style.display=e.classList.contains("on")?"block":"none");}if("autoCalculate"===t){const t=this.container.querySelector("#calculateOptionsArea"),n=this.container.querySelector("#calculateRulesCard"),i=e.classList.contains("on");t&&(t.style.display=i?"block":"none"),n&&(n.style.display=i?"block":"none");}});}),null==(t=this.container.querySelector("#addAgreementSelectorBtn"))||t.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==(d=this.container.querySelector("#cancelEditRuleBtn"))||d.addEventListener("click",()=>this.cancelEditRule()),null==(a=this.container.querySelector("#exportRulesBtn"))||a.addEventListener("click",()=>this.exportSiteRules()),null==(r=this.container.querySelector("#importRulesBtn"))||r.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==(h=this.container.querySelector("#resetBtn"))||h.addEventListener("click",()=>this.resetConfig()),null==(u=this.container.querySelector("#saveBtn"))||u.addEventListener("click",()=>this.saveSettings()),null==(p=this.container.querySelector("#saveBtnFloat"))||p.addEventListener("click",()=>this.saveSettings()));}bindModelEvents(){var e,t,n,i,o,d,a,r,s,c;const l=null==(e=this.container)?void 0:e.querySelector("#modelZone"),h=null==(t=this.container)?void 0:t.querySelector("#modelFile"),p=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==(d=this.container)?void 0:d.querySelector("#charsetsName");null==l||l.addEventListener("click",()=>null==h?void 0:h.click()),null==h||h.addEventListener("change",()=>{var e;(null==(e=h.files)?void 0:e[0])&&(p.textContent=`[OK] ${h.files[0].name}`);}),null==m||m.addEventListener("click",()=>null==g?void 0:g.click()),null==g||g.addEventListener("change",()=>{var e;(null==(e=g.files)?void 0:e[0])&&(b.textContent=`[OK] ${g.files[0].name}`);}),null==(r=null==(a=this.container)?void 0:a.querySelector("#uploadBtn"))||r.addEventListener("click",async()=>{var e,t;const n=null==(e=null==h?void 0:h.files)?void 0:e[0],i=null==(t=null==g?void 0:g.files)?void 0:t[0];if(n&&i)try{await async function(e,t){const n=await e.arrayBuffer(),i=await t.text(),o=JSON.parse(i),d=new ModelCache;await d.setUploadedModel(n,o);}(n,i),saveConfig({useUploadedModel:!0}),u.show({title:"成功",content:"模型已保存,请刷新页面",icon:""});}catch(o){u.show({title:"错误",content:String(o),icon:""});}else u.show({title:"提示",content:"请选择模型文件和字符集文件",icon:""});}),null==(c=null==(s=this.container)?void 0:s.querySelector("#deleteModelBtn"))||c.addEventListener("click",()=>{u.confirm({title:"删除模型",content:"确定删除已上传的模型吗?",onConfirm:async()=>{await async function(){const e=new ModelCache;await e.deleteUploadedModel();}(),saveConfig({useUploadedModel:false}),u.show({title:"成功",content:"模型已删除",icon:""});}});});}bindAgreementSelectorDeleteEvents(){var e;null==(e=this.container)||e.querySelectorAll(".btn-delete-agreement").forEach(e=>{e.addEventListener("click",e=>{const t=parseInt(e.target.dataset.index||"0");this.deleteAgreementSelector(t);});});}bindCalcRuleDeleteEvents(){var e;null==(e=this.container)||e.querySelectorAll(".btn-delete-calc-rule").forEach(e=>{e.addEventListener("click",e=>{const t=parseInt(e.target.dataset.index||"0");this.deleteCalculateRule(t);});});}bindSiteRuleEvents(){var e,t;null==(e=this.container)||e.querySelectorAll(".btn-edit-site-rule").forEach(e=>{e.addEventListener("click",e=>{const t=e.target.dataset.key;t&&this.editSiteRule(t);});}),null==(t=this.container)||t.querySelectorAll(".btn-delete-site-rule").forEach(e=>{e.addEventListener("click",e=>{const t=e.target.dataset.key;t&&this.deleteSiteRuleUI(t);});});}addAgreementSelector(){var e,t;const n=null==(e=this.container)?void 0:e.querySelector("#newAgreementSelector"),i=null==n?void 0:n.value.trim();if(!i)return void u.show({title:"提示",content:"请输入选择器",icon:""});const o=getConfig().agreementSelectors||[];if(o.includes(i))return void u.show({title:"提示",content:"选择器已存在",icon:""});o.push(i),saveConfig({agreementSelectors:o});const d=null==(t=this.container)?void 0:t.querySelector("#agreementSelectorsList");d&&(d.innerHTML=this.renderAgreementSelectors(o)),this.bindAgreementSelectorDeleteEvents(),n.value="";}deleteAgreementSelector(e){var t;const n=getConfig().agreementSelectors||[];n.splice(e,1),saveConfig({agreementSelectors:n});const i=null==(t=this.container)?void 0:t.querySelector("#agreementSelectorsList");i&&(i.innerHTML=this.renderAgreementSelectors(n)),this.bindAgreementSelectorDeleteEvents();}addCalculateRule(){var e,t,n,i;const o=null==(e=this.container)?void 0:e.querySelector("#newCalcRulePattern"),d=null==(t=this.container)?void 0:t.querySelector("#newCalcRuleMatchType"),a=null==(n=this.container)?void 0:n.querySelector("#newCalcRuleOutputMode"),r=null==o?void 0:o.value.trim();if(!r)return void u.show({title:"提示",content:"请输入站点匹配规则",icon:""});const s=getConfig().calculateRules||[];s.push({pattern:r,matchType:d.value,outputMode:a.value,enabled:true}),saveConfig({calculateRules:s});const c=null==(i=this.container)?void 0:i.querySelector("#calculateRulesList");c&&(c.innerHTML=this.renderCalculateRules(s)),this.bindCalcRuleDeleteEvents(),o.value="";}deleteCalculateRule(e){var t;const n=getConfig().calculateRules||[];n.splice(e,1),saveConfig({calculateRules:n});const i=null==(t=this.container)?void 0:t.querySelector("#calculateRulesList");i&&(i.innerHTML=this.renderCalculateRules(n)),this.bindCalcRuleDeleteEvents();}addSiteRule(){var e,t,n;const i=null==(e=this.container)?void 0:e.querySelector("#newRuleHostname"),o=null==(t=this.container)?void 0:t.querySelector("#newRuleSelector"),d=null==(n=this.container)?void 0:n.querySelector("#newRuleInputSelector"),a=null==i?void 0:i.value.trim(),r=null==o?void 0:o.value.trim(),s=null==d?void 0:d.value.trim();a&&r?(saveSiteRule(a,{selector:r,inputSelector:s||void 0,enabled:true}),this.refreshSiteRulesList(),i.value="",o.value="",d.value=""):u.show({title:"提示",content:"请填写主机名和验证码选择器",icon:""});}editSiteRule(e){var t,n,i,o,d;const a=getSiteRules()[e];if(!a)return;this.currentEditRuleKey=e;const r=null==(t=this.container)?void 0:t.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"),h=null==(d=this.container)?void 0:d.querySelector("#editRuleInput");r&&(r.style.display="block"),s&&(s.value=e),c&&(c.value=e),l&&(l.value=a.selector||""),h&&(h.value=a.inputSelector||"");}saveEditRule(){var e,t,n;const i=null==(e=this.container)?void 0:e.querySelector("#editRuleOriginalKey"),o=null==(t=this.container)?void 0:t.querySelector("#editRuleSelector"),d=null==(n=this.container)?void 0:n.querySelector("#editRuleInput"),a=null==i?void 0:i.value,r=null==o?void 0:o.value.trim(),s=null==d?void 0:d.value.trim();if(r){if(a){const e=getSiteRules()[a];e&&(deleteSiteRule(a),saveSiteRule(e.hostname,{...e,selector:r,inputSelector:s||void 0}));}this.cancelEditRule(),this.refreshSiteRulesList();}else u.show({title:"提示",content:"验证码选择器不能为空",icon:""});}cancelEditRule(){var e;this.currentEditRuleKey=null;const t=null==(e=this.container)?void 0:e.querySelector("#editRuleCard");t&&(t.style.display="none");}deleteSiteRuleUI(e){u.confirm({title:"删除规则",content:`确定删除规则 "${e}" 吗?`,onConfirm:()=>{deleteSiteRule(e),this.refreshSiteRulesList();}});}refreshSiteRulesList(){var e;const t=null==(e=this.container)?void 0:e.querySelector("#siteRulesList");t&&(t.innerHTML=this.renderSiteRules()),this.bindSiteRuleEvents();}exportSiteRules(){const e=getSiteRules(),t=Object.entries(e).map(([e,t])=>({hostname:t.hostname||e,selector:t.selector,inputSelector:t.inputSelector,fullUrl:t.fullUrl}));this.downloadJson(t,"ddddocr-rules.json");}importSiteRules(){const e=document.createElement("input");e.type="file",e.accept=".json",e.onchange=async e=>{var t;const n=null==(t=e.target.files)?void 0:t[0];if(n)try{const e=await n.text(),t=JSON.parse(e);if(!Array.isArray(t))throw new Error("格式错误");for(const n of t)n.hostname&&n.selector&&saveSiteRule(n.hostname,{selector:n.selector,inputSelector:n.inputSelector,fullUrl:n.fullUrl,enabled:!0});this.refreshSiteRulesList(),u.show({title:"成功",content:`已导入 ${t.length} 条规则`,icon:""});}catch{u.show({title:"错误",content:"规则文件格式错误",icon:""});}},e.click();}clearStats(){u.confirm({title:"清除统计",content:"确定要清除所有统计数据吗?",onConfirm:()=>{var e,t,n;f.clear();const i=null==(e=this.container)?void 0:e.querySelector('[data-panel="stats"]');i&&(i.innerHTML=this.renderStats()),null==(n=null==(t=this.container)?void 0:t.querySelector("#clearStatsBtn"))||n.addEventListener("click",()=>this.clearStats());}});}exportConfig(){const e=getConfig();this.downloadJson(e,"ddddocr-config.json");}importConfig(){const e=document.createElement("input");e.type="file",e.accept=".json",e.onchange=async e=>{var t;const n=null==(t=e.target.files)?void 0:t[0];if(n)try{const e=await n.text();saveConfig(JSON.parse(e)),u.show({title:"成功",content:"配置已导入,请刷新页面",icon:""});}catch{u.show({title:"错误",content:"配置文件格式错误",icon:""});}},e.click();}resetConfig(){u.confirm({title:"重置设置",content:"确定重置所有设置吗?",onConfirm:()=>{GM_setValue("ddddocr_config",t),u.show({title:"成功",content:"设置已重置,请刷新页面",icon:""});}});}downloadJson(e,t){const n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),i=URL.createObjectURL(n),o=document.createElement("a");o.href=i,o.download=t,o.click(),URL.revokeObjectURL(i);}switchTab(e){var t;if(this.container&&(this.activeTab=e,this.container.querySelectorAll(".ddddocr-tab").forEach(t=>{t.classList.toggle("active",t.dataset.tab===e);}),this.container.querySelectorAll(".ddddocr-panel").forEach(t=>{t.classList.toggle("active",t.dataset.panel===e);}),"stats"===e)){const e=this.container.querySelector('[data-panel="stats"]');e&&(e.innerHTML=this.renderStats()),null==(t=this.container.querySelector("#clearStatsBtn"))||t.addEventListener("click",()=>this.clearStats());}}saveSettings(){if(!this.container)return;const e={};this.container.querySelectorAll(".ddddocr-switch").forEach(t=>{const n=t.dataset.key;n&&(e[n]=t.classList.contains("on"));}),this.container.querySelectorAll("input[data-key]").forEach(t=>{const n=t.dataset.key;n&&(e[n]=t.value.trim());}),this.container.querySelectorAll("select[data-key]").forEach(t=>{const n=t.dataset.key;n&&(e[n]=t.value);}),this.container.querySelectorAll("textarea[data-key]").forEach(t=>{const n=t.dataset.key;if(n){const i=t.value;e[n]=i.split("\n").filter(e=>e.trim());}}),saveConfig(e),this.onConfigChange(getConfig()),"undefined"!=typeof GM_notification&&GM_notification({title:"设置已保存",text:"配置已成功保存",timeout:2e3}),this.hide();}async show(){var e,t,n;this.container||await this.createContainer(),this.isVisible=true,null==(e=this.overlay)||e.classList.add("visible"),null==(t=this.container)||t.classList.add("visible"),isMobile()&&(null==(n=this.container)||n.classList.add("mobile"),document.body.style.overflow="hidden");}hide(){var e,t;this.isVisible=false,null==(e=this.overlay)||e.classList.remove("visible"),null==(t=this.container)||t.classList.remove("visible"),document.body.style.overflow="",window.removeEventListener("resize",this.handleResize);}setOnConfigChange(e){this.onConfigChange=e;}}class LoadingIndicator{constructor(){this.container=null,this.create();}create(){const e=document.createElement("style");e.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(e),this.container=document.createElement("div"),this.container.className="ddddocr-loading-indicator",document.body.appendChild(this.container);const t=document.createElement("div");t.className="ddddocr-loading-text",t.id="ddddocr-loading-text",t.textContent="正在初始化 DDDD OCR...",document.body.appendChild(t);}show(e){if(!this.container)return;this.container.classList.add("visible");const t=document.getElementById("ddddocr-loading-text");t&&(e&&(t.textContent=e),t.classList.add("visible"));}updateText(e){const t=document.getElementById("ddddocr-loading-text");t&&(t.textContent=e);}hide(){if(!this.container)return;this.container.classList.remove("visible");const e=document.getElementById("ddddocr-loading-text");e&&e.classList.remove("visible"),setTimeout(()=>{var t;null==(t=this.container)||t.remove(),null==e||e.remove(),this.container=null;},300);}}class DdddOCR{constructor(){this.engine=new OCREngine({getModel:loadModel,wasmPaths:"https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.0/dist/"});}async init(){await async function(){try{await l.init();}catch(t){}(async function(){await Promise.allSettled(c.map(async e=>{try{if(await l.get(e))return;const t=await downloadWASM(e);await l.set(e,t);}catch(t){}}));})().catch(()=>{});const e=window.fetch;window.fetch=async function(n,i){const o="string"==typeof n?n:n instanceof URL?n.href:n.url,d=c.find(e=>o.includes(e));if(!d)return e.call(this,n,i);try{let e=await l.get(d);return e||(e=await downloadWASM(d),l.set(d,e).catch(()=>{})),new Response(e,{status:200,headers:{"Content-Type":"application/wasm","Content-Length":String(e.byteLength)}})}catch(t){return e.call(this,n,i)}};}(),await this.engine.init();}async recognize(e){return this.engine.recognize(e)}}class AutoDetector{constructor(e,t){this.observer=null,this.enabled=false,this.checkInterval=null,this.eventEmitter=null,this.autoFill=new AutoFill,this.initialScanDone=false,this.initialScanTimer=null,this.processingElements=new WeakSet,this.processedElements=new WeakMap,this.customCaptchaElement=null,this.customInputElement=null,this.ocr=e,this.detector=new CaptchaDetector,this.eventEmitter=t||null;}start(){this.enabled||(this.enabled=true,i.info("启动验证码自动检测"),this.applyStoredSiteRule(),this.scheduleInitialDetect(),this.observer=new MutationObserver(e=>{let t=false;for(const n of e){if(n.addedNodes.forEach(e=>{e instanceof HTMLElement&&(this.checkElement(e),(e.matches('input[type="checkbox"]')||e.querySelector('input[type="checkbox"]'))&&(t=true));}),"attributes"===n.type){const e=n.target;e instanceof HTMLElement&&(e instanceof HTMLImageElement?"src"!==n.attributeName&&"data-src"!==n.attributeName||this.recheckImage(e):e instanceof HTMLCanvasElement?this.recheckCanvas(e):"style"===n.attributeName&&e.style.backgroundImage&&this.recheckDiv(e));}"childList"===n.type&&n.target instanceof SVGElement&&this.recheckSVG(n.target);}t&&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 e;this.enabled&&(this.enabled=false,i.info("停止验证码自动检测"),null==(e=this.observer)||e.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 e=getSiteRules(),t=window.location.href,n=window.location.hostname;let o=null;for(const i of Object.keys(e)){const d=e[i];if(d.enabled){if(d.fullUrl&&t===d.fullUrl){o=d;break}if(d.urlPattern&&t.startsWith(d.urlPattern)){o=d;break}d.hostname!==n||d.fullUrl||d.urlPattern||(o=d);}}if(o){const e=document.querySelector(o.selector);e&&(this.customCaptchaElement=e,o.inputSelector&&(this.customInputElement=document.querySelector(o.inputSelector)),i.info("应用站点规则:",o.selector));}}checkAgreementBoxes(){const e=getConfig();if(!e.autoCheckAgreement)return;let t=[];e.agreementSelectors&&e.agreementSelectors.length>0&&(t=e.agreementSelectors);const n=this.detector.guessAgreementCheckboxes();for(const d of n){const e=d.element;if(e.checked)continue;const t=d.clickTarget;t?(t.click(),i.info("点击协议复选框容器")):(e.checked=true,e.dispatchEvent(new Event("change",{bubbles:true})),e.dispatchEvent(new Event("input",{bubbles:true})),i.info("直接勾选协议复选框")),this.detector.markAgreementChecked(e);}for(const d of t)if(d.trim())try{document.querySelectorAll(d).forEach(e=>{e instanceof HTMLInputElement&&"checkbox"===e.type&&!e.checked&&(e.checked=!0,e.dispatchEvent(new Event("change",{bubbles:!0})),e.dispatchEvent(new Event("input",{bubbles:!0})),i.info("通过选择器勾选协议:",d));});}catch(o){}}scheduleInitialDetect(){this.initialScanDone||(this.detectExistingCaptchas(false),this.initialScanTimer=window.setTimeout(()=>{this.initialScanDone||this.detectExistingCaptchas(true);},3e3));}startIntervalCheck(){this.checkInterval=window.setInterval(()=>{const e=this.detector.scan();if(e&&0!==e.length)for(const t of e)if(this.hasElementChanged(t.element)){this.processDetectedCaptcha(t);break}},e.AUTO_DETECT_INTERVAL);}detectExistingCaptchas(e){i.debug("检测页面已存在的验证码"),document.querySelectorAll("img").forEach(t=>this.checkImage(t,e)),document.querySelectorAll("canvas").forEach(t=>this.checkCanvas(t,e)),document.querySelectorAll("svg").forEach(t=>this.checkSVG(t,e)),document.querySelectorAll('div[style*="background"]').forEach(t=>this.checkDiv(t,e)),e&&(this.initialScanDone=true);}checkElement(e){e instanceof HTMLImageElement&&this.checkImage(e,true),e instanceof HTMLCanvasElement&&this.checkCanvas(e,true),e instanceof SVGElement&&this.checkSVG(e,true),e.style.backgroundImage&&this.checkDiv(e,true),e.querySelectorAll("img").forEach(e=>this.checkImage(e,true)),e.querySelectorAll("canvas").forEach(e=>this.checkCanvas(e,true)),e.querySelectorAll("svg").forEach(e=>this.checkSVG(e,true));}async waitForImageLoad(e,t=5e3){return !!(e.complete&&e.naturalWidth>0)||new Promise(n=>{const i=setTimeout(()=>{cleanup(),n(false);},t),onLoad=()=>{cleanup(),n(true);},onError=()=>{cleanup(),n(false);},cleanup=()=>{clearTimeout(i),e.removeEventListener("load",onLoad),e.removeEventListener("error",onError);};e.addEventListener("load",onLoad),e.addEventListener("error",onError),e.complete&&e.naturalWidth>0&&(cleanup(),n(true));})}async recheckImage(e){await this.waitForImageLoad(e)&&await this.checkImage(e,true);}async recheckCanvas(e){await new Promise(e=>requestAnimationFrame(e)),await this.checkCanvas(e,true);}async recheckSVG(e){await new Promise(e=>requestAnimationFrame(e)),await this.checkSVG(e,true);}async recheckDiv(e){await new Promise(e=>requestAnimationFrame(e)),await this.checkDiv(e,true);}async checkImage(e,t){var n;const i=getConfig();if(i.captchaSelector){if(!e.matches(i.captchaSelector))return}else if(!this.isCaptchaImage(e))return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:e,type:"img"}),!t)return;const o=this.findNearbyInput(e);o&&(o.value.trim()&&(o.value="",o.dispatchEvent(new Event("input",{bubbles:true}))),await this.waitForImageLoad(e)&&e.naturalWidth&&await this.recognizeAndFill(e,o));}async checkCanvas(e,t){var n;const i=getConfig();if(i.captchaSelector){if(!e.matches(i.captchaSelector))return}else if(!this.isCaptchaCanvas(e))return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:e,type:"canvas"}),!t)return;const o=this.findNearbyInput(e);if(!o)return;await new Promise(e=>requestAnimationFrame(e));const d=await new Promise((t,n)=>{e.toBlob(e=>{e?t(e):n(new Error("Canvas转换失败"));},"image/png");});await this.recognizeAndFillBlob(e,d,o);}async checkSVG(e,t){var n;const i=getConfig();if(i.captchaSelector){if(!e.matches(i.captchaSelector))return}else if(!this.isCaptchaSVG(e))return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:e,type:"svg"}),!t)return;const o=this.findNearbyInput(e);if(!o)return;const d=await this.svgToBlob(e);await this.recognizeAndFillBlob(e,d,o);}async checkDiv(e,t){var n;const i=getConfig();if(i.captchaSelector){if(!e.matches(i.captchaSelector))return}else if(!this.isCaptchaDiv(e))return;const o=e.style.backgroundImage;if(!o)return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:e,type:"div"}),!t)return;const d=this.findNearbyInput(e);if(!d)return;const a=o.match(/url\(['"]?(.+?)['"]?\)/);if(!a)return;const r=a[1],s=Date.now();let c="";if(r.startsWith("data:")){const e=await fetch(r),t=await e.blob();c=(await this.ocr.recognize(t)).text;}else c=(await this.ocr.recognize(r)).text;const l=Date.now()-s,h=this.processResult(c);await this.fillInput(d,h),this.markElementProcessed(e),f.record(window.location.hostname,l);}async svgToBlob(e){const t=(new XMLSerializer).serializeToString(e),n=new Blob([t],{type:"image/svg+xml;charset=utf-8"}),i=URL.createObjectURL(n),o=new Image;o.src=i,await new Promise((e,t)=>{o.onload=e,o.onerror=t,setTimeout(t,5e3);});const d=document.createElement("canvas");return d.width=e.clientWidth||150,d.height=e.clientHeight||50,d.getContext("2d").drawImage(o,0,0),URL.revokeObjectURL(i),new Promise((e,t)=>{d.toBlob(n=>{n?e(n):t(new Error("SVG转换失败"));},"image/png");})}async recognizeAndFill(e,t){var n,o,d;if(this.processingElements.has(e))return;this.processingElements.add(e);const a=Date.now();i.time("recognizeAndFill");try{null==(n=this.eventEmitter)||n.emit("recognize:start",{element:e});const d=await this.ocr.recognize(e),r=this.processResult(d.text);null==(o=this.eventEmitter)||o.emit("recognize:complete",{element:e,result:{text:r}}),await this.fillInput(t,r),this.markElementProcessed(e);const s=Date.now()-a;f.record(window.location.hostname,s),i.timeEnd("recognizeAndFill"),i.info("识别完成:",r);}catch(r){null==(d=this.eventEmitter)||d.emit("recognize:error",{element:e,error:r});}finally{this.processingElements.delete(e);}}async recognizeAndFillBlob(e,t,n){var o,d,a;if(this.processingElements.has(e))return;this.processingElements.add(e);const r=Date.now();try{null==(o=this.eventEmitter)||o.emit("recognize:start",{element:e});const a=await this.ocr.recognize(t),s=this.processResult(a.text);null==(d=this.eventEmitter)||d.emit("recognize:complete",{element:e,result:{text:s}}),await this.fillInput(n,s),this.markElementProcessed(e);const c=Date.now()-r;f.record(window.location.hostname,c),i.info("识别完成:",s);}catch(s){null==(a=this.eventEmitter)||a.emit("recognize:error",{element:e,error:s});}finally{this.processingElements.delete(e);}}processResult(e){const t=getConfig();return t.autoCalculate?d.processResult(e,{autoCalculate:true,outputMode:t.calculateOutputMode,rules:t.calculateRules||[]},window.location.hostname):e}async fillInput(e,t){const n=getConfig();await this.autoFill.fill(e,t,{simulate:true,autoSubmit:false,typewriterEffect:n.typewriterEffect}),n.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:"验证码已自动填充",text:`识别结果: ${t}`,timeout:3e3});}processDetectedCaptcha(e){const t=e.inputElement||this.detector.findRelatedInput(e.element);if(t)if("image"===e.type)this.recognizeAndFill(e.element,t);else if("canvas"===e.type){const n=e.element;n.toBlob(e=>{e&&this.recognizeAndFillBlob(n,e,t);},"image/png");}}isCaptchaImage(t){const n=t.naturalWidth||t.width,i=t.naturalHeight||t.height;if(ne.MAX_CAPTCHA_WIDTH||i>e.MAX_CAPTCHA_HEIGHT)return false;const o=(t.src+t.className+t.id+t.alt+(t.getAttribute("data-src")||"")).toLowerCase();return e.CAPTCHA_KEYWORDS.some(e=>o.includes(e))}isCaptchaCanvas(t){const n=t.width,i=t.height;if(ne.MAX_CAPTCHA_WIDTH||i>e.MAX_CAPTCHA_HEIGHT)return false;const o=(t.className+t.id+(t.getAttribute("data-type")||"")).toLowerCase();return e.CAPTCHA_KEYWORDS.some(e=>o.includes(e))}isCaptchaSVG(t){const n=t.clientWidth||parseInt(t.getAttribute("width")||"0"),i=t.clientHeight||parseInt(t.getAttribute("height")||"0");if(ne.MAX_CAPTCHA_WIDTH||i>e.MAX_CAPTCHA_HEIGHT)return false;const o=(t.className.baseVal+t.id).toLowerCase();return e.CAPTCHA_KEYWORDS.some(e=>o.includes(e))}isCaptchaDiv(t){const n=t.clientWidth,i=t.clientHeight;if(ne.MAX_CAPTCHA_WIDTH||i>e.MAX_CAPTCHA_HEIGHT)return false;const o=(t.className+t.id).toLowerCase();return e.CAPTCHA_KEYWORDS.some(e=>o.includes(e))}findNearbyInput(e){const t=getConfig();if(t.inputSelector){const e=document.querySelector(t.inputSelector);if(e instanceof HTMLInputElement)return e}return this.detector.findRelatedInput(e)}getElementHash(e){if(e instanceof HTMLImageElement)return e.src+"_"+e.naturalWidth+"_"+e.naturalHeight;if(e instanceof HTMLCanvasElement)try{return e.toDataURL()}catch{return "canvas_"+Date.now()}else {if(e instanceof SVGElement)return e.outerHTML;if(e instanceof HTMLElement&&e.style.backgroundImage)return e.style.backgroundImage}return ""}hasElementChanged(e){const t=this.getElementHash(e),n=this.processedElements.get(e);return !n||t!==n}markElementProcessed(e){const t=this.getElementHash(e);this.processedElements.set(e,t);}}class OCRApp{constructor(){this.loadingIndicator=null,this.initialized=false,this.menuCommandIds=new Map,this.eventEmitter=new EventEmitter,this.ocr=new DdddOCR,this.detector=new AutoDetector(this.ocr,this.eventEmitter),this.settingsUI=new SettingsUI,this.registerMenuCommands(),this.settingsUI.setOnConfigChange(e=>this.handleConfigChange(e));const e=getConfig();i.setDebugMode(e.debugMode||false);}async init(){var e;if(!shouldExecuteScript())return void i.debug("当前站点不满足执行条件");if(this.initialized)return;const t=getConfig();this.initialized=true,this.loadingIndicator=new LoadingIndicator,i.info("DDDD OCR 启动");try{this.loadingIndicator.show("正在初始化 DDDD OCR"),this.loadingIndicator.updateText("正在加载模型文件"),await this.ocr.init(),i.info("OCR 已就绪"),this.loadingIndicator.updateText("DDDD OCR 已就绪"),t.autoDetect&&(this.detector.start(),i.info("自动检测已启动")),setTimeout(()=>{var e;return null==(e=this.loadingIndicator)?void 0:e.hide()},2e3),this.showNotification("DDDD OCR 已就绪",t.autoDetect?"自动检测已启用":"点击菜单启用自动检测"),this.refreshMenuCommands();}catch(n){null==(e=this.loadingIndicator)||e.updateText("初始化失败: "+String(n)),setTimeout(()=>{var e;return null==(e=this.loadingIndicator)?void 0:e.hide()},3e3),this.showNotification("初始化失败",String(n),true);}}registerMenuCommands(){this.refreshMenuCommands();}refreshMenuCommands(){const e=GM_registerMenuCommand("打开设置",()=>this.settingsUI.show(),"s");this.menuCommandIds.set("settings",e);const t=GM_registerMenuCommand("清除缓存",async()=>{u.confirm({title:"清除缓存",content:"确定要清除所有缓存吗(包括模型和 WASM)?下次启动将重新下载。",confirmText:"确定清除",cancelText:"取消",onConfirm:async()=>{await async function(){const e=new ModelCache;await e.delete();}(),await async function(){await l.clear();}(),this.showNotification("缓存已清除","请刷新页面");}});},"d");this.menuCommandIds.set("cache",t);const n=GM_registerMenuCommand("查看状态",()=>this.showStatus(),"i");this.menuCommandIds.set("status",n);}showStatus(){var e,t,n;const i=getConfig(),o=isWhitelisted(),d=getSiteRules(),a=f.getStats(),r=`\n脚本状态: ${this.initialized?"已初始化":"未初始化"}\n当前站点: ${window.location.hostname}\n白名单状态: ${i.enableWhitelist?"已启用":"已禁用"}\n白名单数量: ${(null==(e=i.whitelist)?void 0:e.length)||0} 个站点\n当前站点匹配: ${o?"在白名单中":"不在白名单中"}\n自动检测: ${i.autoDetect?"已启用":"已禁用"}\n打字机效果: ${i.typewriterEffect?"已启用":"已禁用"}\n自动勾选协议: ${i.autoCheckAgreement?"已启用":"已禁用"}\n协议选择器数: ${(null==(t=i.agreementSelectors)?void 0:t.length)||0} 个\n自动计算: ${i.autoCalculate?"已启用":"已禁用"}\n计算输出: ${"result"===i.calculateOutputMode?"仅结果":"完整等式"}\n计算规则数: ${(null==(n=i.calculateRules)?void 0:n.length)||0} 条\n站点规则数: ${Object.keys(d).length} 条\n调试模式: ${i.debugMode?"已启用":"已禁用"}\n上传模型: ${i.useUploadedModel?"已启用":"未启用"}\n自动下载: ${i.autoDownload?"已启用":"已禁用"}\n总识别次数: ${a.total} 次`;u.show({title:"当前状态",content:r});}handleConfigChange(e){i.setDebugMode(e.debugMode||false),e.autoDetect&&!this.initialized&&this.init(),e.autoDetect?this.detector.start():this.detector.stop(),this.refreshMenuCommands();}showNotification(e,t,n=false){getConfig().enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:e,text:t,timeout:n?5e3:3e3});}}function bootstrap(){const e=new OCRApp;shouldExecuteScript()?setTimeout(()=>e.init(),500):i.debug("DDDD OCR 不满足执行条件,仅注册菜单命令");}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",bootstrap):bootstrap(); })();