// ==UserScript== // @name DDDD OCR WEB - 验证码自动识别 // @namespace https://github.com/MakotoArai-CN/ddddocr-webjs // @version 1.1.6-4/14/2026, 6:57:27 PM // @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_unregisterMenuCommand // @grant GM_xmlhttpRequest // @grant unsafeWindow // ==/UserScript== (function () { 'use strict'; class e{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 s=i.getImageData(0,0,t.width,t.height),o=this.toGrayscale(s.data);return "string"!=typeof e&&URL.revokeObjectURL(t.src),{data:o,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),s=i.getContext("2d");s.fillStyle="#FFFFFF",s.fillRect(0,0,i.width,i.height),s.drawImage(n,0,0);const o=s.getImageData(0,0,i.width,i.height),a=this.toGrayscale(o.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 t=e();if(t)return console.log("✅ ort 已存在"),t;console.log("⏳ 等待 ort 加载...");for(let n=0;n<100;n++)if(await new Promise(e=>setTimeout(e,100)),t=e(),t)return console.log("✅ ort 已就绪"),t;throw new Error("等待 ort 超时")}async recognize(t){this.initialized&&this.session||await this.init();const n=Date.now(),{data:i,width:s,height:o}=await e.loadImage(t),a=Math.floor(s*(64/o)),r=e.resize(i,s,o,a,64),d=e.normalize(r),l={input1:new this.ort.Tensor("float32",d,[1,1,64,a])},c=(await this.session.run(l)).output,u=this.decodeOutput(c);return console.log(`识别完成: ${u} (耗时: ${Date.now()-n}ms)`),{text:u}}decodeOutput(e){const t=this.convertToNumberArray(e.data),n=[];let i=-1;for(const s of t){if(s===i)continue;if(i=s,s<=0||s>=this.charsets.length)continue;const e=this.charsets[s];e&&n.push(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 s=new InputEvent("input",{bubbles:true,cancelable:true,inputType:"insertText",data:i});e.dispatchEvent(s),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 i={MODEL_VERSION:"1.5.1",MODEL_REPO:"MakotoArai-CN/ddddocr-webjs",MODEL_BRANCH:"main",MODEL_PATH:"public/common.onnx",CHARSETS_PATH:"public/charsets.json",WASM_VERSION:"1.17.0",CACHE_DURATION:2592e6,CAPTCHA_KEYWORDS:["captcha","verify","code","vcode","authcode","验证码","checkcode","yzm","capimg","signCaptcha","imgcode","seccode","validcode","yanzhengma","validatecode","piccode","imgverify","codeimg","randcode","identify","kaptcha","verifycode","imgCaptcha","captchaImg","vcodeImg"],INPUT_KEYWORDS:["captcha","verify","code","vcode","authcode","验证码","checkcode","yzm","validatecode","validcode","seccode","imgcode","randcode","identify","kaptcha","answer","verifycode","captchaInput","vcodeInput"],AGREEMENT_KEYWORDS:["agree","agreement","accept","terms","policy","privacy","同意","协议","条款","隐私","用户协议","隐私政策","tos","consent"],INPUT_EXCLUDE_KEYWORDS:["手机","短信","sms","phone","mobile","手机验证码","短信验证码","手机号","滑动验证码","email","mail","邮箱","邮箱验证码","邮件验证码","username","user","account","账号","用户名","otp","one time","verification code","动态码","校验码","短信校验","手机校验码"],EXCLUDED_INPUT_TYPES:["password","email","tel","phone","mobile","hidden","submit","button","reset","file","image","checkbox","radio"],EXCLUDED_INPUT_NAMES:["username","user","account","email","mail","phone","mobile","tel","password","pwd","pass","name","realname","nickname","search","query","q","keyword","address","city"],EXCLUDE_PATTERNS:["avatar","logo","icon","banner","ad","sponsor","background","bg","profile","user","photo","emoji","emoticon","sticker","gif","loading","spinner","placeholder","slider","slide","drag","puzzle","jigsaw"],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"]},s={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",language:"auto",typewriterEffect:true,autoCalculate:false,calculateOutputMode:"result",calculateRules:[],customIncludeKeywords:[],customExcludePatterns:[],customAgreementKeywords:[],customInputExcludeKeywords:[],disabledCaptchaKeywords:[],disabledExcludePatterns:[],disabledAgreementKeywords:[],disabledInputExcludeKeywords:[],enableInteractiveCaptchaAssist:false,enableInteractiveCaptchaDebugOverlay:false,enableSliderPuzzleAssist:true,enableSingleSliderAssist:true,enableClickSelectAssist:false,enableNotification:true,autoSubmit:false,autoSolveOnRule:true,siteBlacklist:[]};function o(e){const t="undefined"!=typeof window&&window.matchMedia("(prefers-color-scheme: dark)").matches;return "dark"===e||"auto"===e&&t?{"--primary":"#4A90E2","--primary-hover":"#357ABD","--primary-light":"rgba(74, 144, 226, 0.15)","--accent":"#FF69B4","--accent-hover":"#FF1493","--success":"#10b981","--error":"#ef4444","--warning":"#f59e0b","--bg-primary":"#0f0f1a","--bg-secondary":"#1a1a2e","--bg-tertiary":"#252540","--bg-hover":"#2a2a4a","--text-primary":"#ffffff","--text-secondary":"#a1a1aa","--text-muted":"#71717a","--border":"#27272a"}:{"--primary":"#4A90E2","--primary-hover":"#357ABD","--primary-light":"rgba(74, 144, 226, 0.1)","--accent":"#FF69B4","--accent-hover":"#FF1493","--success":"#10b981","--error":"#ef4444","--warning":"#f59e0b","--bg-primary":"#ffffff","--bg-secondary":"#f8fbff","--bg-tertiary":"#e8f0fe","--bg-hover":"#d0e2f5","--text-primary":"#1a1a2e","--text-secondary":"#52525b","--text-muted":"#a1a1aa","--border":"#e4e4e7"}}const a=class{static setDebugMode(e){this.debugMode=e;}static isDebugMode(){return this.debugMode}static debug(...e){this.debugMode&&console.log(`${this.prefix} [DEBUG]`,...e);}static info(...e){this.debugMode&&console.info(`${this.prefix} [INFO]`,...e);}static warn(...e){console.warn(`${this.prefix} [WARN]`,...e);}static error(...e){console.error(`${this.prefix} [ERROR]`,...e);}static group(e){this.debugMode&&console.group(`${this.prefix} ${e}`);}static groupEnd(){this.debugMode&&console.groupEnd();}static table(e){this.debugMode&&console.table(e);}static time(e){this.debugMode&&console.time(`${this.prefix} ${e}`);}static timeEnd(e){this.debugMode&&console.timeEnd(`${this.prefix} ${e}`);}};a.debugMode=false,a.prefix="[DDDD OCR]";let r=a;const d=class{static parseExpression(e){const t=e.trim();let n=t;for(const o of this.NOISE_CHARS)n=n.split(o).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 o of i){const e=n.match(o);if(e){const n=parseFloat(e[1]),i=e[2],s=parseFloat(e[3]);if(!isNaN(n)&&!isNaN(s))return {num1:n,operator:i,num2:s,originalText:t,cleanExpression:`${n}${this.normalizeOperator(i)}${s}`}}}const s=t.match(/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]\s*(\d+)$/);if(s){const e=parseFloat(s[1]),n=s[2],i=parseFloat(s[3]),o=parseFloat(s[4]);if(!isNaN(e)&&!isNaN(i)){const s=this.compute(e,n,i);if(null!==s&&Math.abs(s-o)>.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 s=this.calculate(i);return null===s?e:"equation"===this.getOutputModeForHostname(n,t.rules,t.outputMode)?this.formatEquation(i,s):this.formatResult(s)}static isExpression(e){return null!==this.parseExpression(e)}};d.OPERATORS=["+","-","×","*","÷","/","x","X"],d.EQUALS_CHARS=["=","="],d.QUESTION_CHARS=["?","?","〇","o","O","0"],d.NOISE_CHARS=["?","?","〇"," ","\t","\n","\r"];let l=d;class c{constructor(){this.detectedCaptchas=[],this.processedElements=new WeakMap,this.checkedAgreements=new WeakSet,this.customIncludeKeywords=[],this.customExcludePatterns=[],this.customAgreementKeywords=[],this.customInputExcludeKeywords=[];}setCustomPatterns(e,t,n,i){this.customIncludeKeywords=e.map(e=>e.toLowerCase().trim()).filter(Boolean),this.customExcludePatterns=t.map(e=>e.toLowerCase().trim()).filter(Boolean),this.customAgreementKeywords=(n||[]).map(e=>e.toLowerCase().trim()).filter(Boolean),this.customInputExcludeKeywords=(i||[]).map(e=>e.toLowerCase().trim()).filter(Boolean);}getCaptchaKeywords(){return 0===this.customIncludeKeywords.length?i.CAPTCHA_KEYWORDS:[...i.CAPTCHA_KEYWORDS,...this.customIncludeKeywords]}getExcludePatterns(){return 0===this.customExcludePatterns.length?i.EXCLUDE_PATTERNS:[...i.EXCLUDE_PATTERNS,...this.customExcludePatterns]}getAgreementKeywords(){return 0===this.customAgreementKeywords.length?i.AGREEMENT_KEYWORDS:[...i.AGREEMENT_KEYWORDS,...this.customAgreementKeywords]}getInputExcludeKeywords(){return 0===this.customInputExcludeKeywords.length?i.INPUT_EXCLUDE_KEYWORDS:[...i.INPUT_EXCLUDE_KEYWORDS,...this.customInputExcludeKeywords]}hasNearbyCaptchaInput(e){const t=this.findRelatedInput(e);return !!t&&this.isCaptchaInputByName(t)}isExcludedElement(e){var t,n;const i=((null==(n=null==(t=e.className)?void 0:t.toString)?void 0:n.call(t))||"").toLowerCase(),s=(e.id||"").toLowerCase(),o=this.getExcludePatterns(),a=`${i} ${s}`.trim();return o.some(e=>a.includes(e))}scan(){return this.detectedCaptchas=[],r.time("CaptchaDetector.scan"),this.scanImages(),this.scanCanvas(),this.scanSvg(),this.scanBackgroundImages(),r.timeEnd("CaptchaDetector.scan"),r.debug("扫描结果:",this.detectedCaptchas.length,"个验证码"),this.detectedCaptchas}scanImages(){document.querySelectorAll("img").forEach((e,t)=>{if(this.isLikelyCaptcha(e)){const n=e.getBoundingClientRect(),i={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(i),r.debug("检测到图片验证码:",i.elementInfo);}});}scanCanvas(){document.querySelectorAll("canvas").forEach((e,t)=>{if(this.isLikelyCanvasCaptcha(e)){const n=e.getBoundingClientRect(),i={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(i),r.debug("检测到Canvas验证码:",i.elementInfo);}});}scanSvg(){document.querySelectorAll("svg").forEach((e,t)=>{if(this.isLikelySvgCaptcha(e)){const n=e.getBoundingClientRect(),i={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(i),r.debug("检测到SVG验证码:",i.elementInfo);}});}scanBackgroundImages(){document.querySelectorAll('div[style*="background"], span[style*="background"], td[style*="background"]').forEach((e,t)=>{const n=e;if(this.isLikelyBackgroundCaptcha(n)){const e=n.getBoundingClientRect(),i={id:`captcha-bg-${t}`,type:"background",element:n,src:n.style.backgroundImage||"",rect:e,confidence:this.calculateConfidence(n),inputElement:this.findRelatedInput(n),elementInfo:this.extractCaptchaInfo(n)};this.detectedCaptchas.push(i),r.debug("检测到背景图验证码:",i.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"}}getEffectiveSize(e){const t=e.getBoundingClientRect();let n=t.width,i=t.height;return e instanceof HTMLImageElement&&(0===n&&e.naturalWidth>0&&(n=e.naturalWidth),0===i&&e.naturalHeight>0&&(i=e.naturalHeight),0===n&&(n=parseInt(e.getAttribute("width")||"0")||0),0===i&&(i=parseInt(e.getAttribute("height")||"0")||0)),{width:n,height:i}}isLikelyCaptcha(e){const{width:t,height:n}=this.getEffectiveSize(e);return !(!this.isCaptchaSize(t,n)||!this.isVisibleOrHasSize(e,t,n)||this.isExcludedImage(e)||!this.matchesKeywords(e)&&!this.srcContainsKeywords(e.src)&&!this.parentContainsKeywords(e)&&!this.hasNearbyCaptchaInput(e)&&(!this.isDataUrlImage(e)||!this.isCaptchaSize(t,n)||!this.hasNearbyCaptchaInput(e)&&!this.parentContainsKeywords(e)))}isDataUrlImage(e){return e.src&&(e.src.startsWith("data:image/")||e.src.startsWith("blob:"))?e.src:null}isVisibleOrHasSize(e,t,n){const i=window.getComputedStyle(e);if("none"===i.display||"hidden"===i.visibility||"0"===i.opacity)return false;const s=e.getBoundingClientRect();return !(s.width<=0&&s.height<=0)&&t>0&&n>0}getImageSrcForExclusionCheck(e){const t=(e.currentSrc||e.src||"").trim();if(!t)return "";if(t.startsWith("data:image/")||t.startsWith("blob:"))return "";try{const e=new URL(t,window.location.href);return (e.origin+e.pathname).toLowerCase()}catch{return t.slice(0,200).toLowerCase()}}isExcludedImage(e){var t,n;const i=this.getImageSrcForExclusionCheck(e),s=(e.alt||"").toLowerCase(),o=((null==(n=null==(t=e.className)?void 0:t.toString)?void 0:n.call(t))||"").toLowerCase(),a=(e.id||"").toLowerCase(),r=this.getExcludePatterns(),d=`${i} ${s} ${o} ${a}`.trim();return r.some(e=>d.includes(e))}isLikelyCanvasCaptcha(e){const t=e.getBoundingClientRect();return !(!this.isCaptchaSize(t.width,t.height)||!this.isVisible(e)||this.isExcludedElement(e)||!this.matchesKeywords(e)&&!this.parentContainsKeywords(e)&&!this.hasNearbyCaptchaInput(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.isExcludedElement(e)||!this.matchesKeywords(e)&&!this.parentContainsKeywords(e)&&!this.hasNearbyCaptchaInput(e))}isLikelyBackgroundCaptcha(e){const t=e.style.backgroundImage||"";if(!t||"none"===t)return false;const n=e.getBoundingClientRect();return !!this.isCaptchaSize(n.width,n.height)&&!!this.isVisible(e)&&!this.isExcludedElement(e)&&(!!this.matchesKeywords(e)||!!this.parentContainsKeywords(e)||!!this.hasNearbyCaptchaInput(e)||!!t.includes("data:image/")&&(this.hasNearbyCaptchaInput(e)||this.parentContainsKeywords(e)))}isCaptchaSize(e,t){return e>=i.MIN_CAPTCHA_WIDTH&&e<=i.MAX_CAPTCHA_WIDTH&&t>=i.MIN_CAPTCHA_HEIGHT&&t<=i.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 s=e.closest(".van-checkbox");return s?s.querySelector(".van-checkbox__icon")||s:e.closest("label")||null}matchesKeywords(e){var t,n;const i=((null==(n=null==(t=e.className)?void 0:t.toString)?void 0:n.call(t))||"").toLowerCase(),s=(e.id||"").toLowerCase();return this.getCaptchaKeywords().some(e=>i.includes(e)||s.includes(e))}srcContainsKeywords(e){if(!e)return false;const t=e.toLowerCase();return this.getCaptchaKeywords().some(e=>t.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)}getInputLabelText(e){try{if(e.id){const t=document.querySelector(`label[for="${CSS.escape(e.id)}"]`);if(t)return (t.textContent||"").trim()}const t=e.closest("label");if(t)return (t.textContent||"").trim()}catch{}return ""}getInputSearchText(e){const t=[];return t.push(e.name||""),t.push(e.id||""),t.push(e.className||""),t.push(e.placeholder||""),t.push(e.getAttribute("aria-label")||""),t.push(e.getAttribute("data-label")||""),t.push(e.getAttribute("data-name")||""),t.push(this.getInputLabelText(e)),t.join(" ").toLowerCase()}isCaptchaInputByName(e){const t=this.getInputSearchText(e);return i.INPUT_KEYWORDS.some(e=>t.includes(e))}isExcludedInputByText(e){const t=this.getInputSearchText(e);return ["username","user","account","email","phone","mobile","tel","password","pwd","pass","search","query","keyword","用户名","账号","密码","手机号","邮箱","搜索","查询","关键字",...this.getInputExcludeKeywords()].some(e=>t.includes(e))}scoreInputCandidate(e,t,n){const i=this.calculateDistance(t,n);let s=0;const o=this.getInputSearchText(e);return this.isCaptchaInputByName(e)&&(s+=120),o.includes("验证码")&&(s+=140),o.includes("verify")&&(s+=80),o.includes("vcode")&&(s+=80),o.includes("authcode")&&(s+=80),o.includes("checkcode")&&(s+=80),o.includes("yzm")&&(s+=60),this.isExcludedInputByText(e)&&(s-=200),i-s}findClosestInputInContainer(e,t,n=Infinity){const i=e.querySelectorAll("input");let s=null,o=Infinity,a=Infinity;for(const r of i){const e=r;if(!this.isValidCaptchaInput(e))continue;const i=r.getBoundingClientRect(),d=this.calculateDistance(t,i);if(d>n)continue;const l=this.scoreInputCandidate(e,t,i);(ln.right&&t.left-n.right<220&&Math.abs(t.top-n.top)<90||t.top>n.bottom&&t.top-n.bottom<160&&Math.abs(t.left-n.left)<160||this.calculateDistance(n,t)<240))continue;const i=this.scoreInputCandidate(e,n,t);i{if(!this.isVisible(e))return;const{width:t,height:s}=this.getEffectiveSize(e);if(!this.isCaptchaSize(t,s))return;if(this.isExcludedImage(e))return;const o=e.getBoundingClientRect(),a=this.calculateDistance(n,o);i.push({element:e,distance:a,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 s=this.calculateDistance(n,t);i.push({element:e,distance:s,type:"canvas"});}),document.querySelectorAll("svg").forEach(e=>{if(!this.isVisible(e))return;const t=e.clientWidth||parseInt(e.getAttribute("width")||"0"),s=e.clientHeight||parseInt(e.getAttribute("height")||"0");if(!this.isCaptchaSize(t,s))return;const o=e.getBoundingClientRect(),a=this.calculateDistance(n,o);i.push({element:e,distance:a,type:"svg"});}),document.querySelectorAll('div[style*="background"], span[style*="background"]').forEach(e=>{const t=e;if(!this.isVisible(t))return;const s=t.style.backgroundImage||"";if(!s||"none"===s)return;const o=t.getBoundingClientRect();if(!this.isCaptchaSize(o.width,o.height))return;const a=this.calculateDistance(n,o);i.push({element:t,distance:a,type:"background"});}),i.sort((e,t)=>e.distance-t.distance);const s=i.slice(0,3);for(const o of s){const e=Math.max(0,100-Math.floor(o.distance/5));t.push({element:o.element,type:"captcha",confidence:e,selector:this.generateSelector(o.element)});}return r.debug("猜测的验证码元素:",t),t}guessRelatedInput(e){const t=[],n=e.getBoundingClientRect();r.debug("开始猜测关联的输入框, 验证码位置:",n);const i=[];document.querySelectorAll("input").forEach(e=>{const t=e;if(!this.isValidCaptchaInput(t))return;if(!this.isVisible(t))return;const s=t.getBoundingClientRect(),o=this.calculateDistance(n,s),a=this.isCaptchaInputByName(t),r=this.scoreInputCandidate(t,n,s);i.push({element:t,distance:o,hasKeyword:a,score:r});}),i.sort((e,t)=>e.score-t.score);const s=i.slice(0,3);for(const o of s){let e=Math.max(0,100-Math.floor(o.distance/5));o.hasKeyword&&(e=Math.min(100,e+20)),t.push({element:o.element,type:"input",confidence:e,selector:this.generateSelector(o.element)});}return r.debug("猜测的输入框元素:",t),t}guessAgreementCheckboxes(){const e=[];return document.querySelectorAll('input[type="checkbox"]').forEach(t=>{var n;const i=t;if(!this.isCheckboxFunctional(i))return;if(this.checkedAgreements.has(i))return;const s=[];s.push(i.name||""),s.push(i.id||""),s.push(i.className||""),s.push(i.getAttribute("data-type")||""),s.push(i.getAttribute("data-name")||""),s.push(i.getAttribute("aria-label")||""),s.push(i.getAttribute("data-v-inspector")||"");const o=i.id?document.querySelector(`label[for="${i.id}"]`):null;o&&(s.push(o.textContent||""),s.push(o.className||""));const a=i.closest("label");a&&(s.push(a.textContent||""),s.push(a.className||""));const r=[i.closest(".el-checkbox"),i.closest(".ant-checkbox-wrapper"),i.closest(".ivu-checkbox-wrapper"),i.closest(".van-checkbox"),i.closest('[class*="checkbox"]')];for(const e of r)e&&(s.push(e.textContent||""),s.push(e.className||""));let d=i.parentElement,l=0;for(;d&&l<6;){const e=d.tagName.toLowerCase();if(s.push(d.className||""),s.push(d.id||""),["label","div","span","p","li","td"].includes(e)){const e=d.children;for(let t=0;tu.includes(e))){const t=this.findClickableTarget(i);e.push({element:i,type:"agreement",confidence:80,selector:this.generateSelector(i),clickTarget:t||void 0});}}),r.debug("猜测的协议复选框:",e),e}findAgreementsBySelectors(e){const t=[];for(const i of e)if(i.trim())try{document.querySelectorAll(i).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:i,clickTarget:n||void 0});}});}catch(n){r.warn("无效的协议选择器:",i,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,s=t.left+t.width/2,o=t.top+t.height/2;return Math.sqrt(Math.pow(s-n,2)+Math.pow(o-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);case "background":return this.captureBackgroundElement(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);case "background":return this.captureBackgroundAsBlob(e.element)}}async captureImgElement(e){await this.waitForImageLoad(e);const t=document.createElement("canvas"),n=t.getContext("2d"),i=e.naturalWidth||e.width,s=e.naturalHeight||e.height;t.width=i,t.height=s,n.drawImage(e,0,0,i,s);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,s=e.naturalHeight||e.height;return t.width=i,t.height=s,n.fillStyle="#FFFFFF",n.fillRect(0,0,i,s),n.drawImage(e,0,0,i,s),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),s=()=>{a(),t();},o=()=>{a(),n(new Error("图片加载失败"));},a=()=>{clearTimeout(i),e.removeEventListener("load",s),e.removeEventListener("error",o);};e.addEventListener("load",s),e.addEventListener("error",o);})}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)),t.getAttribute("xmlns")||t.setAttribute("xmlns","http://www.w3.org/2000/svg");const i=(new XMLSerializer).serializeToString(t),s=new Blob([i],{type:"image/svg+xml"}),o=URL.createObjectURL(s);try{const e=await new Promise((e,t)=>{const n=new Image;n.onload=()=>e(n),n.onerror=()=>t(new Error("SVG转换失败")),n.src=o;}),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(o);}}async captureBackgroundElement(e){const t=await this.captureBackgroundAsBlob(e);return await this.blobToDataURL(t)}async captureBackgroundAsBlob(e){const t=(e.style.backgroundImage||window.getComputedStyle(e).backgroundImage||"").match(/url\(['"]?(.+?)['"]?\)/);if(!t)throw new Error("无法提取背景图URL");const n=t[1];if(n.startsWith("data:")){const e=await fetch(n);return await e.blob()}const i=new Image;i.crossOrigin="anonymous",i.src=n,await new Promise((e,t)=>{i.onload=()=>e(),i.onerror=()=>t(new Error("背景图加载失败")),setTimeout(()=>t(new Error("背景图加载超时")),5e3);});const s=document.createElement("canvas"),o=e.getBoundingClientRect();s.width=Math.max(1,Math.round(o.width)),s.height=Math.max(1,Math.round(o.height));const a=s.getContext("2d");return a.fillStyle="#FFFFFF",a.fillRect(0,0,s.width,s.height),a.drawImage(i,0,0,s.width,s.height),new Promise((e,t)=>{s.toBlob(n=>{n?e(n):t(new Error("背景图转换失败"));},"image/png");})}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 u{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(n=>{try{n(t);}catch(i){console.error(`Event handler error [${String(e)}]:`,i);}});}clear(){this.listeners.clear();}}let p="en";function h(e){p=e&&"auto"!==e?e:function(){try{if("undefined"!=typeof chrome&&chrome.i18n&&"function"==typeof chrome.i18n.getUILanguage){const e=chrome.i18n.getUILanguage().toLowerCase();return e.startsWith("zh")?"zh":e.startsWith("ja")?"ja":"en"}}catch{}try{const e=(navigator.language||navigator.userLanguage||"").toLowerCase();if(e.startsWith("zh"))return "zh";if(e.startsWith("ja"))return "ja"}catch{}return "en"}();}function m(e){p=e;}function g(){return p}function b(e,...t){let n=(f[p]||f.en)[e]??f.en[e]??e;for(let i=0;iddddocr 项目的模型进行开发,遵循 MIT License 许可证开源发布。如果有帮到你,请给我点个⭐,你的⭐是我持续开发的动力😁!',"about.openSource.repoInfo":'🏠 仓库地址:ddddocr-webjs 开源不易,基于本项目修改请注明出处,感谢你的支持和肯定。',"settings.pageTitle":"DDDD OCR - 设置","picker.selectCaptcha":"点击选择验证码元素","picker.selectInput":"点击选择输入框","picker.cancel":"取消 (ESC)","picker.guessCaptcha":"点击粉色虚线框选择验证码","picker.guessInput":"点击粉色虚线框选择输入框","us.ready":"DDDD OCR 已就绪","us.readyAutoDetect":"自动检测已启用","us.readyManual":"点击菜单启用自动检测","us.initFailed":"初始化失败","us.initFailedMsg":"初始化失败: {0}","us.loading":"正在初始化 DDDD OCR","us.loadingDefault":"正在初始化 DDDD OCR...","us.loadingModel":"正在加载模型文件","us.captchaFilled":"验证码已自动填充","us.captchaFilledResult":"识别结果: {0}","us.menuOpenSettings":"打开设置","us.menuClearCache":"清除缓存","us.menuViewStatus":"查看状态","us.clearCacheTitle":"清除缓存","us.clearCacheMsg":"确定要清除所有缓存吗(包括模型和 WASM)?下次启动将重新下载。","us.clearCacheConfirm":"确定清除","us.cacheCleared":"缓存已清除","us.cacheClearedMsg":"请刷新页面","status.title":"当前状态","status.scriptStatus":"脚本状态:","status.initialized":"已初始化","status.notInitialized":"未初始化","status.currentSite":"当前站点:","status.whitelistStatus":"白名单状态:","status.whitelistCount":"白名单数量:","status.siteMatch":"当前站点匹配:","status.inWhitelist":"在白名单中","status.notInWhitelist":"不在白名单中","status.autoDetect":"自动检测:","status.typewriterEffect":"打字机效果:","status.autoCheckAgreement":"自动勾选协议:","status.agreementSelectorCount":"协议选择器数:","status.autoCalculate":"自动计算:","status.calcOutput":"计算输出:","status.calcOutputResult":"仅结果","status.calcOutputEquation":"完整等式","status.calcRuleCount":"计算规则数:","status.siteRuleCount":"站点规则数:","status.debugMode":"调试模式:","status.uploadedModel":"上传模型:","status.autoDownload":"自动下载:","status.totalRecognitions":"总识别次数:","dialog.defaultTitle":"提示","dialog.confirmTitle":"确认","popup.settings":"设置","popup.autoRecognizing":"自动识别中","popup.captchaCount":"{0} 个验证码","popup.detected":"检测到验证码","popup.type":"类型:","popup.status":"状态:","popup.status.init":"初始化","popup.status.ready":"就绪","popup.status.fault":"故障","popup.preview":"预览","popup.result":"识别结果","popup.copy":"复制","popup.copied":"已复制","popup.copyFailed":"复制失败","popup.elapsed":"耗时: {0}","popup.elapsedEmpty":"耗时: -","popup.ruleSaved":"已保存此网站规则","popup.ruleRemembered":"已记住: {0}","popup.deleteRule":"删除规则","popup.ruleDeleted":"已删除网站规则","popup.deleteFailed":"删除失败","popup.noRuleFound":"未找到可删除的规则","popup.inputSelected":"已手动选择输入框","popup.clearInput":"清除选择","popup.inputCleared":"已清除输入框选择","popup.clearInputConfirm":"确定要清除本页手动选择的输入框吗?","popup.selectCaptcha":"选择验证码","popup.selectInput":"选择输入框","popup.selecting":"选择验证码...","popup.selectingInput":"选择输入框...","popup.selectionMode":"已进入选择模式","popup.selectionFailed":"选择失败","popup.tabError":"无法获取当前标签页","popup.captchaRuleSaved":"已保存验证码规则","popup.inputChosen":"已选择输入框","popup.previewOpened":"预览窗口已在页面中打开","popup.previewFailed":"预览失败","popup.previewTitle":"验证码预览","popup.size":"尺寸:","content.unknownAction":"未知操作","content.processing":"正在处理中","content.captchaNotFound":"未找到验证码","content.inputNotFound":"未找到验证码输入框","content.imageTimeout":"图片加载超时","content.imageFailed":"图片加载失败","content.recognitionFailed":"识别失败","popup.waitRecognize":"等待识别","popup.selectMissing":"请选择缺少的元素","popup.autoDetecting":"自动检测中","popup.loadFailed":"加载状态失败","popup.cannotInject":"当前页面不支持注入内容脚本","popup.cannotConnect":"无法连接内容脚本","popup.cannotConnectRefresh":"无法连接内容脚本,请刷新页面后重试","popup.clearFailed":"清除失败","rules.title":"网站规则","rules.description":"管理已保存的网站验证码规则","rules.saved":"已保存的规则","rules.empty":"暂无保存的规则","rules.emptyHint":'使用弹窗中的"选择元素"功能添加规则',"rules.fullUrlMatch":"完整URL匹配","rules.edit":"编辑规则","rules.editLoaded":"已加载规则到编辑区","rules.ruleId":"规则标识 (URL/主机名)","rules.ruleId.placeholder":"例如: example.com 或完整URL","rules.captchaSelector":"验证码选择器","rules.captchaSelector.placeholder":"例如: img.captcha","rules.inputSelector":"输入框选择器","rules.inputSelector.placeholder":"例如: input#code","rules.fullUrl":"完整URL匹配","rules.fullUrl.placeholder":"留空则使用主机名匹配","rules.saveEdit":"保存修改","rules.selectorRequired":"验证码选择器不能为空","rules.updated":"规则已更新","rules.notFound":"规则不存在","rules.deleted":"规则已删除","rules.deleteConfirm":"删除规则","rules.deleteConfirmMsg":'确定删除规则 "{0}" 吗?',"rules.deleteRuleConfirmMsg":"确定要删除当前网站规则吗?","rules.bulk":"批量添加规则","rules.bulkLabel":"规则列表 (JSON格式)","rules.bulkAdd":"添加规则","rules.bulkAdded":"已添加 {0} 条规则","rules.bulkEmpty":"请输入规则","rules.jsonError":"JSON格式错误","rules.formatError":"格式错误","rules.imported":"规则已导入","rules.importedCount":"已导入 {0} 条规则","rules.importFormatError":"规则文件格式错误","rules.ruleAdded":"规则已添加","settings.selectors":"自定义选择器","settings.selectors.default":"默认选择器","settings.captchaSelector":"验证码选择器","settings.captchaSelector.placeholder":"例如: img.captcha, #captchaImage","settings.captchaSelector.hint":"留空则自动检测","settings.inputSelector":"输入框选择器","settings.inputSelector.placeholder":"例如: input#captcha","settings.inputSelector.hint":"留空则自动查找","settings.submitSelector":"提交按钮选择器","settings.submitSelector.placeholder":"例如: button[type=submit]","settings.submitSelector.hint":"留空则自动查找","settings.agreementSelector":"协议复选框选择器","settings.agreementSelector.placeholder":"例如: input#agree, .privacy-checkbox","settings.agreementSelector.hint":"支持添加多个协议复选框选择器","settings.agreementSelector.empty":"暂无协议选择器","settings.agreementSelector.add":"选择器已添加","settings.agreementSelector.exists":"选择器已存在","settings.agreementSelector.deleted":"选择器已删除","settings.agreementSelector.enterSelector":"请输入选择器","settings.language":"语言","settings.language.auto":"自动","settings.language.zh":"中文","settings.language.ja":"日本語","settings.language.en":"English","settings.language.hint":"选择界面语言,自动模式跟随系统语言","settings.title":"DDDD OCR 设置","settings.tab.general":"基本设置","settings.tab.rules":"网站规则","settings.tab.stats":"识别统计","settings.tab.calculate":"四则运算","settings.tab.model":"模型管理","settings.tab.whitelist":"站点白名单","settings.tab.advanced":"高级选项","settings.tab.about":"关于","settings.save":"保存","settings.saveSettings":"保存设置","settings.saved":"设置已保存","settings.configSaved":"配置已成功保存","settings.appearance":"外观","settings.theme":"主题","settings.theme.auto":"跟随系统","settings.theme.light":"浅色","settings.theme.dark":"深色","settings.theme.hint":"自动模式会跟随系统主题变化即时切换","settings.theme.toggle":"切换主题","settings.theme.changed":"主题: {0}","settings.theme.switchFailed":"主题切换失败","stats.title":"识别统计","stats.description":"查看验证码识别统计数据","stats.totalCount":"总识别次数","stats.siteCount":"统计站点数","stats.avgTime":"平均识别耗时","stats.lastUpdate":"最后更新","stats.ranking":"站点排行榜","stats.empty":"暂无统计数据","stats.emptyHint":"开始使用后将自动记录","stats.clear":"清除统计","stats.clearConfirm":"确定要清除所有统计数据吗?","stats.clearConfirmBtn":"确定清除","stats.cleared":"统计数据已清除","stats.avg":"平均 {0}ms","stats.last":"最后: {0}","stats.unit.times":"次","stats.unit.sites":"个","stats.loadFailed":"加载统计失败","stats.clearFailed":"清除失败","calc.title":"四则运算","calc.arithmetic":"四则运算","calc.autoCalc":"自动计算结果","calc.autoCalcHint":'识别到 "3+5=" 自动计算并填充',"calc.outputMode":"默认输出格式","calc.outputResult":"仅结果","calc.outputResultExample":"仅结果 (如: 8)","calc.outputEquation":"完整等式","calc.outputEquationExample":"完整等式 (如: 3+5=8)","calc.outputHint":"可为不同站点配置不同的输出格式","calc.siteRules":"站点计算规则","calc.noRules":"暂无规则,将使用默认输出格式","calc.regex":"正则","calc.wildcard":"通配符","calc.regexFull":"正则表达式","calc.addRule":"添加规则","calc.addNew":"添加新规则","calc.patternPlaceholder":"站点匹配 (如: *.example.com)","calc.wildcardHint":"* 匹配任意字符,? 匹配单个字符","calc.regexHint":"使用标准正则表达式语法","calc.matchHint":"通配符: * 匹配任意字符,? 匹配单个字符
正则: 使用标准正则表达式语法","calc.enterPattern":"请输入站点匹配规则","calc.ruleDeleted":"规则已删除","calc.ruleAdded":"规则已添加"}, // ==================== Japanese (ja) ==================== ja:{"common.confirm":"OK","common.cancel":"キャンセル","common.save":"保存","common.delete":"削除","common.close":"閉じる","common.export":"エクスポート","common.import":"インポート","common.add":"追加","common.edit":"編集","common.reset":"リセット","common.success":"成功","common.error":"エラー","common.hint":"ヒント","common.enabled":"有効","common.disabled":"無効","common.notEnabled":"未有効","common.yes":"はい","common.no":"いいえ","common.times":"回","common.items":"件","common.sites":"サイト","settings.generalDesc":"CAPTCHA認識の基本動作を設定","settings.advancedDesc":"高度な設定とデバッグオプション","settings.detect.title":"検出と入力","settings.detect.auto":"自動検出して入力","settings.detect.autoHint":"ページのCAPTCHAを自動認識して結果を入力","settings.autoFill":"自動入力","settings.autoFill.label":"認識成功後に自動入力","settings.autoFill.hint":"認識結果を自動的に入力欄に入力","settings.typewriter":"タイプライター効果","settings.typewriter.hint":"人間のように一文字ずつ入力、無効で一括入力","settings.autoCheckAgreement":"規約の自動チェック","settings.autoCheckAgreement.hint":"利用規約やプライバシーポリシーのチェックボックスを自動チェック","settings.notification":"通知","settings.notification.hint":"認識完了後にデスクトップ通知を表示","settings.debugMode":"デバッグモード","settings.debugMode.hint":"コンソールに詳細ログを出力","settings.debugMode.hintExt":"コンソールに詳細ログを出力し、問題の調査に役立ちます","settings.autoSolveOnRule":"ルール一致時に自動認識","settings.autoSolveOnRule.hint":"保存済みルールを検出したら自動的に認識を開始","settings.autoSubmit":"フォーム自動送信","settings.autoSubmit.hint":"入力後に自動送信(CAPTCHA認識精度は100%ではないため慎重に)","settings.keywords.title":"カスタム検出ルール","settings.keywords.triggerTitle":"トリガーキーワード","settings.keywords.triggerPlaceholder":"入力してEnterでキーワード追加","settings.keywords.triggerHint":"組み込みキーワードは削除可能、「デフォルトに戻す」で復元できます。","settings.keywords.excludeTitle":"除外キーワード","settings.keywords.excludePlaceholder":"入力してEnterで除外ワード追加","settings.keywords.excludeHint":"アバター、ロゴ、バナー、広告画像などの誤認識を防止します。","settings.keywords.agreementTitle":"規約検出キーワード","settings.keywords.agreementPlaceholder":"入力してEnterで規約ワード追加","settings.keywords.agreementHint":"規約、プライバシー、利用条件のチェックボックスを自動チェックします。","settings.keywords.inputExcludeTitle":"入力欄除外キーワード","settings.keywords.inputExcludePlaceholder":"入力してEnterで入力欄除外ワード追加","settings.keywords.inputExcludeHint":"メール、SMS、ワンタイムコードの入力欄がCAPTCHA入力欄と誤認識されるのを防止します。","settings.keywords.builtinDeletable":"組み込みは削除可","settings.keywords.resetDefault":"デフォルトに戻す","settings.keywords.resetDone":"デフォルトキーワードに戻しました","settings.keywords.exists":"キーワードは既に存在します","settings.keywords.empty":"キーワードなし","settings.keywords.builtin":"組み込み","settings.keywords.custom":"カスタム","settings.keywords.onePerLine":"1行に1キーワード","settings.keywords.builtinList":"組み込みキーワード","model.title":"モデル管理","model.source":"モデルソース","model.upload":"モデルファイルのアップロード","model.selectFiles":"モデルファイルと文字セットファイルを選択してください","model.saved":"モデルを保存しました。ページを更新してください","model.deleteTitle":"モデル削除","model.deleteConfirm":"アップロードしたモデルを削除しますか?","model.deleted":"モデルを削除しました","model.downloadTimeout":"ダウンロードタイムアウト","model.downloadDisabled":"自動ダウンロードが無効です。モデルをアップロードするか自動ダウンロードを有効にしてください","model.allMirrorsFailed":"すべてのミラーが失敗しました。ネットワークを確認するかモデルをアップロードしてください","model.downloadFailed":"モデルのダウンロードに失敗","whitelist.title":"ホワイトリスト","whitelist.settings":"ホワイトリスト設定","blacklist.title":"ブラックリスト","blacklist.label":"自動認識しないサイト","blacklist.hint":"これらのサイトではCAPTCHAを自動認識しません。ドメイン、完全URL、ワイルドカードに対応","blacklist.placeholder":"1行に1ドメイン、ワイルドカード対応","config.title":"データ管理","config.importExport":"設定のインポート/エクスポート","config.exportAll":"全設定をエクスポート","config.importConfig":"設定をインポート","config.imported":"設定をインポートしました","config.importedRefresh":"設定をインポートしました。ページを更新してください","config.importError":"設定ファイルの形式エラー","config.importFailed":"インポートに失敗しました。ファイル形式を確認してください","config.exportFailed":"エクスポートに失敗","config.resetAll":"すべての設定をリセット","config.resetConfirm":"すべての設定をリセットしますか?この操作は元に戻せません。","config.resetConfirmSimple":"すべての設定をリセットしますか?","config.resetConfirmBtn":"リセット","config.resetDone":"すべての設定をリセットしました","config.resetDoneRefresh":"設定をリセットしました。ページを更新してください","config.resetFailed":"リセットに失敗","request.title":"リクエスト設定","request.timeout":"タイムアウト (秒)","request.retryCount":"リトライ回数","debug.title":"デバッグ","about.title":"情報","about.description":"DDDD OCR オフラインCAPTCHA認識拡張機能","about.version":"バージョン情報","about.versionLabel":"バージョン:","about.modelVersion":"モデルバージョン:","about.features":"機能","about.feature.offline":"完全オフライン動作、ネットワーク不要","about.feature.formats":"img/canvas/svg CAPTCHAに対応","about.feature.autoDetect":"CAPTCHA自動検出","about.feature.customSelector":"カスタムセレクター対応","about.feature.autoSave":"サイトルール自動保存","about.feature.theme":"ダーク/ライト/自動テーマ","about.feature.calc":"四則演算の自動計算に対応","about.feature.framework":"Vue/React/Angularフレームワーク対応","about.feature.guessInput":"関連要素の自動推測","about.feature.debugLog":"詳細なデバッグログ","about.openSource":"オープンソース","about.openSource.modelCredit":'🚚 ddddocr プロジェクトのモデルを使用して開発。MIT License に基づきオープンソースで公開。役に立ったら⭐をお願いします。あなたの⭐が開発の原動力です😁!',"about.openSource.repoInfo":'🏠 リポジトリ:ddddocr-webjs オープンソースの維持は大変です。本プロジェクトを改変する場合は出典を明記してください。ご支援に感謝します。',"settings.pageTitle":"DDDD OCR - 設定","picker.selectCaptcha":"クリックしてCAPTCHA要素を選択","picker.selectInput":"クリックして入力欄を選択","picker.cancel":"キャンセル (ESC)","picker.guessCaptcha":"ピンクの点線枠をクリックしてCAPTCHAを選択","picker.guessInput":"ピンクの点線枠をクリックして入力欄を選択","us.ready":"DDDD OCR 準備完了","us.readyAutoDetect":"自動検出が有効です","us.readyManual":"メニューから自動検出を有効にしてください","us.initFailed":"初期化に失敗","us.initFailedMsg":"初期化に失敗: {0}","us.loading":"DDDD OCRを初期化中","us.loadingDefault":"DDDD OCRを初期化中...","us.loadingModel":"モデルファイルを読み込み中","us.captchaFilled":"CAPTCHAを自動入力しました","us.captchaFilledResult":"認識結果: {0}","us.menuOpenSettings":"設定を開く","us.menuClearCache":"キャッシュをクリア","us.menuViewStatus":"ステータスを表示","us.clearCacheTitle":"キャッシュクリア","us.clearCacheMsg":"すべてのキャッシュ(モデルとWASMを含む)をクリアしますか?次回起動時に再ダウンロードされます。","us.clearCacheConfirm":"クリア","us.cacheCleared":"キャッシュをクリアしました","us.cacheClearedMsg":"ページを更新してください","status.title":"現在のステータス","status.scriptStatus":"スクリプト状態:","status.initialized":"初期化済み","status.notInitialized":"未初期化","status.currentSite":"現在のサイト:","status.whitelistStatus":"ホワイトリスト状態:","status.whitelistCount":"ホワイトリスト数:","status.siteMatch":"サイト一致:","status.inWhitelist":"ホワイトリスト内","status.notInWhitelist":"ホワイトリスト外","status.autoDetect":"自動検出:","status.typewriterEffect":"タイプライター効果:","status.autoCheckAgreement":"規約自動チェック:","status.agreementSelectorCount":"規約セレクター数:","status.autoCalculate":"自動計算:","status.calcOutput":"計算出力:","status.calcOutputResult":"結果のみ","status.calcOutputEquation":"完全な式","status.calcRuleCount":"計算ルール数:","status.siteRuleCount":"サイトルール数:","status.debugMode":"デバッグモード:","status.uploadedModel":"アップロードモデル:","status.autoDownload":"自動ダウンロード:","status.totalRecognitions":"合計認識回数:","dialog.defaultTitle":"お知らせ","dialog.confirmTitle":"確認","popup.settings":"設定","popup.autoRecognizing":"自動認識中","popup.captchaCount":"{0} 件のCAPTCHA","popup.detected":"CAPTCHAを検出","popup.type":"タイプ:","popup.status":"ステータス:","popup.status.init":"初期化中","popup.status.ready":"準備完了","popup.status.fault":"エラー","popup.preview":"プレビュー","popup.result":"認識結果","popup.copy":"コピー","popup.copied":"コピーしました","popup.copyFailed":"コピーに失敗","popup.elapsed":"所要時間: {0}","popup.elapsedEmpty":"所要時間: -","popup.ruleSaved":"このサイトルールを保存しました","popup.ruleRemembered":"記憶済み: {0}","popup.deleteRule":"ルール削除","popup.ruleDeleted":"サイトルールを削除しました","popup.deleteFailed":"削除に失敗","popup.noRuleFound":"削除可能なルールが見つかりません","popup.inputSelected":"手動で入力欄を選択しました","popup.clearInput":"選択をクリア","popup.inputCleared":"入力欄の選択をクリアしました","popup.clearInputConfirm":"このページで手動選択した入力欄をクリアしますか?","popup.selectCaptcha":"CAPTCHAを選択","popup.selectInput":"入力欄を選択","popup.selecting":"CAPTCHAを選択中...","popup.selectingInput":"入力欄を選択中...","popup.selectionMode":"選択モードに入りました","popup.selectionFailed":"選択に失敗","popup.tabError":"現在のタブを取得できません","popup.captchaRuleSaved":"CAPTCHAルールを保存しました","popup.inputChosen":"入力欄を選択しました","popup.previewOpened":"プレビューウィンドウをページ内に開きました","popup.previewFailed":"プレビューに失敗","popup.previewTitle":"CAPTCHAプレビュー","popup.size":"サイズ:","content.unknownAction":"不明な操作","content.processing":"処理中","content.captchaNotFound":"CAPTCHAが見つかりません","content.inputNotFound":"CAPTCHA入力欄が見つかりません","content.imageTimeout":"画像の読み込みがタイムアウト","content.imageFailed":"画像の読み込みに失敗","content.recognitionFailed":"認識に失敗","popup.waitRecognize":"認識待ち","popup.selectMissing":"不足している要素を選択してください","popup.autoDetecting":"自動検出中","popup.loadFailed":"ステータスの読み込みに失敗","popup.cannotInject":"このページではコンテンツスクリプトを注入できません","popup.cannotConnect":"コンテンツスクリプトに接続できません","popup.cannotConnectRefresh":"コンテンツスクリプトに接続できません。ページを更新して再試行してください","popup.clearFailed":"クリアに失敗","rules.title":"サイトルール","rules.description":"保存済みサイトCAPTCHAルールの管理","rules.saved":"保存済みルール","rules.empty":"保存済みルールなし","rules.emptyHint":"ポップアップの「要素を選択」機能でルールを追加","rules.fullUrlMatch":"完全URL一致","rules.edit":"ルール編集","rules.editLoaded":"ルールを編集エリアに読み込みました","rules.ruleId":"ルール識別 (URL/ホスト名)","rules.ruleId.placeholder":"例: example.com または完全URL","rules.captchaSelector":"CAPTCHAセレクター","rules.captchaSelector.placeholder":"例: img.captcha","rules.inputSelector":"入力欄セレクター","rules.inputSelector.placeholder":"例: input#code","rules.fullUrl":"完全URL一致","rules.fullUrl.placeholder":"空欄でホスト名一致を使用","rules.saveEdit":"変更を保存","rules.selectorRequired":"CAPTCHAセレクターは必須です","rules.updated":"ルールを更新しました","rules.notFound":"ルールが見つかりません","rules.deleted":"ルールを削除しました","rules.deleteConfirm":"ルール削除","rules.deleteConfirmMsg":"ルール「{0}」を削除しますか?","rules.deleteRuleConfirmMsg":"このサイトルールを削除しますか?","rules.bulk":"一括ルール追加","rules.bulkLabel":"ルールリスト (JSON形式)","rules.bulkAdd":"ルール追加","rules.bulkAdded":"{0} 件のルールを追加しました","rules.bulkEmpty":"ルールを入力してください","rules.jsonError":"JSON形式エラー","rules.formatError":"形式エラー","rules.imported":"ルールをインポートしました","rules.importedCount":"{0} 件のルールをインポートしました","rules.importFormatError":"ルールファイルの形式エラー","rules.ruleAdded":"ルールを追加しました","settings.selectors":"カスタムセレクター","settings.selectors.default":"デフォルトセレクター","settings.captchaSelector":"CAPTCHAセレクター","settings.captchaSelector.placeholder":"例: img.captcha, #captchaImage","settings.captchaSelector.hint":"空欄で自動検出","settings.inputSelector":"入力欄セレクター","settings.inputSelector.placeholder":"例: input#captcha","settings.inputSelector.hint":"空欄で自動検索","settings.submitSelector":"送信ボタンセレクター","settings.submitSelector.placeholder":"例: button[type=submit]","settings.submitSelector.hint":"空欄で自動検索","settings.agreementSelector":"規約チェックボックスセレクター","settings.agreementSelector.placeholder":"例: input#agree, .privacy-checkbox","settings.agreementSelector.hint":"複数の規約チェックボックスセレクターを追加可能","settings.agreementSelector.empty":"規約セレクターなし","settings.agreementSelector.add":"セレクターを追加しました","settings.agreementSelector.exists":"セレクターは既に存在します","settings.agreementSelector.deleted":"セレクターを削除しました","settings.agreementSelector.enterSelector":"セレクターを入力してください","settings.language":"言語","settings.language.auto":"自動","settings.language.zh":"中国語","settings.language.ja":"日本語","settings.language.en":"English","settings.language.hint":"表示言語を選択、自動モードはシステム言語に従います","settings.title":"DDDD OCR 設定","settings.tab.general":"基本設定","settings.tab.rules":"サイトルール","settings.tab.stats":"認識統計","settings.tab.calculate":"四則演算","settings.tab.model":"モデル管理","settings.tab.whitelist":"ホワイトリスト","settings.tab.advanced":"高度な設定","settings.tab.about":"情報","settings.save":"保存","settings.saveSettings":"設定を保存","settings.saved":"設定を保存しました","settings.configSaved":"設定を保存しました","settings.appearance":"外観","settings.theme":"テーマ","settings.theme.auto":"システム","settings.theme.light":"ライト","settings.theme.dark":"ダーク","settings.theme.hint":"自動モードはシステムテーマに連動します","settings.theme.toggle":"テーマ切替","settings.theme.changed":"テーマ: {0}","settings.theme.switchFailed":"テーマの切替に失敗","stats.title":"認識統計","stats.description":"CAPTCHA認識の統計データを表示","stats.totalCount":"合計認識回数","stats.siteCount":"統計サイト数","stats.avgTime":"平均認識時間","stats.lastUpdate":"最終更新","stats.ranking":"サイトランキング","stats.empty":"統計データなし","stats.emptyHint":"使用開始後に自動的に記録されます","stats.clear":"統計をクリア","stats.clearConfirm":"すべての統計データをクリアしますか?","stats.clearConfirmBtn":"クリア","stats.cleared":"統計データをクリアしました","stats.avg":"平均 {0}ms","stats.last":"最終: {0}","stats.unit.times":"回","stats.unit.sites":"","stats.loadFailed":"統計の読み込みに失敗","stats.clearFailed":"クリアに失敗","calc.title":"四則演算","calc.arithmetic":"四則演算","calc.autoCalc":"結果を自動計算","calc.autoCalcHint":'"3+5=" を認識したら自動計算して入力',"calc.outputMode":"デフォルト出力形式","calc.outputResult":"結果のみ","calc.outputResultExample":"結果のみ (例: 8)","calc.outputEquation":"完全な式","calc.outputEquationExample":"完全な式 (例: 3+5=8)","calc.outputHint":"サイトごとに異なる出力形式を設定可能","calc.siteRules":"サイト計算ルール","calc.noRules":"ルールなし、デフォルト出力形式を使用","calc.regex":"正規表現","calc.wildcard":"ワイルドカード","calc.regexFull":"正規表現","calc.addRule":"ルール追加","calc.addNew":"新しいルールを追加","calc.patternPlaceholder":"サイト一致 (例: *.example.com)","calc.wildcardHint":"* は任意文字、? は1文字に一致","calc.regexHint":"標準正規表現構文を使用","calc.matchHint":"ワイルドカード: * は任意文字、? は1文字に一致
正規表現: 標準正規表現構文を使用","calc.enterPattern":"サイト一致ルールを入力してください","calc.ruleDeleted":"ルールを削除しました","calc.ruleAdded":"ルールを追加しました"}, // ==================== English (en) ==================== en:{"common.confirm":"OK","common.cancel":"Cancel","common.save":"Save","common.delete":"Delete","common.close":"Close","common.export":"Export","common.import":"Import","common.add":"Add","common.edit":"Edit","common.reset":"Reset","common.success":"Success","common.error":"Error","common.hint":"Hint","common.enabled":"Enabled","common.disabled":"Disabled","common.notEnabled":"Not enabled","common.yes":"Yes","common.no":"No","common.times":"","common.items":"","common.sites":"sites","settings.generalDesc":"Configure basic CAPTCHA recognition behavior","settings.advancedDesc":"Advanced configuration and debugging options","settings.detect.title":"Detection & Fill","settings.detect.auto":"Auto detect and fill","settings.detect.autoHint":"Automatically recognize page CAPTCHAs and fill in results","settings.autoFill":"Auto Fill","settings.autoFill.label":"Auto fill after recognition","settings.autoFill.hint":"Automatically fill recognition results into input fields","settings.typewriter":"Typewriter effect","settings.typewriter.hint":"Simulate typing one character at a time. Disable for instant fill","settings.autoCheckAgreement":"Auto check agreements","settings.autoCheckAgreement.hint":"Automatically check user agreement and privacy policy checkboxes","settings.notification":"Notifications","settings.notification.hint":"Show desktop notification after recognition","settings.debugMode":"Debug mode","settings.debugMode.hint":"Output detailed logs to console","settings.debugMode.hintExt":"Output detailed logs to console for troubleshooting","settings.autoSolveOnRule":"Auto solve on rule match","settings.autoSolveOnRule.hint":"Automatically start recognition when a saved rule is detected","settings.autoSubmit":"Auto submit form","settings.autoSubmit.hint":"Auto submit after fill (use with caution, recognition accuracy is not 100%)","settings.keywords.title":"Custom Detection Rules","settings.keywords.triggerTitle":"Trigger Keywords","settings.keywords.triggerPlaceholder":"Type and press Enter to add keyword","settings.keywords.triggerHint":'Built-in keywords can be deleted and restored via "Reset Default".',"settings.keywords.excludeTitle":"Exclude Keywords","settings.keywords.excludePlaceholder":"Type and press Enter to add exclude word","settings.keywords.excludeHint":"Exclude avatars, logos, banners, ads, and other misidentified images.","settings.keywords.agreementTitle":"Agreement Keywords","settings.keywords.agreementPlaceholder":"Type and press Enter to add agreement word","settings.keywords.agreementHint":"Auto check agreement, privacy, and terms checkboxes.","settings.keywords.inputExcludeTitle":"Input Exclude Keywords","settings.keywords.inputExcludePlaceholder":"Type and press Enter to add input exclude word","settings.keywords.inputExcludeHint":"Prevent email, SMS, and OTP inputs from being misidentified as CAPTCHA inputs.","settings.keywords.builtinDeletable":"Built-in can be deleted","settings.keywords.resetDefault":"Reset Default","settings.keywords.resetDone":"Keywords restored to default","settings.keywords.exists":"Keyword already exists","settings.keywords.empty":"No keywords","settings.keywords.builtin":"Built-in","settings.keywords.custom":"Custom","settings.keywords.onePerLine":"One keyword per line","settings.keywords.builtinList":"Built-in keywords","model.title":"Model Management","model.source":"Model Source","model.upload":"Upload Model File","model.selectFiles":"Please select model and charset files","model.saved":"Model saved. Please refresh the page","model.deleteTitle":"Delete Model","model.deleteConfirm":"Delete the uploaded model?","model.deleted":"Model deleted","model.downloadTimeout":"Download timeout","model.downloadDisabled":"Auto download is disabled. Please upload a model or enable auto download","model.allMirrorsFailed":"All mirrors failed. Check network or upload model","model.downloadFailed":"Model download failed","whitelist.title":"Site Whitelist","whitelist.settings":"Whitelist Settings","blacklist.title":"Site Blacklist","blacklist.label":"Sites excluded from auto recognition","blacklist.hint":"CAPTCHAs will not be auto-recognized on these sites. Supports domains, full URLs, and wildcards","blacklist.placeholder":"One domain per line, wildcards supported","config.title":"Data Management","config.importExport":"Import/Export Config","config.exportAll":"Export All Config","config.importConfig":"Import Config","config.imported":"Config imported","config.importedRefresh":"Config imported. Please refresh the page","config.importError":"Config file format error","config.importFailed":"Import failed. Please check file format","config.exportFailed":"Export failed","config.resetAll":"Reset All Settings","config.resetConfirm":"Reset all settings? This cannot be undone.","config.resetConfirmSimple":"Reset all settings?","config.resetConfirmBtn":"Reset","config.resetDone":"All settings reset","config.resetDoneRefresh":"Settings reset. Please refresh the page","config.resetFailed":"Reset failed","request.title":"Request Settings","request.timeout":"Timeout (seconds)","request.retryCount":"Retry count","debug.title":"Debug","about.title":"About","about.description":"DDDD OCR Offline CAPTCHA Recognition Extension","about.version":"Version Info","about.versionLabel":"Version:","about.modelVersion":"Model version:","about.features":"Features","about.feature.offline":"Fully offline, no network required","about.feature.formats":"Supports img/canvas/svg CAPTCHAs","about.feature.autoDetect":"Smart auto CAPTCHA detection","about.feature.customSelector":"Custom selector support","about.feature.autoSave":"Auto-save site rules","about.feature.theme":"Dark/Light/Auto themes","about.feature.calc":"Auto arithmetic calculation","about.feature.framework":"Vue/React/Angular framework support","about.feature.guessInput":"Smart related element guessing","about.feature.debugLog":"Detailed debug logging","about.openSource":"Open Source","about.openSource.modelCredit":'🚚 Built with the ddddocr project model, released under the MIT License. If this helped you, please give us a ⭐ — your support keeps development going 😁!',"about.openSource.repoInfo":'🏠 Repository: ddddocr-webjs Open source is hard work. If you modify this project, please credit the source. Thank you for your support!',"settings.pageTitle":"DDDD OCR - Settings","picker.selectCaptcha":"Click to select CAPTCHA element","picker.selectInput":"Click to select input field","picker.cancel":"Cancel (ESC)","picker.guessCaptcha":"Click pink dashed box to select CAPTCHA","picker.guessInput":"Click pink dashed box to select input","us.ready":"DDDD OCR is ready","us.readyAutoDetect":"Auto detection enabled","us.readyManual":"Click menu to enable auto detection","us.initFailed":"Initialization failed","us.initFailedMsg":"Initialization failed: {0}","us.loading":"Initializing DDDD OCR","us.loadingDefault":"Initializing DDDD OCR...","us.loadingModel":"Loading model file","us.captchaFilled":"CAPTCHA auto filled","us.captchaFilledResult":"Result: {0}","us.menuOpenSettings":"Open Settings","us.menuClearCache":"Clear Cache","us.menuViewStatus":"View Status","us.clearCacheTitle":"Clear Cache","us.clearCacheMsg":"Clear all cache (including model and WASM)? They will be re-downloaded on next start.","us.clearCacheConfirm":"Clear","us.cacheCleared":"Cache cleared","us.cacheClearedMsg":"Please refresh the page","status.title":"Current Status","status.scriptStatus":"Script status:","status.initialized":"Initialized","status.notInitialized":"Not initialized","status.currentSite":"Current site:","status.whitelistStatus":"Whitelist status:","status.whitelistCount":"Whitelist count:","status.siteMatch":"Current site match:","status.inWhitelist":"In whitelist","status.notInWhitelist":"Not in whitelist","status.autoDetect":"Auto detect:","status.typewriterEffect":"Typewriter effect:","status.autoCheckAgreement":"Auto check agreement:","status.agreementSelectorCount":"Agreement selector count:","status.autoCalculate":"Auto calculate:","status.calcOutput":"Calc output:","status.calcOutputResult":"Result only","status.calcOutputEquation":"Full equation","status.calcRuleCount":"Calc rule count:","status.siteRuleCount":"Site rule count:","status.debugMode":"Debug mode:","status.uploadedModel":"Uploaded model:","status.autoDownload":"Auto download:","status.totalRecognitions":"Total recognitions:","dialog.defaultTitle":"Notice","dialog.confirmTitle":"Confirm","popup.settings":"Settings","popup.autoRecognizing":"Auto recognizing","popup.captchaCount":"{0} CAPTCHAs","popup.detected":"CAPTCHA detected","popup.type":"Type:","popup.status":"Status:","popup.status.init":"Initializing","popup.status.ready":"Ready","popup.status.fault":"Fault","popup.preview":"Preview","popup.result":"Recognition Result","popup.copy":"Copy","popup.copied":"Copied","popup.copyFailed":"Copy failed","popup.elapsed":"Time: {0}","popup.elapsedEmpty":"Time: -","popup.ruleSaved":"Site rule saved","popup.ruleRemembered":"Remembered: {0}","popup.deleteRule":"Delete Rule","popup.ruleDeleted":"Site rule deleted","popup.deleteFailed":"Delete failed","popup.noRuleFound":"No rule found to delete","popup.inputSelected":"Input field manually selected","popup.clearInput":"Clear Selection","popup.inputCleared":"Input selection cleared","popup.clearInputConfirm":"Clear manually selected input on this page?","popup.selectCaptcha":"Select CAPTCHA","popup.selectInput":"Select Input","popup.selecting":"Selecting CAPTCHA...","popup.selectingInput":"Selecting input...","popup.selectionMode":"Entered selection mode","popup.selectionFailed":"Selection failed","popup.tabError":"Cannot get current tab","popup.captchaRuleSaved":"CAPTCHA rule saved","popup.inputChosen":"Input field selected","popup.previewOpened":"Preview window opened in page","popup.previewFailed":"Preview failed","popup.previewTitle":"CAPTCHA Preview","popup.size":"Size:","content.unknownAction":"Unknown action","content.processing":"Processing","content.captchaNotFound":"CAPTCHA not found","content.inputNotFound":"CAPTCHA input not found","content.imageTimeout":"Image load timeout","content.imageFailed":"Image load failed","content.recognitionFailed":"Recognition failed","popup.waitRecognize":"Waiting for recognition","popup.selectMissing":"Please select missing elements","popup.autoDetecting":"Auto detecting","popup.loadFailed":"Failed to load status","popup.cannotInject":"Content script injection not supported on this page","popup.cannotConnect":"Cannot connect to content script","popup.cannotConnectRefresh":"Cannot connect to content script. Please refresh and try again","popup.clearFailed":"Clear failed","rules.title":"Site Rules","rules.description":"Manage saved site CAPTCHA rules","rules.saved":"Saved Rules","rules.empty":"No saved rules","rules.emptyHint":'Use the "Select Element" feature in the popup to add rules',"rules.fullUrlMatch":"Full URL match","rules.edit":"Edit Rule","rules.editLoaded":"Rule loaded into editor","rules.ruleId":"Rule ID (URL/Hostname)","rules.ruleId.placeholder":"e.g. example.com or full URL","rules.captchaSelector":"CAPTCHA selector","rules.captchaSelector.placeholder":"e.g. img.captcha","rules.inputSelector":"Input selector","rules.inputSelector.placeholder":"e.g. input#code","rules.fullUrl":"Full URL match","rules.fullUrl.placeholder":"Leave empty for hostname match","rules.saveEdit":"Save Changes","rules.selectorRequired":"CAPTCHA selector is required","rules.updated":"Rule updated","rules.notFound":"Rule not found","rules.deleted":"Rule deleted","rules.deleteConfirm":"Delete Rule","rules.deleteConfirmMsg":'Delete rule "{0}"?',"rules.deleteRuleConfirmMsg":"Delete this site rule?","rules.bulk":"Bulk Add Rules","rules.bulkLabel":"Rule list (JSON format)","rules.bulkAdd":"Add Rules","rules.bulkAdded":"Added {0} rules","rules.bulkEmpty":"Please enter rules","rules.jsonError":"JSON format error","rules.formatError":"Format error","rules.imported":"Rules imported","rules.importedCount":"Imported {0} rules","rules.importFormatError":"Rule file format error","rules.ruleAdded":"Rule added","settings.selectors":"Custom Selectors","settings.selectors.default":"Default Selectors","settings.captchaSelector":"CAPTCHA selector","settings.captchaSelector.placeholder":"e.g. img.captcha, #captchaImage","settings.captchaSelector.hint":"Leave empty for auto detection","settings.inputSelector":"Input selector","settings.inputSelector.placeholder":"e.g. input#captcha","settings.inputSelector.hint":"Leave empty for auto search","settings.submitSelector":"Submit button selector","settings.submitSelector.placeholder":"e.g. button[type=submit]","settings.submitSelector.hint":"Leave empty for auto search","settings.agreementSelector":"Agreement checkbox selector","settings.agreementSelector.placeholder":"e.g. input#agree, .privacy-checkbox","settings.agreementSelector.hint":"Supports adding multiple agreement checkbox selectors","settings.agreementSelector.empty":"No agreement selectors","settings.agreementSelector.add":"Selector added","settings.agreementSelector.exists":"Selector already exists","settings.agreementSelector.deleted":"Selector deleted","settings.agreementSelector.enterSelector":"Please enter a selector","settings.language":"Language","settings.language.auto":"Auto","settings.language.zh":"Chinese","settings.language.ja":"Japanese","settings.language.en":"English","settings.language.hint":"Select UI language. Auto mode follows system language","settings.title":"DDDD OCR Settings","settings.tab.general":"General","settings.tab.rules":"Site Rules","settings.tab.stats":"Statistics","settings.tab.calculate":"Arithmetic","settings.tab.model":"Model","settings.tab.whitelist":"Whitelist","settings.tab.advanced":"Advanced","settings.tab.about":"About","settings.save":"Save","settings.saveSettings":"Save Settings","settings.saved":"Settings saved","settings.configSaved":"Configuration saved successfully","settings.appearance":"Appearance","settings.theme":"Theme","settings.theme.auto":"System","settings.theme.light":"Light","settings.theme.dark":"Dark","settings.theme.hint":"Auto mode follows system theme changes in real time","settings.theme.toggle":"Toggle theme","settings.theme.changed":"Theme: {0}","settings.theme.switchFailed":"Theme switch failed","stats.title":"Statistics","stats.description":"View CAPTCHA recognition statistics","stats.totalCount":"Total recognitions","stats.siteCount":"Sites tracked","stats.avgTime":"Average time","stats.lastUpdate":"Last updated","stats.ranking":"Site Ranking","stats.empty":"No statistics yet","stats.emptyHint":"Will be recorded automatically after use","stats.clear":"Clear Statistics","stats.clearConfirm":"Clear all statistics?","stats.clearConfirmBtn":"Clear","stats.cleared":"Statistics cleared","stats.avg":"Avg {0}ms","stats.last":"Last: {0}","stats.unit.times":"","stats.unit.sites":"","stats.loadFailed":"Failed to load statistics","stats.clearFailed":"Clear failed","calc.title":"Arithmetic","calc.arithmetic":"Arithmetic","calc.autoCalc":"Auto calculate result","calc.autoCalcHint":'Auto calculate and fill when "3+5=" is recognized',"calc.outputMode":"Default output format","calc.outputResult":"Result only","calc.outputResultExample":"Result only (e.g. 8)","calc.outputEquation":"Full equation","calc.outputEquationExample":"Full equation (e.g. 3+5=8)","calc.outputHint":"Different output formats can be set per site","calc.siteRules":"Site Calculation Rules","calc.noRules":"No rules, default output format will be used","calc.regex":"Regex","calc.wildcard":"Wildcard","calc.regexFull":"Regular Expression","calc.addRule":"Add Rule","calc.addNew":"Add New Rule","calc.patternPlaceholder":"Site match (e.g. *.example.com)","calc.wildcardHint":"* matches any characters, ? matches a single character","calc.regexHint":"Use standard regular expression syntax","calc.matchHint":"Wildcard: * matches any characters, ? matches a single character
Regex: Use standard regular expression syntax","calc.enterPattern":"Please enter a site match pattern","calc.ruleDeleted":"Rule deleted","calc.ruleAdded":"Rule added"}},v="ddddocr_model_cache",w="ddddocr_uploaded_model";class y{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((e,t)=>{const n=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(v);n.onerror=()=>t(n.error),n.onsuccess=()=>{const t=n.result;if(t)return Date.now()-t.timestamp>i.CACHE_DURATION||t.version!==i.MODEL_VERSION?(this.delete(),void e(null)):void e(t);e(null);};})}async set(e,t){this.db||await this.init();const n={model:e,charsets:t,timestamp:Date.now(),version:i.MODEL_VERSION};return new Promise((e,t)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,v);i.onerror=()=>t(i.error),i.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(v);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(w);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,w);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(w);n.onerror=()=>t(n.error),n.onsuccess=()=>e();})}}function x(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(b("model.downloadTimeout")))});})}function C(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(b("model.downloadTimeout")))});})}function S(e,t){const n=e.replace(/\/+$/,""),s=t.replace(/^\/+/,"");if(n.includes("jsdelivr"))return `${n}/${i.MODEL_REPO}@${i.MODEL_BRANCH}/${s}`;const o=`/${i.MODEL_REPO}/`;return n.includes(o)?`${n}/${s}`:`${n}/${i.MODEL_REPO}/${i.MODEL_BRANCH}/${s}`}async function E(){const e=GM_getValue("ddddocr_config")||{},t=new y;if(e.useUploadedModel){const e=await t.getUploadedModel();if(e)return console.log("✅ 使用上传的模型"),{model:e.model,charsets:e.charsets}}if(false===e.autoDownload)throw new Error(b("model.downloadDisabled"));const n=await t.get();if(n)return console.log("✅ 使用缓存的模型"),{model:n.model,charsets:n.charsets};console.log("📥 开始下载模型");let s=null,o=null;for(let r=0;re.includes("jsdelivr")?`${e}/npm/onnxruntime-web@${i.WASM_VERSION}/dist/`:e.includes("unpkg")?`${e}/onnxruntime-web@${i.WASM_VERSION}/dist/`:e.includes("cdnjs")?`${e}/ajax/libs/onnxruntime-web/${i.WASM_VERSION}/`:e.includes("npmmirror")?`${e}/onnxruntime-web/${i.WASM_VERSION}/files/dist/`:`${e}/onnxruntime-web@${i.WASM_VERSION}/dist/`),A=["ort-wasm.wasm","ort-wasm-simd.wasm","ort-wasm-threaded.wasm","ort-wasm-simd-threaded.wasm"],R=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=>{console.warn("[WASMCache] 数据库错误:",e);},e();},n.onupgradeneeded=e=>{const t=e.target.result;t.objectStoreNames.contains(this.storeName)||t.createObjectStore(this.storeName);},n.onblocked=()=>{console.warn("[WASMCache] 数据库被阻塞");};})}async handleVersionError(){return console.warn("[WASMCache] 检测到数据库版本冲突,正在重建数据库..."),new Promise((e,t)=>{const n=indexedDB.deleteDatabase(this.dbName);n.onerror=()=>{t(new Error("无法删除旧数据库"));},n.onsuccess=()=>{console.log("[WASMCache] 旧数据库已删除,正在创建新数据库..."),this.openDatabase().then(e).catch(t);},n.onblocked=()=>{console.warn("[WASMCache] 删除数据库被阻塞"),setTimeout(()=>{this.openDatabase().then(e).catch(t);},100);};})}async get(e){return this.memoryCache.has(e)?this.memoryCache.get(e):(this.db||await this.init(),new Promise((t,n)=>{try{const s=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(e);s.onerror=()=>n(s.error),s.onsuccess=()=>{const n=s.result;if(n){if(Date.now()-n.timestamp>i.CACHE_DURATION||n.version!==i.WASM_VERSION)return this.delete(e).catch(()=>{}),void t(null);this.memoryCache.set(e,n.data),t(n.data);}else t(null);};}catch(s){n(s);}}))}async set(e,t){this.db||await this.init(),this.memoryCache.set(e,t);const n={data:t,timestamp:Date.now(),version:i.WASM_VERSION};return new Promise((t,i)=>{try{const s=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,e);s.onerror=()=>i(s.error),s.onsuccess=()=>t();}catch(s){i(s);}})}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 I(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===k.length-1)throw new Error(`所有 WASM CDN 均下载失败: ${e}`)}}throw new Error(`下载 WASM 失败: ${e}`)}const T=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 s=document.createElement("div");s.className="ddddocr-dialog",this.isMobile()&&s.classList.add("mobile"),s.innerHTML=`\n
${e.icon||"❓"} ${e.title}
\n
\n
${e.content}
\n
\n \n `,i.appendChild(s),document.body.appendChild(i),this.container=i,s.addEventListener("mousedown",this.stopPropagation),s.addEventListener("mouseup",this.stopPropagation),s.addEventListener("click",this.stopPropagation),s.addEventListener("dblclick",this.stopPropagation),s.addEventListener("wheel",this.stopPropagation),s.addEventListener("keydown",this.stopPropagation),s.addEventListener("keyup",this.stopPropagation),s.addEventListener("keypress",this.stopPropagation),s.addEventListener("contextmenu",this.stopPropagation),s.addEventListener("touchstart",this.stopPropagation,{passive:true}),s.addEventListener("touchmove",this.stopPropagation,{passive:true}),s.addEventListener("touchend",this.stopPropagation),null==(t=s.querySelector(".confirm-btn"))||t.addEventListener("click",()=>{var t;null==(t=e.onConfirm)||t.call(e),this.close();}),null==(n=s.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;}};T.container=null,T.stylesInjected=false;let M=T;const D="ddddocr_config_version",L="ddddocr_stats",$="ddddocr_site_rules",P=function(e,t,n){const i=()=>e(D)||1,o=e=>t(D,e);return {getConfig:()=>function(e,t,n){if(!e)return n(2),{...s};const i=t();let o={...s};for(const a of Object.keys(e)){const t=e[a];void 0!==t&&a in s&&(o[a]=t);}if(i<2&&e.agreementSelector&&(!o.agreementSelectors||0===o.agreementSelectors.length)){const t=e.agreementSelector.trim();t&&(o.agreementSelectors=[t]);}for(const a of Object.keys(s)) void 0===o[a]&&(o[a]=s[a]);return 2!==i&&n(2),o}(e(n),i,o),saveConfig(e){const i={...this.getConfig(),...e};t(n,i);},resetConfig(){t(n,s),o(2);}}}(e=>GM_getValue(e),(e,t)=>GM_setValue(e,t),"ddddocr_config");function H(){return P.getConfig()}function F(e){P.saveConfig(e);}function N(){return GM_getValue($)||{}}function O(e,t){const n=N(),i=t.fullUrl||t.urlPattern||e,s=n[i]||{};n[i]={...s,...t,hostname:e,createdAt:s.createdAt||Date.now(),updatedAt:Date.now(),enabled:false!==t.enabled},GM_setValue($,n);}function _(e){const t=N();delete t[e],GM_setValue($,t);}const z=new class{constructor(e){this.dirty=false,this.saveTimer=null,this.storage=e,this.data=this.load();}load(){const e=this.storage.get(L);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(L,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 B(){const e=H();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 q(){const e=H();if(e.enableWhitelist){if(!e.whitelist||0===e.whitelist.length)return false;if(!B())return false}return true}function U(){return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<=768}function W(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function K(e){return e?new Date(e).toLocaleDateString():"-"}class j{constructor(){this.container=null,this.overlay=null,this.isVisible=false,this.onConfigChange=()=>{},this.activeTab="general",this.currentEditRuleKey=null,this.containerLocale="",this.mediaQuery=null,this.mediaQueryHandler=null,this.CHIP_META={customIncludeKeywords:{builtin:[...i.CAPTCHA_KEYWORDS],disabledKey:"disabledCaptchaKeywords"},customExcludePatterns:{builtin:[...i.EXCLUDE_PATTERNS],disabledKey:"disabledExcludePatterns"},customAgreementKeywords:{builtin:[...i.AGREEMENT_KEYWORDS],disabledKey:"disabledAgreementKeywords"},customInputExcludeKeywords:{builtin:[...i.INPUT_EXCLUDE_KEYWORDS],disabledKey:"disabledInputExcludeKeywords"}},this.createStyles(),this.handleResize=this.handleResize.bind(this);}handleResize(){this.container&&this.container.classList.toggle("mobile",U());}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: var(--bg-secondary);\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: 24px;\n}\n.ddddocr-content::-webkit-scrollbar { width: 6px; }\n.ddddocr-content::-webkit-scrollbar-track { background: var(--border); 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: var(--bg-primary);\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: var(--text-primary);\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 var(--border);\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: var(--text-primary); font-weight: 500; }\n.ddddocr-modal.mobile .ddddocr-row-label { font-size: 15px; }\n.ddddocr-row-desc { font-size: 12px; color: var(--text-muted); 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: var(--border);\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: var(--bg-primary);\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 var(--border);\n border-radius: 10px;\n font-size: 14px;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n background: var(--bg-primary);\n color: var(--text-primary);\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 var(--border);\n border-radius: 10px;\n font-size: 14px;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n background: var(--bg-primary);\n color: var(--text-primary);\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 var(--border);\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 background: var(--bg-primary);\n color: var(--text-primary);\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: var(--text-secondary); }\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: var(--bg-tertiary); color: var(--text-primary); }\n.ddddocr-btn-secondary:hover { background: var(--border); }\n.ddddocr-btn-secondary:active { background: var(--bg-hover); }\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: var(--text-secondary);\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: var(--bg-secondary);\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: var(--text-primary); word-break: break-all; min-width: 0; }\n.ddddocr-rule-type { font-size: 11px; padding: 4px 8px; background: var(--border); border-radius: 4px; color: var(--text-secondary); 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: var(--text-muted); 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/* 统计样式 */\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: var(--bg-secondary);\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: var(--bg-tertiary); }\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: var(--border);\n color: var(--text-secondary);\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: var(--text-primary); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.ddddocr-rank-meta { font-size: 12px; color: var(--text-muted); 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: var(--border); 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: var(--bg-secondary);\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: var(--text-primary); word-break: break-all; margin-bottom: 4px; }\n.ddddocr-site-rule-selector { font-size: 12px; color: var(--text-secondary); 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\n/* Chip keyword styles */\n.ddddocr-keyword-group {\n padding: 16px;\n background: var(--bg-tertiary);\n border: 1px solid var(--border);\n border-radius: 12px;\n margin-bottom: 12px;\n}\n.ddddocr-keyword-group:last-child { margin-bottom: 0; }\n.ddddocr-keyword-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 12px;\n flex-wrap: wrap;\n}\n.ddddocr-keyword-actions {\n display: flex;\n align-items: center;\n gap: 10px;\n flex-wrap: wrap;\n}\n.ddddocr-keyword-subtitle {\n font-size: 12px;\n color: var(--text-muted);\n}\n.ddddocr-chip-list {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n min-height: 38px;\n}\n.ddddocr-chip-item {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 5px 10px;\n border-radius: 999px;\n background: var(--bg-secondary);\n border: 1px solid var(--border);\n max-width: 100%;\n font-size: 13px;\n}\n.ddddocr-chip-item.builtin { border-color: rgba(74, 144, 226, 0.35); }\n.ddddocr-chip-item.custom { border-color: rgba(255, 105, 180, 0.35); }\n.ddddocr-chip-text {\n color: var(--text-primary);\n word-break: break-all;\n}\n.ddddocr-chip-meta {\n font-size: 11px;\n color: var(--text-muted);\n}\n.ddddocr-chip-remove {\n width: 20px;\n height: 20px;\n border: none;\n border-radius: 50%;\n background: var(--bg-hover);\n color: var(--text-secondary);\n cursor: pointer;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n font-size: 14px;\n transition: all 0.2s;\n}\n.ddddocr-chip-remove:hover { background: rgba(239, 68, 68, 0.15); color: #ef4444; }\n.ddddocr-chip-input-row { margin-top: 12px; }\n.ddddocr-chip-input {\n width: 100%;\n padding: 10px 14px;\n border: 2px solid var(--border);\n border-radius: 10px;\n font-size: 13px;\n box-sizing: border-box;\n background: var(--bg-primary);\n color: var(--text-primary);\n transition: all 0.2s;\n}\n.ddddocr-chip-input:focus { outline: none; border-color: #4A90E2; box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.15); }\n.ddddocr-chip-reset {\n padding: 4px 10px;\n font-size: 11px;\n border: 1px solid var(--border);\n border-radius: 6px;\n background: var(--bg-primary);\n color: var(--text-secondary);\n cursor: pointer;\n transition: all 0.2s;\n}\n.ddddocr-chip-reset:hover { border-color: #4A90E2; color: #4A90E2; }\n.ddddocr-chip-empty {\n width: 100%;\n text-align: center;\n padding: 12px;\n color: var(--text-muted);\n font-size: 12px;\n}\n",document.getElementById("ddddocr-settings-styles")||document.head.appendChild(e);}applyTheme(){if(!this.container)return;const e=o(H().theme||"auto");for(const[t,n]of Object.entries(e))this.container.style.setProperty(t,n);}setupThemeMediaQuery(){this.mediaQuery&&this.mediaQueryHandler&&"function"==typeof this.mediaQuery.removeEventListener&&this.mediaQuery.removeEventListener("change",this.mediaQueryHandler),this.mediaQuery=window.matchMedia("(prefers-color-scheme: dark)"),this.mediaQueryHandler=()=>{"auto"===(H().theme||"auto")&&this.applyTheme();},"function"==typeof this.mediaQuery.addEventListener?this.mediaQuery.addEventListener("change",this.mediaQueryHandler):"function"==typeof this.mediaQuery.addListener&&this.mediaQuery.addListener(this.mediaQueryHandler);}async createContainer(){this.overlay=document.createElement("div"),this.overlay.className="ddddocr-overlay",this.container=document.createElement("div"),this.container.className="ddddocr-modal",U()&&this.container.classList.add("mobile");const e=H();let t=false,n=0;try{const e=new y,i=await e.getUploadedModel();i&&(t=!0,n=i.model.byteLength);}catch(r){console.warn("Failed to load uploaded model info:",r);}const i=this.renderCalculateRules(e.calculateRules||[]),s=this.renderSiteRules(),o=this.renderStats(),a=this.renderAgreementSelectors(e.agreementSelectors||[]);this.container.innerHTML=`\n
\n
${b("settings.title")}
\n \n
\n
\n \n \n \n \n \n \n
\n
\n \x3c!-- General --\x3e\n
\n
\n
${b("settings.detect.title")}
\n ${this.renderSwitchRow("autoDetect",b("settings.detect.auto"),b("settings.detect.autoHint"),e.autoDetect)}\n ${this.renderSwitchRow("typewriterEffect",b("settings.typewriter"),b("settings.typewriter.hint"),e.typewriterEffect)}\n ${this.renderSwitchRow("autoCheckAgreement",b("settings.autoCheckAgreement"),b("settings.autoCheckAgreement.hint"),e.autoCheckAgreement)}\n ${this.renderSwitchRow("enableNotification",b("settings.notification"),b("settings.notification.hint"),e.enableNotification)}\n ${this.renderSwitchRow("autoSubmit",b("settings.autoSubmit"),b("settings.autoSubmit.hint"),e.autoSubmit??false)}\n ${this.renderSwitchRow("autoSolveOnRule",b("settings.autoSolveOnRule"),b("settings.autoSolveOnRule.hint"),e.autoSolveOnRule??true)}\n ${this.renderSwitchRow("debugMode",b("settings.debugMode"),b("settings.debugMode.hint"),e.debugMode)}\n
\n
\n
${b("settings.selectors")}
\n
${b("settings.captchaSelector")}
\n \n
${b("settings.inputSelector")}
\n \n
${b("settings.submitSelector")}
\n \n
${b("settings.captchaSelector.hint")}
\n
${b("settings.agreementSelector")}
\n
${a}
\n
\n \n \n
\n
${b("settings.agreementSelector.hint")}
\n
\n
\n
${b("settings.appearance")}
\n
\n
\n
${b("settings.theme")}
\n
\n \n
\n
\n
\n
${b("settings.language")}
\n
${b("settings.language.hint")}
\n
\n \n
\n
\n
\n
${b("settings.keywords.title")}
\n
\n ${this.renderKeywordChipGroupsHtml()}\n
\n
\n
\n\n \x3c!-- Site Rules --\x3e\n
\n
\n
\n
${b("rules.saved")}
\n
\n \n \n
\n
\n
${s}
\n
\n \n
\n
${b("rules.bulk")}
\n
${b("rules.ruleId")}
\n \n
${b("rules.captchaSelector")}
\n \n
${b("rules.inputSelector")}
\n \n \n
\n
\n\n \x3c!-- Statistics --\x3e\n
\n ${o}\n
\n\n \x3c!-- Arithmetic --\x3e\n
\n
\n
${b("calc.arithmetic")}
\n ${this.renderSwitchRow("autoCalculate",b("calc.autoCalc"),b("calc.autoCalcHint"),e.autoCalculate)}\n
\n
${b("calc.outputMode")}
\n \n
${b("calc.outputHint")}
\n
\n
\n
\n
${b("calc.siteRules")}
\n
${i}
\n
\n \n \n \n \n
\n
\n ${b("calc.wildcard")}: ${b("calc.wildcardHint")}
\n ${b("calc.regex")}: ${b("calc.regexHint")}\n
\n
\n
\n\n \x3c!-- Model Management --\x3e\n
\n
\n
${b("model.source")}
\n ${t?`
[${b("common.enabled")}] ${b("model.upload")} (${(n/1024/1024).toFixed(1)} MB)
`:""}\n ${this.renderSwitchRow("useUploadedModel",b("model.source"),b("model.upload"),e.useUploadedModel)}\n ${this.renderSwitchRow("autoDownload",b("settings.detect.auto"),b("model.downloadDisabled"),e.autoDownload)}\n
\n
\n
${b("model.upload")}
\n
\n \n
[ONNX]
\n
${b("model.selectFiles")} common.onnx
\n
\n
\n
\n \n
[JSON]
\n
${b("model.selectFiles")} charsets.json
\n
\n
\n
\n \n \n
\n
\n
\n\n \x3c!-- Site Whitelist --\x3e\n
\n
\n
${b("whitelist.settings")}
\n ${this.renderSwitchRow("enableWhitelist",b("whitelist.title"),b("whitelist.settings"),e.enableWhitelist)}\n
\n \n
${window.location.hostname}
\n
\n
\n
\n
${b("blacklist.title")}
\n
${b("blacklist.label")}
\n \n
${b("blacklist.hint")}
\n
\n
\n
${b("config.importExport")}
\n
\n \n \n \n
\n
\n
\n
\n `,document.body.appendChild(this.overlay),document.body.appendChild(this.container),this.containerLocale=g(),this.applyTheme(),this.setupThemeMediaQuery(),this.renderAllChipGroups(),this.bindEvents(),this.bindChipEvents(),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 ${W(e.pattern)}\n ${"regex"===e.matchType?b("calc.regex"):b("calc.wildcard")}\n ${"result"===e.outputMode?b("calc.outputResult"):b("calc.outputEquation")}\n \n
\n `).join(""):`
${b("calc.noRules")}
`}renderSiteRules(){const e=N(),t=Object.keys(e);return 0===t.length?`
${b("rules.empty")}
`:t.map(t=>{const n=e[t],i=t.length>35?t.substring(0,35)+"...":t,s=n.selector.length>40?n.selector.substring(0,40)+"...":n.selector;return `\n
\n
\n
${W(i)}
\n
${W(s)}
\n ${n.fullUrl?`
${b("rules.fullUrlMatch")}
`:""}\n
\n
\n \n \n
\n
\n `}).join("")}renderStats(){var e;const t=z.getStats(),n=Object.entries(t.sites||{}),i=n.reduce((e,[,t])=>e+t.totalTime,0),s=t.total>0?Math.round(i/t.total):0,o=t.updated?K(t.updated):"-";let a="";if(0===n.length)a=`
${b("stats.empty")}
`;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 s=t.count>0?Math.round(t.totalTime/t.count):0,o=K(t.lastTime),a=Math.round(t.count/i*100);return `\n
\n
${n+1}
\n
\n
${W(e)}
\n
\n ${b("stats.avg",s)}\n ${b("stats.last",o)}\n
\n
\n
\n
\n
\n
${t.count}
\n
\n `}).join("");}return `\n
\n
\n
${b("stats.totalCount")}
\n
${t.total}${b("common.times")}
\n
\n
\n
${b("stats.siteCount")}
\n
${n.length}${b("common.items")}
\n
\n
\n
${b("stats.avgTime")}
\n
${s}ms
\n
\n
\n
${b("stats.lastUpdate")}
\n
${o}
\n
\n
\n
\n
\n
${b("stats.ranking")}
\n \n
\n
${a}
\n
\n `}renderAgreementSelectors(e){return e&&0!==e.length?e.map((e,t)=>`\n
\n ${W(e)}\n \n
\n `).join(""):`
${b("settings.agreementSelector.empty")}
`}stopPropagation(e){e.stopPropagation();}bindEvents(){var e,t,n,i,s,a,r,d,l,c,u,p;if(!this.container||!this.overlay)return;["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,n=e.classList.contains("on");if(t&&(F({[t]:n}),this.onConfigChange(H())),"enableWhitelist"===t){const e=this.container.querySelector("#whitelistArea");e&&(e.style.display=n?"block":"none");}if("autoCalculate"===t){const e=this.container.querySelector("#calculateOptionsArea"),t=this.container.querySelector("#calculateRulesCard");e&&(e.style.display=n?"block":"none"),t&&(t.style.display=n?"block":"none");}});}),this.container.querySelectorAll("input[data-key]").forEach(e=>{e.addEventListener("change",()=>{const t=e.dataset.key;t&&(F({[t]:e.value.trim()}),this.onConfigChange(H()));});}),this.container.querySelectorAll("select[data-key]").forEach(e=>{e.addEventListener("change",()=>{const t=e.dataset.key,n=e.value;if(t){if(F({[t]:n}),"theme"===t&&this.container){const e=o(n);for(const[t,n]of Object.entries(e))this.container.style.setProperty(t,n);}if("language"===t)return "auto"===n?h("auto"):m(n),this.onConfigChange(H()),this.destroyContainer(),void this.createContainer().then(()=>{var e,t,n;this.isVisible=true,null==(e=this.overlay)||e.classList.add("visible"),null==(t=this.container)||t.classList.add("visible"),U()&&(null==(n=this.container)||n.classList.add("mobile"));});this.onConfigChange(H());}});});let g=null;this.container.querySelectorAll("textarea[data-key]").forEach(e=>{e.addEventListener("input",()=>{g&&clearTimeout(g),g=window.setTimeout(()=>{const t=e.dataset.key;if(t){const n=e.value;F({[t]:n.split("\n").filter(e=>e.trim())}),this.onConfigChange(H());}},500);});}),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==(s=this.container.querySelector("#saveEditRuleBtn"))||s.addEventListener("click",()=>this.saveEditRule()),null==(a=this.container.querySelector("#cancelEditRuleBtn"))||a.addEventListener("click",()=>this.cancelEditRule()),null==(r=this.container.querySelector("#exportRulesBtn"))||r.addEventListener("click",()=>this.exportSiteRules()),null==(d=this.container.querySelector("#importRulesBtn"))||d.addEventListener("click",()=>this.importSiteRules()),this.bindSiteRuleEvents(),null==(l=this.container.querySelector("#clearStatsBtn"))||l.addEventListener("click",()=>this.clearStats()),this.bindModelEvents(),null==(c=this.container.querySelector("#exportBtn"))||c.addEventListener("click",()=>this.exportConfig()),null==(u=this.container.querySelector("#importBtn"))||u.addEventListener("click",()=>this.importConfig()),null==(p=this.container.querySelector("#resetBtn"))||p.addEventListener("click",()=>this.resetConfig());}bindModelEvents(){var e,t,n,i,s,o,a,r,d,l;const c=null==(e=this.container)?void 0:e.querySelector("#modelZone"),u=null==(t=this.container)?void 0:t.querySelector("#modelFile"),p=null==(n=this.container)?void 0:n.querySelector("#modelName"),h=null==(i=this.container)?void 0:i.querySelector("#charsetsZone"),m=null==(s=this.container)?void 0:s.querySelector("#charsetsFile"),g=null==(o=this.container)?void 0:o.querySelector("#charsetsName");null==c||c.addEventListener("click",()=>null==u?void 0:u.click()),null==u||u.addEventListener("change",()=>{var e;(null==(e=u.files)?void 0:e[0])&&(p.textContent=`[OK] ${u.files[0].name}`);}),null==h||h.addEventListener("click",()=>null==m?void 0:m.click()),null==m||m.addEventListener("change",()=>{var e;(null==(e=m.files)?void 0:e[0])&&(g.textContent=`[OK] ${m.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==u?void 0:u.files)?void 0:e[0],i=null==(t=null==m?void 0:m.files)?void 0:t[0];if(n&&i)try{await async function(e,t){const n=await e.arrayBuffer(),i=await t.text(),s=JSON.parse(i),o=new y;await o.setUploadedModel(n,s),console.log("✅ 上传的模型已保存");}(n,i),F({useUploadedModel:!0}),M.show({title:b("common.success"),content:b("model.saved"),icon:""});}catch(s){M.show({title:b("common.error"),content:String(s),icon:""});}else M.show({title:b("common.hint"),content:b("model.selectFiles"),icon:""});}),null==(l=null==(d=this.container)?void 0:d.querySelector("#deleteModelBtn"))||l.addEventListener("click",()=>{M.confirm({title:b("model.deleteTitle"),content:b("model.deleteConfirm"),onConfirm:async()=>{await async function(){const e=new y;await e.deleteUploadedModel(),console.log("🗑️ 上传的模型已删除");}(),F({useUploadedModel:false}),M.show({title:b("common.success"),content:b("model.deleted"),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 M.show({title:b("common.hint"),content:b("settings.agreementSelector.enterSelector"),icon:""});const s=H().agreementSelectors||[];if(s.includes(i))return void M.show({title:b("common.hint"),content:b("settings.agreementSelector.exists"),icon:""});s.push(i),F({agreementSelectors:s});const o=null==(t=this.container)?void 0:t.querySelector("#agreementSelectorsList");o&&(o.innerHTML=this.renderAgreementSelectors(s)),this.bindAgreementSelectorDeleteEvents(),n.value="";}deleteAgreementSelector(e){var t;const n=H().agreementSelectors||[];n.splice(e,1),F({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 s=null==(e=this.container)?void 0:e.querySelector("#newCalcRulePattern"),o=null==(t=this.container)?void 0:t.querySelector("#newCalcRuleMatchType"),a=null==(n=this.container)?void 0:n.querySelector("#newCalcRuleOutputMode"),r=null==s?void 0:s.value.trim();if(!r)return void M.show({title:b("common.hint"),content:b("calc.enterPattern"),icon:""});const d=H().calculateRules||[];d.push({pattern:r,matchType:o.value,outputMode:a.value,enabled:true}),F({calculateRules:d});const l=null==(i=this.container)?void 0:i.querySelector("#calculateRulesList");l&&(l.innerHTML=this.renderCalculateRules(d)),this.bindCalcRuleDeleteEvents(),s.value="";}deleteCalculateRule(e){var t;const n=H().calculateRules||[];n.splice(e,1),F({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"),s=null==(t=this.container)?void 0:t.querySelector("#newRuleSelector"),o=null==(n=this.container)?void 0:n.querySelector("#newRuleInputSelector"),a=null==i?void 0:i.value.trim(),r=null==s?void 0:s.value.trim(),d=null==o?void 0:o.value.trim();a&&r?(O(a,{selector:r,inputSelector:d||void 0,enabled:true}),this.refreshSiteRulesList(),i.value="",s.value="",o.value=""):M.show({title:b("common.hint"),content:b("rules.selectorRequired"),icon:""});}editSiteRule(e){var t,n,i,s,o;const a=N()[e];if(!a)return;this.currentEditRuleKey=e;const r=null==(t=this.container)?void 0:t.querySelector("#editRuleCard"),d=null==(n=this.container)?void 0:n.querySelector("#editRuleKey"),l=null==(i=this.container)?void 0:i.querySelector("#editRuleOriginalKey"),c=null==(s=this.container)?void 0:s.querySelector("#editRuleSelector"),u=null==(o=this.container)?void 0:o.querySelector("#editRuleInput");r&&(r.style.display="block"),d&&(d.value=e),l&&(l.value=e),c&&(c.value=a.selector||""),u&&(u.value=a.inputSelector||"");}saveEditRule(){var e,t,n;const i=null==(e=this.container)?void 0:e.querySelector("#editRuleOriginalKey"),s=null==(t=this.container)?void 0:t.querySelector("#editRuleSelector"),o=null==(n=this.container)?void 0:n.querySelector("#editRuleInput"),a=null==i?void 0:i.value,r=null==s?void 0:s.value.trim(),d=null==o?void 0:o.value.trim();if(r){if(a){const e=N()[a];e&&(_(a),O(e.hostname,{...e,selector:r,inputSelector:d||void 0}));}this.cancelEditRule(),this.refreshSiteRulesList();}else M.show({title:b("common.hint"),content:b("rules.selectorRequired"),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){M.confirm({title:b("rules.deleteConfirm"),content:b("rules.deleteConfirmMsg",e),onConfirm:()=>{_(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=N(),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(b("rules.formatError"));for(const n of t)n.hostname&&n.selector&&O(n.hostname,{selector:n.selector,inputSelector:n.inputSelector,fullUrl:n.fullUrl,enabled:!0});this.refreshSiteRulesList(),M.show({title:b("common.success"),content:b("rules.importedCount",t.length),icon:""});}catch{M.show({title:b("common.error"),content:b("rules.importFormatError"),icon:""});}},e.click();}clearStats(){M.confirm({title:b("stats.clear"),content:b("stats.clearConfirm"),onConfirm:()=>{var e,t,n;z.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=H();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();F(JSON.parse(e)),M.show({title:b("common.success"),content:b("config.importedRefresh"),icon:""});}catch{M.show({title:b("common.error"),content:b("config.importError"),icon:""});}},e.click();}resetConfig(){M.confirm({title:b("common.reset"),content:b("config.resetConfirmSimple"),onConfirm:()=>{GM_setValue("ddddocr_config",s),M.show({title:b("common.success"),content:b("config.resetDoneRefresh"),icon:""});}});}downloadJson(e,t){const n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),i=URL.createObjectURL(n),s=document.createElement("a");s.href=i,s.download=t,s.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());}}renderKeywordChipGroupsHtml(){const e={customIncludeKeywords:{titleKey:"settings.keywords.triggerTitle",placeholderKey:"settings.keywords.triggerPlaceholder",hintKey:"settings.keywords.triggerHint"},customExcludePatterns:{titleKey:"settings.keywords.excludeTitle",placeholderKey:"settings.keywords.excludePlaceholder",hintKey:"settings.keywords.excludeHint"},customAgreementKeywords:{titleKey:"settings.keywords.agreementTitle",placeholderKey:"settings.keywords.agreementPlaceholder",hintKey:"settings.keywords.agreementHint"},customInputExcludeKeywords:{titleKey:"settings.keywords.inputExcludeTitle",placeholderKey:"settings.keywords.inputExcludePlaceholder",hintKey:"settings.keywords.inputExcludeHint"}};return Object.keys(this.CHIP_META).map(t=>{const n=e[t];return `\n
\n
\n
${b(n.titleKey)}
\n
\n ${b("settings.keywords.builtinDeletable")}\n \n
\n
\n
\n
\n \n
\n
${b(n.hintKey)}
\n
\n `}).join("")}getEnabledBuiltinKeywords(e,t){const n=this.CHIP_META[e],i=new Set((t[n.disabledKey]||[]).map(e=>e.toLowerCase()));return n.builtin.filter(e=>!i.has(e.toLowerCase()))}renderChipList(e,t){var n;const i=null==(n=this.container)?void 0:n.querySelector(`#ddddocr-${e}-list`);if(!i)return;const s=[...this.getEnabledBuiltinKeywords(e,t).map(e=>({value:e,kind:"builtin"})),...(t[e]||[]).map(e=>({value:e,kind:"custom"}))];0!==s.length?i.innerHTML=s.map(t=>`\n \n ${W(t.value)}\n ${"builtin"===t.kind?b("settings.keywords.builtin"):b("settings.keywords.custom")}\n \n \n `).join(""):i.innerHTML=`
${b("settings.keywords.empty")}
`;}renderAllChipGroups(){const e=H();Object.keys(this.CHIP_META).forEach(t=>this.renderChipList(t,e));}bindChipEvents(){var e;this.container&&(Object.keys(this.CHIP_META).forEach(e=>{var t;const n=null==(t=this.container)?void 0:t.querySelector(`#ddddocr-${e}-input`);null==n||n.addEventListener("keydown",t=>{if("Enter"!==t.key)return;t.preventDefault();const i=n.value.trim();if(!i)return;const s=H();if(new Set([...(s[e]||[]).map(e=>e.toLowerCase()),...this.CHIP_META[e].builtin.map(e=>e.toLowerCase())]).has(i.toLowerCase()))return void M.show({title:b("common.hint"),content:b("settings.keywords.exists"),icon:""});const o=s[e]||[];F({[e]:[...o,i]}),n.value="",this.renderAllChipGroups();});}),null==(e=this.container.querySelector("#ddddocr-keyword-chip-groups"))||e.addEventListener("click",e=>{this.handleChipClick(e);}));}handleChipClick(e){const t=e.target,n=t.closest(".ddddocr-chip-remove");if(n){const e=n.dataset.chipField,t=n.dataset.chipKind,i=n.dataset.chipValue||"",s=H();if("builtin"===t){const t=this.CHIP_META[e].disabledKey,n=s[t]||[];F({[t]:Array.from(new Set([...n,i]))});}else {const t=s[e]||[];F({[e]:t.filter(e=>e.toLowerCase()!==i.toLowerCase())});}return void this.renderAllChipGroups()}const i=t.closest(".ddddocr-chip-reset");if(i){const e=i.dataset.chipField;F({[e]:[],[this.CHIP_META[e].disabledKey]:[]}),this.renderAllChipGroups();}}destroyContainer(){this.overlay&&(this.overlay.remove(),this.overlay=null),this.container&&(this.container.remove(),this.container=null),this.containerLocale="";}async show(){var e,t,n;this.container&&this.containerLocale===g()||(this.destroyContainer(),await this.createContainer()),this.applyTheme(),this.isVisible=true,null==(e=this.overlay)||e.classList.add("visible"),null==(t=this.container)||t.classList.add("visible"),U()&&(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 V{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=b("us.loadingDefault"),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 G{constructor(){this.engine=new t({getModel:E,wasmPaths:"https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.0/dist/"});}async init(){await async function(){try{await R.init();}catch(t){console.warn("[WASMCache] 初始化失败:",t);}(async function(){console.log("📦 开始预下载 WASM 文件"),await Promise.allSettled(A.map(async e=>{try{if(await R.get(e))return;const t=await I(e);await R.set(e,t);}catch(t){console.warn(`⚠️ ${e} 下载失败`,t);}}));})().catch(()=>{});const e=window.fetch;window.fetch=async function(n,i){const s="string"==typeof n?n:n instanceof URL?n.href:n.url,o=A.find(e=>s.includes(e));if(!o)return e.call(this,n,i);try{let e=await R.get(o);return e||(e=await I(o),R.set(o,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)}},console.log("✅ WASM 缓存已启用");}(),await this.engine.init();}async recognize(e){return this.engine.recognize(e)}}class X{constructor(e,t){this.observer=null,this.enabled=false,this.checkInterval=null,this.eventEmitter=null,this.autoFill=new n,this.initialScanDone=false,this.initialScanTimer=null,this.processingElements=new WeakSet,this.processedElements=new WeakMap,this.customCaptchaElement=null,this.customInputElement=null,this.ocr=e,this.detector=new c,this.eventEmitter=t||null;}start(){this.enabled||(this.enabled=true,r.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,r.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=N(),t=window.location.href,n=window.location.hostname;let i=null;for(const s of Object.keys(e)){const o=e[s];if(o.enabled){if(o.fullUrl&&t===o.fullUrl){i=o;break}if(o.urlPattern&&t.startsWith(o.urlPattern)){i=o;break}o.hostname!==n||o.fullUrl||o.urlPattern||(i=o);}}if(i){const e=document.querySelector(i.selector);e&&(this.customCaptchaElement=e,i.inputSelector&&(this.customInputElement=document.querySelector(i.inputSelector)),r.info("应用站点规则:",i.selector));}}checkAgreementBoxes(){const e=H();if(!e.autoCheckAgreement)return;let t=[];e.agreementSelectors&&e.agreementSelectors.length>0&&(t=e.agreementSelectors);const n=this.detector.guessAgreementCheckboxes();for(const s of n){const e=s.element;if(e.checked)continue;const t=s.clickTarget;t?(t.click(),r.info("点击协议复选框容器")):(e.checked=true,e.dispatchEvent(new Event("change",{bubbles:true})),e.dispatchEvent(new Event("input",{bubbles:true})),r.info("直接勾选协议复选框")),this.detector.markAgreementChecked(e);}for(const s of t)if(s.trim())try{document.querySelectorAll(s).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})),r.info("通过选择器勾选协议:",s));});}catch(i){r.warn("无效的协议选择器:",s);}}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}},i.AUTO_DETECT_INTERVAL);}detectExistingCaptchas(e){r.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(()=>{a(),n(false);},t),s=()=>{a(),n(true);},o=()=>{a(),n(false);},a=()=>{clearTimeout(i),e.removeEventListener("load",s),e.removeEventListener("error",o);};e.addEventListener("load",s),e.addEventListener("error",o),e.complete&&e.naturalWidth>0&&(a(),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=H();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 s=this.findNearbyInput(e);s&&(s.value.trim()&&(s.value="",s.dispatchEvent(new Event("input",{bubbles:true}))),await this.waitForImageLoad(e)&&e.naturalWidth&&await this.recognizeAndFill(e,s));}async checkCanvas(e,t){var n;const i=H();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 s=this.findNearbyInput(e);if(!s)return;await new Promise(e=>requestAnimationFrame(e));const o=await new Promise((t,n)=>{e.toBlob(e=>{e?t(e):n(new Error("Canvas转换失败"));},"image/png");});await this.recognizeAndFillBlob(e,o,s);}async checkSVG(e,t){var n;const i=H();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 s=this.findNearbyInput(e);if(!s)return;const o=await this.svgToBlob(e);await this.recognizeAndFillBlob(e,o,s);}async checkDiv(e,t){var n;const i=H();if(i.captchaSelector){if(!e.matches(i.captchaSelector))return}else if(!this.isCaptchaDiv(e))return;const s=e.style.backgroundImage;if(!s)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 o=this.findNearbyInput(e);if(!o)return;const a=s.match(/url\(['"]?(.+?)['"]?\)/);if(!a)return;const r=a[1],d=Date.now();let l="";if(r.startsWith("data:")){const e=await fetch(r),t=await e.blob();l=(await this.ocr.recognize(t)).text;}else l=(await this.ocr.recognize(r)).text;const c=Date.now()-d,u=this.processResult(l);await this.fillInput(o,u),this.markElementProcessed(e),z.record(window.location.hostname,c);}async svgToBlob(e){const t=(new XMLSerializer).serializeToString(e),n=new Blob([t],{type:"image/svg+xml;charset=utf-8"}),i=URL.createObjectURL(n),s=new Image;s.src=i,await new Promise((e,t)=>{s.onload=e,s.onerror=t,setTimeout(t,5e3);});const o=document.createElement("canvas");return o.width=e.clientWidth||150,o.height=e.clientHeight||50,o.getContext("2d").drawImage(s,0,0),URL.revokeObjectURL(i),new Promise((e,t)=>{o.toBlob(n=>{n?e(n):t(new Error("SVG转换失败"));},"image/png");})}async recognizeAndFill(e,t){var n,i,s;if(this.processingElements.has(e))return;this.processingElements.add(e);const o=Date.now();r.time("recognizeAndFill");try{null==(n=this.eventEmitter)||n.emit("recognize:start",{element:e});const s=await this.ocr.recognize(e),a=this.processResult(s.text);null==(i=this.eventEmitter)||i.emit("recognize:complete",{element:e,result:{text:a}}),await this.fillInput(t,a),this.markElementProcessed(e);const d=Date.now()-o;z.record(window.location.hostname,d),r.timeEnd("recognizeAndFill"),r.info("识别完成:",a);}catch(a){r.error("识别失败:",a),null==(s=this.eventEmitter)||s.emit("recognize:error",{element:e,error:a});}finally{this.processingElements.delete(e);}}async recognizeAndFillBlob(e,t,n){var i,s,o;if(this.processingElements.has(e))return;this.processingElements.add(e);const a=Date.now();try{null==(i=this.eventEmitter)||i.emit("recognize:start",{element:e});const o=await this.ocr.recognize(t),d=this.processResult(o.text);null==(s=this.eventEmitter)||s.emit("recognize:complete",{element:e,result:{text:d}}),await this.fillInput(n,d),this.markElementProcessed(e);const l=Date.now()-a;z.record(window.location.hostname,l),r.info("识别完成:",d);}catch(d){r.error("识别失败:",d),null==(o=this.eventEmitter)||o.emit("recognize:error",{element:e,error:d});}finally{this.processingElements.delete(e);}}processResult(e){const t=H();return t.autoCalculate?l.processResult(e,{autoCalculate:true,outputMode:t.calculateOutputMode,rules:t.calculateRules||[]},window.location.hostname):e}async fillInput(e,t){const n=H();await this.autoFill.fill(e,t,{simulate:true,autoSubmit:n.autoSubmit??false,typewriterEffect:n.typewriterEffect}),n.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:b("us.captchaFilled"),text:b("us.captchaFilledResult",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(e){const t=e.naturalWidth||e.width,n=e.naturalHeight||e.height;if(ti.MAX_CAPTCHA_WIDTH||n>i.MAX_CAPTCHA_HEIGHT)return false;const s=(e.src+e.className+e.id+e.alt+(e.getAttribute("data-src")||"")).toLowerCase();return !i.EXCLUDE_PATTERNS.some(e=>s.includes(e))&&i.CAPTCHA_KEYWORDS.some(e=>s.includes(e))}isCaptchaCanvas(e){const t=e.width,n=e.height;if(ti.MAX_CAPTCHA_WIDTH||n>i.MAX_CAPTCHA_HEIGHT)return false;const s=(e.className+e.id+(e.getAttribute("data-type")||"")).toLowerCase();return !i.EXCLUDE_PATTERNS.some(e=>s.includes(e))&&i.CAPTCHA_KEYWORDS.some(e=>s.includes(e))}isCaptchaSVG(e){var t,n,s;const o=e.clientWidth||parseInt(e.getAttribute("width")||"0"),a=e.clientHeight||parseInt(e.getAttribute("height")||"0");if(oi.MAX_CAPTCHA_WIDTH||a>i.MAX_CAPTCHA_HEIGHT)return false;const r=(((null==(t=e.className)?void 0:t.baseVal)||"")+(e.id||"")).toLowerCase();if(i.CAPTCHA_KEYWORDS.some(e=>r.includes(e)))return true;let d=e.parentElement,l=0;for(;d&&l<3;){const e=(((null==(s=null==(n=d.className)?void 0:n.toString)?void 0:s.call(n))||"")+(d.id||"")).toLowerCase();if(i.CAPTCHA_KEYWORDS.some(t=>e.includes(t)))return true;d=d.parentElement,l++;}const c=this.findNearbyInput(e);if(!c)return false;const u=(c.name+c.id+c.className+c.placeholder).toLowerCase();return i.INPUT_KEYWORDS.some(e=>u.includes(e))}isCaptchaDiv(e){const t=e.clientWidth,n=e.clientHeight;if(ti.MAX_CAPTCHA_WIDTH||n>i.MAX_CAPTCHA_HEIGHT)return false;const s=(e.className+e.id).toLowerCase();return i.CAPTCHA_KEYWORDS.some(e=>s.includes(e))}findNearbyInput(e){const t=H();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 Y{constructor(){this.loadingIndicator=null,this.initialized=false,this.menuCommandIds=new Map,this.eventEmitter=new u,this.ocr=new G,this.detector=new X(this.ocr,this.eventEmitter),this.settingsUI=new j;const e=H();h(e.language),r.setDebugMode(e.debugMode||false),this.registerMenuCommands(),this.settingsUI.setOnConfigChange(e=>this.handleConfigChange(e));}async init(){var e;if(q()){if(!this.initialized){this.initialized=true,this.loadingIndicator=new V,r.info("DDDD OCR 启动");try{this.loadingIndicator.show(b("us.loading")),this.loadingIndicator.updateText(b("us.loadingModel")),await this.ocr.init(),r.info("OCR 已就绪"),this.loadingIndicator.updateText(b("us.ready"));const e=H();e.autoDetect&&(this.detector.start(),r.info("自动检测已启动")),setTimeout(()=>{var e;return null==(e=this.loadingIndicator)?void 0:e.hide()},2e3),this.showNotification(b("us.ready"),e.autoDetect?b("us.readyAutoDetect"):b("us.readyManual"));}catch(t){r.error("初始化失败:",t),null==(e=this.loadingIndicator)||e.updateText(b("us.initFailedMsg",String(t))),setTimeout(()=>{var e;return null==(e=this.loadingIndicator)?void 0:e.hide()},3e3),this.showNotification(b("us.initFailed"),String(t),true);}}}else r.debug("当前站点不满足执行条件");}registerMenuCommands(){this.refreshMenuCommands();}refreshMenuCommands(){for(const i of this.menuCommandIds.values())try{GM_unregisterMenuCommand(i);}catch{}this.menuCommandIds.clear();const e=GM_registerMenuCommand(b("us.menuOpenSettings"),()=>this.settingsUI.show(),"s");this.menuCommandIds.set("settings",e);const t=GM_registerMenuCommand(b("us.menuClearCache"),async()=>{M.confirm({title:b("us.clearCacheTitle"),content:b("us.clearCacheMsg"),confirmText:b("us.clearCacheConfirm"),cancelText:b("common.cancel"),onConfirm:async()=>{await async function(){const e=new y;await e.delete(),console.log("🗑️ 模型缓存已清除");}(),await async function(){await R.clear();}(),this.showNotification(b("us.cacheCleared"),b("us.cacheClearedMsg"));}});},"d");this.menuCommandIds.set("cache",t);const n=GM_registerMenuCommand(b("us.menuViewStatus"),()=>this.showStatus(),"i");this.menuCommandIds.set("status",n);}showStatus(){var e,t,n;const i=H(),s=B(),o=N(),a=z.getStats(),r=e=>b(e?"common.enabled":"common.disabled"),d=`\n${b("status.scriptStatus")} ${this.initialized?b("status.initialized"):b("status.notInitialized")}\n${b("status.currentSite")} ${window.location.hostname}\n${b("status.whitelistStatus")} ${r(i.enableWhitelist)}\n${b("status.whitelistCount")} ${(null==(e=i.whitelist)?void 0:e.length)||0} ${b("common.sites")}\n${b("status.siteMatch")} ${b(s?"status.inWhitelist":"status.notInWhitelist")}\n${b("status.autoDetect")} ${r(i.autoDetect)}\n${b("status.typewriterEffect")} ${r(i.typewriterEffect)}\n${b("status.autoCheckAgreement")} ${r(i.autoCheckAgreement)}\n${b("status.agreementSelectorCount")} ${(null==(t=i.agreementSelectors)?void 0:t.length)||0}\n${b("status.autoCalculate")} ${r(i.autoCalculate)}\n${b("status.calcOutput")} ${"result"===i.calculateOutputMode?b("status.calcOutputResult"):b("status.calcOutputEquation")}\n${b("status.calcRuleCount")} ${(null==(n=i.calculateRules)?void 0:n.length)||0}\n${b("status.siteRuleCount")} ${Object.keys(o).length}\n${b("status.debugMode")} ${r(i.debugMode)}\n${b("status.uploadedModel")} ${i.useUploadedModel?b("common.enabled"):b("common.notEnabled")}\n${b("status.autoDownload")} ${r(i.autoDownload)}\n${b("status.totalRecognitions")} ${a.total} ${b("common.times")}`;M.show({title:b("status.title"),content:d});}handleConfigChange(e){"auto"===e.language?h("auto"):m(e.language),r.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){H().enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:e,text:t,timeout:n?5e3:3e3});}}function Q(){const e=new Y;q()?setTimeout(()=>e.init(),500):r.debug("DDDD OCR 不满足执行条件,仅注册菜单命令");}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",Q):Q(); })();