// ==UserScript== // @name Mieru-OCR - 验证码自动识别 // @namespace https://github.com/MakotoArai-CN/Mieru-OCR // @version 1.2.0-5/11/2026, 3:40:07 PM // @author MakotoArai-CN // @description 自动检测并识别页面验证码,自动填充到输入框。首次使用需设置白名单,会自动下载约50MB模型文件以及20MB左右的ONNX推理运行时文件。 // @license MIT // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAOu0lEQVR4AYSZe5Ce5VnGr/vbbzfZ3WwOmyOEEHJgSKVmtBxHxKYt9IAjOJU61kNKa60yYu3gaNV/9C9bbWqth+owQqUtVqENDCrVmDIFppViAwgNjY0Jh5SEhIScNtns4ftef9f9vO+3u7SOzz73c1/3dR+e+3ne9/t2Ay3NGlVVjSBXdzqdT3W73SeQY8h0t9Ot0EgHAWN3ujO4+Arfw11sC7Hdbo2tsalfWbrgbneur9ut7eKb7na77uEJ4j/l3pCRWS2rdwAclyN30uGOiPgIQVcgo6rUpwDl7AGoGtcq3QSrqnpwLoa2i/jI7BBKOcxbnJ8EC27y+6BGsa7A/Ih7A981OTl5GTpnHoDG3fznYd6jiDknFJnwM7PZyBph4itrE0s9JY462cpCN5o9msM2XBPvcj/Y5zfk5na7/QUOcbnTWmxm8ncxNvXquwCEJ36rGXEjbFTVwTZV5UpMyKkR2E0DQJPFxMiADJUyThK0JffKQAdJst/Jqgd2xkib+vv7Pwoe8RO4FPfbe3F1LlxO105g3sUtEMl7MZ/aQOxpQ2U4ttDwULNcvB6a2ZMgYkMh0WRPVA/cGY8ZQQx21a3eMTU1dakP8G4KjQg+haDmdjkhlh21crKD2EyJ4Zv5f9l1OnvMNOycJj79LEzT2ajr22i0seNpPP2ODY3wFN7dqjrVm2XCQRZwBAs47AhAM13Adu1v6KLtrFEFLpOmAaYzD2CN6jXi2DwdpH2ubcFU7g/JlEejjUvZn2gRs8H2DxQnONDiANvWFnOWBlPI0BKJq1zlZsIsks2iPc1bN1IB7J8tUN83nefYUnODD7Aog0gsrwwWmLVMB1qcZMbaYq65OfheikH6csFTpms7rVisjkN5zuHdoMhNjYfpGItr9J4cBPbiFrqN5CQt9f+7zAlkB2wmac2nB+jDZRPGRTKmady+GkeUby+hS+TrVuJoFjcVmhg4oto+AJqZDgLoB4t3l9XYAszZYGtL5uDJYhBMKkAwGx/QM8IeJDVM5qCZbg7V23PuNVAUZwS5zmkEzrMcwKQtYqwkg5Iojx40KOJNmo0L40AkN0K7pgXoh2GVHWYwi+MKmbsVCD8TnNScTpxjSU9ZWuWdIqzZzAUwi3v26uK2izOi6IaJbCOyR3NFsA2s6vo+uByL3VS0zhA5PfAGALbeA6vY9pOHkmpfqwEwKiPDC/SaJsWM5Xe1xhRKV82zA8i+RjAdQBxIYkN7QqFmFBQwriu0xVEI8Xm5yUqyLaHCC9sRI838MafoceThdAIchmQsj0rBj5HMWTB8qxXa0/rQWKVvHaz0yPPol6Uj2M05HMNORXkNL5VSGX6fVJL3aQpYQ0HKo+XFb42141w8FKiMkkwaWltUj14hiWhNTFd66uCU/vjhcX3yaxPa/mxHO7/b1fZvV/qTr1Xa9khXuw8r48RwyRTqWEPV09WADZ97OsJ8rQ0zpOIJmMPISVJqL5kISH8ueSjfNmyeudPtGurEeFf37hrTg8+c1abloQ9e1a/furZPH90Suv3HQ7dcFrqQ3zZf2FXp/t2VxqeVh26+BOp+5NHUN07eW1vS8GIDLzAiOACAzpQDQpTOIs1h0s/SywtNd7ra9cx3dPS1ExqbqPTZr5/U3sMT2nrFsH7q0vkcoq2lQy2dOTuhJUPSG88L/czm0IeuCi0dlFohib2Onzilp57Zw1taF5cdkvDJI3V2Y6snzcFNlFfIqBFqMJVFZtdNkvf52Gv64v3/phVLl2gZ8tU9Y/re8Und9pYlWre0rdasimPnprXv0GlNTXfVput1S6W3XRy66/Fz+sbzU1q6ZJHOW7Vcf333l3Tg4GF1ubQQA132Lw1EJCtOKvMR2I6RVLZLAquZPZsCdaBdz+7Zp7+95wG9afMlWnP+Kp0429E3953VzZct1MqF5Rd6KOQpxqrFg1ow2Nbxscl85aByvmFln1YuIA5r1YqluumdW/Tlf/6qnv72Hph6si+7pwEszdtKw6CI/0FTkOvZmVIouZP6MM99d7/+7I57dNM73qwfunidIkJ7X5ng35uV3nDegMrw1yGP3DUghub3afmi+errg4c7xWdl21eOauPS0LLh0AP/Na5zU5XOX7lc73zrNfrMXffq6d17RfFyYPckyao5jHrDrNSKiB6VwLapRtj42ImTuvOe+/WT11+rSzdtUNTvyZMvjGvNaL+GB/p07OQ5PXfghPYcOKnvIM8dOK4XXhlTsDMl9NpYhyc2rdEFLbU5ULtPunJtvwbabMTctPEi3ciT+MRf3a0XXjpI00FuSCCuhFVzBmXTLq9QwnppPI2O0L/seFRnx89py49dVh5l7Tt8sqMF8/poSBqc187b9o1bViwa1OKRAXnnMxNdfezBQ/r0Vw7rPVcs0tBA6L7Hj2t0uE991A+V8a63XaORBUO6/6GHdW5ykqdQNoogwlLCsgeeaVqtXFl8SygmSY1hjbli+ajOnh1XZ7qD3xOSmv42mOL7X3Tp12Sg3VJ/X4tbRYMHwHSRH+zzFvfr/MUDaoU0j1u/fP0wB8fwIxID2OHb7eSp0xoZWYCvRVW36fvHP2uye8/qfQbygCzpRJNNEFWZ1179Jm1cf6Hu+6ed+RWaPgJXL2rr4LEpTUx1NT7RyQ/ribOTOnFmMvHJ8SlqSEP9Ld1+w0p98K3L9Qf3HtFTz49r/Yp5+ta+cU0SQilNTU3rri8+oNHFi/TT79rC56aP3Cq3ooW8dYicabtHrFZEmsAyI1PAFeLr4ykMDc7X+997kw68fFgP7XxMvimHXblxiPd+Qif5NhqgyQXz2xqe1+a1QowH2q6gyU6lh58d0zf++4yu/+FhrVnWLx6QVo+28+n46/Oxx5/US997Rb992y3y16t3lzexZC9iBMJMVcgW5syk2Z6RQbaCEqHVq1bod257n/a9+LIe+Y8n+UqutG75PG5XemjXaQ5V8d52UsYniz5Xv3JnznX1mYeO6I5/fVVXbhzW/lek2z97SkuG22r3hfbueyl/MX74V96rtRes8qbsaUWTYd0INp7ZbfLndO1s2DrB77f8dGzznlotXjSiW2+5WWNjZ7Rn7/Mani/dxIfycw8f1bMvTmjV6JAuWGYZ1mr0Sr5CReK8/tB1P7JQ121eqCmexsIh6ZLVbTbuaj8X8vX/fFq/uvVmnbdyGdzrpvuiRmENKkpaW6QWVu2Lout1tuUaFby5eQMD8tfp0OBgHuQtm0f0s9cs0R/+/SHd99hxjXHbhPZm1ZXmc4Bf2jKqZSNtfXL7Ua1eErrthmF1pydy+/f/3I1ayLdPk+R9GpzaDWQkH4Va57tJU70PMe9ExqbDi2+/MIoIBZj41H2tVj7qxQtHNMhX4geuX6Zfv2G57tzxqrZu26+7dx7V0/vPaO+hce1+6awe/OZpbf3Ei/r0A6/qjRfO47dzX9YZGR7UurWrxQfRO7KDkpcHe8qWdYpyGJouhpwbPpaExw0qB1zqWcscykY4JXP53OrGqxfrjg+v1aY18/W5nUd061+8oJ//+H792p+/qM//+1GtXdHW392+RluvW8ITaZXC7FmASi0xGq5pJm8f3jO8IObAfs3rzwDRkKHAywSzlomrgLLaLN/MIDZjzdvzN/b6lfP0R++7QP/4+xfrjt9cr7+89SL9zW9cpH/4vQ360w+t0SUXzK93KBVyt2YvCs2xsyqkt3VMI7ZriQi16ooSRpbNKpoZ2D6pFPxozij8HCqNZfxht/miIV21aVg/umFIq5b0y6+J2CMD5FpRYK417vmTzCNoNgfOPdElQmolMMEJIyJfCcma08P5sxHB/Rqj8eDFVhmBlQifelgM8pMDmg/rInlRBc5d6z3IlMjtpYCTwx/B3mjVoxwgvYSnzqV21woKbzEoYBDyj5ES5c2UO+MSQjlyowbDUIc1461npHaYICcz0PJeuFw7ObHCs3KvOIgvB4CZcyvYcrISEObJya0a4XdDA+dq55hptDdqqjeaM3JYexxZpK7f7GtNgDOaSqUdWwGMTMsDcKhCJJcLO5DNJgDhlId79m2k7f+p4U0cU6cobSLTdj6YaTTHRU5EKPAJbeV9QoFytJV1ZUZqYtyo6kGoUR4gz26iMsXCzKRMtAPeCmG6OgRBLpiElMo2zckjcwk1tthXc7K2LbIoY3eRxqgUgQ+yQrKk7aRgUtuh+kOsKFZvJaiHAa8zYerpPCSbKVQJLasZvDPVM47rsnZD2ZmjEOyZLGzHkOl8VHnnHdAIIZ5+AtMOyFqOppAs9joYXSuuE9T44CFy7cXLBaAIy3pAZbx5izPstON1GtMRKDnH2u+/sRgR9jYC4QBp2gc4iSnZZ9KiephDmN5ZyiJiJKOenTmFy9VxBtZiGKOk6P2UAwYUIgaqSi+Y28dUhFdsz6pZADP0iZa6+h+7emInMT3bwJy1eYuxixsj/jybylOat0ETVnMk65BA95VsVMXd5MDLvG2La1jEcDhK8L0vEmlfq4rq0cxLJ0vWzCX7yWBoz3ykBo3URcOb1JiXVbJNTOa6lMV+awFoglm2TS6D7TFgX0hqsGIzAVkLmPWtEbhHW4ztZJxOB0lgydXlUQHZsDKWQGUxcKzFWAxjVM46P6JxwtY1QLlFai+zQmyqyUFH1E5UBEsGSDU61el0tvszsFsROxDlaALnNJSeXDh1ai9NT5Vc0lL35lzXSV1H2o34KVrMRpioDJEoTwQk89bpIsa4kfQlt6O/v383f2PF6Yj4GE9gT8bnQnQQZHETmMIUdijosrQAIq0StCNSzCVoFucTkAcHh8pPdovdhFEUT23BZ7zNYMFmlaiTedKe6enpj0fEaT8B+NgVrdYv8Dp9WSFeJ80aVKhqs9GYJHslfJYfS4GNh5MpsW3yQlFsMYBuWPZZ3KC1hVgmrgwimGkeRc3TCn0pWvGLAwMDu0zlAQwi4kn0B9Bv5363gZ9AjpDAf/gA5XRpSxrCV0QM72exOwAWaDb1KsfmreKSR8+P0WBgM+tY730E7gnsbVzy9RHxy0g2D6//BQAA//+uEzUNAAAABklEQVQDAJSxOonxEWxHAAAAAElFTkSuQmCC // @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_info // @grant GM_notification // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_unregisterMenuCommand // @grant GM_xmlhttpRequest // @grant unsafeWindow // ==/UserScript== !function(){'use strict';var e,t=class{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 s=n.getImageData(0,0,t.width,t.height);return{data:this.toGrayscale(s.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 s=n.getContext("2d");s.fillStyle="#FFFFFF",s.fillRect(0,0,t.width,t.height),s.drawImage(t,0,0);const i=s.getImageData(0,0,t.width,t.height),o=this.toGrayscale(i.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)e.startsWith("data:"),t=await(await fetch(e)).blob();else{if(!(e instanceof Blob))throw new Error("Service Worker 环境不支持 HTMLImageElement");t=e}const n=await createImageBitmap(t),s=new OffscreenCanvas(n.width,n.height),i=s.getContext("2d");i.fillStyle="#FFFFFF",i.fillRect(0,0,s.width,s.height),i.drawImage(n,0,0);const o=i.getImageData(0,0,s.width,s.height),a=this.toGrayscale(o.data);return n.close(),{data:a,width:s.width,height:s.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(e){this.initialized&&this.session||await this.init();const n=Date.now(),{data:s,width:i,height:o}=await t.loadImage(e);let a=Math.floor(i*(64/o));a<1&&(a=1);const r=t.resize(s,i,o,a,64);let d,c=1;if("standardize"===(this.options.preprocess??"simple")){const e=this.options.preprocessMean??.456,n=this.options.preprocessStd??.224;d=t.normalizeStd(r,e,n),c=(1-e)/n}else d=t.normalize(r),c=1;let l=a;this.options.fixedWidth&&(d=t.padOrCropWidth(d,a,64,this.options.fixedWidth,c),l=this.options.fixedWidth);const u={input1:new this.ort.Tensor("float32",d,[1,1,64,l])},p=(await this.session.run(u)).output,h=this.decodeOutput(p);return console.log(`识别完成: ${h} (耗时: ${Date.now()-n}ms)`),{text:h}}getCharsets(){return this.charsets}decodeOutput(e){const t=this.convertToNumberArray(e.data),n=[];let s=-1;for(const i of t){if(i===s)continue;if(s=i,i<=0||i>=this.charsets.length)continue;const e=this.charsets[i];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:!0}),n=new CompositionEvent("compositionend",{bubbles:!0,data:e.value});e.dispatchEvent(t),e.dispatchEvent(n)}}async simulateTyping(e,t,n=!1){for(const s of t){this.dispatchKeyEvent(e,"keydown",s);const t=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value")?.set;t?t.call(e,e.value+s):e.value+=s;const n=new InputEvent("input",{bubbles:!0,cancelable:!0,inputType:"insertText",data:s});e.dispatchEvent(n),this.dispatchKeyEvent(e,"keyup",s),await this.delay(50+100*Math.random())}this.dispatchEvent(e,"change"),n||this.dispatchEvent(e,"blur")}dispatchEvent(e,t){e.dispatchEvent(new Event(t,{bubbles:!0,cancelable:!0}))}dispatchKeyEvent(e,t,n){e.dispatchEvent(new KeyboardEvent(t,{key:n,code:`Key${n.toUpperCase()}`,charCode:n.charCodeAt(0),keyCode:n.charCodeAt(0),bubbles:!0,cancelable:!0}))}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){const t=e.closest("form");if(t){const e=new Event("submit",{bubbles:!0,cancelable:!0});t.dispatchEvent(e)&&t.submit()}else{const t=(e.parentElement?.parentElement||document).querySelector("button[type=\"submit\"], input[type=\"submit\"], button:not([type])");t&&t.click()}}getLastFilledInput(){return this.lastFilledInput}},i="ddddocr_diag_log_",o=["sw","content","options","popup","offscreen","userscript"],a=[],r=null,d=null,c=!1;function l(){if(d)return d;try{if("undefined"!=typeof self&&self.ServiceWorkerGlobalScope&&self instanceof self.ServiceWorkerGlobalScope)return d="sw"}catch{}if("undefined"!=typeof window){const e="undefined"!=typeof location&&location.href||"";return d=e.includes("options")?"options":e.includes("popup")?"popup":e.includes("offscreen")?"offscreen":"function"==typeof globalThis.GM_getValue?"userscript":"content"}return d="unknown"}function u(){if(void 0!==e)return e;try{const t=globalThis.chrome;if(t?.storage?.local)return e={get:e=>t.storage.local.get(e).then(t=>t[e]),set:(e,n)=>t.storage.local.set({[e]:n})}}catch{}try{const t=globalThis.browser;if(t?.storage?.local)return e={get:e=>t.storage.local.get(e).then(t=>t[e]),set:(e,n)=>t.storage.local.set({[e]:n})}}catch{}const t=globalThis.GM_getValue,n=globalThis.GM_setValue;return"function"==typeof t&&"function"==typeof n?e={get:async e=>t(e),set:async(e,t)=>n(e,t)}:(e=null,null)}function p(e){if(null==e)return String(e);if("string"==typeof e)return e;if("number"==typeof e||"boolean"==typeof e)return String(e);if(e instanceof Error)return`${e.name}: ${e.message}\n${e.stack||""}`;try{return JSON.stringify(e,(e,t)=>t instanceof Error?{name:t.name,message:t.message,stack:t.stack}:t)}catch{return"[unserializable]"}}function h(e,t){var n;if(c)try{const s=(n=t.map(p).join(" ")).length>300?n.slice(0,299)+"…":n;for(a.push({ts:Date.now(),level:e,ctx:l(),msg:s});a.length>200;)a.shift();r||(r=setTimeout(()=>{r=null,async function(){const e=u();if(e)try{await e.set(i+l(),a.slice())}catch{}}()},1e3))}catch{}}function m(e){let t=0;for(let n=0;n>>0).toString(16).padStart(8,"0")}function g(e){return`[${e.length} chars · ${m(e)}]`}var b={MODEL_VERSION:"1.5.1",MODEL_REPO:"MakotoArai-CN/Mieru-OCR",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","search","url","color","range","date","time","datetime-local","month","week"],SLIDER_KEYWORDS:["slider","slide-captcha","slide-verify","puzzle","jigsaw","drag-verify","滑块","滑动","拖动","拖拽","拼图","geetest","nc-container","nc_wrapper","verify-slide","btn_slide"],CLICK_SELECT_KEYWORDS:["click-captcha","click-verify","point-captcha","pickword","pick-word","点选","文字点选","图形点选","text-click"],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/Mieru-OCR/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"]},f={debugMode:!1,autoDetect:!0,captchaSelector:"",inputSelector:"",submitSelector:"",agreementSelector:"",agreementSelectors:[],autoCheckAgreement:!0,useLocalModel:!1,localModelPath:"",localCharsetsPath:"",autoDownload:!0,enableWhitelist:!0,whitelist:[],useUploadedModel:!1,useUploadedWasm:!1,theme:"auto",language:"auto",typewriterEffect:!0,autoCalculate:!1,calculateOutputMode:"result",calculateRules:[],customIncludeKeywords:[],customExcludePatterns:[],customAgreementKeywords:[],customInputExcludeKeywords:[],disabledCaptchaKeywords:[],disabledExcludePatterns:[],disabledAgreementKeywords:[],disabledInputExcludeKeywords:[],enableInteractiveCaptchaAssist:!1,enableInteractiveCaptchaDebugOverlay:!1,enableSliderPuzzleAssist:!0,enableSingleSliderAssist:!0,enableClickSelectAssist:!1,enableNotification:!0,autoSubmit:!1,autoSolveOnRule:!0,siteBlacklist:[],imageContextMenuEnabled:!1,imageContextMenuAutoFill:!0,preserveFocus:!1};function y(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"}}var w=class{static{this.debugMode=!1}static{this.prefix="[Mieru-OCR]"}static setDebugMode(e){this.debugMode=e,function(e){c=e}(e)}static isDebugMode(){return this.debugMode}static debug(...e){this.debugMode&&(console.log(`${this.prefix} [DEBUG]`,...e),h("debug",e))}static info(...e){this.debugMode&&(console.info(`${this.prefix} [INFO]`,...e),h("info",e))}static warn(...e){console.warn(`${this.prefix} [WARN]`,...e),this.debugMode&&h("warn",e)}static error(...e){console.error(`${this.prefix} [ERROR]`,...e),this.debugMode&&h("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}`)}},v=class{static{this.OPERATORS=["+","-","×","*","÷","/","x","X"]}static{this.EQUALS_CHARS=["=","="]}static{this.QUESTION_CHARS=["?","?","〇","o","O","0"]}static{this.NOISE_CHARS=["?","?","〇"," ","\t","\n","\r"]}static parseExpression(e){const t=e.trim();let n=t;for(const i of this.NOISE_CHARS)n=n.split(i).join("");for(const i of[/^(\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+)?)$/]){const e=n.match(i);if(e){const n=parseFloat(e[1]),s=e[2],i=parseFloat(e[3]);if(!isNaN(n)&&!isNaN(i))return{num1:n,operator:s,num2:i,originalText:t,cleanExpression:`${n}${this.normalizeOperator(s)}${i}`}}}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!1}}static getOutputModeForHostname(e,t,n){for(const s of t)if(s.enabled&&this.matchesPattern(e,s.pattern,s.matchType))return s.outputMode;return n}static shouldCalculateForHostname(e,t){if(!t||0===t.length)return!0;const n=t.filter(e=>e.enabled);if(0===n.length)return!0;for(const s of n)if(this.matchesPattern(e,s.pattern,s.matchType))return!0;return!1}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 s=this.parseExpression(e);if(!s)return e;const i=this.calculate(s);return null===i?e:"equation"===this.getOutputModeForHostname(n,t.rules,t.outputMode)?this.formatEquation(s,i):this.formatResult(i)}static isExpression(e){return null!==this.parseExpression(e)}},x=class{constructor(){this.detectedCaptchas=[],this.processedElements=new WeakMap,this.checkedAgreements=new WeakSet,this.customIncludeKeywords=[],this.customExcludePatterns=[],this.customAgreementKeywords=[],this.customInputExcludeKeywords=[]}setCustomPatterns(e,t,n,s){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=(s||[]).map(e=>e.toLowerCase().trim()).filter(Boolean)}getCaptchaKeywords(){return 0===this.customIncludeKeywords.length?b.CAPTCHA_KEYWORDS:[...b.CAPTCHA_KEYWORDS,...this.customIncludeKeywords]}getExcludePatterns(){return 0===this.customExcludePatterns.length?b.EXCLUDE_PATTERNS:[...b.EXCLUDE_PATTERNS,...this.customExcludePatterns]}getAgreementKeywords(){return 0===this.customAgreementKeywords.length?b.AGREEMENT_KEYWORDS:[...b.AGREEMENT_KEYWORDS,...this.customAgreementKeywords]}getInputExcludeKeywords(){return 0===this.customInputExcludeKeywords.length?b.INPUT_EXCLUDE_KEYWORDS:[...b.INPUT_EXCLUDE_KEYWORDS,...this.customInputExcludeKeywords]}hasNearbyCaptchaInput(e){const t=this.findRelatedInput(e);return!!t&&this.isCaptchaInputByName(t)}isExcludedElement(e){const t=(e.className?.toString?.()||"").toLowerCase(),n=(e.id||"").toLowerCase(),s=this.getExcludePatterns(),i=`${t} ${n}`.trim();return s.some(e=>i.includes(e))}scan(){return this.detectedCaptchas=[],w.time("CaptchaDetector.scan"),this.scanImages(),this.scanCanvas(),this.scanSvg(),this.scanBackgroundImages(),this.scanInteractiveContainers(),w.timeEnd("CaptchaDetector.scan"),w.debug("扫描结果:",this.detectedCaptchas.length,"个验证码"),this.detectedCaptchas}scanImages(){document.querySelectorAll("img").forEach((e,t)=>{if(this.isLikelyCaptcha(e)){const n=e.getBoundingClientRect(),s={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(s),w.debug("检测到图片验证码:",s.elementInfo)}})}scanCanvas(){document.querySelectorAll("canvas").forEach((e,t)=>{if(this.isLikelyCanvasCaptcha(e)){const n=e.getBoundingClientRect(),s={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(s),w.debug("检测到Canvas验证码:",s.elementInfo)}})}scanSvg(){document.querySelectorAll("svg").forEach((e,t)=>{if(this.isLikelySvgCaptcha(e)){const n=e.getBoundingClientRect(),s={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(s),w.debug("检测到SVG验证码:",s.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(),s={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(s),w.debug("检测到背景图验证码:",s.elementInfo)}})}scanInteractiveContainers(){const e=b.SLIDER_KEYWORDS,t=b.CLICK_SELECT_KEYWORDS;if(!e&&!t)return;const n=(e||[]).map(e=>e.toLowerCase()),s=(t||[]).map(e=>e.toLowerCase());let i=0;const o=new Set,a=(e,t)=>{const n=((e.className?.toString?.()||"")+" "+(e.id||"")+" "+(e.getAttribute("data-captcha-type")||"")+" "+(e.getAttribute("aria-label")||"")).toLowerCase();return!!n.trim()&&t.some(e=>n.includes(e))},r=(e,t,n)=>{if(o.has(e)||++i>600)return;if(o.add(e),!this.isVisible(e))return;const s=e.querySelector("canvas, img");if(!s)return;const a=e.getBoundingClientRect();if(a.width<60||a.height<24)return;const r=s;if(this.detectedCaptchas.some(t=>t.element===e||t.element===r))return;const d={id:`captcha-${t}-${n}`,type:"canvas",subType:t,element:e,innerCanvas:r,rect:a,confidence:this.calculateConfidence(e)+10,inputElement:this.findRelatedInput(e),elementInfo:this.extractCaptchaInfo(e)};this.detectedCaptchas.push(d),w.debug(`检测到交互式验证码 (${t}):`,d.elementInfo)},d=e=>e.flatMap(e=>[`[class*="${e}" i]`,`[id*="${e}" i]`,`[data-captcha-type*="${e}" i]`]).join(",");if(n.length){const e=d(n);try{document.querySelectorAll(e).forEach((e,t)=>{a(e,n)&&r(e,"slider",t)})}catch{document.querySelectorAll("div, section, span").forEach((e,t)=>{i>600||a(e,n)&&r(e,"slider",t)})}}if(s.length){const e=d(s);try{document.querySelectorAll(e).forEach((e,t)=>{a(e,s)&&r(e,"click-select",t)})}catch{document.querySelectorAll("div, section, span").forEach((e,t)=>{i>600||a(e,s)&&r(e,"click-select",t)})}}}extractCaptchaInfo(e){const t=e.getBoundingClientRect();return{tagName:e.tagName.toLowerCase(),id:e.id||null,className:e.className?.toString?.()||"",width:Math.round(t.width),height:Math.round(t.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,s=t.height;return e instanceof HTMLImageElement&&(0===n&&e.naturalWidth>0&&(n=e.naturalWidth),0===s&&e.naturalHeight>0&&(s=e.naturalHeight),0===n&&(n=parseInt(e.getAttribute("width")||"0")||0),0===s&&(s=parseInt(e.getAttribute("height")||"0")||0)),{width:n,height:s}}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 s=window.getComputedStyle(e);if("none"===s.display||"hidden"===s.visibility||"0"===s.opacity)return!1;const i=e.getBoundingClientRect();return!(i.width<=0&&i.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){const t=this.getImageSrcForExclusionCheck(e),n=(e.alt||"").toLowerCase(),s=(e.className?.toString?.()||"").toLowerCase(),i=(e.id||"").toLowerCase(),o=this.getExcludePatterns(),a=`${t} ${n} ${s} ${i}`.trim();return o.some(e=>a.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!1;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>=b.MIN_CAPTCHA_WIDTH&&e<=b.MAX_CAPTCHA_WIDTH&&t>=b.MIN_CAPTCHA_HEIGHT&&t<=b.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){for(const t of["el-checkbox__original","ant-checkbox-input","ivu-checkbox-input","van-checkbox__input","weui-check","mdui-checkbox-input","mdc-checkbox__native-control"])if(e.classList.contains(t))return!0;for(const t of[".el-checkbox",".ant-checkbox",".ant-checkbox-wrapper",".ivu-checkbox",".ivu-checkbox-wrapper",".van-checkbox",".weui-check__label",".mdui-checkbox",".mdc-checkbox"])if(e.closest(t))return!0;return!1}isCheckboxFunctional(e){if(e.disabled)return!1;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!0}let n=e.parentElement,s=0;for(;n&&s<5;){const e=window.getComputedStyle(n);if("none"===e.display)return!1;if("hidden"===e.visibility)return!1;n=n.parentElement,s++}return!0}if("none"===window.getComputedStyle(e).display)return!1;let t=e.parentElement,n=0;for(;t&&n<5;){const e=window.getComputedStyle(t);if("none"===e.display||"hidden"===e.visibility)return!1;t=t.parentElement,n++}return!0}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 s=e.closest(".ivu-checkbox-wrapper");if(s)return s.querySelector(".ivu-checkbox-inner")||s;const i=e.closest(".van-checkbox");return i?i.querySelector(".van-checkbox__icon")||i:e.closest("label")||null}matchesKeywords(e){const t=(e.className?.toString?.()||"").toLowerCase(),n=(e.id||"").toLowerCase();return this.getCaptchaKeywords().some(e=>t.includes(e)||n.includes(e))}srcContainsKeywords(e){if(!e)return!1;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!0;t=t.parentElement,n++}return!1}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 b.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 s=this.calculateDistance(t,n);let i=0;const o=this.getInputSearchText(e);return this.isCaptchaInputByName(e)&&(i+=120),o.includes("验证码")&&(i+=140),o.includes("verify")&&(i+=80),o.includes("vcode")&&(i+=80),o.includes("authcode")&&(i+=80),o.includes("checkcode")&&(i+=80),o.includes("yzm")&&(i+=60),this.isExcludedInputByText(e)&&(i-=200),s-i}findClosestInputInContainer(e,t,n=Infinity){const s=e.querySelectorAll("input");let i=null,o=Infinity,a=Infinity;for(const r of s){const e=r;if(!this.isValidCaptchaInput(e))continue;if(this.isExcludedInputByText(e)&&!this.isCaptchaInputByName(e))continue;const s=r.getBoundingClientRect(),d=this.calculateDistance(t,s);if(d>n)continue;const c=this.scoreInputCandidate(e,t,s);(cn.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 s=this.scoreInputCandidate(e,n,t);s{if(!this.isVisible(e))return;const{width:t,height:i}=this.getEffectiveSize(e);if(!this.isCaptchaSize(t,i))return;if(this.isExcludedImage(e))return;const o=e.getBoundingClientRect(),a=this.calculateDistance(n,o);s.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 i=this.calculateDistance(n,t);s.push({element:e,distance:i,type:"canvas"})}),document.querySelectorAll("svg").forEach(e=>{if(!this.isVisible(e))return;const t=e.clientWidth||parseInt(e.getAttribute("width")||"0"),i=e.clientHeight||parseInt(e.getAttribute("height")||"0");if(!this.isCaptchaSize(t,i))return;const o=e.getBoundingClientRect(),a=this.calculateDistance(n,o);s.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 i=t.style.backgroundImage||"";if(!i||"none"===i)return;const o=t.getBoundingClientRect();if(!this.isCaptchaSize(o.width,o.height))return;const a=this.calculateDistance(n,o);s.push({element:t,distance:a,type:"background"})}),s.sort((e,t)=>e.distance-t.distance);const i=s.slice(0,3);for(const o of i){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 w.debug("猜测的验证码元素:",t),t}guessRelatedInput(e){const t=[],n=e.getBoundingClientRect();w.debug("开始猜测关联的输入框, 验证码位置:",n);const s=[];document.querySelectorAll("input").forEach(e=>{const t=e;if(!this.isValidCaptchaInput(t))return;if(!this.isVisible(t))return;const i=t.getBoundingClientRect(),o=this.calculateDistance(n,i),a=this.isCaptchaInputByName(t),r=this.scoreInputCandidate(t,n,i);s.push({element:t,distance:o,hasKeyword:a,score:r})}),s.sort((e,t)=>e.score-t.score);const i=s.slice(0,3);for(const o of i){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 w.debug("猜测的输入框元素:",t),t}guessAgreementCheckboxes(){const e=[];return document.querySelectorAll("input[type=\"checkbox\"]").forEach(t=>{const n=t;if(!this.isCheckboxFunctional(n))return;if(this.checkedAgreements.has(n))return;const s=[];s.push(n.name||""),s.push(n.id||""),s.push(n.className||""),s.push(n.getAttribute("data-type")||""),s.push(n.getAttribute("data-name")||""),s.push(n.getAttribute("aria-label")||""),s.push(n.getAttribute("data-v-inspector")||"");const i=n.id?document.querySelector(`label[for="${n.id}"]`):null;i&&(s.push(i.textContent||""),s.push(i.className||""));const o=n.closest("label");o&&(s.push(o.textContent||""),s.push(o.className||""));const a=[n.closest(".el-checkbox"),n.closest(".ant-checkbox-wrapper"),n.closest(".ivu-checkbox-wrapper"),n.closest(".van-checkbox"),n.closest("[class*=\"checkbox\"]")];for(const e of a)e&&(s.push(e.textContent||""),s.push(e.className||""));let r=n.parentElement,d=0;for(;r&&d<6;){const e=r.tagName.toLowerCase();if(s.push(r.className||""),s.push(r.id||""),["label","div","span","p","li","td"].includes(e)){const e=r.children;for(let t=0;tl.includes(e))){const t=this.findClickableTarget(n);e.push({element:n,type:"agreement",confidence:80,selector:this.generateSelector(n),clickTarget:t||void 0})}}),w.debug("猜测的协议复选框:",e),e}findAgreementsBySelectors(e){const t=[];for(const s of e)if(s.trim())try{document.querySelectorAll(s).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:s,clickTarget:n||void 0})}})}catch(n){w.warn("无效的协议选择器:",s,n)}return t}markAgreementChecked(e){this.checkedAgreements.add(e)}calculateDistance(e,t){const n=e.left+e.width/2,s=e.top+e.height/2,i=t.left+t.width/2,o=t.top+t.height/2;return Math.sqrt(Math.pow(i-n,2)+Math.pow(o-s,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 s=e;for(;s&&s!==document.body&&n.length<5;){let e=s.tagName.toLowerCase();if(s.id){n.unshift("#"+s.id);break}const t=s.parentElement;if(t){const n=Array.from(t.children).filter(e=>e.tagName===s.tagName);n.length>1&&(e+=":nth-of-type("+(n.indexOf(s)+1)+")")}n.unshift(e),s=s.parentElement}return n.join(" > ")}async captureImage(e){if(e.innerCanvas)return e.innerCanvas instanceof HTMLCanvasElement?this.captureCanvasElement(e.innerCanvas):this.captureImgElement(e.innerCanvas);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){return await(await this.captureBlob(e)).arrayBuffer()}async captureBlob(e){if(e.innerCanvas)return e.innerCanvas instanceof HTMLCanvasElement?this.captureCanvasAsBlob(e.innerCanvas):this.captureImgAsBlob(e.innerCanvas);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"),s=e.naturalWidth||e.width,i=e.naturalHeight||e.height;t.width=s,t.height=i,n.drawImage(e,0,0,s,i);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"),s=e.naturalWidth||e.width,i=e.naturalHeight||e.height;return t.width=s,t.height=i,n.fillStyle="#FFFFFF",n.fillRect(0,0,s,i),n.drawImage(e,0,0,s,i),await new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("图片转换失败"))},"image/png")})}async waitForImageLoad(e){if(!(e.complete&&e.naturalWidth>0||e.src?.startsWith("data:")&&e.naturalWidth>0))return new Promise((t,n)=>{const s=setTimeout(()=>n(new Error("图片加载超时")),5e3),i=()=>{a(),t()},o=()=>{a(),n(new Error("图片加载失败"))},a=()=>{clearTimeout(s),e.removeEventListener("load",i),e.removeEventListener("error",o)};e.addEventListener("load",i),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(!0),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 s=(new XMLSerializer).serializeToString(t),i=new Blob([s],{type:"image/svg+xml"}),o=URL.createObjectURL(i);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 s=t.getContext("2d");return s.fillStyle="#FFFFFF",s.fillRect(0,0,t.width,t.height),s.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:"))return await(await fetch(n)).blob();const s=new Image;s.crossOrigin="anonymous",s.src=n,await new Promise((e,t)=>{s.onload=()=>e(),s.onerror=()=>t(new Error("背景图加载失败")),setTimeout(()=>t(new Error("背景图加载超时")),5e3)});const i=document.createElement("canvas"),o=e.getBoundingClientRect();i.width=Math.max(1,Math.round(o.width)),i.height=Math.max(1,Math.round(o.height));const a=i.getContext("2d");return a.fillStyle="#FFFFFF",a.fillRect(0,0,i.width,i.height),a.drawImage(s,0,0,i.width,i.height),new Promise((e,t)=>{i.toBlob(n=>{n?e(n):t(new Error("背景图转换失败"))},"image/png")})}blobToDataURL(e){return new Promise((t,n)=>{const s=new FileReader;s.onload=()=>t(String(s.result)),s.onerror=()=>n(new Error("读取失败")),s.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""}},C=class{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){this.listeners.get(e)?.delete(t)}emit(e,t){this.listeners.get(e)?.forEach(n=>{try{n(t)}catch(s){console.error(`Event handler error [${String(e)}]:`,s)}})}clear(){this.listeners.clear()}},S="en";function E(e){S=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 k(e){S=e}function A(){return S}function R(e,...t){let n=(I[S]||I.en)[e]??I.en[e]??e;for(let s=0;sddddocr 项目的模型进行开发,遵循 MIT License 许可证开源发布。如果有帮到你,请给我点个⭐,你的⭐是我持续开发的动力😁!","about.openSource.repoInfo":"🏠 仓库地址:Mieru-OCR 开源不易,基于本项目修改请注明出处,感谢你的支持和肯定。","settings.pageTitle":"Mieru-OCR - 设置","picker.selectCaptcha":"点击选择验证码元素","picker.selectInput":"点击选择输入框","picker.cancel":"取消 (ESC)","picker.guessCaptcha":"点击粉色虚线框选择验证码","picker.guessInput":"点击粉色虚线框选择输入框","us.ready":"Mieru-OCR 已就绪","us.readyAutoDetect":"自动检测已启用","us.readyManual":"点击菜单启用自动检测","us.initFailed":"初始化失败","us.initFailedMsg":"初始化失败: {0}","us.loading":"正在初始化 Mieru-OCR","us.loadingDefault":"正在初始化 Mieru-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.unknownError":"未知错误","ctxToast.resultLabel":"识别结果","ctxToast.errorLabel":"识别出错","ctxToast.filled":"已填入输入框","ctxToast.copied":"已复制","ctxToast.noInput":"未找到输入框(可手动粘贴)","ctxToast.fillFailed":"填入失败(可手动粘贴)","ctxToast.copyFailed":"复制失败","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":"Mieru-OCR 设置","settings.tab.general":"基本设置","settings.tab.rules":"网站规则","settings.tab.stats":"识别统计","settings.tab.calculate":"四则运算","settings.tab.model":"模型管理","settings.tab.whitelist":"站点白名单","settings.tab.subscription":"订阅规则","sub.title":"订阅规则","sub.add":"添加订阅","sub.url":"订阅 URL","sub.urlPlaceholder":"https://example.com/rules.json","sub.name":"名称(可选)","sub.namePlaceholder":"订阅名称","sub.updateInterval":"自动更新(小时)","sub.intervalNever":"不自动更新","sub.refresh":"更新","sub.refreshAll":"全部更新","sub.delete":"删除","sub.enabled":"启用","sub.disabled":"已禁用","sub.empty":"尚未添加订阅","sub.statusNever":"从未更新","sub.statusSuccess":"更新成功","sub.statusError":"更新失败","sub.statusPending":"更新中...","sub.lastUpdated":"上次更新","sub.invalidUrl":"URL 格式无效","sub.exists":"该订阅已存在","sub.added":"已添加订阅","sub.refreshing":"正在更新订阅...","sub.refreshSuccess":"订阅 {0} 更新成功","sub.refreshFailed":"订阅 {0} 更新失败:{1}","sub.deleteConfirm":"确定删除订阅 {0}?同时移除它带来的所有规则。","sub.hint":"订阅 URL 必须返回 JSON 格式的规则包。可定时自动更新。","sub.formatLink":"查看订阅规则包格式说明","sub.rulesCount":"{0} 站点规则、{1} 关键词","model.builtinName":"内置默认模型","model.activeLabel":"当前使用","model.customTitle":"自定义模型","model.uploadTitle":"上传新模型","model.modelName":"模型名称","model.modelNamePlaceholder":"例如:my-captcha-v2","model.modelDescription":"描述(可选)","model.modelFile":"模型文件 (.onnx)","model.charsetsFile":"字符表文件 (charsets.json)","model.uploadBtn":"上传","model.deleteBtn":"删除","model.useThis":"使用此模型","model.usedNow":"✓ 使用中","model.testBtn":"测试","model.empty":"尚未上传自定义模型","model.uploaded":"上传时间","model.fileSize":"大小","model.charsetsCount":"字符数","model.uploadSuccess":"模型 {0} 上传成功","model.uploadFailed":"上传失败:{0}","model.testing":"正在测试模型...","model.testOk":"✓ 模型可正常运行","model.testFailed":"✗ 模型测试失败:{0}","model.deleteConfirm":"确定删除模型「{0}」?","model.deleted":"模型已删除","model.activated":"已切换到模型「{0}」","model.storageUsage":"自定义模型已用:{0}(自定义 {1} 个 · 内置 {2} 个)","model.fillBoth":"请同时选择模型文件和字符表文件","model.nameRequired":"请输入模型名称","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":"规则已添加"},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":"サイト","common.chooseFile":"ファイルを選択","common.noFileChosen":"ファイルが選択されていません","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":"コンソールに詳細ログを出力し、診断レポート用に最近のログを本地にキャッシュします。オフにすると即座に収集を停止","diag.title":"診断レポート","diag.hint":"デバッグモード時のみ収集。すべて本地保存され、エクスポート時に長い URL や CSS セレクタ、統計のドメインを匿名化します。エクスポート後、内容を確認してから Issue に添付してください","diag.includeLogs":"実行ログ","diag.includeEnv":"環境情報","diag.includeSettings":"設定 + モデル","diag.includeStats":"認識統計","diag.export":"診断レポートをエクスポート (.json)","diag.clear":"収集済みログを消去","diag.disabled":"先に「デバッグモード」をオンにして収集を開始してください","diag.exporting":"レポートを生成中…","diag.exported":"{0} をダウンロードしました(ログ {1} 件)","diag.exportFailed":"エクスポート失敗:{0}","diag.cleared":"{0} 個のコンテキストのログを消去しました","diag.clearFailed":"消去失敗:{0}","settings.autoSolveOnRule":"ルール一致時に自動認識","settings.autoSolveOnRule.hint":"保存済みルールを検出したら自動的に認識を開始","settings.imageContextMenuEnabled":"画像右クリックメニュー","settings.imageContextMenuEnabled.hint":"ブラウザのネイティブ右クリックメニューに「Mieru-OCR でこの画像を認識」を追加(画像上のみ表示)","settings.imageContextMenuAutoFill":"右クリック認識後に自動入力","settings.imageContextMenuAutoFill.hint":"認識結果は常にクリップボードにコピー。有効時は近くの入力欄への自動入力も試みます","settings.preserveFocus":"入力時にフォーカスを保持","settings.preserveFocus.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.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":"Mieru-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":"🏠 リポジトリ:Mieru-OCR オープンソースの維持は大変です。本プロジェクトを改変する場合は出典を明記してください。ご支援に感謝します。","settings.pageTitle":"Mieru-OCR - 設定","picker.selectCaptcha":"クリックしてCAPTCHA要素を選択","picker.selectInput":"クリックして入力欄を選択","picker.cancel":"キャンセル (ESC)","picker.guessCaptcha":"ピンクの点線枠をクリックしてCAPTCHAを選択","picker.guessInput":"ピンクの点線枠をクリックして入力欄を選択","us.ready":"Mieru-OCR 準備完了","us.readyAutoDetect":"自動検出が有効です","us.readyManual":"メニューから自動検出を有効にしてください","us.initFailed":"初期化に失敗","us.initFailedMsg":"初期化に失敗: {0}","us.loading":"Mieru-OCRを初期化中","us.loadingDefault":"Mieru-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.unknownError":"不明なエラー","ctxToast.resultLabel":"認識結果","ctxToast.errorLabel":"認識エラー","ctxToast.filled":"入力欄に自動入力","ctxToast.copied":"コピー済み","ctxToast.noInput":"入力欄が見つかりません(手動で貼り付け可)","ctxToast.fillFailed":"入力に失敗(手動で貼り付け可)","ctxToast.copyFailed":"コピー失敗","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":"Mieru-OCR 設定","settings.tab.general":"基本設定","settings.tab.rules":"サイトルール","settings.tab.stats":"認識統計","settings.tab.calculate":"四則演算","settings.tab.model":"モデル管理","settings.tab.whitelist":"ホワイトリスト","settings.tab.subscription":"購読ルール","sub.title":"購読ルール","sub.add":"購読を追加","sub.url":"購読 URL","sub.urlPlaceholder":"https://example.com/rules.json","sub.name":"名前(任意)","sub.namePlaceholder":"購読名","sub.updateInterval":"自動更新(時間)","sub.intervalNever":"自動更新しない","sub.refresh":"更新","sub.refreshAll":"すべて更新","sub.delete":"削除","sub.enabled":"有効","sub.disabled":"無効","sub.empty":"購読が追加されていません","sub.statusNever":"未更新","sub.statusSuccess":"更新成功","sub.statusError":"更新失敗","sub.statusPending":"更新中...","sub.lastUpdated":"最終更新","sub.invalidUrl":"URL の形式が無効です","sub.exists":"この購読は既に存在します","sub.added":"購読を追加しました","sub.refreshing":"購読を更新中...","sub.refreshSuccess":"購読 {0} を更新しました","sub.refreshFailed":"購読 {0} の更新に失敗:{1}","sub.deleteConfirm":"購読 {0} を削除しますか?関連するルールもすべて削除されます。","sub.hint":"購読 URL は JSON 形式のルールパッケージを返す必要があります。定期的に自動更新できます。","sub.formatLink":"購読ルールパッケージのフォーマット説明を見る","sub.rulesCount":"{0} サイトルール、{1} キーワード","model.builtinName":"組み込みモデル","model.activeLabel":"使用中","model.customTitle":"カスタムモデル","model.uploadTitle":"新しいモデルをアップロード","model.modelName":"モデル名","model.modelNamePlaceholder":"例: my-captcha-v2","model.modelDescription":"説明(任意)","model.modelFile":"モデルファイル (.onnx)","model.charsetsFile":"文字表ファイル (charsets.json)","model.uploadBtn":"アップロード","model.deleteBtn":"削除","model.useThis":"このモデルを使用","model.usedNow":"✓ 使用中","model.testBtn":"テスト","model.empty":"カスタムモデルなし","model.uploaded":"アップロード時刻","model.fileSize":"サイズ","model.charsetsCount":"文字数","model.uploadSuccess":"モデル {0} をアップロードしました","model.uploadFailed":"アップロード失敗:{0}","model.testing":"モデルをテスト中...","model.testOk":"✓ モデルは正常に動作します","model.testFailed":"✗ モデルテスト失敗:{0}","model.deleteConfirm":"モデル「{0}」を削除しますか?","model.deleted":"モデルを削除しました","model.activated":"モデル「{0}」に切り替えました","model.storageUsage":"カスタムモデル使用量:{0}(カスタム {1} 個 · 内蔵 {2} 個)","model.fillBoth":"モデルファイルと文字表ファイルの両方を選択してください","model.nameRequired":"モデル名を入力してください","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":"ルールを追加しました"},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","common.chooseFile":"Choose File","common.noFileChosen":"No file chosen","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 and cache recent entries locally for diagnostic export. Turning off stops collection immediately","diag.title":"Diagnostic report","diag.hint":"Collected only while debug mode is on. Everything stays local; export redacts long URLs / CSS selectors / hostnames in stats. Review the .json before attaching to an Issue","diag.includeLogs":"Runtime logs","diag.includeEnv":"Environment","diag.includeSettings":"Settings + model","diag.includeStats":"Recognition stats","diag.export":"Export diagnostic report (.json)","diag.clear":"Clear collected logs","diag.disabled":"Turn on \"Debug mode\" first to start collecting logs","diag.exporting":"Building report…","diag.exported":"Downloaded {0} ({1} log entries)","diag.exportFailed":"Export failed: {0}","diag.cleared":"Cleared logs from {0} contexts","diag.clearFailed":"Clear failed: {0}","settings.autoSolveOnRule":"Auto solve on rule match","settings.autoSolveOnRule.hint":"Automatically start recognition when a saved rule is detected","settings.imageContextMenuEnabled":"Image right-click menu","settings.imageContextMenuEnabled.hint":"Add \"Recognize image with Mieru-OCR\" to the browser's native context menu, only on images","settings.imageContextMenuAutoFill":"Auto-fill after right-click recognition","settings.imageContextMenuAutoFill.hint":"Result is always copied to clipboard; if enabled, also tries to fill a nearby input","settings.preserveFocus":"Preserve focus while filling","settings.preserveFocus.hint":"Off: steal focus to the captcha input (more visible, but may trigger anti-bot fingerprinting on some sites). On: fill silently and restore focus to where the user was","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.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":"Mieru-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: Mieru-OCR Open source is hard work. If you modify this project, please credit the source. Thank you for your support!","settings.pageTitle":"Mieru-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":"Mieru-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 Mieru-OCR","us.loadingDefault":"Initializing Mieru-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.unknownError":"Unknown error","ctxToast.resultLabel":"Recognized","ctxToast.errorLabel":"Error","ctxToast.filled":"Filled into input","ctxToast.copied":"Copied","ctxToast.noInput":"No input found (paste manually)","ctxToast.fillFailed":"Fill failed (paste manually)","ctxToast.copyFailed":"Copy failed","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":"Mieru-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.subscription":"Subscriptions","sub.title":"Rule Subscriptions","sub.add":"Add Subscription","sub.url":"Subscription URL","sub.urlPlaceholder":"https://example.com/rules.json","sub.name":"Name (optional)","sub.namePlaceholder":"Subscription name","sub.updateInterval":"Auto-update (hours)","sub.intervalNever":"Never auto-update","sub.refresh":"Refresh","sub.refreshAll":"Refresh All","sub.delete":"Delete","sub.enabled":"Enabled","sub.disabled":"Disabled","sub.empty":"No subscriptions added yet","sub.statusNever":"Never updated","sub.statusSuccess":"Updated successfully","sub.statusError":"Update failed","sub.statusPending":"Updating...","sub.lastUpdated":"Last updated","sub.invalidUrl":"Invalid URL format","sub.exists":"Subscription already exists","sub.added":"Subscription added","sub.refreshing":"Refreshing subscription...","sub.refreshSuccess":"Subscription {0} refreshed","sub.refreshFailed":"Failed to refresh {0}: {1}","sub.deleteConfirm":"Delete subscription {0}? All rules from it will be removed.","sub.hint":"Subscription URL must return a JSON rule package. Can auto-update on schedule.","sub.formatLink":"View subscription rule package format","sub.rulesCount":"{0} site rules, {1} keywords","model.builtinName":"Built-in Default Model","model.activeLabel":"In Use","model.customTitle":"Custom Models","model.uploadTitle":"Upload New Model","model.modelName":"Model Name","model.modelNamePlaceholder":"e.g. my-captcha-v2","model.modelDescription":"Description (optional)","model.modelFile":"Model File (.onnx)","model.charsetsFile":"Charsets File (charsets.json)","model.uploadBtn":"Upload","model.deleteBtn":"Delete","model.useThis":"Use This Model","model.usedNow":"✓ Active","model.testBtn":"Test","model.empty":"No custom models uploaded yet","model.uploaded":"Uploaded","model.fileSize":"Size","model.charsetsCount":"Chars","model.uploadSuccess":"Model {0} uploaded","model.uploadFailed":"Upload failed: {0}","model.testing":"Testing model...","model.testOk":"✓ Model runs correctly","model.testFailed":"✗ Model test failed: {0}","model.deleteConfirm":"Delete model \"{0}\"?","model.deleted":"Model deleted","model.activated":"Switched to model \"{0}\"","model.storageUsage":"Custom models used: {0} ({1} custom · {2} built-in)","model.fillBoth":"Please select both the model and charsets files","model.nameRequired":"Please enter a model name","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"}},T="ddddocr_model_cache",M="ddddocr_uploaded_model",L=class{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(T);n.onerror=()=>t(n.error),n.onsuccess=()=>{const t=n.result;if(t)return Date.now()-t.timestamp>b.CACHE_DURATION||t.version!==b.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:b.MODEL_VERSION};return new Promise((e,t)=>{const s=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,T);s.onerror=()=>t(s.error),s.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(T);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(M);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 s=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,M);s.onerror=()=>t(s.error),s.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(M);n.onerror=()=>t(n.error),n.onsuccess=()=>e()})}};function $(e,t=3e4){return new Promise((n,s)=>{GM_xmlhttpRequest({method:"GET",url:e,responseType:"arraybuffer",timeout:t,headers:{"Cache-Control":"max-age=2592000"},onload:e=>{200===e.status?n(e.response):s(new Error(`HTTP ${e.status}`))},onerror:e=>s(e),ontimeout:()=>s(new Error(R("model.downloadTimeout")))})})}function P(e,t=3e4){return new Promise((n,s)=>{GM_xmlhttpRequest({method:"GET",url:e,responseType:"json",timeout:t,headers:{"Cache-Control":"max-age=2592000"},onload:e=>{200===e.status?n(e.response):s(new Error(`HTTP ${e.status}`))},onerror:e=>s(e),ontimeout:()=>s(new Error(R("model.downloadTimeout")))})})}function F(e,t){const n=e.replace(/\/+$/,""),s=t.replace(/^\/+/,"");if(n.includes("jsdelivr"))return`${n}/${b.MODEL_REPO}@${b.MODEL_BRANCH}/${s}`;const i=`/${b.MODEL_REPO}/`;return n.includes(i)?`${n}/${s}`:`${n}/${b.MODEL_REPO}/${b.MODEL_BRANCH}/${s}`}async function D(){const e=GM_getValue("ddddocr_config")||{},t=new L;if(e.useUploadedModel){const e=await t.getUploadedModel();if(e)return console.log("✅ 使用上传的模型"),{model:e.model,charsets:e.charsets}}if(!1===e.autoDownload)throw new Error(R("model.downloadDisabled"));const n=await t.get();if(n)return console.log("✅ 使用缓存的模型"),{model:n.model,charsets:n.charsets};console.log("📥 开始下载模型");let s=null,i=null;for(let a=0;ae.includes("jsdelivr")?`${e}/npm/onnxruntime-web@${b.WASM_VERSION}/dist/`:e.includes("unpkg")?`${e}/onnxruntime-web@${b.WASM_VERSION}/dist/`:e.includes("cdnjs")?`${e}/ajax/libs/onnxruntime-web/${b.WASM_VERSION}/`:e.includes("npmmirror")?`${e}/onnxruntime-web/${b.WASM_VERSION}/files/dist/`:`${e}/onnxruntime-web@${b.WASM_VERSION}/dist/`),H=["ort-wasm.wasm","ort-wasm-simd.wasm","ort-wasm-threaded.wasm","ort-wasm-simd-threaded.wasm"],O=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>b.CACHE_DURATION||n.version!==b.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:b.WASM_VERSION};return new Promise((t,s)=>{try{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,e);i.onerror=()=>s(i.error),i.onsuccess=()=>t()}catch(i){s(i)}})}async delete(e){return this.memoryCache.delete(e),this.db||await this.init(),new Promise((t,n)=>{try{const s=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(e);s.onerror=()=>n(s.error),s.onsuccess=()=>t()}catch(s){n(s)}})}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 _(e){for(let n=0;n{GM_xmlhttpRequest({method:"GET",url:s,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===N.length-1)throw new Error(`所有 WASM CDN 均下载失败: ${e}`)}}throw new Error(`下载 WASM 失败: ${e}`)}var z=class{static{this.container=null}static{this.stylesInjected=!1}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=!0}static stopPropagation(e){e.stopPropagation()}static show(e){this.injectStyles(),this.close();const t=document.createElement("div");t.className="ddddocr-dialog-overlay";const n=document.createElement("div");n.className="ddddocr-dialog",this.isMobile()&&n.classList.add("mobile"),n.innerHTML=`\n
${e.icon||"ℹ️"} ${e.title}
\n
\n
${e.content}
\n
\n \n `,t.appendChild(n),document.body.appendChild(t),this.container=t,n.addEventListener("mousedown",this.stopPropagation),n.addEventListener("mouseup",this.stopPropagation),n.addEventListener("click",this.stopPropagation),n.addEventListener("dblclick",this.stopPropagation),n.addEventListener("wheel",this.stopPropagation),n.addEventListener("keydown",this.stopPropagation),n.addEventListener("keyup",this.stopPropagation),n.addEventListener("keypress",this.stopPropagation),n.addEventListener("contextmenu",this.stopPropagation),n.addEventListener("touchstart",this.stopPropagation,{passive:!0}),n.addEventListener("touchmove",this.stopPropagation,{passive:!0}),n.addEventListener("touchend",this.stopPropagation),n.querySelector(".ddddocr-dialog-button")?.addEventListener("click",()=>{e.onConfirm?.(),this.close()}),t.addEventListener("click",e=>{e.target===t&&this.close()})}static confirm(e){this.injectStyles(),this.close();const t=document.createElement("div");t.className="ddddocr-dialog-overlay";const n=document.createElement("div");n.className="ddddocr-dialog",this.isMobile()&&n.classList.add("mobile"),n.innerHTML=`\n
${e.icon||"❓"} ${e.title}
\n
\n
${e.content}
\n
\n \n `,t.appendChild(n),document.body.appendChild(t),this.container=t,n.addEventListener("mousedown",this.stopPropagation),n.addEventListener("mouseup",this.stopPropagation),n.addEventListener("click",this.stopPropagation),n.addEventListener("dblclick",this.stopPropagation),n.addEventListener("wheel",this.stopPropagation),n.addEventListener("keydown",this.stopPropagation),n.addEventListener("keyup",this.stopPropagation),n.addEventListener("keypress",this.stopPropagation),n.addEventListener("contextmenu",this.stopPropagation),n.addEventListener("touchstart",this.stopPropagation,{passive:!0}),n.addEventListener("touchmove",this.stopPropagation,{passive:!0}),n.addEventListener("touchend",this.stopPropagation),n.querySelector(".confirm-btn")?.addEventListener("click",()=>{e.onConfirm?.(),this.close()}),n.querySelector(".cancel-btn")?.addEventListener("click",()=>{e.onCancel?.(),this.close()}),t.addEventListener("click",n=>{n.target===t&&(e.onCancel?.(),this.close())})}static close(){this.container?.remove(),this.container=null}},B="ddddocr_config_version",U="ddddocr_stats",K="ddddocr_site_rules",q=function(e,t,n){const s=()=>e(B)||1,i=e=>t(B,e);return{getConfig:()=>function(e,t,n){if(!e)return n(2),{...f};const s=t();let i={...f};for(const o of Object.keys(e)){const t=e[o];void 0!==t&&o in f&&(i[o]=t)}if(s<2&&e.agreementSelector&&(!i.agreementSelectors||0===i.agreementSelectors.length)){const t=e.agreementSelector.trim();t&&(i.agreementSelectors=[t])}for(const o of Object.keys(f))void 0===i[o]&&(i[o]=f[o]);return 2!==s&&n(2),i}(e(n),s,i),saveConfig(e){t(n,{...this.getConfig(),...e})},resetConfig(){t(n,f),i(2)}}}(e=>GM_getValue(e),(e,t)=>GM_setValue(e,t),"ddddocr_config");function j(){return q.getConfig()}function W(e){q.saveConfig(e)}function V(){return GM_getValue(K)||{}}function G(e,t){const n=V(),s=t.fullUrl||t.urlPattern||e,i=n[s]||{};n[s]={...i,...t,hostname:e,createdAt:i.createdAt||Date.now(),updatedAt:Date.now(),enabled:!1!==t.enabled},GM_setValue(K,n)}function X(e){const t=V();delete t[e],GM_setValue(K,t)}var Y=new class{constructor(e){this.dirty=!1,this.saveTimer=null,this.storage=e,this.data=this.load()}load(){const e=this.storage.get(U);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(U,this.data),this.dirty=!1)}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=!0,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=!0,this.flush()}}({get:e=>GM_getValue(e),set:(e,t)=>GM_setValue(e,t)});function J(){const e=j();if(!e.enableWhitelist)return!0;if(!e.whitelist||0===e.whitelist.length)return!1;const t=window.location.hostname;return e.whitelist.some(e=>new RegExp("^"+e.replace(/\*/g,".*")+"$","i").test(t))}function Q(){const e=j();if(e.enableWhitelist){if(!e.whitelist||0===e.whitelist.length)return!1;if(!J())return!1}return!0}function Z(e){return!!e.enabled&&!(e.updateInterval<=0)&&("never"===e.lastStatus||"error"===e.lastStatus||Date.now()-e.lastUpdated>=3600*e.updateInterval*1e3)}var ee="ddddocr_subscriptions",te={fetch:(e,t=3e4)=>new Promise((n,s)=>{try{GM_xmlhttpRequest({method:"GET",url:e,timeout:t,headers:{Accept:"application/json"},onload:e=>{e.status>=200&&e.status<300?n(e.responseText):s(new Error(`HTTP ${e.status}`))},onerror:()=>s(new Error("网络请求失败")),ontimeout:()=>s(new Error("请求超时"))})}catch(i){s(i)}})};function ne(){return GM_getValue(ee)||[]}function se(e){GM_setValue(ee,e)}function ie(e,t){const n=ne(),s=n.findIndex(t=>t.id===e);s<0||(n[s]={...n[s],...t},se(n))}async function oe(e){const t=ne(),n=t.findIndex(t=>t.id===e);if(n<0)return{success:!1,error:"订阅不存在"};const s=t[n];ie(e,{lastStatus:"pending"});try{const t=await async function(e,t,n=3e4){const s=await t.fetch(e,n);let i;try{i=JSON.parse(s)}catch(a){throw new Error("订阅内容不是有效的 JSON: "+a.message)}const o=function(e){return e&&"object"==typeof e?e.name&&"string"==typeof e.name?e.version&&"string"==typeof e.version?{valid:!0,pkg:{name:e.name,description:"string"==typeof e.description?e.description:void 0,version:e.version,author:"string"==typeof e.author?e.author:void 0,siteRules:"object"==typeof e.siteRules&&null!==e.siteRules?e.siteRules:void 0,calculateRules:Array.isArray(e.calculateRules)?e.calculateRules:void 0,includeKeywords:Array.isArray(e.includeKeywords)?e.includeKeywords.filter(e=>"string"==typeof e):void 0,excludePatterns:Array.isArray(e.excludePatterns)?e.excludePatterns.filter(e=>"string"==typeof e):void 0,agreementKeywords:Array.isArray(e.agreementKeywords)?e.agreementKeywords.filter(e=>"string"==typeof e):void 0,inputExcludeKeywords:Array.isArray(e.inputExcludeKeywords)?e.inputExcludeKeywords.filter(e=>"string"==typeof e):void 0,agreementSelectors:Array.isArray(e.agreementSelectors)?e.agreementSelectors.filter(e=>"string"==typeof e):void 0,siteBlacklist:Array.isArray(e.siteBlacklist)?e.siteBlacklist.filter(e=>"string"==typeof e):void 0,updatedAt:"number"==typeof e.updatedAt?e.updatedAt:Date.now()}}:{valid:!1,error:"缺少 version 字段"}:{valid:!1,error:"缺少 name 字段"}:{valid:!1,error:"订阅内容不是有效的 JSON 对象"}}(i);if(!o.valid)throw new Error(o.error||"订阅格式错误");return o.pkg}(s.url,te);return s.cachedPackage&&ae(s.id,s.cachedPackage),function(e,t){const n=j(),s=V(),i=function(e,t,n){const s=(e,t)=>{if(!t)return[];const n=new Set(e.map(e=>e.toLowerCase()));return t.filter(e=>{const t=e.toLowerCase();return!n.has(t)&&(n.add(t),!0)})},i=[];if(e.calculateRules){const n=new Set(t.calculateRules.map(e=>e.pattern+"::"+e.matchType));for(const t of e.calculateRules){const e=t.pattern+"::"+t.matchType;n.has(e)||(i.push(t),n.add(e))}}const o=[];if(e.siteRules)for(const[a,r]of Object.entries(e.siteRules))o.push({key:a,rule:{...r,hostname:r.hostname||a,subscriptionId:n}});return{includeKeywordsToAdd:s(t.customIncludeKeywords,e.includeKeywords),excludePatternsToAdd:s(t.customExcludePatterns,e.excludePatterns),agreementKeywordsToAdd:s(t.customAgreementKeywords,e.agreementKeywords),inputExcludeKeywordsToAdd:s(t.customInputExcludeKeywords,e.inputExcludeKeywords),agreementSelectorsToAdd:s(t.agreementSelectors,e.agreementSelectors),siteBlacklistToAdd:s(t.siteBlacklist,e.siteBlacklist),siteRulesToWrite:o,calculateRulesToAdd:i}}(t,{customIncludeKeywords:n.customIncludeKeywords||[],customExcludePatterns:n.customExcludePatterns||[],customAgreementKeywords:n.customAgreementKeywords||[],customInputExcludeKeywords:n.customInputExcludeKeywords||[],agreementSelectors:n.agreementSelectors||[],siteBlacklist:n.siteBlacklist||[],calculateRules:n.calculateRules||[],siteRulesKeys:Object.keys(s)},e),o={};i.includeKeywordsToAdd.length&&(o.customIncludeKeywords=[...n.customIncludeKeywords||[],...i.includeKeywordsToAdd]),i.excludePatternsToAdd.length&&(o.customExcludePatterns=[...n.customExcludePatterns||[],...i.excludePatternsToAdd]),i.agreementKeywordsToAdd.length&&(o.customAgreementKeywords=[...n.customAgreementKeywords||[],...i.agreementKeywordsToAdd]),i.inputExcludeKeywordsToAdd.length&&(o.customInputExcludeKeywords=[...n.customInputExcludeKeywords||[],...i.inputExcludeKeywordsToAdd]),i.agreementSelectorsToAdd.length&&(o.agreementSelectors=[...n.agreementSelectors||[],...i.agreementSelectorsToAdd]),i.siteBlacklistToAdd.length&&(o.siteBlacklist=[...n.siteBlacklist||[],...i.siteBlacklistToAdd]),i.calculateRulesToAdd.length&&(o.calculateRules=[...n.calculateRules||[],...i.calculateRulesToAdd]),Object.keys(o).length&&W(o);for(const{key:a,rule:r}of i.siteRulesToWrite)G(r.hostname||a,{...r,enabled:!0})}(s.id,t),ie(e,{lastStatus:"success",lastUpdated:Date.now(),lastError:void 0,cachedPackage:t,name:s.name===s.url?t.name:s.name}),w.info("订阅更新成功:",s.url,t.name),{success:!0,pkg:t}}catch(i){const n=i.message||String(i);return ie(e,{lastStatus:"error",lastError:n,lastUpdated:Date.now()}),w.error("订阅更新失败:",s.url,n),{success:!1,error:n}}}function ae(e,t){const n=j(),s=e=>e.toLowerCase(),i=(e,t)=>{if(!e||!t||!t.length)return e;const n=new Set(t.map(s));return e.filter(e=>!n.has(s(e)))},o={};if(t.includeKeywords&&(o.customIncludeKeywords=i(n.customIncludeKeywords,t.includeKeywords)),t.excludePatterns&&(o.customExcludePatterns=i(n.customExcludePatterns,t.excludePatterns)),t.agreementKeywords&&(o.customAgreementKeywords=i(n.customAgreementKeywords,t.agreementKeywords)),t.inputExcludeKeywords&&(o.customInputExcludeKeywords=i(n.customInputExcludeKeywords,t.inputExcludeKeywords)),t.agreementSelectors&&(o.agreementSelectors=i(n.agreementSelectors,t.agreementSelectors)),t.siteBlacklist&&(o.siteBlacklist=i(n.siteBlacklist,t.siteBlacklist)),t.calculateRules){const e=new Set(t.calculateRules.map(e=>e.pattern+"::"+e.matchType));o.calculateRules=(n.calculateRules||[]).filter(t=>!e.has(t.pattern+"::"+t.matchType))}if(Object.keys(o).length&&W(o),t.siteRules)for(const a of Object.keys(t.siteRules))X(a)}function re(){return/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)||window.innerWidth<=768}function de(e){const t=document.createElement("div");return t.textContent=e,t.innerHTML}function ce(e){return e?new Date(e).toLocaleDateString():"-"}var le=class{constructor(){this.container=null,this.overlay=null,this.isVisible=!1,this.onConfigChange=()=>{},this.activeTab="general",this.currentEditRuleKey=null,this.containerLocale="",this.mediaQuery=null,this.mediaQueryHandler=null,this.CHIP_META={customIncludeKeywords:{builtin:[...b.CAPTCHA_KEYWORDS],disabledKey:"disabledCaptchaKeywords"},customExcludePatterns:{builtin:[...b.EXCLUDE_PATTERNS],disabledKey:"disabledExcludePatterns"},customAgreementKeywords:{builtin:[...b.AGREEMENT_KEYWORDS],disabledKey:"disabledAgreementKeywords"},customInputExcludeKeywords:{builtin:[...b.INPUT_EXCLUDE_KEYWORDS],disabledKey:"disabledInputExcludeKeywords"}},this.createStyles(),this.handleResize=this.handleResize.bind(this)}handleResize(){this.container&&this.container.classList.toggle("mobile",re())}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=y(j().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"===(j().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",re()&&this.container.classList.add("mobile");const e=j();let t=!1,n=0;try{const e=await(new L).getUploadedModel();e&&(t=!0,n=e.model.byteLength)}catch(r){console.warn("Failed to load uploaded model info:",r)}const s=this.renderCalculateRules(e.calculateRules||[]),i=this.renderSiteRules(),o=this.renderStats(),a=this.renderAgreementSelectors(e.agreementSelectors||[]);this.container.innerHTML=`\n
\n
${R("settings.title")}
\n \n
\n
\n \n \n \n \n \n \n \n
\n
\n \x3c!-- General --\x3e\n
\n
\n
${R("settings.detect.title")}
\n ${this.renderSwitchRow("autoDetect",R("settings.detect.auto"),R("settings.detect.autoHint"),e.autoDetect)}\n ${this.renderSwitchRow("typewriterEffect",R("settings.typewriter"),R("settings.typewriter.hint"),e.typewriterEffect)}\n ${this.renderSwitchRow("autoCheckAgreement",R("settings.autoCheckAgreement"),R("settings.autoCheckAgreement.hint"),e.autoCheckAgreement)}\n ${this.renderSwitchRow("enableNotification",R("settings.notification"),R("settings.notification.hint"),e.enableNotification)}\n ${this.renderSwitchRow("autoSubmit",R("settings.autoSubmit"),R("settings.autoSubmit.hint"),e.autoSubmit??!1)}\n ${this.renderSwitchRow("autoSolveOnRule",R("settings.autoSolveOnRule"),R("settings.autoSolveOnRule.hint"),e.autoSolveOnRule??!0)}\n ${this.renderSwitchRow("preserveFocus",R("settings.preserveFocus"),R("settings.preserveFocus.hint"),e.preserveFocus??!1)}\n ${this.renderSwitchRow("debugMode",R("settings.debugMode"),R("settings.debugMode.hint"),e.debugMode)}\n
\n
\n
${R("diag.title")}
\n
${R("diag.hint")}
\n
\n \n \n
\n
\n
\n
\n
${R("settings.selectors")}
\n
${R("settings.captchaSelector")}
\n \n
${R("settings.inputSelector")}
\n \n
${R("settings.submitSelector")}
\n \n
${R("settings.captchaSelector.hint")}
\n
${R("settings.agreementSelector")}
\n
${a}
\n
\n \n \n
\n
${R("settings.agreementSelector.hint")}
\n
\n
\n
${R("settings.appearance")}
\n
\n
\n
${R("settings.theme")}
\n
\n \n
\n
\n
\n
${R("settings.language")}
\n
${R("settings.language.hint")}
\n
\n \n
\n
\n
\n
${R("settings.keywords.title")}
\n
\n ${this.renderKeywordChipGroupsHtml()}\n
\n
\n
\n\n \x3c!-- Site Rules --\x3e\n
\n
\n
\n
${R("rules.saved")}
\n
\n \n \n
\n
\n
${i}
\n
\n \n
\n
${R("rules.bulk")}
\n
${R("rules.ruleId")}
\n \n
${R("rules.captchaSelector")}
\n \n
${R("rules.inputSelector")}
\n \n \n
\n
\n\n \x3c!-- Subscriptions --\x3e\n
\n
\n
\n
${R("sub.title")}
\n \n
\n
${this.renderSubscriptions()}
\n
\n
\n
${R("sub.add")}
\n
${R("sub.url")}
\n \n
${R("sub.name")}
\n \n
${R("sub.updateInterval")}
\n \n \n
${R("sub.hint")}
\n
\n
\n\n \x3c!-- Statistics --\x3e\n
\n ${o}\n
\n\n \x3c!-- Arithmetic --\x3e\n
\n
\n
${R("calc.arithmetic")}
\n ${this.renderSwitchRow("autoCalculate",R("calc.autoCalc"),R("calc.autoCalcHint"),e.autoCalculate)}\n
\n
${R("calc.outputMode")}
\n \n
${R("calc.outputHint")}
\n
\n
\n
\n
${R("calc.siteRules")}
\n
${s}
\n
\n \n \n \n \n
\n
\n ${R("calc.wildcard")}: ${R("calc.wildcardHint")}
\n ${R("calc.regex")}: ${R("calc.regexHint")}\n
\n
\n
\n\n \x3c!-- Model Management --\x3e\n
\n
\n
${R("model.source")}
\n ${t?`
[${R("common.enabled")}] ${R("model.upload")} (${(n/1024/1024).toFixed(1)} MB)
`:""}\n ${this.renderSwitchRow("useUploadedModel",R("model.source"),R("model.upload"),e.useUploadedModel)}\n ${this.renderSwitchRow("autoDownload",R("settings.detect.auto"),R("model.downloadDisabled"),e.autoDownload)}\n
\n
\n
${R("model.upload")}
\n
\n \n
[ONNX]
\n
${R("model.selectFiles")} common.onnx
\n
\n
\n
\n \n
[JSON]
\n
${R("model.selectFiles")} charsets.json
\n
\n
\n
\n \n \n
\n
\n
\n\n \x3c!-- Site Whitelist --\x3e\n
\n
\n
${R("whitelist.settings")}
\n ${this.renderSwitchRow("enableWhitelist",R("whitelist.title"),R("whitelist.settings"),e.enableWhitelist)}\n
\n \n
${window.location.hostname}
\n
\n
\n
\n
${R("blacklist.title")}
\n
${R("blacklist.label")}
\n \n
${R("blacklist.hint")}
\n
\n
\n
${R("config.importExport")}
\n
\n \n \n \n
\n
\n
\n
\n `,document.body.appendChild(this.overlay),document.body.appendChild(this.container),this.containerLocale=A(),this.applyTheme(),this.setupThemeMediaQuery(),this.renderAllChipGroups(),this.bindEvents(),this.bindChipEvents(),window.addEventListener("resize",this.handleResize)}renderSwitchRow(e,t,n,s){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 ${de(e.pattern)}\n ${"regex"===e.matchType?R("calc.regex"):R("calc.wildcard")}\n ${"result"===e.outputMode?R("calc.outputResult"):R("calc.outputEquation")}\n \n
\n `).join(""):`
${R("calc.noRules")}
`}renderSiteRules(){const e=V(),t=Object.keys(e);return 0===t.length?`
${R("rules.empty")}
`:t.map(t=>{const n=e[t],s=t.length>35?t.substring(0,35)+"...":t,i=n.selector.length>40?n.selector.substring(0,40)+"...":n.selector;return`\n
\n
\n
${de(s)}
\n
${de(i)}
\n ${n.fullUrl?`
${R("rules.fullUrlMatch")}
`:""}\n
\n
\n \n \n
\n
\n `}).join("")}renderStats(){const e=Y.getStats(),t=Object.entries(e.sites||{}),n=t.reduce((e,[,t])=>e+t.totalTime,0),s=e.total>0?Math.round(n/e.total):0,i=e.updated?ce(e.updated):"-";let o="";if(0===t.length)o=`
${R("stats.empty")}
`;else{t.sort((e,t)=>t[1].count-e[1].count);const e=t.slice(0,15),n=e[0]?.[1].count||1;o=e.map(([e,t],s)=>{const i=t.count>0?Math.round(t.totalTime/t.count):0,o=ce(t.lastTime),a=Math.round(t.count/n*100);return`\n
\n
${s+1}
\n
\n
${de(e)}
\n
\n ${R("stats.avg",i)}\n ${R("stats.last",o)}\n
\n
\n
\n
\n
\n
${t.count}
\n
\n `}).join("")}return`\n
\n
\n
${R("stats.totalCount")}
\n
${e.total}${R("common.times")}
\n
\n
\n
${R("stats.siteCount")}
\n
${t.length}${R("common.items")}
\n
\n
\n
${R("stats.avgTime")}
\n
${s}ms
\n
\n
\n
${R("stats.lastUpdate")}
\n
${i}
\n
\n
\n
\n
\n
${R("stats.ranking")}
\n \n
\n
${o}
\n
\n `}renderAgreementSelectors(e){return e&&0!==e.length?e.map((e,t)=>`\n
\n ${de(e)}\n \n
\n `).join(""):`
${R("settings.agreementSelector.empty")}
`}renderSubscriptions(){const e=ne();return e&&0!==e.length?e.map(e=>{const t=e.cachedPackage?Object.keys(e.cachedPackage.siteRules||{}).length:0,n=e.cachedPackage?(e.cachedPackage.includeKeywords?.length||0)+(e.cachedPackage.excludePatterns?.length||0)+(e.cachedPackage.agreementKeywords?.length||0)+(e.cachedPackage.inputExcludeKeywords?.length||0):0;return`\n
\n
\n
${de(e.name)}
\n
${de(e.url)}
\n
\n ${(e=>{switch(e.lastStatus){case"success":return`✓ ${R("sub.statusSuccess")}`;case"error":return`✗ ${R("sub.statusError")}`;case"pending":return`⟳ ${R("sub.statusPending")}`;default:return`${R("sub.statusNever")}`}})(e)}\n ${R("sub.lastUpdated")}: ${s=e.lastUpdated,s?new Date(s).toLocaleString():"-"}\n ${e.cachedPackage?`${R("sub.rulesCount",t,n)}`:""}\n
\n
\n
\n
\n
\n
\n \n \n
\n
\n `;var s}).join(""):`
${R("sub.empty")}
`}refreshSubscriptionsList(){const e=this.container?.querySelector("#subscriptionsList");e&&(e.innerHTML=this.renderSubscriptions()),this.bindSubscriptionEvents()}bindSubscriptionEvents(){this.container&&(this.container.querySelectorAll(".btn-refresh-sub").forEach(e=>{e.addEventListener("click",async e=>{const t=e.currentTarget.dataset.subId;if(!t)return;z.show({title:R("common.hint"),content:R("sub.refreshing"),icon:""});const n=await oe(t),s=ne().find(e=>e.id===t);n.success?z.show({title:R("common.success"),content:R("sub.refreshSuccess",s?.name||t),icon:""}):z.show({title:R("common.error"),content:R("sub.refreshFailed",s?.name||t,n.error||""),icon:""}),this.refreshSubscriptionsList(),this.onConfigChange(j())})}),this.container.querySelectorAll(".btn-delete-sub").forEach(e=>{e.addEventListener("click",e=>{const t=e.currentTarget.dataset.subId;if(!t)return;const n=ne().find(e=>e.id===t);z.confirm({title:R("sub.delete"),content:R("sub.deleteConfirm",n?.name||t),onConfirm:()=>{(function(e,t=!0){const n=ne(),s=n.find(t=>t.id===e);s&&(t&&s.cachedPackage&&ae(s.id,s.cachedPackage),se(n.filter(t=>t.id!==e)))})(t,!0),this.refreshSubscriptionsList(),this.onConfigChange(j())}})})}),this.container.querySelectorAll("[data-sub-toggle]").forEach(e=>{e.addEventListener("click",()=>{const t=e.dataset.subToggle;t&&(e.classList.toggle("on"),ie(t,{enabled:e.classList.contains("on")}))})}))}stopPropagation(e){e.stopPropagation()}bindEvents(){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:!0}),this.container.addEventListener("touchmove",this.stopPropagation,{passive:!0}),this.container.addEventListener("touchend",this.stopPropagation),this.container.querySelector(".ddddocr-close")?.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&&(W({[t]:n}),this.onConfigChange(j())),"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&&(W({[t]:e.value.trim()}),this.onConfigChange(j()))})}),this.container.querySelectorAll("select[data-key]").forEach(e=>{e.addEventListener("change",()=>{const t=e.dataset.key,n=e.value;if(t){if(W({[t]:n}),"theme"===t&&this.container){const e=y(n);for(const[t,n]of Object.entries(e))this.container.style.setProperty(t,n)}if("language"===t)return"auto"===n?E("auto"):k(n),this.onConfigChange(j()),this.destroyContainer(),void this.createContainer().then(()=>{this.isVisible=!0,this.overlay?.classList.add("visible"),this.container?.classList.add("visible"),re()&&this.container?.classList.add("mobile")});this.onConfigChange(j())}})});let e=null;this.container.querySelectorAll("textarea[data-key]").forEach(t=>{t.addEventListener("input",()=>{e&&clearTimeout(e),e=window.setTimeout(()=>{const e=t.dataset.key;if(e){const n=t.value;W({[e]:n.split("\n").filter(e=>e.trim())}),this.onConfigChange(j())}},500)})}),this.container.querySelector("#addAgreementSelectorBtn")?.addEventListener("click",()=>this.addAgreementSelector()),this.bindAgreementSelectorDeleteEvents(),this.container.querySelector("#addCalcRuleBtn")?.addEventListener("click",()=>this.addCalculateRule()),this.bindCalcRuleDeleteEvents(),this.container.querySelector("#addSiteRuleBtn")?.addEventListener("click",()=>this.addSiteRule()),this.container.querySelector("#saveEditRuleBtn")?.addEventListener("click",()=>this.saveEditRule()),this.container.querySelector("#cancelEditRuleBtn")?.addEventListener("click",()=>this.cancelEditRule()),this.container.querySelector("#exportRulesBtn")?.addEventListener("click",()=>this.exportSiteRules()),this.container.querySelector("#importRulesBtn")?.addEventListener("click",()=>this.importSiteRules()),this.bindSiteRuleEvents(),this.container.querySelector("#addSubBtn")?.addEventListener("click",()=>this.handleAddSubscription()),this.container.querySelector("#refreshAllSubsBtn")?.addEventListener("click",()=>this.handleRefreshAllSubs()),this.bindSubscriptionEvents(),this.container.querySelector("#clearStatsBtn")?.addEventListener("click",()=>this.clearStats()),this.bindModelEvents(),this.container.querySelector("#exportBtn")?.addEventListener("click",()=>this.exportConfig()),this.container.querySelector("#importBtn")?.addEventListener("click",()=>this.importConfig()),this.container.querySelector("#resetBtn")?.addEventListener("click",()=>this.resetConfig()),this.container.querySelector("#ddddocr-diag-export")?.addEventListener("click",()=>this.exportDiagnosticReport()),this.container.querySelector("#ddddocr-diag-clear")?.addEventListener("click",()=>this.clearDiagnosticLogs())}bindModelEvents(){const e=this.container?.querySelector("#modelZone"),t=this.container?.querySelector("#modelFile"),n=this.container?.querySelector("#modelName"),s=this.container?.querySelector("#charsetsZone"),i=this.container?.querySelector("#charsetsFile"),o=this.container?.querySelector("#charsetsName");e?.addEventListener("click",()=>t?.click()),t?.addEventListener("change",()=>{t.files?.[0]&&(n.textContent=`[OK] ${t.files[0].name}`)}),s?.addEventListener("click",()=>i?.click()),i?.addEventListener("change",()=>{i.files?.[0]&&(o.textContent=`[OK] ${i.files[0].name}`)}),this.container?.querySelector("#uploadBtn")?.addEventListener("click",async()=>{const e=t?.files?.[0],n=i?.files?.[0];if(e&&n)try{await async function(e,t){const n=await e.arrayBuffer(),s=await t.text(),i=JSON.parse(s);await(new L).setUploadedModel(n,i),console.log("✅ 上传的模型已保存")}(e,n),W({useUploadedModel:!0}),z.show({title:R("common.success"),content:R("model.saved"),icon:""})}catch(s){z.show({title:R("common.error"),content:String(s),icon:""})}else z.show({title:R("common.hint"),content:R("model.selectFiles"),icon:""})}),this.container?.querySelector("#deleteModelBtn")?.addEventListener("click",()=>{z.confirm({title:R("model.deleteTitle"),content:R("model.deleteConfirm"),onConfirm:async()=>{await async function(){await(new L).deleteUploadedModel(),console.log("🗑️ 上传的模型已删除")}(),W({useUploadedModel:!1}),z.show({title:R("common.success"),content:R("model.deleted"),icon:""})}})})}bindAgreementSelectorDeleteEvents(){this.container?.querySelectorAll(".btn-delete-agreement").forEach(e=>{e.addEventListener("click",e=>{const t=parseInt(e.target.dataset.index||"0");this.deleteAgreementSelector(t)})})}bindCalcRuleDeleteEvents(){this.container?.querySelectorAll(".btn-delete-calc-rule").forEach(e=>{e.addEventListener("click",e=>{const t=parseInt(e.target.dataset.index||"0");this.deleteCalculateRule(t)})})}bindSiteRuleEvents(){this.container?.querySelectorAll(".btn-edit-site-rule").forEach(e=>{e.addEventListener("click",e=>{const t=e.target.dataset.key;t&&this.editSiteRule(t)})}),this.container?.querySelectorAll(".btn-delete-site-rule").forEach(e=>{e.addEventListener("click",e=>{const t=e.target.dataset.key;t&&this.deleteSiteRuleUI(t)})})}addAgreementSelector(){const e=this.container?.querySelector("#newAgreementSelector"),t=e?.value.trim();if(!t)return void z.show({title:R("common.hint"),content:R("settings.agreementSelector.enterSelector"),icon:""});const n=j().agreementSelectors||[];if(n.includes(t))return void z.show({title:R("common.hint"),content:R("settings.agreementSelector.exists"),icon:""});n.push(t),W({agreementSelectors:n});const s=this.container?.querySelector("#agreementSelectorsList");s&&(s.innerHTML=this.renderAgreementSelectors(n)),this.bindAgreementSelectorDeleteEvents(),e.value=""}deleteAgreementSelector(e){const t=j().agreementSelectors||[];t.splice(e,1),W({agreementSelectors:t});const n=this.container?.querySelector("#agreementSelectorsList");n&&(n.innerHTML=this.renderAgreementSelectors(t)),this.bindAgreementSelectorDeleteEvents()}addCalculateRule(){const e=this.container?.querySelector("#newCalcRulePattern"),t=this.container?.querySelector("#newCalcRuleMatchType"),n=this.container?.querySelector("#newCalcRuleOutputMode"),s=e?.value.trim();if(!s)return void z.show({title:R("common.hint"),content:R("calc.enterPattern"),icon:""});const i=j().calculateRules||[];i.push({pattern:s,matchType:t.value,outputMode:n.value,enabled:!0}),W({calculateRules:i});const o=this.container?.querySelector("#calculateRulesList");o&&(o.innerHTML=this.renderCalculateRules(i)),this.bindCalcRuleDeleteEvents(),e.value=""}deleteCalculateRule(e){const t=j().calculateRules||[];t.splice(e,1),W({calculateRules:t});const n=this.container?.querySelector("#calculateRulesList");n&&(n.innerHTML=this.renderCalculateRules(t)),this.bindCalcRuleDeleteEvents()}addSiteRule(){const e=this.container?.querySelector("#newRuleHostname"),t=this.container?.querySelector("#newRuleSelector"),n=this.container?.querySelector("#newRuleInputSelector"),s=e?.value.trim(),i=t?.value.trim(),o=n?.value.trim();s&&i?(G(s,{selector:i,inputSelector:o||void 0,enabled:!0}),this.refreshSiteRulesList(),e.value="",t.value="",n.value=""):z.show({title:R("common.hint"),content:R("rules.selectorRequired"),icon:""})}editSiteRule(e){const t=V()[e];if(!t)return;this.currentEditRuleKey=e;const n=this.container?.querySelector("#editRuleCard"),s=this.container?.querySelector("#editRuleKey"),i=this.container?.querySelector("#editRuleOriginalKey"),o=this.container?.querySelector("#editRuleSelector"),a=this.container?.querySelector("#editRuleInput");n&&(n.style.display="block"),s&&(s.value=e),i&&(i.value=e),o&&(o.value=t.selector||""),a&&(a.value=t.inputSelector||"")}saveEditRule(){const e=this.container?.querySelector("#editRuleOriginalKey"),t=this.container?.querySelector("#editRuleSelector"),n=this.container?.querySelector("#editRuleInput"),s=e?.value,i=t?.value.trim(),o=n?.value.trim();if(i){if(s){const e=V()[s];e&&(X(s),G(e.hostname,{...e,selector:i,inputSelector:o||void 0}))}this.cancelEditRule(),this.refreshSiteRulesList()}else z.show({title:R("common.hint"),content:R("rules.selectorRequired"),icon:""})}cancelEditRule(){this.currentEditRuleKey=null;const e=this.container?.querySelector("#editRuleCard");e&&(e.style.display="none")}deleteSiteRuleUI(e){z.confirm({title:R("rules.deleteConfirm"),content:R("rules.deleteConfirmMsg",e),onConfirm:()=>{X(e),this.refreshSiteRulesList()}})}refreshSiteRulesList(){const e=this.container?.querySelector("#siteRulesList");e&&(e.innerHTML=this.renderSiteRules()),this.bindSiteRuleEvents()}async handleAddSubscription(){const e=this.container?.querySelector("#newSubUrl"),t=this.container?.querySelector("#newSubName"),n=this.container?.querySelector("#newSubInterval"),s=e?.value.trim(),i=t?.value.trim(),o=parseInt(n?.value||"24",10);if(s)try{const n=function(e){if(!function(e){try{const t=new URL(e);return"http:"===t.protocol||"https:"===t.protocol}catch{return!1}}(e.url))throw new Error("无效的 URL");const t=ne();if(t.some(t=>t.url===e.url))throw new Error("该订阅已存在");const n={id:"sub_"+Date.now().toString(36)+"_"+Math.random().toString(36).slice(2,10),url:e.url,name:e.name||e.url,enabled:!0,updateInterval:e.updateInterval??24,lastUpdated:0,lastStatus:"never",createdAt:Date.now()};return t.push(n),se(t),n}({url:s,name:i||void 0,updateInterval:o});e.value="",t.value="",this.refreshSubscriptionsList(),z.show({title:R("common.hint"),content:R("sub.refreshing"),icon:""});const a=await oe(n.id);a.success?z.show({title:R("common.success"),content:R("sub.refreshSuccess",a.pkg?.name||n.name),icon:""}):z.show({title:R("common.error"),content:R("sub.refreshFailed",n.name,a.error||""),icon:""}),this.refreshSubscriptionsList(),this.onConfigChange(j())}catch(a){z.show({title:R("common.error"),content:a.message||String(a),icon:""})}else z.show({title:R("common.hint"),content:R("sub.url"),icon:""})}async handleRefreshAllSubs(){const e=ne();if(0===e.length)return void z.show({title:R("common.hint"),content:R("sub.empty"),icon:""});z.show({title:R("common.hint"),content:R("sub.refreshing"),icon:""});let t=0,n=0;for(const s of e)s.enabled&&((await oe(s.id)).success?t++:n++);this.refreshSubscriptionsList(),this.onConfigChange(j()),z.show({title:R("common.success"),content:`${R("sub.refreshSuccess","")}: ${t} / ${t+n}`,icon:""})}exportSiteRules(){const e=V(),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=>{const t=e.target.files?.[0];if(t)try{const e=await t.text(),n=JSON.parse(e);if(!Array.isArray(n))throw new Error(R("rules.formatError"));for(const t of n)t.hostname&&t.selector&&G(t.hostname,{selector:t.selector,inputSelector:t.inputSelector,fullUrl:t.fullUrl,enabled:!0});this.refreshSiteRulesList(),z.show({title:R("common.success"),content:R("rules.importedCount",n.length),icon:""})}catch{z.show({title:R("common.error"),content:R("rules.importFormatError"),icon:""})}},e.click()}clearStats(){z.confirm({title:R("stats.clear"),content:R("stats.clearConfirm"),onConfirm:()=>{Y.clear();const e=this.container?.querySelector("[data-panel=\"stats\"]");e&&(e.innerHTML=this.renderStats()),this.container?.querySelector("#clearStatsBtn")?.addEventListener("click",()=>this.clearStats())}})}exportConfig(){const e=j();this.downloadJson(e,"ddddocr-config.json")}setDiagStatus(e,t=!1){const n=this.container?.querySelector("#ddddocr-diag-status");n&&(n.textContent=e,n.style.color=t?"#dc2626":"")}async exportDiagnosticReport(){const e=j();this.setDiagStatus(R("diag.exporting"));try{const t=await async function(e,t){const n={schema:"ddddocr-diag-v1",generatedAt:(new Date).toISOString(),app:{name:t.appName,version:t.appVersion,target:t.target},counts:{logs:0,truncatedLogs:!1}};if(e.includeEnv){const e="undefined"!=typeof navigator?navigator:{},t="undefined"!=typeof screen?screen:{width:0,height:0};n.env={userAgent:e.userAgent||"",platform:e.platform||e.userAgentData?.platform||"",language:e.language||"",screen:{width:t.width||0,height:t.height||0},online:!!e.onLine}}if(e.includeSettings&&t.getSettings)try{n.settings=function(e){if(!e||"object"!=typeof e)return e;const t={...e};for(const n of["whitelist","siteBlacklist","agreementSelectors","customIncludeKeywords","customExcludePatterns","customAgreementKeywords","customInputExcludeKeywords","disabledCaptchaKeywords","disabledExcludePatterns","disabledAgreementKeywords","disabledInputExcludeKeywords"])Array.isArray(t[n])&&(t[n]=t[n].map(e=>g(String(e))));for(const n of["captchaSelector","inputSelector","submitSelector","agreementSelector","localModelPath","localCharsetsPath"])"string"==typeof t[n]&&t[n]&&(t[n]=g(t[n]));return Array.isArray(t.calculateRules)&&(t.calculateRules=t.calculateRules.map(()=>"[redacted-rule]")),t}(await t.getSettings())}catch(s){n.settings={_error:String(s)}}if(e.includeSettings&&t.getActiveModel)try{const e=await t.getActiveModel();e&&(n.activeModel=e)}catch(s){n.activeModel={id:"_error: "+String(s)}}if(e.includeStats&&t.getStats)try{n.stats=function(e){if(!e||"object"!=typeof e)return{total:0,sites:0,recent:[]};const t=e.sites&&"object"==typeof e.sites?e.sites:{},n=Object.entries(t).map(([e,t])=>({host:m(e),count:t?.count||0,avgMs:t?.count?Math.round((t.totalTime||0)/t.count):0,lastTime:t?.lastTime||0})).sort((e,t)=>(t.lastTime||0)-(e.lastTime||0)).slice(0,20);return{total:e.total||0,sites:Object.keys(t).length,recent:n}}(await t.getStats())}catch(s){n.stats={_error:String(s)}}if(e.includeLogs){const e=await async function(){const e=u(),t=[];if(e)for(const a of o)try{const n=await e.get(i+a);Array.isArray(n)&&t.push(...n)}catch{}t.push(...a);const n=new Set,s=t.filter(e=>{const t=`${e.ts}|${e.ctx}|${e.level}|${e.msg}`;return!n.has(t)&&(n.add(t),!0)});return s.sort((e,t)=>e.ts-t.ts),s}();n.counts.logs=e.length,n.counts.truncatedLogs=e.length>=200*o.length,n.logs=e}return n}({includeLogs:!0,includeEnv:!0,includeSettings:!0,includeStats:!0},{appName:"Mieru-OCR Userscript",appVersion:"undefined"!=typeof GM_info&&GM_info?.script?.version||"0.0.0",target:"userscript",getSettings:async()=>e,getStats:async()=>Y.getStats()}),n=`ddddocr-diag-${(new Date).toISOString().replace(/[:.]/g,"-")}.json`;!function(e,t){if("undefined"==typeof document||"undefined"==typeof URL||"function"!=typeof URL.createObjectURL)throw new Error("downloadReport requires a window context with Blob URL support");const n=JSON.stringify(e,null,2),s=new Blob([n],{type:"application/json;charset=utf-8"}),i=URL.createObjectURL(s),o=document.createElement("a");o.href=i,o.download=t||`ddddocr-diag-${(new Date).toISOString().replace(/[:.]/g,"-")}.json`,o.style.display="none",document.body.appendChild(o),o.click(),setTimeout(()=>{try{document.body.removeChild(o)}catch{}URL.revokeObjectURL(i)},200)}(t,n);const s=t.logs?.length??0;this.setDiagStatus(R("diag.exported",n,String(s)))}catch(t){this.setDiagStatus(R("diag.exportFailed",t.message),!0)}}clearDiagnosticLogs(){z.confirm({title:R("diag.clear"),content:R("diag.clear"),onConfirm:async()=>{try{await async function(){a=[];const e=u();if(e)for(const t of o)try{await e.set(i+t,[])}catch{}}(),this.setDiagStatus(R("diag.cleared","6"))}catch(e){this.setDiagStatus(R("diag.clearFailed",e.message),!0)}}})}importConfig(){const e=document.createElement("input");e.type="file",e.accept=".json",e.onchange=async e=>{const t=e.target.files?.[0];if(t)try{const e=await t.text();W(JSON.parse(e)),z.show({title:R("common.success"),content:R("config.importedRefresh"),icon:""})}catch{z.show({title:R("common.error"),content:R("config.importError"),icon:""})}},e.click()}resetConfig(){z.confirm({title:R("common.reset"),content:R("config.resetConfirmSimple"),onConfirm:()=>{GM_setValue("ddddocr_config",f),z.show({title:R("common.success"),content:R("config.resetDoneRefresh"),icon:""})}})}downloadJson(e,t){const n=new Blob([JSON.stringify(e,null,2)],{type:"application/json"}),s=URL.createObjectURL(n),i=document.createElement("a");i.href=s,i.download=t,i.click(),URL.revokeObjectURL(s)}switchTab(e){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()),this.container.querySelector("#clearStatsBtn")?.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
${R(n.titleKey)}
\n
\n ${R("settings.keywords.builtinDeletable")}\n \n
\n
\n
\n
\n \n
\n
${R(n.hintKey)}
\n
\n `}).join("")}getEnabledBuiltinKeywords(e,t){const n=this.CHIP_META[e],s=new Set((t[n.disabledKey]||[]).map(e=>e.toLowerCase()));return n.builtin.filter(e=>!s.has(e.toLowerCase()))}renderChipList(e,t){const n=this.container?.querySelector(`#ddddocr-${e}-list`);if(!n)return;const s=[...this.getEnabledBuiltinKeywords(e,t).map(e=>({value:e,kind:"builtin"})),...(t[e]||[]).map(e=>({value:e,kind:"custom"}))];0!==s.length?n.innerHTML=s.map(t=>`\n \n ${de(t.value)}\n ${"builtin"===t.kind?R("settings.keywords.builtin"):R("settings.keywords.custom")}\n \n \n `).join(""):n.innerHTML=`
${R("settings.keywords.empty")}
`}renderAllChipGroups(){const e=j();Object.keys(this.CHIP_META).forEach(t=>this.renderChipList(t,e))}bindChipEvents(){this.container&&(Object.keys(this.CHIP_META).forEach(e=>{const t=this.container?.querySelector(`#ddddocr-${e}-input`);t?.addEventListener("keydown",n=>{if("Enter"!==n.key)return;n.preventDefault();const s=t.value.trim();if(!s)return;const i=j();if(new Set([...(i[e]||[]).map(e=>e.toLowerCase()),...this.CHIP_META[e].builtin.map(e=>e.toLowerCase())]).has(s.toLowerCase()))return void z.show({title:R("common.hint"),content:R("settings.keywords.exists"),icon:""});const o=i[e]||[];W({[e]:[...o,s]}),t.value="",this.renderAllChipGroups()})}),this.container.querySelector("#ddddocr-keyword-chip-groups")?.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,s=n.dataset.chipValue||"",i=j();if("builtin"===t){const t=this.CHIP_META[e].disabledKey,n=i[t]||[];W({[t]:Array.from(new Set([...n,s]))})}else{const t=i[e]||[];W({[e]:t.filter(e=>e.toLowerCase()!==s.toLowerCase())})}return void this.renderAllChipGroups()}const s=t.closest(".ddddocr-chip-reset");if(s){const e=s.dataset.chipField;W({[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(){this.container&&this.containerLocale===A()||(this.destroyContainer(),await this.createContainer()),this.applyTheme(),this.isVisible=!0,this.overlay?.classList.add("visible"),this.container?.classList.add("visible"),re()&&(this.container?.classList.add("mobile"),document.body.style.overflow="hidden")}hide(){this.isVisible=!1,this.overlay?.classList.remove("visible"),this.container?.classList.remove("visible"),document.body.style.overflow="",window.removeEventListener("resize",this.handleResize)}setOnConfigChange(e){this.onConfigChange=e}},ue=class{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=R("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(()=>{this.container?.remove(),e?.remove(),this.container=null},300)}},pe=class{constructor(){this.engine=new n({getModel:D,wasmPaths:"https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.0/dist/"})}async init(){await async function(){try{await O.init()}catch(t){console.warn("[WASMCache] 初始化失败:",t)}(async function(){console.log("📦 开始预下载 WASM 文件"),await Promise.allSettled(H.map(async e=>{try{if(await O.get(e))return;const t=await _(e);await O.set(e,t)}catch(t){console.warn(`⚠️ ${e} 下载失败`,t)}}))})().catch(()=>{});const e=window.fetch;window.fetch=async function(n,s){const i="string"==typeof n?n:n instanceof URL?n.href:n.url,o=H.find(e=>i.includes(e));if(!o)return e.call(this,n,s);try{let e=await O.get(o);return e||(e=await _(o),O.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,s)}},console.log("✅ WASM 缓存已启用")}(),await this.engine.init()}async recognize(e){return this.engine.recognize(e)}},he=class{constructor(e,t){this.observer=null,this.enabled=!1,this.checkInterval=null,this.eventEmitter=null,this.autoFill=new s,this.initialScanDone=!1,this.initialScanTimer=null,this.processingElements=new WeakSet,this.processedElements=new WeakMap,this.customCaptchaElement=null,this.customInputElement=null,this.ocr=e,this.detector=new x,this.eventEmitter=t||null}start(){this.enabled||(this.enabled=!0,w.info("启动验证码自动检测"),this.applyStoredSiteRule(),this.scheduleInitialDetect(),this.observer=new MutationObserver(e=>{let t=!1;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=!0))}),"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:!0,subtree:!0,attributes:!0,attributeFilter:["src","data-src","srcset","style","href"],characterData:!0}),this.startIntervalCheck(),this.checkAgreementBoxes())}stop(){this.enabled&&(this.enabled=!1,w.info("停止验证码自动检测"),this.observer?.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=V(),t=window.location.href,n=window.location.hostname;let s=null;for(const i of Object.keys(e)){const o=e[i];if(o.enabled){if(o.fullUrl&&t===o.fullUrl){s=o;break}if(o.urlPattern&&t.startsWith(o.urlPattern)){s=o;break}o.hostname!==n||o.fullUrl||o.urlPattern||(s=o)}}if(s){const e=document.querySelector(s.selector);e&&(this.customCaptchaElement=e,s.inputSelector&&(this.customInputElement=document.querySelector(s.inputSelector)),w.info("应用站点规则:",s.selector))}}checkAgreementBoxes(){const e=j();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(),w.info("点击协议复选框容器")):(e.checked=!0,e.dispatchEvent(new Event("change",{bubbles:!0})),e.dispatchEvent(new Event("input",{bubbles:!0})),w.info("直接勾选协议复选框")),this.detector.markAgreementChecked(e)}for(const i of t)if(i.trim())try{document.querySelectorAll(i).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})),w.info("通过选择器勾选协议:",i))})}catch(s){w.warn("无效的协议选择器:",i)}}scheduleInitialDetect(){this.initialScanDone||(this.detectExistingCaptchas(!1),this.initialScanTimer=window.setTimeout(()=>{this.initialScanDone||this.detectExistingCaptchas(!0)},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}},b.AUTO_DETECT_INTERVAL)}detectExistingCaptchas(e){w.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=!0)}checkElement(e){e instanceof HTMLImageElement&&this.checkImage(e,!0),e instanceof HTMLCanvasElement&&this.checkCanvas(e,!0),e instanceof SVGElement&&this.checkSVG(e,!0),e.style.backgroundImage&&this.checkDiv(e,!0),e.querySelectorAll("img").forEach(e=>this.checkImage(e,!0)),e.querySelectorAll("canvas").forEach(e=>this.checkCanvas(e,!0)),e.querySelectorAll("svg").forEach(e=>this.checkSVG(e,!0))}async waitForImageLoad(e,t=5e3){return!!(e.complete&&e.naturalWidth>0)||new Promise(n=>{const s=setTimeout(()=>{a(),n(!1)},t),i=()=>{a(),n(!0)},o=()=>{a(),n(!1)},a=()=>{clearTimeout(s),e.removeEventListener("load",i),e.removeEventListener("error",o)};e.addEventListener("load",i),e.addEventListener("error",o),e.complete&&e.naturalWidth>0&&(a(),n(!0))})}async recheckImage(e){await this.waitForImageLoad(e)&&await this.checkImage(e,!0)}async recheckCanvas(e){await new Promise(e=>requestAnimationFrame(e)),await this.checkCanvas(e,!0)}async recheckSVG(e){await new Promise(e=>requestAnimationFrame(e)),await this.checkSVG(e,!0)}async recheckDiv(e){await new Promise(e=>requestAnimationFrame(e)),await this.checkDiv(e,!0)}async checkImage(e,t){const n=j();if(n.captchaSelector){if(!e.matches(n.captchaSelector))return}else if(!this.isCaptchaImage(e))return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(this.eventEmitter?.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:!0}))),await this.waitForImageLoad(e)&&e.naturalWidth&&await this.recognizeAndFill(e,s))}async checkCanvas(e,t){const n=j();if(n.captchaSelector){if(!e.matches(n.captchaSelector))return}else if(!this.isCaptchaCanvas(e))return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(this.eventEmitter?.emit("detect:found",{element:e,type:"canvas"}),!t)return;const s=this.findNearbyInput(e);if(!s)return;await new Promise(e=>requestAnimationFrame(e));const i=await new Promise((t,n)=>{e.toBlob(e=>{e?t(e):n(new Error("Canvas转换失败"))},"image/png")});await this.recognizeAndFillBlob(e,i,s)}async checkSVG(e,t){const n=j();if(n.captchaSelector){if(!e.matches(n.captchaSelector))return}else if(!this.isCaptchaSVG(e))return;if(!this.hasElementChanged(e))return;if(this.processingElements.has(e))return;if(this.eventEmitter?.emit("detect:found",{element:e,type:"svg"}),!t)return;const s=this.findNearbyInput(e);if(!s)return;const i=await this.svgToBlob(e);await this.recognizeAndFillBlob(e,i,s)}async checkDiv(e,t){const n=j();if(n.captchaSelector){if(!e.matches(n.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(this.eventEmitter?.emit("detect:found",{element:e,type:"div"}),!t)return;const i=this.findNearbyInput(e);if(!i)return;const o=s.match(/url\(['"]?(.+?)['"]?\)/);if(!o)return;const a=o[1],r=Date.now();let d="";if(a.startsWith("data:")){const e=await(await fetch(a)).blob();d=(await this.ocr.recognize(e)).text}else d=(await this.ocr.recognize(a)).text;const c=Date.now()-r,l=this.processResult(d);await this.fillInput(i,l),this.markElementProcessed(e),Y.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"}),s=URL.createObjectURL(n),i=new Image;i.src=s,await new Promise((e,t)=>{i.onload=e,i.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(i,0,0),URL.revokeObjectURL(s),new Promise((e,t)=>{o.toBlob(n=>{n?e(n):t(new Error("SVG转换失败"))},"image/png")})}async recognizeAndFill(e,t){if(this.processingElements.has(e))return;this.processingElements.add(e);const n=Date.now();w.time("recognizeAndFill");try{this.eventEmitter?.emit("recognize:start",{element:e});const s=await this.ocr.recognize(e),i=this.processResult(s.text);this.eventEmitter?.emit("recognize:complete",{element:e,result:{text:i}}),await this.fillInput(t,i),this.markElementProcessed(e);const o=Date.now()-n;Y.record(window.location.hostname,o),w.timeEnd("recognizeAndFill"),w.info("识别完成:",i)}catch(s){w.error("识别失败:",s),this.eventEmitter?.emit("recognize:error",{element:e,error:s})}finally{this.processingElements.delete(e)}}async recognizeAndFillBlob(e,t,n){if(this.processingElements.has(e))return;this.processingElements.add(e);const s=Date.now();try{this.eventEmitter?.emit("recognize:start",{element:e});const i=await this.ocr.recognize(t),o=this.processResult(i.text);this.eventEmitter?.emit("recognize:complete",{element:e,result:{text:o}}),await this.fillInput(n,o),this.markElementProcessed(e);const a=Date.now()-s;Y.record(window.location.hostname,a),w.info("识别完成:",o)}catch(i){w.error("识别失败:",i),this.eventEmitter?.emit("recognize:error",{element:e,error:i})}finally{this.processingElements.delete(e)}}processResult(e){const t=j();return t.autoCalculate?v.processResult(e,{autoCalculate:!0,outputMode:t.calculateOutputMode,rules:t.calculateRules||[]},window.location.hostname):e}async fillInput(e,t){const n=j();await this.autoFill.fill(e,t,{simulate:!0,autoSubmit:n.autoSubmit??!1,typewriterEffect:n.typewriterEffect,preserveFocus:n.preserveFocus??!1}),n.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:R("us.captchaFilled"),text:R("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(tb.MAX_CAPTCHA_WIDTH||n>b.MAX_CAPTCHA_HEIGHT)return!1;const s=(e.src+e.className+e.id+e.alt+(e.getAttribute("data-src")||"")).toLowerCase();return!b.EXCLUDE_PATTERNS.some(e=>s.includes(e))&&b.CAPTCHA_KEYWORDS.some(e=>s.includes(e))}isCaptchaCanvas(e){const t=e.width,n=e.height;if(tb.MAX_CAPTCHA_WIDTH||n>b.MAX_CAPTCHA_HEIGHT)return!1;const s=(e.className+e.id+(e.getAttribute("data-type")||"")).toLowerCase();return!b.EXCLUDE_PATTERNS.some(e=>s.includes(e))&&b.CAPTCHA_KEYWORDS.some(e=>s.includes(e))}isCaptchaSVG(e){const t=e.clientWidth||parseInt(e.getAttribute("width")||"0"),n=e.clientHeight||parseInt(e.getAttribute("height")||"0");if(tb.MAX_CAPTCHA_WIDTH||n>b.MAX_CAPTCHA_HEIGHT)return!1;const s=((e.className?.baseVal||"")+(e.id||"")).toLowerCase();if(b.CAPTCHA_KEYWORDS.some(e=>s.includes(e)))return!0;let i=e.parentElement,o=0;for(;i&&o<3;){const e=((i.className?.toString?.()||"")+(i.id||"")).toLowerCase();if(b.CAPTCHA_KEYWORDS.some(t=>e.includes(t)))return!0;i=i.parentElement,o++}const a=this.findNearbyInput(e);if(!a)return!1;const r=(a.name+a.id+a.className+a.placeholder).toLowerCase();return b.INPUT_KEYWORDS.some(e=>r.includes(e))}isCaptchaDiv(e){const t=e.clientWidth,n=e.clientHeight;if(tb.MAX_CAPTCHA_WIDTH||n>b.MAX_CAPTCHA_HEIGHT)return!1;const s=(e.className+e.id).toLowerCase();return b.CAPTCHA_KEYWORDS.some(e=>s.includes(e))}findNearbyInput(e){const t=j();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)}},me=class{constructor(){this.loadingIndicator=null,this.initialized=!1,this.menuCommandIds=new Map,this.eventEmitter=new C,this.ocr=new pe,this.detector=new he(this.ocr,this.eventEmitter),this.settingsUI=new le;const e=j();E(e.language),w.setDebugMode(e.debugMode||!1),this.registerMenuCommands(),this.settingsUI.setOnConfigChange(e=>this.handleConfigChange(e))}async init(){if(Q()){if(!this.initialized){this.initialized=!0,this.loadingIndicator=new ue,w.info("Mieru-OCR 启动");try{this.loadingIndicator.show(R("us.loading")),this.loadingIndicator.updateText(R("us.loadingModel")),await this.ocr.init(),w.info("OCR 已就绪"),this.loadingIndicator.updateText(R("us.ready"));const e=j();e.autoDetect&&(this.detector.start(),w.info("自动检测已启动")),setTimeout(()=>this.loadingIndicator?.hide(),2e3),this.showNotification(R("us.ready"),e.autoDetect?R("us.readyAutoDetect"):R("us.readyManual")),async function(){const e=ne();for(const t of e)Z(t)&&(w.info("自动更新订阅:",t.url),await oe(t.id))}().catch(e=>w.warn("订阅自动更新失败:",e))}catch(e){w.error("初始化失败:",e),this.loadingIndicator?.updateText(R("us.initFailedMsg",String(e))),setTimeout(()=>this.loadingIndicator?.hide(),3e3),this.showNotification(R("us.initFailed"),String(e),!0)}}}else w.debug("当前站点不满足执行条件")}registerMenuCommands(){this.refreshMenuCommands()}refreshMenuCommands(){for(const s of this.menuCommandIds.values())try{GM_unregisterMenuCommand(s)}catch{}this.menuCommandIds.clear();const e=GM_registerMenuCommand(R("us.menuOpenSettings"),()=>this.settingsUI.show(),"s");this.menuCommandIds.set("settings",e);const t=GM_registerMenuCommand(R("us.menuClearCache"),async()=>{z.confirm({title:R("us.clearCacheTitle"),content:R("us.clearCacheMsg"),confirmText:R("us.clearCacheConfirm"),cancelText:R("common.cancel"),onConfirm:async()=>{await async function(){await(new L).delete(),console.log("🗑️ 模型缓存已清除")}(),await async function(){await O.clear()}(),this.showNotification(R("us.cacheCleared"),R("us.cacheClearedMsg"))}})},"d");this.menuCommandIds.set("cache",t);const n=GM_registerMenuCommand(R("us.menuViewStatus"),()=>this.showStatus(),"i");this.menuCommandIds.set("status",n)}showStatus(){const e=j(),t=J(),n=V(),s=Y.getStats(),i=e=>R(e?"common.enabled":"common.disabled"),o=`\n${R("status.scriptStatus")} ${this.initialized?R("status.initialized"):R("status.notInitialized")}\n${R("status.currentSite")} ${window.location.hostname}\n${R("status.whitelistStatus")} ${i(e.enableWhitelist)}\n${R("status.whitelistCount")} ${e.whitelist?.length||0} ${R("common.sites")}\n${R("status.siteMatch")} ${R(t?"status.inWhitelist":"status.notInWhitelist")}\n${R("status.autoDetect")} ${i(e.autoDetect)}\n${R("status.typewriterEffect")} ${i(e.typewriterEffect)}\n${R("status.autoCheckAgreement")} ${i(e.autoCheckAgreement)}\n${R("status.agreementSelectorCount")} ${e.agreementSelectors?.length||0}\n${R("status.autoCalculate")} ${i(e.autoCalculate)}\n${R("status.calcOutput")} ${"result"===e.calculateOutputMode?R("status.calcOutputResult"):R("status.calcOutputEquation")}\n${R("status.calcRuleCount")} ${e.calculateRules?.length||0}\n${R("status.siteRuleCount")} ${Object.keys(n).length}\n${R("status.debugMode")} ${i(e.debugMode)}\n${R("status.uploadedModel")} ${e.useUploadedModel?R("common.enabled"):R("common.notEnabled")}\n${R("status.autoDownload")} ${i(e.autoDownload)}\n${R("status.totalRecognitions")} ${s.total} ${R("common.times")}`;z.show({title:R("status.title"),content:o})}handleConfigChange(e){"auto"===e.language?E("auto"):k(e.language),w.setDebugMode(e.debugMode||!1),e.autoDetect&&!this.initialized&&this.init(),e.autoDetect?this.detector.start():this.detector.stop(),this.refreshMenuCommands()}showNotification(e,t,n=!1){j().enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:e,text:t,timeout:n?5e3:3e3})}};function ge(){const e=new me;Q()?setTimeout(()=>e.init(),500):w.debug("Mieru-OCR 不满足执行条件,仅注册菜单命令")}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",ge):ge()}();