// ==UserScript== // @name DDDD OCR WEB - 验证码自动识别 // @namespace https://github.com/MakotoArai-CN/ddddocr-webjs // @version 1.1.1-2026/1/20 03:41:36 // @author MakotoArai-CN // @description 自动检测并识别页面验证码,自动填充到输入框。首次使用需设置白名单,会自动下载约50MB模型文件以及20MB左右的ONNX推理运行时文件。 // @license MIT // @icon data:image/png;base64,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 // @match *://*/* // @require https://cdnjs.cloudflare.com/ajax/libs/onnxruntime-web/1.17.0/ort.min.js // @connect cdn.jsdelivr.net // @connect unpkg.com // @connect cdnjs.cloudflare.com // @connect fastly.jsdelivr.net // @connect registry.npmmirror.com // @connect raw.githubusercontent.com // @connect ghproxy.com // @connect ghfast.top // @connect mirror.ghproxy.com // @connect raw.kkgithub.com // @connect github.moeyy.xyz // @connect ghps.cc // @connect cors.isteed.cc // @connect raw.githubusercontents.com // @grant GM_getValue // @grant GM_notification // @grant GM_registerMenuCommand // @grant GM_setValue // @grant GM_xmlhttpRequest // @grant unsafeWindow // ==/UserScript== (function () { 'use strict'; class ImageProcessor{static extractImageFromElement(t){const e=document.createElement("canvas");e.width=t.naturalWidth||t.width,e.height=t.naturalHeight||t.height;const n=e.getContext("2d");n.fillStyle="#FFFFFF",n.fillRect(0,0,e.width,e.height),n.drawImage(t,0,0);const i=n.getImageData(0,0,e.width,e.height);return {data:this.toGrayscale(i.data),width:e.width,height:e.height}}static async loadImage(t){if("undefined"==typeof document)return this.loadImageInServiceWorker(t);if(t instanceof HTMLImageElement)return this.extractImageFromElement(t);const e=new Image;e.crossOrigin="anonymous",e.src="string"==typeof t?t:URL.createObjectURL(t),await new Promise((t,n)=>{e.onload=()=>t(),e.onerror=()=>n(new Error("图片加载失败")),setTimeout(()=>n(new Error("图片加载超时")),1e4);});const n=document.createElement("canvas");n.width=e.width,n.height=e.height;const i=n.getContext("2d");i.fillStyle="#FFFFFF",i.fillRect(0,0,e.width,e.height),i.drawImage(e,0,0);const o=i.getImageData(0,0,e.width,e.height),a=this.toGrayscale(o.data);return "string"!=typeof t&&URL.revokeObjectURL(e.src),{data:a,width:e.width,height:e.height}}static async loadImageInServiceWorker(t){let e;if("string"==typeof t)if(t.startsWith("data:")){const n=await fetch(t);e=await n.blob();}else {const n=await fetch(t);e=await n.blob();}else {if(!(t instanceof Blob))throw new Error("Service Worker 环境不支持 HTMLImageElement");e=t;}const n=await createImageBitmap(e),i=new OffscreenCanvas(n.width,n.height),o=i.getContext("2d");o.fillStyle="#FFFFFF",o.fillRect(0,0,i.width,i.height),o.drawImage(n,0,0);const a=o.getImageData(0,0,i.width,i.height),s=this.toGrayscale(a.data);return n.close(),{data:s,width:i.width,height:i.height}}static toGrayscale(t){const e=new Uint8ClampedArray(t.length/4);for(let n=0;n{if("undefined"!=typeof ort)return ort;if("undefined"!=typeof window&&window.ort)return window.ort;if("undefined"!=typeof globalThis&&globalThis.ort)return globalThis.ort;try{if("undefined"!=typeof unsafeWindow&&unsafeWindow.ort)return unsafeWindow.ort}catch(t){}return null};let t=getOrtInstance();if(t)return t;for(let e=0;e<100;e++)if(await new Promise(t=>setTimeout(t,100)),t=getOrtInstance(),t)return t;throw new Error("等待 ort 超时")}async recognize(t){this.initialized&&this.session||await this.init();const{data:e,width:n,height:i}=await ImageProcessor.loadImage(t),o=Math.floor(n*(64/i)),a=ImageProcessor.resize(e,n,i,o,64),s=ImageProcessor.normalize(a),d={input1:new this.ort.Tensor("float32",s,[1,1,64,o])},r=(await this.session.run(d)).output;return {text:this.decodeOutput(r)}}decodeOutput(t){const e=this.convertToNumberArray(t.data),n=[];let i="";for(const o of e){if(o<=0||o>=this.charsets.length)continue;const t=this.charsets[o];t&&t!==i&&(n.push(t),i=t);}return n.join("")}convertToNumberArray(t){const e=[];for(let n=0;nt.startsWith("__reactProps$")||t.startsWith("__reactFiber$")||t.startsWith("__reactEventHandlers$"))){const e=t._valueTracker;e&&e.setValue("");}if((t.ngModel||t.getAttribute("ng-model")||t.getAttribute("[(ngModel)]"))&&(this.dispatchEvent(t,"input"),this.dispatchEvent(t,"blur")),Object.keys(t).find(t=>t.startsWith("__vue"))||t.hasAttribute("v-model")){const e=new CompositionEvent("compositionstart",{bubbles:true}),n=new CompositionEvent("compositionend",{bubbles:true,data:t.value});t.dispatchEvent(e),t.dispatchEvent(n);}}async simulateTyping(t,e){var n;for(const i of e){this.dispatchKeyEvent(t,"keydown",i);const e=null==(n=Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value"))?void 0:n.set;e?e.call(t,t.value+i):t.value+=i;const o=new InputEvent("input",{bubbles:true,cancelable:true,inputType:"insertText",data:i});t.dispatchEvent(o),this.dispatchKeyEvent(t,"keyup",i),await this.delay(50+100*Math.random());}this.dispatchEvent(t,"change"),this.dispatchEvent(t,"blur");}dispatchEvent(t,e){t.dispatchEvent(new Event(e,{bubbles:true,cancelable:true}));}dispatchKeyEvent(t,e,n){t.dispatchEvent(new KeyboardEvent(e,{key:n,code:`Key${n.toUpperCase()}`,charCode:n.charCodeAt(0),keyCode:n.charCodeAt(0),bubbles:true,cancelable:true}));}delay(t){return new Promise(e=>setTimeout(e,t))}highlightInput(t){const e=t.style.border,n=t.style.boxShadow;t.style.border="2px solid #4CAF50",t.style.boxShadow="0 0 8px rgba(76, 175, 80, 0.5)",setTimeout(()=>{t.style.border=e,t.style.boxShadow=n;},2e3);}async submitForm(t){var e;const n=t.closest("form");if(n){const t=new Event("submit",{bubbles:true,cancelable:true});n.dispatchEvent(t)&&n.submit();}else {const n=((null==(e=t.parentElement)?void 0:e.parentElement)||document).querySelector('button[type="submit"], input[type="submit"], button:not([type])');n&&n.click();}}getLastFilledInput(){return this.lastFilledInput}}const t={MODEL_VERSION:"1.5.1",MODEL_REPO:"MakotoArai-CN/ddddocr-webjs",MODEL_BRANCH:"main",MODEL_PATH:"public/common.onnx",CHARSETS_PATH:"public/charsets.json",WASM_VERSION:"1.17.0",CACHE_DURATION:2592e6,CAPTCHA_KEYWORDS:["captcha","verify","code","vcode","authcode","验证码","checkcode","yzm","capimg","signCaptcha","imgcode","seccode","validcode","yanzhengma","validatecode","piccode","imgverify","codeimg","randcode","identify","kaptcha"],INPUT_KEYWORDS:["captcha","verify","code","vcode","authcode","验证码","checkcode","yzm","validatecode","validcode","seccode","imgcode","randcode","identify","kaptcha","answer"],MIN_CAPTCHA_WIDTH:40,MIN_CAPTCHA_HEIGHT:20,MAX_CAPTCHA_WIDTH:500,MAX_CAPTCHA_HEIGHT:200,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://github.moeyy.xyz/https://raw.githubusercontent.com","https://ghps.cc/https://raw.githubusercontent.com","https://cors.isteed.cc/github.com/MakotoArai-CN/ddddocr-webjs/raw/main","https://raw.githubusercontents.com"],CDN_SOURCES:["https://cdn.jsdelivr.net","https://unpkg.com","https://cdnjs.cloudflare.com","https://fastly.jsdelivr.net","https://registry.npmmirror.com"]},e={autoDetect:true,captchaSelector:"",inputSelector:"",submitSelector:"",agreementSelector:"",useLocalModel:false,localModelPath:"",localCharsetsPath:"",autoDownload:true,enableWhitelist:true,whitelist:[],useUploadedModel:false,theme:"auto",typewriterEffect:true,autoCalculate:false,calculateOutputMode:"result",calculateRules:[],enableNotification:true},n=class{static parseExpression(t){const e=t.trim();let n=e;for(const a of this.NOISE_CHARS)n=n.split(a).join("");const i=[/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]?\s*\d*$/,/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]$/,/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)$/];for(const a of i){const t=n.match(a);if(t){const n=parseFloat(t[1]),i=t[2],o=parseFloat(t[3]);if(!isNaN(n)&&!isNaN(o))return {num1:n,operator:i,num2:o,originalText:e,cleanExpression:`${n}${this.normalizeOperator(i)}${o}`}}}const o=e.match(/^(\d+(?:\.\d+)?)\s*([+\-×*÷/xX])\s*(\d+(?:\.\d+)?)\s*[==]\s*(\d+)$/);if(o){const t=parseFloat(o[1]),n=o[2],i=parseFloat(o[3]),a=parseFloat(o[4]);if(!isNaN(t)&&!isNaN(i)){const o=this.compute(t,n,i);if(null!==o&&Math.abs(o-a)>.001)return {num1:t,operator:n,num2:i,originalText:e,cleanExpression:`${t}${this.normalizeOperator(n)}${i}`}}}return null}static normalizeOperator(t){switch(t){case "x":case "X":case "*":return "×";case "/":return "÷";default:return t}}static compute(t,e,n){switch(e){case "+":return t+n;case "-":return t-n;case "*":case "×":case "x":case "X":return t*n;case "/":case "÷":return 0===n?null:t/n;default:return null}}static calculate(t){return this.compute(t.num1,t.operator,t.num2)}static formatResult(t){return Number.isInteger(t)?String(t):t.toFixed(2).replace(/\.?0+$/,"")}static formatEquation(t,e){const n=this.normalizeOperator(t.operator);return `${t.num1}${n}${t.num2}=${this.formatResult(e)}`}static matchesPattern(t,e,n){try{if("regex"===n)return new RegExp(e,"i").test(t);{const n="^"+e.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".")+"$";return new RegExp(n,"i").test(t)}}catch{return false}}static getOutputModeForHostname(t,e,n){for(const i of e)if(i.enabled&&this.matchesPattern(t,i.pattern,i.matchType))return i.outputMode;return n}static shouldCalculateForHostname(t,e){if(!e||0===e.length)return true;const n=e.filter(t=>t.enabled);if(0===n.length)return true;for(const i of n)if(this.matchesPattern(t,i.pattern,i.matchType))return true;return false}static processResult(t,e,n){if(!e.autoCalculate)return t;if(e.rules&&e.rules.length>0&&!this.shouldCalculateForHostname(n,e.rules))return t;const i=this.parseExpression(t);if(!i)return t;const o=this.calculate(i);return null===o?t:"equation"===this.getOutputModeForHostname(n,e.rules,e.outputMode)?this.formatEquation(i,o):this.formatResult(o)}static isExpression(t){return null!==this.parseExpression(t)}};n.OPERATORS=["+","-","×","*","÷","/","x","X"],n.EQUALS_CHARS=["=","="],n.QUESTION_CHARS=["?","?","〇","o","O","0"],n.NOISE_CHARS=["?","?","〇"," ","\t","\n","\r"];let i=n;class EventEmitter{constructor(){this.listeners=new Map;}on(t,e){this.listeners.has(t)||this.listeners.set(t,new Set),this.listeners.get(t).add(e);}off(t,e){var n;null==(n=this.listeners.get(t))||n.delete(e);}emit(t,e){var n;null==(n=this.listeners.get(t))||n.forEach(t=>{try{t(e);}catch(n){}});}clear(){this.listeners.clear();}}const o="ddddocr_model_cache",a="ddddocr_uploaded_model";class ModelCache{constructor(){this.dbName="DdddOCRDB",this.storeName="modelStore",this.db=null;}async init(){return new Promise((t,e)=>{const n=indexedDB.open(this.dbName,1);n.onerror=()=>e(n.error),n.onsuccess=()=>{this.db=n.result,t();},n.onupgradeneeded=t=>{const e=t.target.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName);};})}async get(){return this.db||await this.init(),new Promise((e,n)=>{const i=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(o);i.onerror=()=>n(i.error),i.onsuccess=()=>{const n=i.result;if(n)return Date.now()-n.timestamp>t.CACHE_DURATION||n.version!==t.MODEL_VERSION?(this.delete(),void e(null)):void e(n);e(null);};})}async set(e,n){this.db||await this.init();const i={model:e,charsets:n,timestamp:Date.now(),version:t.MODEL_VERSION};return new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(i,o);n.onerror=()=>e(n.error),n.onsuccess=()=>t();})}async delete(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(o);n.onerror=()=>e(n.error),n.onsuccess=()=>t();})}async getUploadedModel(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(a);n.onerror=()=>e(n.error),n.onsuccess=()=>t(n.result||null);})}async setUploadedModel(t,e){this.db||await this.init();const n={model:t,charsets:e,timestamp:Date.now(),version:"uploaded"};return new Promise((t,e)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(n,a);i.onerror=()=>e(i.error),i.onsuccess=()=>t();})}async deleteUploadedModel(){return this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(a);n.onerror=()=>e(n.error),n.onsuccess=()=>t();})}}function downloadFile(t,e=3e4){return new Promise((n,i)=>{GM_xmlhttpRequest({method:"GET",url:t,responseType:"arraybuffer",timeout:e,headers:{"Cache-Control":"max-age=2592000"},onload:t=>{200===t.status?n(t.response):i(new Error(`HTTP ${t.status}`));},onerror:t=>i(t),ontimeout:()=>i(new Error("下载超时"))});})}function downloadJSON(t,e=3e4){return new Promise((n,i)=>{GM_xmlhttpRequest({method:"GET",url:t,responseType:"json",timeout:e,headers:{"Cache-Control":"max-age=2592000"},onload:t=>{200===t.status?n(t.response):i(new Error(`HTTP ${t.status}`));},onerror:t=>i(t),ontimeout:()=>i(new Error("下载超时"))});})}function buildURL(e,n){const i=e.replace(/\/+$/,""),o=n.replace(/^\/+/,"");if(i.includes("jsdelivr"))return `${i}/${t.MODEL_REPO}@${t.MODEL_BRANCH}/${o}`;const a=`/${t.MODEL_REPO}/`;return i.includes(a)?`${i}/${o}`:`${i}/${t.MODEL_REPO}/${t.MODEL_BRANCH}/${o}`}async function loadModel(){const e=GM_getValue("ddddocr_config")||{},n=new ModelCache;if(e.useUploadedModel){const t=await n.getUploadedModel();if(t)return {model:t.model,charsets:t.charsets}}if(false===e.autoDownload)throw new Error("自动下载已禁用,请上传模型文件或启用自动下载");const i=await n.get();if(i)return {model:i.model,charsets:i.charsets};let o=null,a=null;for(let d=0;de.includes("jsdelivr")?`${e}/npm/onnxruntime-web@${t.WASM_VERSION}/dist/`:e.includes("unpkg")?`${e}/onnxruntime-web@${t.WASM_VERSION}/dist/`:e.includes("cdnjs")?`${e}/ajax/libs/onnxruntime-web/${t.WASM_VERSION}/`:e.includes("npmmirror")?`${e}/onnxruntime-web/${t.WASM_VERSION}/files/dist/`:`${e}/onnxruntime-web@${t.WASM_VERSION}/dist/`),d=["ort-wasm.wasm","ort-wasm-simd.wasm","ort-wasm-threaded.wasm","ort-wasm-simd-threaded.wasm"],r=new class{constructor(){this.dbName="WASMCacheDB",this.storeName="wasmStore",this.db=null,this.memoryCache=new Map;}async init(){return new Promise((t,e)=>{const n=indexedDB.open(this.dbName,2);n.onerror=()=>e(n.error),n.onsuccess=()=>{this.db=n.result,t();},n.onupgradeneeded=t=>{const e=t.target.result;e.objectStoreNames.contains(this.storeName)||e.createObjectStore(this.storeName);};})}async get(e){return this.memoryCache.has(e)?this.memoryCache.get(e):(this.db||await this.init(),new Promise((n,i)=>{const o=this.db.transaction([this.storeName],"readonly").objectStore(this.storeName).get(e);o.onerror=()=>i(o.error),o.onsuccess=()=>{const i=o.result;if(i){if(Date.now()-i.timestamp>t.CACHE_DURATION||i.version!==t.WASM_VERSION)return this.delete(e),void n(null);this.memoryCache.set(e,i.data),n(i.data);}else n(null);};}))}async set(e,n){this.db||await this.init(),this.memoryCache.set(e,n);const i={data:n,timestamp:Date.now(),version:t.WASM_VERSION};return new Promise((t,n)=>{const o=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).put(i,e);o.onerror=()=>n(o.error),o.onsuccess=()=>t();})}async delete(t){return this.memoryCache.delete(t),this.db||await this.init(),new Promise((e,n)=>{const i=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).delete(t);i.onerror=()=>n(i.error),i.onsuccess=()=>e();})}async clear(){return this.memoryCache.clear(),this.db||await this.init(),new Promise((t,e)=>{const n=this.db.transaction([this.storeName],"readwrite").objectStore(this.storeName).clear();n.onerror=()=>e(n.error),n.onsuccess=()=>t();})}};async function downloadWASM(t){for(let n=0;n{GM_xmlhttpRequest({method:"GET",url:i,responseType:"arraybuffer",timeout:3e4,headers:{Accept:"application/wasm","Cache-Control":"max-age=2592000"},onload:n=>{200===n.status?t(n.response):e(new Error(`HTTP ${n.status}`));},onerror:e,ontimeout:()=>e(new Error("下载超时"))});})}catch(e){if(n===s.length-1)throw new Error(`所有 WASM CDN 均下载失败: ${t}`)}}throw new Error(`下载 WASM 失败: ${t}`)}const c=class{static injectStyles(){if(this.stylesInjected)return;const t=document.createElement("style");t.textContent="\n .ddddocr-dialog-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n z-index: 2147483647;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: ddddocr-fade-in 0.3s ease;\n }\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: 90%;\n max-height: 80vh;\n overflow: hidden;\n animation: ddddocr-scale-in 0.3s ease;\n display: flex;\n flex-direction: column;\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 .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 }\n .ddddocr-dialog-body::-webkit-scrollbar {\n width: 6px;\n }\n .ddddocr-dialog-body::-webkit-scrollbar-track {\n background: #f1f5f9;\n border-radius: 3px;\n }\n .ddddocr-dialog-body::-webkit-scrollbar-thumb {\n background: #FFB6C1;\n border-radius: 3px;\n }\n .ddddocr-dialog-body::-webkit-scrollbar-thumb:hover {\n background: #FF69B4;\n }\n .ddddocr-dialog-content {\n color: #333;\n font-size: 14px;\n line-height: 1.6;\n white-space: pre-wrap;\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 .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 }\n .ddddocr-dialog-button.primary {\n background: #4A90E2;\n color: white;\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 .ddddocr-dialog-button.secondary {\n background: #f1f5f9;\n color: #4A90E2;\n }\n .ddddocr-dialog-button.secondary:hover {\n background: #e2e8f0;\n }\n @keyframes ddddocr-fade-in {\n from { opacity: 0; }\n to { opacity: 1; }\n }\n @keyframes ddddocr-scale-in {\n from { opacity: 0; transform: scale(0.9); }\n to { opacity: 1; transform: scale(1); }\n }\n ",document.head.appendChild(t),this.stylesInjected=true;}static stopPropagation(t){t.stopPropagation();}static show(t){var e;this.injectStyles(),this.close();const n=document.createElement("div");n.className="ddddocr-dialog-overlay";const i=document.createElement("div");i.className="ddddocr-dialog",i.innerHTML=`\n
${t.icon||"ℹ️"} ${t.title}
\n
\n
${t.content}
\n
\n \n `,n.appendChild(i),document.body.appendChild(n),this.container=n,i.addEventListener("mousedown",this.stopPropagation),i.addEventListener("mouseup",this.stopPropagation),i.addEventListener("click",this.stopPropagation),i.addEventListener("dblclick",this.stopPropagation),i.addEventListener("wheel",this.stopPropagation),i.addEventListener("keydown",this.stopPropagation),i.addEventListener("keyup",this.stopPropagation),i.addEventListener("keypress",this.stopPropagation),i.addEventListener("contextmenu",this.stopPropagation),null==(e=i.querySelector(".ddddocr-dialog-button"))||e.addEventListener("click",()=>{var e;null==(e=t.onConfirm)||e.call(t),this.close();}),n.addEventListener("click",t=>{t.target===n&&this.close();});}static confirm(t){var e,n;this.injectStyles(),this.close();const i=document.createElement("div");i.className="ddddocr-dialog-overlay";const o=document.createElement("div");o.className="ddddocr-dialog",o.innerHTML=`\n
${t.icon||"❓"} ${t.title}
\n
\n
${t.content}
\n
\n \n `,i.appendChild(o),document.body.appendChild(i),this.container=i,o.addEventListener("mousedown",this.stopPropagation),o.addEventListener("mouseup",this.stopPropagation),o.addEventListener("click",this.stopPropagation),o.addEventListener("dblclick",this.stopPropagation),o.addEventListener("wheel",this.stopPropagation),o.addEventListener("keydown",this.stopPropagation),o.addEventListener("keyup",this.stopPropagation),o.addEventListener("keypress",this.stopPropagation),o.addEventListener("contextmenu",this.stopPropagation),null==(e=o.querySelector(".confirm-btn"))||e.addEventListener("click",()=>{var e;null==(e=t.onConfirm)||e.call(t),this.close();}),null==(n=o.querySelector(".cancel-btn"))||n.addEventListener("click",()=>{var e;null==(e=t.onCancel)||e.call(t),this.close();}),i.addEventListener("click",e=>{var n;e.target===i&&(null==(n=t.onCancel)||n.call(t),this.close());});}static close(){var t;null==(t=this.container)||t.remove(),this.container=null;}};c.container=null,c.stylesInjected=false;let l=c;const u="ddddocr_config";function getConfig$1(){const t=GM_getValue(u);return t?{...e,...t}:e}function saveConfig$1(t){const e=getConfig$1();GM_setValue(u,{...e,...t});}class SettingsUI{constructor(){this.container=null,this.overlay=null,this.isVisible=false,this.onConfigChange=()=>{},this.activeTab="general",this.createStyles();}createStyles(){const t=document.createElement("style");t.id="ddddocr-settings-styles",t.textContent="\n .ddddocr-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: rgba(0, 0, 0, 0.5);\n backdrop-filter: blur(4px);\n z-index: 2147483646;\n display: none;\n animation: ddddocr-fade 0.2s ease;\n }\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: 560px;\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\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\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-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-close {\n width: 36px;\n 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 }\n .ddddocr-close:hover { background: rgba(255, 255, 255, 0.4); transform: rotate(90deg); }\n\n .ddddocr-tabs {\n display: flex;\n background: rgba(255, 255, 255, 0.1);\n padding: 0 16px;\n overflow-x: auto;\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 }\n .ddddocr-tab:hover { color: white; }\n .ddddocr-tab.active { color: white; }\n .ddddocr-tab.active::after {\n content: '';\n position: absolute;\n bottom: 0;\n left: 50%;\n transform: translateX(-50%);\n width: 30px;\n height: 3px;\n background: white;\n border-radius: 3px 3px 0 0;\n }\n\n .ddddocr-content {\n background: #f8fafc;\n padding: 24px;\n max-height: calc(85vh - 180px);\n overflow-y: auto;\n overflow-x: hidden;\n }\n .ddddocr-content::-webkit-scrollbar {\n width: 6px;\n }\n .ddddocr-content::-webkit-scrollbar-track {\n background: #f1f5f9;\n border-radius: 3px;\n }\n .ddddocr-content::-webkit-scrollbar-thumb {\n background: #FFB6C1;\n border-radius: 3px;\n }\n .ddddocr-content::-webkit-scrollbar-thumb:hover {\n background: #FF69B4;\n }\n\n .ddddocr-panel { display: none; }\n .ddddocr-panel.active { display: block; }\n\n .ddddocr-card {\n background: white;\n border-radius: 16px;\n padding: 20px;\n margin-bottom: 16px;\n box-shadow: 0 2px 12px rgba(74, 144, 226, 0.08);\n border: 1px solid rgba(74, 144, 226, 0.06);\n }\n .ddddocr-card-title {\n font-size: 15px;\n font-weight: 600;\n color: #1e293b;\n margin-bottom: 16px;\n display: flex;\n align-items: center;\n gap: 8px;\n }\n .ddddocr-card-title::before {\n content: '';\n width: 4px;\n height: 16px;\n background: #4A90E2;\n border-radius: 2px;\n }\n\n .ddddocr-row {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 12px 0;\n border-bottom: 1px solid #f1f5f9;\n }\n .ddddocr-row:last-child { border-bottom: none; }\n .ddddocr-row-info { flex: 1; }\n .ddddocr-row-label { font-size: 14px; color: #334155; font-weight: 500; }\n .ddddocr-row-desc { font-size: 12px; color: #94a3b8; margin-top: 2px; }\n\n .ddddocr-switch {\n position: relative;\n width: 48px;\n height: 26px;\n background: #e2e8f0;\n border-radius: 13px;\n cursor: pointer;\n transition: background 0.3s;\n }\n .ddddocr-switch.on { background: #4A90E2; }\n .ddddocr-switch-knob {\n position: absolute;\n top: 3px;\n left: 3px;\n width: 20px;\n height: 20px;\n background: white;\n border-radius: 50%;\n transition: transform 0.3s;\n box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);\n }\n .ddddocr-switch.on .ddddocr-switch-knob { transform: translateX(22px); }\n\n .ddddocr-input {\n width: 100%;\n padding: 12px 14px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n font-size: 14px;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n }\n .ddddocr-input:focus { outline: none; border-color: #4A90E2; box-shadow: 0 0 0 3px rgba(74, 144, 226, 0.15); }\n\n .ddddocr-select {\n width: 100%;\n padding: 12px 14px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n font-size: 14px;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n background: white;\n cursor: pointer;\n }\n .ddddocr-select:focus { outline: none; border-color: #4A90E2; }\n\n .ddddocr-textarea {\n width: 100%;\n padding: 12px 14px;\n border: 2px solid #e2e8f0;\n border-radius: 10px;\n font-size: 13px;\n font-family: 'Monaco', 'Consolas', monospace;\n min-height: 100px;\n resize: vertical;\n transition: all 0.2s;\n margin-top: 8px;\n box-sizing: border-box;\n }\n .ddddocr-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 }\n .ddddocr-file-zone:hover { border-color: #4A90E2; background: rgba(74, 144, 226, 0.05); }\n .ddddocr-file-zone input { display: none; }\n .ddddocr-file-icon { font-size: 32px; margin-bottom: 8px; }\n .ddddocr-file-text { font-size: 13px; color: #64748b; }\n .ddddocr-file-name { font-size: 12px; color: #4A90E2; margin-top: 8px; font-weight: 500; }\n\n .ddddocr-btn-group { display: flex; gap: 12px; margin-top: 16px; }\n .ddddocr-btn {\n flex: 1;\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 }\n .ddddocr-btn-primary {\n background: #4A90E2;\n color: white;\n }\n .ddddocr-btn-primary:hover { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(74, 144, 226, 0.35); }\n .ddddocr-btn-secondary { background: #f1f5f9; color: #475569; }\n .ddddocr-btn-secondary:hover { background: #e2e8f0; }\n .ddddocr-btn-danger { background: #fee2e2; color: #dc2626; }\n .ddddocr-btn-danger:hover { background: #fecaca; }\n .ddddocr-btn-sm { padding: 8px 14px; font-size: 12px; flex: none; }\n\n .ddddocr-hint {\n background: rgba(74, 144, 226, 0.08);\n border: 1px solid rgba(74, 144, 226, 0.15);\n border-radius: 10px;\n padding: 12px 14px;\n font-size: 12px;\n color: #64748b;\n margin-top: 12px;\n }\n\n .ddddocr-badge {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 12px;\n background: rgba(255, 182, 193, 0.2);\n color: #4A90E2;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n margin-bottom: 12px;\n border: 1px solid rgba(255, 182, 193, 0.4);\n }\n\n .ddddocr-rule-item {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 12px;\n background: #f8fafc;\n border-radius: 10px;\n margin-bottom: 8px;\n border: 1px solid rgba(74, 144, 226, 0.08);\n }\n .ddddocr-rule-item:last-child { margin-bottom: 0; }\n .ddddocr-rule-pattern { flex: 1; font-family: monospace; font-size: 13px; color: #334155; }\n .ddddocr-rule-type { font-size: 11px; padding: 4px 8px; background: #e2e8f0; border-radius: 4px; color: #64748b; }\n .ddddocr-rule-output { font-size: 11px; padding: 4px 8px; background: #dbeafe; border-radius: 4px; color: #4A90E2; }\n .ddddocr-rule-delete { background: none; border: none; color: #ef4444; cursor: pointer; font-size: 16px; padding: 4px; }\n\n .ddddocr-empty { text-align: center; padding: 24px; color: #94a3b8; font-size: 13px; }\n\n .ddddocr-add-rule { display: flex; gap: 8px; margin-top: 12px; flex-wrap: wrap; }\n .ddddocr-add-rule input { flex: 2; min-width: 150px; }\n .ddddocr-add-rule select { flex: 1; min-width: 100px; }\n ",document.getElementById("ddddocr-settings-styles")||document.head.appendChild(t);}async createContainer(){this.overlay=document.createElement("div"),this.overlay.className="ddddocr-overlay",this.container=document.createElement("div"),this.container.className="ddddocr-modal";const t=getConfig$1(),e=new ModelCache,n=await e.getUploadedModel(),i=!!n,o=this.renderCalculateRules(t.calculateRules||[]);this.container.innerHTML=`\n
\n
⚡ DDDD OCR 设置
\n \n
\n
\n \n \n \n \n \n
\n
\n
\n
\n
检测与填充
\n
\n
\n
自动检测并填充
\n
自动识别页面验证码并填充结果
\n
\n
\n
\n
\n
\n
\n
\n
打字机效果
\n
模拟人工逐字输入,关闭则一次性填充
\n
\n
\n
\n
\n
\n
\n
\n
系统通知
\n
识别完成后显示桌面通知提醒
\n
\n
\n
\n
\n
\n
\n
\n
自定义选择器
\n
验证码选择器
\n \n
输入框选择器
\n \n
留空则自动检测页面中的验证码元素
\n
\n
\n
\n
\n
四则运算识别
\n
\n
\n
自动计算结果
\n
识别到 "3+5=?" 自动计算并填充
\n
\n
\n
\n
\n
\n
\n
默认输出格式
\n \n
可为不同站点配置不同的输出格式
\n
\n
\n
\n
站点规则
\n
${o}
\n
\n \n \n \n \n
\n
\n 通配符: * 匹配任意字符,? 匹配单个字符
\n 正则: 使用标准正则表达式语法\n
\n
\n
\n
\n
\n
模型来源
\n ${i?`
✓ 已上传本地模型 (${(n.model.byteLength/1024/1024).toFixed(1)} MB)
`:""}\n
\n
\n
使用上传的模型
\n
优先使用本地上传的模型文件
\n
\n
\n
\n
\n
\n
\n
\n
自动下载模型
\n
首次使用时自动从网络下载模型
\n
\n
\n
\n
\n
\n
\n
\n
上传模型文件
\n
\n \n
📦
\n
点击上传 common.onnx
\n
\n
\n
\n \n
📄
\n
点击上传 charsets.json
\n
\n
\n
\n \n \n
\n
\n
\n
\n
\n
白名单设置
\n
\n
\n
启用站点白名单
\n
仅在白名单站点启用脚本功能
\n
\n
\n
\n
\n
\n
\n \n
当前站点: ${window.location.hostname}
\n
\n
\n
\n
配置导入导出
\n
\n \n \n \n
\n
\n
\n
\n `,document.body.appendChild(this.overlay),document.body.appendChild(this.container),this.bindEvents();}renderCalculateRules(t){return t&&0!==t.length?t.map((t,e)=>`\n
\n ${this.escapeHtml(t.pattern)}\n ${"regex"===t.matchType?"正则":"通配符"}\n ${"result"===t.outputMode?"仅结果":"完整等式"}\n \n
\n `).join(""):'
暂无规则,将使用默认输出格式
'}escapeHtml(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}stopPropagation(t){t.stopPropagation();}bindEvents(){var t,n,i,o,a,s,d,r,c;if(!this.container||!this.overlay)return;this.container.addEventListener("mousedown",this.stopPropagation),this.container.addEventListener("mouseup",this.stopPropagation),this.container.addEventListener("click",this.stopPropagation),this.container.addEventListener("dblclick",this.stopPropagation),this.container.addEventListener("wheel",this.stopPropagation),this.container.addEventListener("keydown",this.stopPropagation),this.container.addEventListener("keyup",this.stopPropagation),this.container.addEventListener("keypress",this.stopPropagation),this.container.addEventListener("contextmenu",this.stopPropagation),null==(t=this.container.querySelector(".ddddocr-close"))||t.addEventListener("click",()=>this.hide()),this.overlay.addEventListener("click",()=>this.hide()),null==(n=this.container.querySelector("#cancelBtn"))||n.addEventListener("click",()=>this.hide()),this.container.querySelectorAll(".ddddocr-tab").forEach(t=>{t.addEventListener("click",()=>{const e=t.dataset.tab;this.switchTab(e);});}),this.container.querySelectorAll(".ddddocr-switch").forEach(t=>{t.addEventListener("click",()=>{t.classList.toggle("on");const e=t.dataset.key;if("enableWhitelist"===e&&(this.container.querySelector("#whitelistArea").style.display=t.classList.contains("on")?"block":"none"),"autoCalculate"===e){const e=this.container.querySelector("#calculateOptionsArea"),n=this.container.querySelector("#calculateRulesCard"),i=t.classList.contains("on");e.style.display=i?"block":"none",n.style.display=i?"block":"none";}});});const h=this.container.querySelector("#modelZone"),p=this.container.querySelector("#modelFile"),m=this.container.querySelector("#modelName");h.addEventListener("click",()=>p.click()),p.addEventListener("change",()=>{var t;(null==(t=p.files)?void 0:t[0])&&(m.textContent=`✓ ${p.files[0].name}`);});const g=this.container.querySelector("#charsetsZone"),b=this.container.querySelector("#charsetsFile"),f=this.container.querySelector("#charsetsName");g.addEventListener("click",()=>b.click()),b.addEventListener("change",()=>{var t;(null==(t=b.files)?void 0:t[0])&&(f.textContent=`✓ ${b.files[0].name}`);}),null==(i=this.container.querySelector("#uploadBtn"))||i.addEventListener("click",async()=>{var t,e;const n=null==(t=p.files)?void 0:t[0],i=null==(e=b.files)?void 0:e[0];if(n&&i)try{await async function(t,e){const n=await t.arrayBuffer(),i=await e.text(),o=JSON.parse(i),a=new ModelCache;await a.setUploadedModel(n,o);}(n,i),saveConfig$1({useUploadedModel:!0}),l.show({title:"成功",content:"模型已保存,请刷新页面",icon:"✅"});}catch(o){l.show({title:"错误",content:String(o),icon:"❌"});}else l.show({title:"提示",content:"请选择模型文件和字符集文件",icon:"⚠️"});}),null==(o=this.container.querySelector("#deleteModelBtn"))||o.addEventListener("click",()=>{l.confirm({title:"删除模型",content:"确定删除已上传的模型吗?",icon:"🗑️",onConfirm:async()=>{await async function(){const t=new ModelCache;await t.deleteUploadedModel();}(),saveConfig$1({useUploadedModel:false}),l.show({title:"成功",content:"模型已删除",icon:"✅"});}});}),null==(a=this.container.querySelector("#exportBtn"))||a.addEventListener("click",()=>{const t=getConfig$1(),e=new Blob([JSON.stringify(t,null,2)],{type:"application/json"}),n=URL.createObjectURL(e),i=document.createElement("a");i.href=n,i.download="ddddocr-config.json",i.click(),URL.revokeObjectURL(n);}),null==(s=this.container.querySelector("#importBtn"))||s.addEventListener("click",()=>{const t=document.createElement("input");t.type="file",t.accept=".json",t.onchange=async t=>{var e;const n=null==(e=t.target.files)?void 0:e[0];if(n)try{const t=await n.text();saveConfig$1(JSON.parse(t)),l.show({title:"成功",content:"配置已导入,请刷新页面",icon:"✅"});}catch{l.show({title:"错误",content:"配置文件格式错误",icon:"❌"});}},t.click();}),null==(d=this.container.querySelector("#resetBtn"))||d.addEventListener("click",()=>{l.confirm({title:"重置设置",content:"确定重置所有设置吗?",icon:"⚠️",onConfirm:()=>{GM_setValue(u,e),l.show({title:"成功",content:"设置已重置,请刷新页面",icon:"✅"});}});}),null==(r=this.container.querySelector("#addRuleBtn"))||r.addEventListener("click",()=>this.addCalculateRule()),this.bindRuleDeleteEvents(),null==(c=this.container.querySelector("#saveBtn"))||c.addEventListener("click",()=>this.saveSettings());}bindRuleDeleteEvents(){var t;null==(t=this.container)||t.querySelectorAll(".ddddocr-rule-delete").forEach(t=>{t.addEventListener("click",t=>{const e=parseInt(t.target.dataset.index||"0");this.deleteCalculateRule(e);});});}addCalculateRule(){var t,e,n,i;const o=null==(t=this.container)?void 0:t.querySelector("#newRulePattern"),a=null==(e=this.container)?void 0:e.querySelector("#newRuleMatchType"),s=null==(n=this.container)?void 0:n.querySelector("#newRuleOutputMode"),d=o.value.trim();if(!d)return void l.show({title:"提示",content:"请输入站点匹配规则",icon:"⚠️"});const r=getConfig$1().calculateRules||[];r.push({pattern:d,matchType:a.value,outputMode:s.value,enabled:true}),saveConfig$1({calculateRules:r}),(null==(i=this.container)?void 0:i.querySelector("#calculateRulesList")).innerHTML=this.renderCalculateRules(r),this.bindRuleDeleteEvents(),o.value="";}deleteCalculateRule(t){var e;const n=getConfig$1().calculateRules||[];n.splice(t,1),saveConfig$1({calculateRules:n}),(null==(e=this.container)?void 0:e.querySelector("#calculateRulesList")).innerHTML=this.renderCalculateRules(n),this.bindRuleDeleteEvents();}switchTab(t){this.container&&(this.activeTab=t,this.container.querySelectorAll(".ddddocr-tab").forEach(e=>{e.classList.toggle("active",e.dataset.tab===t);}),this.container.querySelectorAll(".ddddocr-panel").forEach(e=>{e.classList.toggle("active",e.dataset.panel===t);}));}saveSettings(){if(!this.container)return;const t={};this.container.querySelectorAll(".ddddocr-switch").forEach(e=>{const n=e.dataset.key;n&&(t[n]=e.classList.contains("on"));}),this.container.querySelectorAll("input[data-key]").forEach(e=>{const n=e.dataset.key;n&&(t[n]=e.value.trim());}),this.container.querySelectorAll("select[data-key]").forEach(e=>{const n=e.dataset.key;n&&(t[n]=e.value);}),this.container.querySelectorAll("textarea[data-key]").forEach(e=>{const n=e.dataset.key;if(n){const i=e.value;t[n]=i.split("\n").filter(t=>t.trim());}}),saveConfig$1(t),this.onConfigChange(getConfig$1()),"undefined"!=typeof GM_notification&&GM_notification({title:"设置已保存",text:"配置已成功保存",timeout:2e3}),this.hide();}async show(){var t,e;this.container||await this.createContainer(),this.isVisible=true,null==(t=this.overlay)||t.classList.add("visible"),null==(e=this.container)||e.classList.add("visible");}hide(){var t,e;this.isVisible=false,null==(t=this.overlay)||t.classList.remove("visible"),null==(e=this.container)||e.classList.remove("visible");}setOnConfigChange(t){this.onConfigChange=t;}}class LoadingIndicator{constructor(){this.container=null,this.create();}create(){const t=document.createElement("style");t.textContent="\n .ddddocr-loading-indicator {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 4px;\n z-index: 2147483647;\n overflow: hidden;\n background: linear-gradient(90deg, #4A90E2 0%, #FF69B4 25%, #87CEEB 50%, #FF69B4 75%, #4A90E2 100%);\n background-size: 200% 100%;\n animation: ddddocr-wave 3s linear infinite;\n opacity: 0;\n transition: opacity 0.3s;\n }\n .ddddocr-loading-indicator.visible { opacity: 1; }\n @keyframes ddddocr-wave {\n 0% { background-position: 0% 50%; }\n 100% { background-position: 200% 50%; }\n }\n .ddddocr-loading-text {\n position: fixed;\n top: 8px;\n left: 50%;\n transform: translateX(-50%);\n background: #4A90E2;\n color: white;\n padding: 6px 16px;\n border-radius: 20px;\n font-size: 12px;\n font-weight: 500;\n z-index: 2147483647;\n opacity: 0;\n transition: opacity 0.3s;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n }\n .ddddocr-loading-text.visible { opacity: 1; }\n ",document.head.appendChild(t),this.container=document.createElement("div"),this.container.className="ddddocr-loading-indicator",document.body.appendChild(this.container);const e=document.createElement("div");e.className="ddddocr-loading-text",e.id="ddddocr-loading-text",e.textContent="正在初始化 DDDD OCR...",document.body.appendChild(e);}show(t){if(!this.container)return;this.container.classList.add("visible");const e=document.getElementById("ddddocr-loading-text");e&&(t&&(e.textContent=t),e.classList.add("visible"));}updateText(t){const e=document.getElementById("ddddocr-loading-text");e&&(e.textContent=t);}hide(){if(!this.container)return;this.container.classList.remove("visible");const t=document.getElementById("ddddocr-loading-text");t&&t.classList.remove("visible"),setTimeout(()=>{var e;null==(e=this.container)||e.remove(),null==t||t.remove(),this.container=null;},300);}}const h="ddddocr_config";function getConfig(){const t=GM_getValue(h);return t?{...e,...t}:e}function isWhitelisted(){const t=getConfig();if(!t.enableWhitelist)return true;if(!t.whitelist||0===t.whitelist.length)return false;const e=window.location.hostname;return t.whitelist.some(t=>new RegExp("^"+t.replace(/\*/g,".*")+"$","i").test(e))}function shouldExecuteScript(){const t=getConfig();if(t.enableWhitelist){if(!t.whitelist||0===t.whitelist.length)return false;if(!isWhitelisted())return false}return true}class DdddOCR{constructor(){this.engine=new OCREngine({getModel:loadModel,wasmPaths:"https://cdn.jsdelivr.net/npm/onnxruntime-web@1.17.0/dist/"});}async init(){await async function(){await r.init(),async function(){await Promise.allSettled(d.map(async t=>{if(!(await r.get(t)))try{const e=await downloadWASM(t);await r.set(t,e);}catch(e){}}));}().catch(()=>{});const t=window.fetch;window.fetch=async function(e,n){const i="string"==typeof e?e:e instanceof URL?e.href:e.url,o=d.find(t=>i.includes(t));if(!o)return t.call(this,e,n);try{let t=await r.get(o);return t||(t=await downloadWASM(o),r.set(o,t).catch(()=>{})),new Response(t,{status:200,headers:{"Content-Type":"application/wasm","Content-Length":String(t.byteLength)}})}catch(a){return t.call(this,e,n)}};}(),await this.engine.init();}async recognize(t){return this.engine.recognize(t)}}class AutoDetector{constructor(t,e){this.observer=null,this.processedElements=new WeakMap,this.enabled=false,this.checkInterval=null,this.eventEmitter=null,this.autoFill=new AutoFill,this.initialScanDone=false,this.initialScanTimer=null,this.processingElements=new WeakSet,this.ocr=t,this.eventEmitter=e||null;}start(){this.enabled||(this.enabled=true,this.scheduleInitialDetect(),this.observer=new MutationObserver(t=>{for(const e of t){if(e.addedNodes.forEach(t=>{t instanceof HTMLElement&&this.checkElement(t);}),"attributes"===e.type){const t=e.target;t instanceof HTMLElement&&(t instanceof HTMLImageElement?"src"!==e.attributeName&&"data-src"!==e.attributeName&&"srcset"!==e.attributeName||this.recheckImage(t):t instanceof HTMLCanvasElement?this.recheckCanvas(t):"style"===e.attributeName&&t.style.backgroundImage&&this.recheckDiv(t));}"childList"===e.type&&e.target instanceof SVGElement&&this.recheckSVG(e.target);}}),this.observer.observe(document.body,{childList:true,subtree:true,attributes:true,attributeFilter:["src","data-src","srcset","style","href"],characterData:true}),this.startIntervalCheck());}stop(){var t;this.enabled&&(this.enabled=false,null==(t=this.observer)||t.disconnect(),this.observer=null,this.checkInterval&&(clearInterval(this.checkInterval),this.checkInterval=null),this.initialScanTimer&&(clearTimeout(this.initialScanTimer),this.initialScanTimer=null));}scheduleInitialDetect(){this.initialScanDone||(this.detectExistingCaptchas(false),this.initialScanTimer=window.setTimeout(()=>{this.initialScanDone||this.detectExistingCaptchas(true);},3e3));}startIntervalCheck(){this.checkInterval=window.setInterval(()=>{document.querySelectorAll("canvas").forEach(t=>{const e=t;this.isCaptchaCanvas(e)&&this.recheckCanvas(e);});},t.AUTO_DETECT_INTERVAL);}getElementHash(t){if(t instanceof HTMLImageElement){const e=t.getAttribute("data-src")||"",n=t.getAttribute("srcset")||"";return t.src+"_"+e+"_"+n+"_"+t.naturalWidth+"_"+t.naturalHeight}if(t instanceof HTMLCanvasElement)try{return t.toDataURL()}catch(e){return "canvas_"+Date.now()}else {if(t instanceof SVGElement)return t.outerHTML;if(t instanceof HTMLElement&&t.style.backgroundImage)return t.style.backgroundImage}return ""}hasElementChanged(t){const e=this.getElementHash(t),n=this.processedElements.get(t);return !n||e!==n}markElementProcessed(t){const e=this.getElementHash(t);this.processedElements.set(t,e);}detectExistingCaptchas(t){document.querySelectorAll("img").forEach(e=>this.checkImage(e,t)),document.querySelectorAll("canvas").forEach(e=>this.checkCanvas(e,t)),document.querySelectorAll("svg").forEach(e=>this.checkSVG(e,t)),document.querySelectorAll('div[style*="background"]').forEach(e=>this.checkDiv(e,t)),t&&(this.initialScanDone=true);}checkElement(t){t instanceof HTMLImageElement&&this.checkImage(t,true),t instanceof HTMLCanvasElement&&this.checkCanvas(t,true),t instanceof SVGElement&&this.checkSVG(t,true),t.style.backgroundImage&&this.checkDiv(t,true),t.querySelectorAll("img").forEach(t=>this.checkImage(t,true)),t.querySelectorAll("canvas").forEach(t=>this.checkCanvas(t,true)),t.querySelectorAll("svg").forEach(t=>this.checkSVG(t,true)),t.querySelectorAll('div[style*="background"]').forEach(t=>this.checkDiv(t,true));}async waitForImageLoad(t,e=5e3){return !!(t.complete&&t.naturalWidth>0)||new Promise(n=>{const i=setTimeout(()=>{cleanup(),n(false);},e),onLoad=()=>{cleanup(),n(true);},onError=()=>{cleanup(),n(false);},cleanup=()=>{clearTimeout(i),t.removeEventListener("load",onLoad),t.removeEventListener("error",onError);};t.addEventListener("load",onLoad),t.addEventListener("error",onError),t.complete&&t.naturalWidth>0&&(cleanup(),n(true));})}async recheckImage(t){await this.waitForImageLoad(t)&&await this.checkImage(t,true);}async recheckCanvas(t){await new Promise(t=>requestAnimationFrame(t)),await this.checkCanvas(t,true);}async recheckSVG(t){await new Promise(t=>requestAnimationFrame(t)),await this.checkSVG(t,true);}async recheckDiv(t){await new Promise(t=>requestAnimationFrame(t)),await this.checkDiv(t,true);}async checkImage(t,e){var n,o,a,s;const d=getConfig();if(d.captchaSelector){if(!t.matches(d.captchaSelector))return}else if(!this.isCaptchaImage(t))return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"img"}),!e)return;const r=this.findNearbyInput(t);if(r&&r.value.trim()&&(r.value="",r.dispatchEvent(new Event("input",{bubbles:true})),r.dispatchEvent(new Event("change",{bubbles:true}))),await this.waitForImageLoad(t)&&t.naturalWidth&&t.naturalHeight){this.processingElements.add(t);try{null==(o=this.eventEmitter)||o.emit("recognize:start",{element:t});const e=await this.ocr.recognize(t);this.markElementProcessed(t);const n=i.processResult(e.text,{autoCalculate:d.autoCalculate,outputMode:d.calculateOutputMode,rules:d.calculateRules||[]},window.location.hostname);null==(a=this.eventEmitter)||a.emit("recognize:complete",{element:t,result:{text:n}}),r&&await this.autoFill.fill(r,n,{simulate:!0,autoSubmit:!1,typewriterEffect:d.typewriterEffect}),d.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:"验证码已自动填充",text:`识别结果: ${n}`,timeout:3e3});}catch(c){null==(s=this.eventEmitter)||s.emit("recognize:error",{element:t,error:c});}finally{this.processingElements.delete(t);}}}async checkCanvas(t,e){var n,o,a,s;const d=getConfig();if(d.captchaSelector){if(!t.matches(d.captchaSelector))return}else if(!this.isCaptchaCanvas(t))return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"canvas"}),!e)return;const r=this.findNearbyInput(t);r&&r.value.trim()&&(r.value="",r.dispatchEvent(new Event("input",{bubbles:true})),r.dispatchEvent(new Event("change",{bubbles:true}))),await new Promise(t=>requestAnimationFrame(t)),this.processingElements.add(t);try{null==(o=this.eventEmitter)||o.emit("recognize:start",{element:t});const e=await new Promise((e,n)=>{t.toBlob(t=>{t?e(t):n(new Error("Canvas转换失败"));},"image/png");}),n=await this.ocr.recognize(e);this.markElementProcessed(t);const s=i.processResult(n.text,{autoCalculate:d.autoCalculate,outputMode:d.calculateOutputMode,rules:d.calculateRules||[]},window.location.hostname);null==(a=this.eventEmitter)||a.emit("recognize:complete",{element:t,result:{text:s}}),r&&await this.autoFill.fill(r,s,{simulate:!0,autoSubmit:!1,typewriterEffect:d.typewriterEffect}),d.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:"验证码已自动填充",text:`识别结果: ${s}`,timeout:3e3});}catch(c){null==(s=this.eventEmitter)||s.emit("recognize:error",{element:t,error:c});}finally{this.processingElements.delete(t);}}async checkSVG(t,e){var n,o,a,s;const d=getConfig();if(d.captchaSelector){if(!t.matches(d.captchaSelector))return}else if(!this.isCaptchaSVG(t))return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"svg"}),!e)return;const r=this.findNearbyInput(t);r&&r.value.trim()&&(r.value="",r.dispatchEvent(new Event("input",{bubbles:true})),r.dispatchEvent(new Event("change",{bubbles:true}))),this.processingElements.add(t);try{null==(o=this.eventEmitter)||o.emit("recognize:start",{element:t});const e=(new XMLSerializer).serializeToString(t),n=new Blob([e],{type:"image/svg+xml;charset=utf-8"}),s=URL.createObjectURL(n),c=new Image;c.src=s,await new Promise((t,e)=>{c.onload=t,c.onerror=e,setTimeout(e,5e3);});const l=document.createElement("canvas");l.width=t.clientWidth||150,l.height=t.clientHeight||50,l.getContext("2d").drawImage(c,0,0),URL.revokeObjectURL(s);const u=await new Promise((t,e)=>{l.toBlob(n=>{n?t(n):e(new Error("SVG转换失败"));},"image/png");}),h=await this.ocr.recognize(u);this.markElementProcessed(t);const p=i.processResult(h.text,{autoCalculate:d.autoCalculate,outputMode:d.calculateOutputMode,rules:d.calculateRules||[]},window.location.hostname);null==(a=this.eventEmitter)||a.emit("recognize:complete",{element:t,result:{text:p}}),r&&await this.autoFill.fill(r,p,{simulate:!0,autoSubmit:!1,typewriterEffect:d.typewriterEffect}),d.enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:"验证码已自动填充",text:`识别结果: ${p}`,timeout:3e3});}catch(c){null==(s=this.eventEmitter)||s.emit("recognize:error",{element:t,error:c});}finally{this.processingElements.delete(t);}}async checkDiv(t,e){var n,o,a,s;const d=getConfig();if(d.captchaSelector){if(!t.matches(d.captchaSelector))return}else if(!this.isCaptchaDiv(t))return;const r=t.style.backgroundImage;if(!r)return;if(!this.hasElementChanged(t))return;if(this.processingElements.has(t))return;if(null==(n=this.eventEmitter)||n.emit("detect:found",{element:t,type:"div"}),!e)return;const c=this.findNearbyInput(t);c&&c.value.trim()&&(c.value="",c.dispatchEvent(new Event("input",{bubbles:true})),c.dispatchEvent(new Event("change",{bubbles:true}))),this.processingElements.add(t);try{null==(o=this.eventEmitter)||o.emit("recognize:start",{element:t});const e=r.match(/url\(['"]?(.+?)['"]?\)/);if(!e)return;const n=e[1];let s="";if(n.startsWith("data:")){const t=n.split(",")[1],e=atob(t),i=new Uint8Array(e.length);for(let n=0;nt.MAX_CAPTCHA_WIDTH||i>t.MAX_CAPTCHA_HEIGHT)return false;const o=(e.src+e.className+e.id+e.alt+(e.getAttribute("data-src")||"")+(e.getAttribute("srcset")||"")).toLowerCase();return t.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}isCaptchaCanvas(e){const n=e.width,i=e.height;if(nt.MAX_CAPTCHA_WIDTH||i>t.MAX_CAPTCHA_HEIGHT)return false;const o=(e.className+e.id+(e.getAttribute("data-type")||"")).toLowerCase();return t.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}isCaptchaSVG(e){const n=e.clientWidth||parseInt(e.getAttribute("width")||"0"),i=e.clientHeight||parseInt(e.getAttribute("height")||"0");if(nt.MAX_CAPTCHA_WIDTH||i>t.MAX_CAPTCHA_HEIGHT)return false;const o=(e.className.baseVal+e.id).toLowerCase();return t.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}isCaptchaDiv(e){const n=e.clientWidth,i=e.clientHeight;if(nt.MAX_CAPTCHA_WIDTH||i>t.MAX_CAPTCHA_HEIGHT)return false;const o=(e.className+e.id).toLowerCase();return t.CAPTCHA_KEYWORDS.some(t=>o.includes(t))}findNearbyInput(t){const e=getConfig();if(e.inputSelector){const t=document.querySelector(e.inputSelector);if(t instanceof HTMLInputElement)return t}const n=t.closest("form");if(n){const t=n.querySelectorAll('input[type="text"], input[type="password"], input:not([type])');for(const e of t)if(this.isLikelyCaptchaInput(e))return e}let i=t.parentElement;for(let r=0;r<5&&i;r++){const t=i.querySelectorAll('input[type="text"], input[type="password"], input:not([type])');for(const e of t)if(this.isLikelyCaptchaInput(e))return e;i=i.parentElement;}const o=document.querySelectorAll('input[type="text"], input[type="password"], input:not([type])');let a=null,s=Infinity;const d=t.getBoundingClientRect();for(const r of o){if(!this.isLikelyCaptchaInput(r))continue;const t=r.getBoundingClientRect(),e=Math.sqrt(Math.pow(t.left-d.left,2)+Math.pow(t.top-d.top,2));en.includes(t))}}class OCRApp{constructor(){this.loadingIndicator=null,this.initialized=false,this.eventEmitter=new EventEmitter,this.ocr=new DdddOCR,this.detector=new AutoDetector(this.ocr,this.eventEmitter),this.settingsUI=new SettingsUI,this.registerMenuCommands(),this.settingsUI.setOnConfigChange(t=>this.handleConfigChange(t));}async init(){var t;if(!shouldExecuteScript())return;if(this.initialized)return;const e=getConfig();this.initialized=true,this.loadingIndicator=new LoadingIndicator;try{this.loadingIndicator.show("正在初始化 DDDD OCR"),this.loadingIndicator.updateText("正在加载模型文件"),await this.ocr.init(),this.loadingIndicator.updateText("DDDD OCR 已就绪"),e.autoDetect&&this.detector.start(),setTimeout(()=>{var t;return null==(t=this.loadingIndicator)?void 0:t.hide()},2e3),this.showNotification("DDDD OCR 已就绪",e.autoDetect?"自动检测已启用":"点击菜单启用自动检测");}catch(n){null==(t=this.loadingIndicator)||t.updateText("初始化失败: "+String(n)),setTimeout(()=>{var t;return null==(t=this.loadingIndicator)?void 0:t.hide()},3e3),this.showNotification("初始化失败",String(n),true);}}registerMenuCommands(){GM_registerMenuCommand("⚙️ 打开设置",()=>this.settingsUI.show(),"s"),GM_registerMenuCommand("🤖 切换自动检测",()=>this.toggleAutoDetect(),"a"),GM_registerMenuCommand("🗑️ 清除所有缓存",async()=>{l.confirm({title:"清除缓存",content:"确定要清除所有缓存吗(包括模型和 WASM)?下次启动将重新下载。",icon:"🗑️",confirmText:"确定清除",cancelText:"取消",onConfirm:async()=>{await async function(){const t=new ModelCache;await t.delete();}(),await async function(){await r.clear();}(),this.showNotification("缓存已清除","请刷新页面");}});},"d"),GM_registerMenuCommand("ℹ️ 查看状态",()=>this.showStatus(),"i");}showStatus(){var t,e;const n=getConfig(),i=isWhitelisted();let o=`\n脚本状态: ${this.initialized?"✅ 已初始化":"❌ 未初始化"}\n当前站点: ${window.location.hostname}\n白名单状态: ${n.enableWhitelist?"✅ 已启用":"❌ 已禁用"}\n白名单数量: ${(null==(t=n.whitelist)?void 0:t.length)||0} 个站点\n当前站点匹配: ${i?"✅ 在白名单中":"❌ 不在白名单中"}\n自动检测: ${n.autoDetect?"✅ 已启用":"❌ 已禁用"}\n打字机效果: ${n.typewriterEffect?"✅ 已启用":"❌ 已禁用"}\n自动计算: ${n.autoCalculate?"✅ 已启用":"❌ 已禁用"}\n计算输出: ${"result"===n.calculateOutputMode?"仅结果":"完整等式"}\n计算规则数: ${(null==(e=n.calculateRules)?void 0:e.length)||0} 条\n上传模型: ${n.useUploadedModel?"✅ 已启用":"❌ 未启用"}\n自动下载: ${n.autoDownload?"✅ 已启用":"❌ 已禁用"}`;l.show({title:"当前状态",content:o,icon:"ℹ️"});}toggleAutoDetect(){const t=!getConfig().autoDetect;t?this.initialized?(this.detector.start(),this.showNotification("自动检测已启用","将自动识别并填充验证码")):(l.show({title:"需要初始化",content:"启用自动检测需要先初始化 OCR 引擎,请稍候",icon:"⏳"}),this.init().then(()=>{this.detector.start(),this.showNotification("自动检测已启用","将自动识别并填充验证码");})):(this.detector.stop(),this.showNotification("自动检测已关闭","不再自动处理验证码")),function(t){const e=getConfig();GM_setValue(h,{...e,...t});}({autoDetect:t});}handleConfigChange(t){t.autoDetect&&!this.initialized&&this.init(),t.autoDetect?this.detector.start():this.detector.stop();}showNotification(t,e,n=false){getConfig().enableNotification&&"undefined"!=typeof GM_notification&&GM_notification({title:t,text:e,timeout:n?5e3:3e3});}}function bootstrap(){const t=new OCRApp;shouldExecuteScript()&&setTimeout(()=>t.init(),500);}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",bootstrap):bootstrap(); })();