@filteringdev/namulink 20.3.0 → 20.4.0-build.9e0cb5c20b9f

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -8,7 +8,7 @@
8
8
  // @downloadURL https://cdn.jsdelivr.net/npm/@filteringdev/namulink@latest/dist/NamuLink.user.js
9
9
  // @license MPL-2.0
10
10
  //
11
- // @version 20.3.0
11
+ // @version 20.4.0-build.9e0cb5c20b9f
12
12
  // @author PiQuark6046 and contributors
13
13
  //
14
14
  // @grant unsafeWindow
@@ -20,12 +20,10 @@
20
20
  //
21
21
  // @match *://namu.wiki/*
22
22
  // ==/UserScript==
23
- (()=>{"use strict";var t={},e={};// The require function
24
- function r(n){// Check if module is in cache
25
- var a=e[n];if(void 0!==a)return a.exports;// Create a new module (and put it into the cache)
26
- var o=e[n]={exports:{}};// Return the exports of the module
27
- return(// Execute the module function
28
- t[n](o,o.exports,r),o.exports)}function n(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=Array(e);r<e;r++)n[r]=t[r];return n}function a(t){return function(t){if(Array.isArray(t))return n(t)}(t)||function(t){if("u">typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t){if(t){if("string"==typeof t)return n(t,void 0);var e=Object.prototype.toString.call(t).slice(8,-1);if("Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e)return Array.from(e);if("Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e))return n(t,void 0)}}(t)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(t,e){return null!=e&&"u">typeof Symbol&&e[Symbol.hasInstance]?!!e[Symbol.hasInstance](t):t instanceof e}function i(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=Array(e);r<e;r++)n[r]=t[r];return n}function l(t,e,r,n,a,o,i){try{var l=t[o](i),u=l.value}catch(t){r(t);return}l.done?e(u):Promise.resolve(u).then(n,a)}function u(t){return function(){var e=this,r=arguments;return new Promise(function(n,a){var o=t.apply(e,r);function i(t){l(o,n,a,i,u,"next",t)}function u(t){l(o,n,a,i,u,"throw",t)}i(void 0)})}}function c(t,e){return null!=e&&"u">typeof Symbol&&e[Symbol.hasInstance]?!!e[Symbol.hasInstance](t):t instanceof e}function f(t,e){var r,n,a,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),l=Object.defineProperty;return l(i,"next",{value:u(0)}),l(i,"throw",{value:u(1)}),l(i,"return",{value:u(2)}),"function"==typeof Symbol&&l(i,Symbol.iterator,{value:function(){return this}}),i;function u(l){return function(u){var c=[l,u];if(r)throw TypeError("Generator is already executing.");for(;i&&(i=0,c[0]&&(o=0)),o;)try{if(r=1,n&&(a=2&c[0]?n.return:c[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,c[1])).done)return a;switch(n=0,a&&(c=[2&c[0],a.value]),c[0]){case 0:case 1:a=c;break;case 4:return o.label++,{value:c[1],done:!1};case 5:o.label++,n=c[1],c=[0];continue;case 7:c=o.ops.pop(),o.trys.pop();continue;default:if(!(a=(a=o.trys).length>0&&a[a.length-1])&&(6===c[0]||2===c[0])){o=0;continue}if(3===c[0]&&(!a||c[1]>a[0]&&c[1]<a[3])){o.label=c[1];break}if(6===c[0]&&o.label<a[1]){o.label=a[1],a=c;break}if(a&&o.label<a[2]){o.label=a[2],o.ops.push(c);break}a[2]&&o.ops.pop(),o.trys.pop();continue}c=e.call(t,o)}catch(t){c=[6,t],n=0}finally{r=a=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}}}function s(t,e){for(var r=e;r;){var n=t.getComputedStyle(r).backgroundColor;if(n&&"transparent"!==n&&"rgba(0, 0, 0, 0)"!==n)return n;r=r.parentElement}return"rgb(255, 255, 255)"}function h(t,e,r){var n=new Set;function a(t){t&&"transparent"!==t&&"rgba(0, 0, 0, 0)"!==t&&n.add(t)}a(r);var o=t.getComputedStyle(e);if(a(o.backgroundColor),a(o.color),a(t.getComputedStyle(t.document.documentElement).backgroundColor),t.document.body){var l=t.getComputedStyle(t.document.body);a(l.backgroundColor),a(l.color)}return a("rgb(255, 255, 255)"),a("rgb(0, 0, 0)"),function(t){if(Array.isArray(t))return i(t)}(n)||function(t){if("u">typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(n)||function(t){if(t){if("string"==typeof t)return i(t,void 0);var e=Object.prototype.toString.call(t).slice(8,-1);if("Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e)return Array.from(e);if("Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e))return i(t,void 0)}}(n)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function d(t){return"string"==typeof t&&/^image\/svg\+xml(?:\s*;|$)/i.test(t)}function g(t,e,r){return u(function(){var n,a,o,i,l,c,s,h;return f(this,function(d){var g,m,p;switch(d.label){case 0:g=e.getBoundingClientRect(),m=Math.max(1,t.devicePixelRatio||1),a=(n={Width:Math.max(1,Math.round((g.width||e.clientWidth||96)*m)),Height:Math.max(1,Math.round((g.height||e.clientHeight||32)*m))}).Width,o=n.Height,i=function(t,e,r,n){var a=new t.DOMParser().parseFromString(e,"image/svg+xml");if(a.querySelector("parsererror"))throw Error("Failed to parse SVG markup");var o=a.documentElement;if(!o||"svg"!==o.nodeName.toLowerCase())throw Error("SVG root element not found");return o.getAttribute("xmlns")||o.setAttribute("xmlns","http://www.w3.org/2000/svg"),o.getAttribute("width")||o.setAttribute("width",String(r)),o.getAttribute("height")||o.setAttribute("height",String(n)),new t.XMLSerializer().serializeToString(a)}(t,r,a,o),l=t.URL.createObjectURL(new t.Blob([i],{type:"image/svg+xml"})),d.label=1;case 1:return d.trys.push([1,,3,4]),[4,(p=l,u(function(){var e;return f(this,function(r){switch(r.label){case 0:(e=new t.Image).decoding="async",e.src=p,r.label=1;case 1:return r.trys.push([1,3,,4]),[4,e.decode()];case 2:if(r.sent(),e.naturalWidth>0)return[2,e];return[3,4];case 3:return r.sent(),[3,4];case 4:var n;return[4,(n=e).complete&&n.naturalWidth>0?Promise.resolve():new Promise(function(t,e){var r=function(){n.removeEventListener("load",a),n.removeEventListener("error",o)},a=function(){r(),t()},o=function(){r(),e(Error("Failed to load SVG image"))};n.addEventListener("load",a),n.addEventListener("error",o)})];case 5:return r.sent(),[2,e]}})})())];case 2:if(c=d.sent(),(s=t.document.createElement("canvas")).width=a,s.height=o,!(h=s.getContext("2d",{willReadFrequently:!0})))throw Error("2D context unavailable");return h.clearRect(0,0,a,o),h.drawImage(c,0,0,a,o),[2,h.getImageData(0,0,a,o)];case 3:return t.URL.revokeObjectURL(l),[7];case 4:return[2]}})})()}function m(t,e,r){return u(function(){var n,a;return f(this,function(o){var i;switch(o.label){case 0:if(!/^data:image\/svg\+xml(?:[;,]|$)/i.test(r))return[3,2];return n=function(t,e){var r=e.indexOf(",");if(r<0)throw Error("Invalid SVG data URL");var n=e.slice(0,r).toLowerCase(),a=e.slice(r+1);if(n.includes(";base64")){for(var o=t.atob(a),i=new Uint8Array(o.length),l=0;l<o.length;l++)i[l]=o.charCodeAt(l);return new TextDecoder().decode(i)}return decodeURIComponent(a)}(t,r),[4,g(t,e,n)];case 1:case 5:case 7:return[2,o.sent()];case 2:return[4,new Promise(function(t,e){GM.xmlHttpRequest({url:r,method:"GET",responseType:"blob",onload:function(r){if(r.status<200||r.status>=300)return void e(Error("Failed to fetch image: ".concat(r.status," ").concat(r.statusText)));var n=r.response;if(!c(n,Blob))return void e(Error("Failed to fetch image: invalid blob response"));var a=r.responseHeaders.match(/^content-type:\s*(.+)$/im);t({BlobData:n,ContentTypeHeader:a?a[1].trim():null})},onerror:e,ontimeout:e})})];case 3:if(!(d((a=o.sent()).BlobData.type)||d(a.ContentTypeHeader)))return[3,6];return[4,a.BlobData.text()];case 4:return[4,g(t,e,o.sent())];case 6:return[4,(i=a.BlobData,u(function(){var e,r,n;return f(this,function(a){switch(a.label){case 0:return[4,t.createImageBitmap(i)];case 1:e=a.sent();try{if((r=t.document.createElement("canvas")).width=e.width,r.height=e.height,!(n=r.getContext("2d",{willReadFrequently:!0})))throw Error("2D context unavailable");return n.drawImage(e,0,0),[2,n.getImageData(0,0,r.width,r.height)]}finally{e.close()}}})})())]}})})()}/*!
23
+
24
+
25
+ (()=>{function D(e,t={}){let n=t.QuietMs??120,r=t.EventName??"vue:settled",o=t.ChangeEventName??"vue:dom-changed",m=t.UrlChange??"vue:url-changed";if(!(e instanceof HTMLElement))throw new TypeError("TargetEl must be an HTMLElement");let l=-1,C=0,h=!1,c=performance.now(),f=new URL(location.href),u=a=>{e.dispatchEvent(new CustomEvent(o,{detail:{Seq:C,At:c,MutationCount:a.length,Mutations:a}}))},i=()=>{requestAnimationFrame(()=>{requestAnimationFrame(()=>{h||e.dispatchEvent(new CustomEvent(r,{detail:{Seq:C,QuietMs:n,SettledAt:performance.now(),ElapsedSinceLastMutation:performance.now()-c,Target:e}}))})})},d=()=>{let a=new URL(location.href);a.href!==f.href&&(f=a,e.dispatchEvent(new CustomEvent(m,{detail:{Seq:C,At:performance.now(),URL:a}})))},y=()=>{clearTimeout(l),l=setTimeout(i,n)},p=new MutationObserver(a=>{C+=1,c=performance.now(),u(a),a.flatMap(g=>[...g.addedNodes,...g.removedNodes,...g.nextSibling?[g.nextSibling]:[],...g.previousSibling?[g.previousSibling]:[],...g.target?[g.target]:[]]).length>=15&&(y(),setTimeout(y,n*3)),d()});return p.observe(e,{subtree:!0,childList:!0,attributes:!0,characterData:!0}),y(),{Disconnect(){h=!0,clearTimeout(l),p.disconnect(),e.dispatchEvent(new CustomEvent("vue:observer-disconnected",{detail:{Target:e}}))}}}function M(e,t=document.documentElement){return new Promise(n=>{let r=t.querySelector(e);if(r&&r instanceof HTMLElement){n(r);return}let o=new MutationObserver(()=>{let m=t.querySelector(e);m&&m instanceof HTMLElement&&(o.disconnect(),n(m))});o.observe(t,{subtree:!0,childList:!0,attributes:!0})})}function z(e){let t=e.trim();if(!t||t==="none")return null;let n=t.match(/^url\((.*)\)$/i);if(!n)return null;let r=n[1].trim();return(r.startsWith('"')&&r.endsWith('"')||r.startsWith("'")&&r.endsWith("'"))&&(r=r.slice(1,-1)),r}function w(e,t){let n=t;for(;n;){let r=e.getComputedStyle(n).backgroundColor;if(r&&r!=="transparent"&&r!=="rgba(0, 0, 0, 0)")return r;n=n.parentElement}return"rgb(255, 255, 255)"}function L(e,t,n){let r=new Set;function o(l){l&&(l==="transparent"||l==="rgba(0, 0, 0, 0)"||r.add(l))}o(n);let m=e.getComputedStyle(t);if(o(m.backgroundColor),o(m.color),o(e.getComputedStyle(e.document.documentElement).backgroundColor),e.document.body){let l=e.getComputedStyle(e.document.body);o(l.backgroundColor),o(l.color)}return o("rgb(255, 255, 255)"),o("rgb(0, 0, 0)"),[...r]}function N(e,t){if(t instanceof e.HTMLImageElement)return t.currentSrc||t.src||""||null;let n=e.getComputedStyle(t).backgroundImage;return z(n)}function U(){return{XhrResponses:new Map,PendingXhrResponses:new Map,ImageDataValues:new Map,PendingImageDataValues:new Map,OcrResults:new Map,PendingOcrResults:new Map}}function Z(e){e.XhrResponses.clear(),e.PendingXhrResponses.clear(),e.ImageDataValues.clear(),e.PendingImageDataValues.clear(),e.OcrResults.clear(),e.PendingOcrResults.clear()}function T(e,t){try{return new e.URL(t,e.location.href).href}catch{return t}}function v(e){return JSON.stringify(e)}function X(e){return v(["bitmap-image-data",e])}function I(e,t,n){let{Width:r,Height:o}=V(e,t);return v(["svg-image-data",n,r,o])}function $(e,t,n,r){return v(["ocr-result",e,t.width,t.height,n,r?.FontCandidates??null,r?.ScoreThreshold??.32])}function O(e,t){let n=0,r=new Map,o=U();t.addEventListener("message",c=>{let f=c.data;if(!f||!("RequestId"in f))return;let u=r.get(f.RequestId);if(u){if(r.delete(f.RequestId),f.Kind==="detect-result"){u.Resolve(f.Result);return}u.Reject(new Error(f.Error))}});function m(c){let f=`ocr-${Date.now()}-${n++}`,u={Kind:"detect",RequestId:f,...c};return new Promise((i,d)=>{r.set(f,{Resolve:i,Reject:d}),t.postMessage(u)})}function l(c,f,u,i){let d=$(c,f,u,i);if(o.OcrResults.has(d))return Promise.resolve(o.OcrResults.get(d)??null);let y=o.PendingOcrResults.get(d);if(y)return y;let p=m({ImageData:f,BackgroundCandidates:u,FontCandidates:i?.FontCandidates,ScoreThreshold:i?.ScoreThreshold}).then(a=>(o.OcrResults.set(d,a),a)).finally(()=>{o.PendingOcrResults.delete(d)});return o.PendingOcrResults.set(d,p),p}async function C(c,f){let u=N(e,c);if(!u)return null;let i=T(e,u),d=await A(e,c,i,o);if(!d)return null;let y=w(e,c),p=L(e,c,y);return l(i,d,p,f)}async function h(c){let f=T(e,c.SourceUrl),u=await A(e,c.HostElement,f,o);if(!u)return null;let i=w(e,c.HostElement),d=L(e,c.HostElement,i);return l(f,u,d,c)}return{DetectFromElement:C,DetectFromSource:h,Terminate(){for(let c of r.values())c.Reject(new Error("OCR worker terminated"));r.clear(),Z(o),t.terminate()}}}function _(e){return/^data:image\/svg\+xml(?:[;,]|$)/i.test(e)}function G(e,t){let n=e.atob(t),r=new Uint8Array(n.length);for(let o=0;o<n.length;o++)r[o]=n.charCodeAt(o);return new TextDecoder().decode(r)}function j(e,t){let n=t.indexOf(",");if(n<0)throw new Error("Invalid SVG data URL");let r=t.slice(0,n).toLowerCase(),o=t.slice(n+1);return r.includes(";base64")?G(e,o):decodeURIComponent(o)}function K(e,t,n,r){let m=new e.DOMParser().parseFromString(t,"image/svg+xml");if(m.querySelector("parsererror"))throw new Error("Failed to parse SVG markup");let l=m.documentElement;if(!l||l.nodeName.toLowerCase()!=="svg")throw new Error("SVG root element not found");return l.getAttribute("xmlns")||l.setAttribute("xmlns","http://www.w3.org/2000/svg"),l.getAttribute("width")||l.setAttribute("width",String(n)),l.getAttribute("height")||l.setAttribute("height",String(r)),new e.XMLSerializer().serializeToString(m)}function Q(e){return e.complete&&e.naturalWidth>0?Promise.resolve():new Promise((t,n)=>{function r(){e.removeEventListener("load",o),e.removeEventListener("error",m)}function o(){r(),t()}function m(){r(),n(new Error("Failed to load SVG image"))}e.addEventListener("load",o),e.addEventListener("error",m)})}async function B(e,t){let n=new e.Image;n.decoding="async",n.src=t;try{if(await n.decode(),n.naturalWidth>0)return n}catch{}return await Q(n),n}function H(e){return typeof e=="string"&&/^image\/svg\+xml(?:\s*;|$)/i.test(e)}function V(e,t){let n=t.getBoundingClientRect(),r=Math.max(1,e.devicePixelRatio||1);return{Width:Math.max(1,Math.round((n.width||t.clientWidth||96)*r)),Height:Math.max(1,Math.round((n.height||t.clientHeight||32)*r))}}async function F(e,t,n){let{Width:r,Height:o}=V(e,t),m=K(e,n,r,o),l=e.URL.createObjectURL(new e.Blob([m],{type:"image/svg+xml"}));try{let C=await B(e,l),h=e.document.createElement("canvas");h.width=r,h.height=o;let c=h.getContext("2d",{willReadFrequently:!0});if(!c)throw new Error("2D context unavailable");return c.clearRect(0,0,r,o),c.drawImage(C,0,0,r,o),c.getImageData(0,0,r,o)}finally{e.URL.revokeObjectURL(l)}}async function W(e,t){let n=await e.createImageBitmap(t);try{let r=e.document.createElement("canvas");r.width=n.width,r.height=n.height;let o=r.getContext("2d",{willReadFrequently:!0});if(!o)throw new Error("2D context unavailable");return o.drawImage(n,0,0),o.getImageData(0,0,r.width,r.height)}finally{n.close()}}async function A(e,t,n,r){if(_(n)){let c=I(e,t,n);return await R(r,c,async()=>{let f=j(e,n);return await F(e,t,f)})}let o=X(n),m=P(r,o);if(m)return m;let l=I(e,t,n),C=P(r,l);if(C)return C;let h=await J(r,n);return h?H(h.BlobData.type)||H(h.ContentTypeHeader)?await R(r,l,async()=>{let c=await h.BlobData.text();return await F(e,t,c)}):await R(r,o,async()=>await W(e,h.BlobData)):null}function P(e,t){return e.ImageDataValues.has(t)?e.ImageDataValues.get(t)??null:null}function R(e,t,n){let r=P(e,t);if(r)return Promise.resolve(r);let o=e.PendingImageDataValues.get(t);if(o)return o;let m=n().then(l=>(e.ImageDataValues.set(t,l),l)).finally(()=>{e.PendingImageDataValues.delete(t)});return e.PendingImageDataValues.set(t,m),m}function J(e,t){if(e.XhrResponses.has(t))return Promise.resolve(e.XhrResponses.get(t)??null);let n=e.PendingXhrResponses.get(t);if(n)return n;let r=Y(t).then(o=>(o&&e.XhrResponses.set(t,o),o)).finally(()=>{e.PendingXhrResponses.delete(t)});return e.PendingXhrResponses.set(t,r),r}function Y(e){return new Promise(t=>{GM.xmlHttpRequest({url:e,method:"GET",responseType:"blob",onload:n=>{if(n.status<200||n.status>=300){t(null);return}let r=n.response;if(!(r instanceof Blob)){t(null);return}let m=(typeof n.responseHeaders=="string"?n.responseHeaders:"").match(/^content-type:\s*(.+)$/im),l=m?m[1].trim():null;t({BlobData:r,ContentTypeHeader:l})},onerror:()=>t(null),ontimeout:()=>t(null)})})}var S=typeof unsafeWindow<"u"?unsafeWindow:window,E="NamuLink";(async()=>{let e=S.Reflect.apply,t=[[/function *[A-Za-z0-9]+ *\([A-Za-z0-9]+ * *\) *{ *function *[A-Za-z0-9]+ *\( *[a-zA-Z]+ *, *[A-Za-z]+ *\) *{ *return *[A-Za-z0-9]+ *\( */,/{ *return *[A-Za-z0-9]+ *\( *[a-zA-Z]+[- ]*0x[a-f0-9]+ *, *[a-zA-Z]+ *\) *; *\} *[A-Za-z0-9]+ *\( *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+/,/\( *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *\( *0x[a-f0-9]+ *, *0x[a-f0-9]+ *\) *, *[A-Za-z0-9]+ *\) *;/]];S.Promise.prototype.then=new Proxy(S.Promise.prototype.then,{apply(u,i,d){if(typeof d[0]!="function"||typeof d[1]!="function")return e(u,i,d);let y=[String(d[0]),String(d[1])];if(y.every(p=>t.filter(a=>a.filter(g=>g.test(p)).length===a.length).length===1)){console.debug(`[${E}] Detected PL2 Promise.then`,y,d),setTimeout(()=>{let p=[...document.querySelectorAll("#app div[class] div[class] ~ div[class]")].filter(a=>a instanceof HTMLElement);p=p.filter(a=>parseFloat(getComputedStyle(a).getPropertyValue("margin-bottom"))>=12.5),p=p.filter(a=>a.innerText.trim().length===0),p=p.filter(a=>[...a.querySelectorAll("*")].filter(g=>g instanceof HTMLElement).some(g=>{let s=g.getBoundingClientRect().height;return s>0&&s<=5})),console.debug(`[${E}] Detected PL2 Promise.then Targeted`,p),p.forEach(a=>{a.style.setProperty("display","none","important")})},250);return}return e(u,i,d)}});let n=await M("#app",S.document);D(n,{QuietMs:75,EventName:"vue:settled",ChangeEventName:"vue:change",UrlChange:"vue:url-changed"});let l=O(S,new Worker(URL.createObjectURL(new Blob(['(()=>{var b=["\\uD30C\\uC6CC\\uB9C1\\uD06C","\\uAD11\\uACE0","\\uAD11\\uACE0\\uB4F1\\uB85D"],k=["Pretendard JP, sans-serif","Pretendard, sans-serif","system-ui, sans-serif","Apple SD Gothic Neo, sans-serif","Nanum Gothic, sans-serif","Noto Sans KR, sans-serif","Arial, sans-serif"],H=new Map;function T(t,n){return new OffscreenCanvas(Math.max(1,Math.floor(t)),Math.max(1,Math.floor(n)))}function C(t){let n=t.getContext("2d",{willReadFrequently:!0});if(!n)throw new Error("2D context unavailable");return n}function Y(t){let n=C(t),{width:a,height:e}=t,r=n.getImageData(0,0,a,e).data,o=new Uint8ClampedArray(a*e);for(let i=0,s=0;i<r.length;i+=4,s++){let l=r[i],h=r[i+1],g=r[i+2];o[s]=Math.round(.299*l+.587*h+.114*g)}return{Width:a,Height:e,Data:o}}function A(t){let n=new Uint32Array(256);for(let l=0;l<t.Data.length;l++)n[t.Data[l]]++;let a=t.Data.length,e=0;for(let l=0;l<256;l++)e+=l*n[l];let r=0,o=0,i=-1,s=127;for(let l=0;l<256;l++){if(o+=n[l],o===0)continue;let h=a-o;if(h===0)break;r+=l*n[l];let g=r/o,d=(e-r)/h,c=o*h*(g-d)*(g-d);c>i&&(i=c,s=l)}return s}function M(t){let n=A(t),a=0,e=0;for(let i=0;i<t.Data.length;i++)t.Data[i]<n?a++:e++;let r=a<e,o=new Uint8Array(t.Width*t.Height);for(let i=0;i<t.Data.length;i++){let s=r?t.Data[i]<n:t.Data[i]>n;o[i]=s?1:0}return{Width:t.Width,Height:t.Height,Data:o}}function O(t){let n=new Uint8Array(t.Width*t.Height);for(let a=1;a<t.Height-1;a++)for(let e=1;e<t.Width-1;e++){let r=1;for(let o=-1;o<=1&&r;o++)for(let i=-1;i<=1;i++)if(t.Data[(a+o)*t.Width+(e+i)]===0){r=0;break}n[a*t.Width+e]=r}return{Width:t.Width,Height:t.Height,Data:n}}function w(t){let n=new Uint8Array(t.Width*t.Height);for(let a=1;a<t.Height-1;a++)for(let e=1;e<t.Width-1;e++){let r=0;for(let o=-1;o<=1&&!r;o++)for(let i=-1;i<=1;i++)if(t.Data[(a+o)*t.Width+(e+i)]===1){r=1;break}n[a*t.Width+e]=r}return{Width:t.Width,Height:t.Height,Data:n}}function N(t){return w(O(w(t)))}function U(t,n=20){let a=new Uint8Array(t.Width*t.Height),e=[],r=new Int32Array(t.Width*t.Height),o=new Int32Array(t.Width*t.Height);for(let i=0;i<t.Height;i++)for(let s=0;s<t.Width;s++){let l=i*t.Width+s;if(a[l]||t.Data[l]===0)continue;let h=0,g=0;r[g]=s,o[g]=i,g++,a[l]=1;let d=s,c=i,u=s,f=i,X=0;for(;h<g;){let m=r[h],D=o[h];h++,X++,m<d&&(d=m),D<c&&(c=D),m>u&&(u=m),D>f&&(f=D);for(let I=-1;I<=1;I++)for(let y=-1;y<=1;y++){if(y===0&&I===0)continue;let W=m+y,B=D+I;if(W<0||B<0||W>=t.Width||B>=t.Height)continue;let x=B*t.Width+W;a[x]||t.Data[x]===0||(a[x]=1,r[g]=W,o[g]=B,g++)}}X>=n&&e.push({X:d,Y:c,Width:u-d+1,Height:f-c+1})}return e}function v(t,n=8,a=4){let e=[...t],r=!0;function o(i,s){let l=i.X+i.Width,h=i.Y+i.Height,g=s.X+s.Width,d=s.Y+s.Height;return!(l+n<s.X||g+n<i.X||h+a<s.Y||d+a<i.Y)}for(;r;){r=!1;t:for(let i=0;i<e.length;i++)for(let s=i+1;s<e.length;s++){if(!o(e[i],e[s]))continue;let l=e[i],h=e[s];e[i]={X:Math.min(l.X,h.X),Y:Math.min(l.Y,h.Y),Width:Math.max(l.X+l.Width,h.X+h.Width)-Math.min(l.X,h.X),Height:Math.max(l.Y+l.Height,h.Y+h.Height)-Math.min(l.Y,h.Y)},e.splice(s,1),r=!0;break t}}return e}function R(t,n){let a=new Uint8Array(n.Width*n.Height);for(let e=0;e<n.Height;e++)for(let r=0;r<n.Width;r++)a[e*n.Width+r]=t.Data[(n.Y+e)*t.Width+(n.X+r)];return{Width:n.Width,Height:n.Height,Data:a}}function E(t){let n=t.Width,a=t.Height,e=-1,r=-1;for(let o=0;o<t.Height;o++)for(let i=0;i<t.Width;i++)t.Data[o*t.Width+i]!==0&&(i<n&&(n=i),o<a&&(a=o),i>e&&(e=i),o>r&&(r=o));return e<n||r<a?{Width:1,Height:1,Data:new Uint8Array([0])}:R(t,{X:n,Y:a,Width:e-n+1,Height:r-a+1})}function P(t,n,a){let e=new Uint8Array(n*a);for(let r=0;r<a;r++)for(let o=0;o<n;o++){let i=Math.min(t.Width-1,Math.floor(o/n*t.Width)),s=Math.min(t.Height-1,Math.floor(r/a*t.Height));e[r*n+o]=t.Data[s*t.Width+i]}return{Width:n,Height:a,Data:e}}function p(t,n=64){let a=E(t),e=Math.max(a.Width,a.Height),r=new Uint8Array(e*e),o=Math.floor((e-a.Width)/2),i=Math.floor((e-a.Height)/2);for(let s=0;s<a.Height;s++)for(let l=0;l<a.Width;l++)r[(s+i)*e+(l+o)]=a.Data[s*a.Width+l];return P({Width:e,Height:e,Data:r},n,n)}function F(t,n){if(t.Width!==n.Width||t.Height!==n.Height)throw new Error("Image size mismatch");let a=0;for(let e=0;e<t.Data.length;e++)t.Data[e]!==n.Data[e]&&a++;return a/t.Data.length}function K(t,n){let a=`${t}__${n}`,e=H.get(a);if(e)return e;let r=256,o=96,i=T(r,o),s=C(i);s.fillStyle="white",s.fillRect(0,0,r,o);let l=Math.floor(o*.72);for(;l>8;){s.clearRect(0,0,r,o),s.fillStyle="white",s.fillRect(0,0,r,o),s.fillStyle="black",s.textAlign="center",s.textBaseline="middle",s.font=`700 ${l}px ${n}`;let g=s.measureText(t),d=g.width,c=(g.actualBoundingBoxAscent||l*.8)+(g.actualBoundingBoxDescent||l*.2);if(d<=r*.9&&c<=o*.9){s.fillText(t,r/2,o/2);let u=Y(i),f=p(M(u));return H.set(a,f),f}l--}s.font=`700 12px ${n}`,s.fillStyle="black",s.textAlign="center",s.textBaseline="middle",s.fillText(t,r/2,o/2);let h=p(M(Y(i)));return H.set(a,h),h}function V(t,n,a){let e=p(t),r=Number.POSITIVE_INFINITY;for(let o of a){let i=K(n,o),s=F(e,i);s<r&&(r=s)}return r}function z(t){let n=U(t,16);return v(n,10,6).filter(e=>{if(e.Width<8||e.Height<8)return!1;let r=e.Width/e.Height;return r>.5&&r<12})}async function $(t){let a=q(t.ImageData)?t.BackgroundCandidates:t.BackgroundCandidates.slice(0,1),e=t.FontCandidates??k,r=t.ScoreThreshold??.32,o=null;for(let i of a){let s=_(t.ImageData,i),l=G(s),h=N(M(l)),g=z(h);if(g.length!==0)for(let d of g){let c=R(h,d);for(let u of b){let f=V(c,u,e);(!o||f<o.Score)&&(o={Label:u,Score:f,Box:d})}}}return!o||o.Score>r?null:o}function G(t){let{width:n,height:a,data:e}=t,r=new Uint8ClampedArray(n*a);for(let o=0,i=0;o<e.length;o+=4,i++){let s=e[o],l=e[o+1],h=e[o+2];r[i]=Math.round(.299*s+.587*l+.114*h)}return{Width:n,Height:a,Data:r}}function q(t){let n=t.data;for(let a=3;a<n.length;a+=4)if(n[a]<255)return!0;return!1}function _(t,n){let a=T(t.width,t.height),e=C(a);return e.fillStyle=n,e.fillRect(0,0,t.width,t.height),e.putImageData(t,0,0),e.getImageData(0,0,t.width,t.height)}self.addEventListener("message",t=>{t.origin===""&&(async()=>{let n=t.data;if(!(!n||n.Kind!=="detect"))try{let a=await $(n),e={Kind:"detect-result",RequestId:n.RequestId,Result:a};self.postMessage(e)}catch(a){let e=a instanceof Error?a.message:String(a),r={Kind:"detect-error",RequestId:n.RequestId,Error:e};self.postMessage(r)}})()});})();\n'],{type:"application/javascript"}))));async function C(u){let i=[];for(let d of u){let y=[...d.querySelectorAll("*")].filter(a=>a instanceof HTMLElement).filter(a=>a instanceof HTMLImageElement||getComputedStyle(a).backgroundImage!=="none").filter(a=>parseFloat(getComputedStyle(a).getPropertyValue("width"))>=5&&parseFloat(getComputedStyle(a).getPropertyValue("height"))>=5).filter(a=>parseFloat(getComputedStyle(a).getPropertyValue("width"))<=50&&parseFloat(getComputedStyle(a).getPropertyValue("height"))<=50),p=0;for(let a of y)if(await l.DetectFromElement(a,{ScoreThreshold:.32})!==null&&(p+=1),p>=1){i.push(d);break}}return i}function h(u){let i=new Set([u]);for(let d=0;;d++){let y=[...i][d].parentElement;if(y===null)break;i.add(y)}return i}async function c(u){let i=[...document.querySelectorAll("#app div[class] div[class] ~ div[class]")].filter(a=>a instanceof HTMLElement);i=i.filter(a=>parseFloat(getComputedStyle(a).getPropertyValue("padding-top"))>=20||parseFloat(getComputedStyle(a).getPropertyValue("margin-top"))>=20||parseFloat(getComputedStyle(a).getPropertyValue("margin-bottom"))>=12.5),i=i.filter(a=>{let g=[...a.querySelectorAll("*")].filter(s=>s instanceof HTMLElement);return g.filter(s=>parseFloat(getComputedStyle(s).getPropertyValue("padding-top"))>=5&&parseFloat(getComputedStyle(s).getPropertyValue("border-bottom-width"))>=.1).length===1?!0:g.filter(s=>(s instanceof HTMLTableElement||s instanceof HTMLTableCellElement)&&parseFloat(getComputedStyle(s).getPropertyValue("padding-top"))>=5&&parseFloat(getComputedStyle(s).getPropertyValue("padding-bottom"))>=5).length>=2}),i=i.filter(a=>![...a.querySelectorAll("*")].filter(s=>s instanceof HTMLElement).some(s=>parseFloat(getComputedStyle(s).getPropertyValue("margin-bottom"))>=10&&parseFloat(getComputedStyle(s).getPropertyValue("padding-bottom"))>=1&&parseFloat(getComputedStyle(s).getPropertyValue("padding-top"))>=1&&parseFloat(getComputedStyle(s).getPropertyValue("border-top-width"))>=.25&&parseFloat(getComputedStyle(s).getPropertyValue("border-bottom-width"))>=.25)),i=i.filter(a=>{let g=[...a.querySelectorAll("*")].filter(s=>s instanceof HTMLElement);return g=g.filter(s=>parseFloat(getComputedStyle(s).getPropertyValue("padding-right"))>=10&&parseFloat(getComputedStyle(s).getPropertyValue("padding-bottom"))>=10),g=g.filter(s=>parseFloat(getComputedStyle(s).getPropertyValue("margin-left"))>=2.5),g.length===0}),i=i.filter(a=>a.getBoundingClientRect().width<500&&S.document.body.getBoundingClientRect().width>500?!1:[...a.querySelectorAll("*[style]")].filter(s=>s instanceof HTMLElement&&s.style.length>0).filter(s=>{if(!(s instanceof HTMLElement))return!1;let x=getComputedStyle(s);return[...s.style].filter(b=>{let k=s.style.getPropertyValue(b).trim(),q=x.getPropertyValue(b).trim();return k!==q}).length<=1}).length<5),i=await C(i),i.forEach(a=>i.push(...new Set([...a.querySelectorAll("*")].filter(g=>g instanceof HTMLElement)))),i=[...new Set(i)];let d=i.filter(a=>parseFloat(getComputedStyle(a).getPropertyValue("padding-left"))>=5&&parseFloat(getComputedStyle(a).getPropertyValue("border-right-width"))>=.1);console.debug(`[${E}] ${u.type} RealTargeted`,d,u),d.forEach(a=>{a.style.setProperty("display","none","important")});let y=i.filter(a=>!(a instanceof HTMLElement)||!(a instanceof HTMLTableElement)?!1:[...a.querySelectorAll("*")].filter(s=>s instanceof HTMLElement).some(s=>parseFloat(getComputedStyle(s).getPropertyValue("padding-top"))>=5&&parseFloat(getComputedStyle(s).getPropertyValue("padding-bottom"))>=5));console.debug(`[${E}] ${u.type} RealTabletTargeted`,y,u),y.forEach(a=>{a.style.setProperty("display","none","important")});let p=new Set([...d,...y]);p.forEach(a=>{[...h(a)].filter(s=>s.innerText.trim().length===0).forEach(s=>p.add(s))}),console.debug(`[${E}] ${u.type} PlaceHolderCandidated`,p,u),[...p].forEach(a=>{a.style.setProperty("display","none","important")})}n.addEventListener("vue:settled",u=>c(u)),n.addEventListener("vue:url-changed",u=>setTimeout(()=>c(u),250)),["https://fonts.googleapis.com/css2?family=Nanum Gothic&display=swap"].forEach(u=>{let i=S.document.createElement("link");i.rel="stylesheet",i.href=u,S.document.head.appendChild(i)})})();})();
26
+ /*!
29
27
  * @license MPL-2.0
30
28
  * This Source Code Form is subject to the terms of the Mozilla Public
31
29
  * License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -33,6 +31,4 @@ t[n](o,o.exports,r),o.exports)}function n(t,e){(null==e||e>t.length)&&(e=t.lengt
33
31
  *
34
32
  * Contributors:
35
33
  * - See Git history at https://github.com/FilteringDev/NamuLink for detailed authorship information.
36
- */function p(t,e){(null==e||e>t.length)&&(e=t.length);for(var r=0,n=Array(e);r<e;r++)n[r]=t[r];return n}function y(t,e,r,n,a,o,i){try{var l=t[o](i),u=l.value}catch(t){r(t);return}l.done?e(u):Promise.resolve(u).then(n,a)}function v(t){return function(){var e=this,r=arguments;return new Promise(function(n,a){var o=t.apply(e,r);function i(t){y(o,n,a,i,l,"next",t)}function l(t){y(o,n,a,i,l,"throw",t)}i(void 0)})}}function b(t,e){return null!=e&&"u">typeof Symbol&&e[Symbol.hasInstance]?!!e[Symbol.hasInstance](t):t instanceof e}function w(t){return function(t){if(Array.isArray(t))return p(t)}(t)||function(t){if("u">typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t){if(t){if("string"==typeof t)return p(t,void 0);var e=Object.prototype.toString.call(t).slice(8,-1);if("Object"===e&&t.constructor&&(e=t.constructor.name),"Map"===e||"Set"===e)return Array.from(e);if("Arguments"===e||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(e))return p(t,void 0)}}(t)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function S(t,e){var r,n,a,o={label:0,sent:function(){if(1&a[0])throw a[1];return a[1]},trys:[],ops:[]},i=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),l=Object.defineProperty;return l(i,"next",{value:u(0)}),l(i,"throw",{value:u(1)}),l(i,"return",{value:u(2)}),"function"==typeof Symbol&&l(i,Symbol.iterator,{value:function(){return this}}),i;function u(l){return function(u){var c=[l,u];if(r)throw TypeError("Generator is already executing.");for(;i&&(i=0,c[0]&&(o=0)),o;)try{if(r=1,n&&(a=2&c[0]?n.return:c[0]?n.throw||((a=n.return)&&a.call(n),0):n.next)&&!(a=a.call(n,c[1])).done)return a;switch(n=0,a&&(c=[2&c[0],a.value]),c[0]){case 0:case 1:a=c;break;case 4:return o.label++,{value:c[1],done:!1};case 5:o.label++,n=c[1],c=[0];continue;case 7:c=o.ops.pop(),o.trys.pop();continue;default:if(!(a=(a=o.trys).length>0&&a[a.length-1])&&(6===c[0]||2===c[0])){o=0;continue}if(3===c[0]&&(!a||c[1]>a[0]&&c[1]<a[3])){o.label=c[1];break}if(6===c[0]&&o.label<a[1]){o.label=a[1],a=c;break}if(a&&o.label<a[2]){o.label=a[2],o.ops.push(c);break}a[2]&&o.ops.pop(),o.trys.pop();continue}c=e.call(t,o)}catch(t){c=[6,t],n=0}finally{r=a=0}if(5&c[0])throw c[1];return{value:c[0]?c[1]:void 0,done:!0}}}}r.rv=()=>"1.7.11",r.ruid="bundler=rspack@1.7.11",!function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"NamuLink";v(function(){var r,n,i,l;function d(r){return v(function(){var n,a,o,i,u;return S(this,function(c){switch(c.label){case 0:var f;return[4,(f=a=(a=(a=(a=(a=(a=w(document.querySelectorAll("#app div[class] div[class] ~ div[class]")).filter(function(t){return b(t,HTMLElement)})).filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("padding-top"))>=20||parseFloat(getComputedStyle(t).getPropertyValue("margin-top"))>=20||parseFloat(getComputedStyle(t).getPropertyValue("margin-bottom"))>=12.5})).filter(function(t){var e=w(t.querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)});return(// non-HTMLTableElement
37
- 1===e.filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("padding-top"))>=5&&parseFloat(getComputedStyle(t).getPropertyValue("border-bottom-width"))>=.1}).length||e.filter(function(t){return(b(t,HTMLTableElement)||b(t,HTMLTableCellElement))&&parseFloat(getComputedStyle(t).getPropertyValue("padding-top"))>=5&&parseFloat(getComputedStyle(t).getPropertyValue("padding-bottom"))>=5}).length>=2)})).filter(function(t){return!w(t.querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)}).some(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("margin-bottom"))>=10&&parseFloat(getComputedStyle(t).getPropertyValue("padding-bottom"))>=1&&parseFloat(getComputedStyle(t).getPropertyValue("padding-top"))>=1&&parseFloat(getComputedStyle(t).getPropertyValue("border-top-width"))>=.25&&parseFloat(getComputedStyle(t).getPropertyValue("border-bottom-width"))>=.25})})).filter(function(t){var e=w(t.querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)});return 0===(e=(e=e.filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("padding-right"))>=10&&parseFloat(getComputedStyle(t).getPropertyValue("padding-bottom"))>=10})).filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("margin-left"))>=2.5})).length})).filter(function(e){return(!(e.getBoundingClientRect().width<500)||!(t.document.body.getBoundingClientRect().width>500))&&w(e.querySelectorAll("*[style]")).filter(function(t){return b(t,HTMLElement)&&t.style.length>0}).filter(function(t){if(!b(t,HTMLElement))return!1;var e=getComputedStyle(t);return w(t.style).filter(function(r){return t.style.getPropertyValue(r).trim()!==e.getPropertyValue(r).trim()}).length<=1}).length<5}),v(function(){var t,e,r,n,a,o,i,u,c,s,h,d,g,m,p,y;return S(this,function(v){switch(v.label){case 0:t=[],e=!0,r=!1,n=void 0,v.label=1;case 1:v.trys.push([1,12,13,14]),a=f[Symbol.iterator](),v.label=2;case 2:if(e=(o=a.next()).done)return[3,11];u=w((i=o.value).querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)}).filter(function(t){return b(t,HTMLImageElement)||"none"!==getComputedStyle(t).backgroundImage}).filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("width"))>=5&&parseFloat(getComputedStyle(t).getPropertyValue("height"))>=5}).filter(function(t){return 50>=parseFloat(getComputedStyle(t).getPropertyValue("width"))&&50>=parseFloat(getComputedStyle(t).getPropertyValue("height"))}),c=0,s=!0,h=!1,d=void 0,v.label=3;case 3:v.trys.push([3,8,9,10]),g=u[Symbol.iterator](),v.label=4;case 4:if(s=(m=g.next()).done)return[3,7];return p=m.value,[4,l.DetectFromElement(p,{ScoreThreshold:.32})];case 5:if(null!==v.sent()&&(c+=1),c>=1)return t.push(i),[3,7];v.label=6;case 6:return s=!0,[3,4];case 7:return[3,10];case 8:return y=v.sent(),h=!0,d=y,[3,10];case 9:try{s||null==g.return||g.return()}finally{if(h)throw d}return[7];case 10:return e=!0,[3,2];case 11:return[3,14];case 12:return y=v.sent(),r=!0,n=y,[3,14];case 13:try{e||null==a.return||a.return()}finally{if(r)throw n}return[7];case 14:return[2,t]}})})())];case 1:return(a=c.sent()).forEach(function(t){return(n=a).push.apply(n,w(new Set(w(t.querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)}))))}),o=(a=w(new Set(a))).filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("padding-left"))>=5&&parseFloat(getComputedStyle(t).getPropertyValue("border-right-width"))>=.1}),console.debug("[".concat(e,"] ").concat(r.type," RealTargeted"),o,r),o.forEach(function(t){t.style.setProperty("display","none","important")}),i=a.filter(function(t){return!!b(t,HTMLElement)&&!!b(t,HTMLTableElement)&&w(t.querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)}).some(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("padding-top"))>=5&&parseFloat(getComputedStyle(t).getPropertyValue("padding-bottom"))>=5})}),console.debug("[".concat(e,"] ").concat(r.type," RealTabletTargeted"),i,r),i.forEach(function(t){t.style.setProperty("display","none","important")}),// leftover
38
- (u=new Set(w(o).concat(w(i)))).forEach(function(t){w(function(t){for(var e=new Set([t]),r=0;;r++){var n=w(e)[r].parentElement;if(null===n)break;e.add(n)}return e}(t)).filter(function(t){return 0===t.innerText.trim().length}).forEach(function(t){return u.add(t)})}),console.debug("[".concat(e,"] ").concat(r.type," PlaceHolderCandidated"),u,r),w(u).forEach(function(t){t.style.setProperty("display","none","important")}),[2]}})})()}return S(this,function(g){switch(g.label){case 0:return r=t.Reflect.apply,n=[[/function *[A-Za-z0-9]+ *\([A-Za-z0-9]+ * *\) *{ *function *[A-Za-z0-9]+ *\( *[a-zA-Z]+ *, *[A-Za-z]+ *\) *{ *return *[A-Za-z0-9]+ *\( */,/{ *return *[A-Za-z0-9]+ *\( *[a-zA-Z]+[- ]*0x[a-f0-9]+ *, *[a-zA-Z]+ *\) *; *\} *[A-Za-z0-9]+ *\( *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+/,/\( *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *\( *0x[a-f0-9]+ *, *0x[a-f0-9]+ *\) *, *[A-Za-z0-9]+ *\) *;/]],t.Promise.prototype.then=new Proxy(t.Promise.prototype.then,{apply:function(t,a,o){if("function"!=typeof o[0]||"function"!=typeof o[1])return r(t,a,o);var i=[String(o[0]),String(o[1])];if(i.every(function(t){return 1===n.filter(function(e){return e.filter(function(e){return e.test(t)}).length===e.length}).length})){console.debug("[".concat(e,"] Detected PL2 Promise.then"),i,o),setTimeout(function(){var t=w(document.querySelectorAll("#app div[class] div[class] ~ div[class]")).filter(function(t){return b(t,HTMLElement)});t=(t=(t=t.filter(function(t){return parseFloat(getComputedStyle(t).getPropertyValue("margin-bottom"))>=12.5})).filter(function(t){return 0===t.innerText.trim().length})).filter(function(t){return w(t.querySelectorAll("*")).filter(function(t){return b(t,HTMLElement)}).some(function(t){var e=t.getBoundingClientRect().height;return e>0&&e<=5})}),console.debug("[".concat(e,"] Detected PL2 Promise.then Targeted"),t),t.forEach(function(t){t.style.setProperty("display","none","important")})},250);return}return r(t,a,o)}}),[4,function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:document.documentElement;return new Promise(function(r){var n=e.querySelector(t);if(n&&o(n,HTMLElement))return void r(n);var a=new MutationObserver(function(){var n=e.querySelector(t);n&&o(n,HTMLElement)&&(a.disconnect(),r(n))});a.observe(e,{subtree:!0,childList:!0,attributes:!0})})}("#app",t.document)];case 1:return!function(t){var e,r,n,o,i,l=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},u=null!=(r=l.QuietMs)?r:120,c=null!=(n=l.EventName)?n:"vue:settled",f=null!=(o=l.ChangeEventName)?o:"vue:dom-changed",s=null!=(i=l.UrlChange)?i:"vue:url-changed";if(null!=(e=HTMLElement)&&"u">typeof Symbol&&e[Symbol.hasInstance]?!e[Symbol.hasInstance](t):!(t instanceof e))throw TypeError("TargetEl must be an HTMLElement");var h=-1,d=0,g=performance.now(),m=new URL(location.href),p=function(e){t.dispatchEvent(new CustomEvent(f,{detail:{Seq:d,At:g,MutationCount:e.length,Mutations:e}}))},y=function(){requestAnimationFrame(function(){requestAnimationFrame(function(){t.dispatchEvent(new CustomEvent(c,{detail:{Seq:d,QuietMs:u,SettledAt:performance.now(),ElapsedSinceLastMutation:performance.now()-g,Target:t}}))})})},v=function(){var e=new URL(location.href);e.href!==m.href&&(m=e,t.dispatchEvent(new CustomEvent(s,{detail:{Seq:d,At:performance.now(),URL:e}})))},b=function(){clearTimeout(h),h=setTimeout(y,u)};new MutationObserver(function(t){d+=1,g=performance.now(),p(t),t.flatMap(function(t){return a(t.addedNodes).concat(a(t.removedNodes),a(t.nextSibling?[t.nextSibling]:[]),a(t.previousSibling?[t.previousSibling]:[]),a(t.target?[t.target]:[]))}).length>=15&&(b(),setTimeout(b,3*u)),v()}).observe(t,{subtree:!0,childList:!0,attributes:!0,characterData:!0}),b()}(i=g.sent(),{QuietMs:75,EventName:"vue:settled",ChangeEventName:"vue:change",UrlChange:"vue:url-changed"}),l=function(t,e){var r=0,n=new Map;function a(t){var a="ocr-".concat(Date.now(),"-").concat(r++),o=function(t){for(var e=1;e<arguments.length;e++){var r=null!=arguments[e]?arguments[e]:{},n=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(n=n.concat(Object.getOwnPropertySymbols(r).filter(function(t){return Object.getOwnPropertyDescriptor(r,t).enumerable}))),n.forEach(function(e){var n;n=r[e],e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n})}return t}({Kind:"detect",RequestId:a},t);return new Promise(function(t,r){n.set(a,{Resolve:t,Reject:r}),e.postMessage(o)})}return e.addEventListener("message",function(t){var e=t.data;if(e&&"RequestId"in e){var r=n.get(e.RequestId);if(r){if(n.delete(e.RequestId),"detect-result"===e.Kind)return void r.Resolve(e.Result);r.Reject(Error(e.Error))}}}),{DetectFromElement:function(e,r){return u(function(){var n,o,i;return f(this,function(l){switch(l.label){case 0:if(!(n=function(t,e){if(c(e,t.HTMLImageElement))return e.currentSrc||e.src||null;var r=t.getComputedStyle(e).backgroundImage.trim();if(!r||"none"===r)return null;var n=r.match(/^url\((.*)\)$/i);if(!n)return null;var a=n[1].trim();return(a.startsWith('"')&&a.endsWith('"')||a.startsWith("'")&&a.endsWith("'"))&&(a=a.slice(1,-1)),a}(t,e)))return[2,null];return[4,m(t,e,n)];case 1:return o=l.sent(),i=s(t,e),[2,a({ImageData:o,BackgroundCandidates:h(t,e,i),FontCandidates:null==r?void 0:r.FontCandidates,ScoreThreshold:null==r?void 0:r.ScoreThreshold})]}})})()},DetectFromSource:function(e){return u(function(){var r,n;return f(this,function(o){switch(o.label){case 0:return[4,m(t,e.HostElement,e.SourceUrl)];case 1:return r=o.sent(),n=s(t,e.HostElement),[2,a({ImageData:r,BackgroundCandidates:h(t,e.HostElement,n),FontCandidates:e.FontCandidates,ScoreThreshold:e.ScoreThreshold})]}})})()},Terminate:function(){var t=!0,r=!1,a=void 0;try{for(var o,i=n.values()[Symbol.iterator]();!(t=(o=i.next()).done);t=!0)o.value.Reject(Error("OCR worker terminated"))}catch(t){r=!0,a=t}finally{try{t||null==i.return||i.return()}finally{if(r)throw a}}n.clear(),e.terminate()}}}(t,new Worker(URL.createObjectURL(new Blob(['(()=>{"use strict";var t={},r={};function e(a){var n=r[a];if(void 0!==n)return n.exports;var i=r[a]={exports:{}};return t[a](i,i.exports,e),i.exports}function a(t,r){(null==r||r>t.length)&&(r=t.length);for(var e=0,a=Array(r);e<r;e++)a[e]=t[e];return a}function n(t,r,e,a,n,i,o){try{var h=t[i](o),l=h.value}catch(t){e(t);return}h.done?r(l):Promise.resolve(l).then(a,n)}function i(t){return function(){var r=this,e=arguments;return new Promise(function(a,i){var o=t.apply(r,e);function h(t){n(o,a,i,h,l,"next",t)}function l(t){n(o,a,i,h,l,"throw",t)}h(void 0)})}}function o(t,r){var e,a,n,i={label:0,sent:function(){if(1&n[0])throw n[1];return n[1]},trys:[],ops:[]},o=Object.create(("function"==typeof Iterator?Iterator:Object).prototype),h=Object.defineProperty;return h(o,"next",{value:l(0)}),h(o,"throw",{value:l(1)}),h(o,"return",{value:l(2)}),"function"==typeof Symbol&&h(o,Symbol.iterator,{value:function(){return this}}),o;function l(h){return function(l){var f=[h,l];if(e)throw TypeError("Generator is already executing.");for(;o&&(o=0,f[0]&&(i=0)),i;)try{if(e=1,a&&(n=2&f[0]?a.return:f[0]?a.throw||((n=a.return)&&n.call(a),0):a.next)&&!(n=n.call(a,f[1])).done)return n;switch(a=0,n&&(f=[2&f[0],n.value]),f[0]){case 0:case 1:n=f;break;case 4:return i.label++,{value:f[1],done:!1};case 5:i.label++,a=f[1],f=[0];continue;case 7:f=i.ops.pop(),i.trys.pop();continue;default:if(!(n=(n=i.trys).length>0&&n[n.length-1])&&(6===f[0]||2===f[0])){i=0;continue}if(3===f[0]&&(!n||f[1]>n[0]&&f[1]<n[3])){i.label=f[1];break}if(6===f[0]&&i.label<n[1]){i.label=n[1],n=f;break}if(n&&i.label<n[2]){i.label=n[2],i.ops.push(f);break}n[2]&&i.ops.pop(),i.trys.pop();continue}f=r.call(t,i)}catch(t){f=[6,t],a=0}finally{e=n=0}if(5&f[0])throw f[1];return{value:f[0]?f[1]:void 0,done:!0}}}}e.rv=()=>"1.7.11",e.ruid="bundler=rspack@1.7.11";var h=["파워링크","광고","광고등록"],l=["Pretendard JP, sans-serif","Pretendard, sans-serif","system-ui, sans-serif","Apple SD Gothic Neo, sans-serif","Nanum Gothic, sans-serif","Noto Sans KR, sans-serif","Arial, sans-serif"],f=new Map;function u(t,r){return new OffscreenCanvas(Math.max(1,Math.floor(t)),Math.max(1,Math.floor(r)))}function c(t){var r=t.getContext("2d",{willReadFrequently:!0});if(!r)throw Error("2D context unavailable");return r}function d(t){for(var r=c(t),e=t.width,a=t.height,n=r.getImageData(0,0,e,a).data,i=new Uint8ClampedArray(e*a),o=0,h=0;o<n.length;o+=4,h++){var l=n[o],f=n[o+1],u=n[o+2];i[h]=Math.round(.299*l+.587*f+.114*u)}return{Width:e,Height:a,Data:i}}function s(t){for(var r=function(t){for(var r=new Uint32Array(256),e=0;e<t.Data.length;e++)r[t.Data[e]]++;for(var a=t.Data.length,n=0,i=0;i<256;i++)n+=i*r[i];for(var o=0,h=0,l=-1,f=127,u=0;u<256;u++)if(0!==(h+=r[u])){var c=a-h;if(0===c)break;var d=(o+=u*r[u])/h,s=(n-o)/c,v=h*c*(d-s)*(d-s);v>l&&(l=v,f=u)}return f}(t),e=0,a=0,n=0;n<t.Data.length;n++)t.Data[n]<r?e++:a++;for(var i=e<a,o=new Uint8Array(t.Width*t.Height),h=0;h<t.Data.length;h++){var l=i?t.Data[h]<r:t.Data[h]>r;o[h]=+!!l}return{Width:t.Width,Height:t.Height,Data:o}}function v(t){for(var r=new Uint8Array(t.Width*t.Height),e=1;e<t.Height-1;e++)for(var a=1;a<t.Width-1;a++){for(var n=0,i=-1;i<=1&&!n;i++)for(var o=-1;o<=1;o++)if(1===t.Data[(e+i)*t.Width+(a+o)]){n=1;break}r[e*t.Width+a]=n}return{Width:t.Width,Height:t.Height,Data:r}}function g(t,r){for(var e=new Uint8Array(r.Width*r.Height),a=0;a<r.Height;a++)for(var n=0;n<r.Width;n++)e[a*r.Width+n]=t.Data[(r.Y+a)*t.Width+(r.X+n)];return{Width:r.Width,Height:r.Height,Data:e}}function y(t){for(var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:64,e=function(t){for(var r=t.Width,e=t.Height,a=-1,n=-1,i=0;i<t.Height;i++)for(var o=0;o<t.Width;o++)0!==t.Data[i*t.Width+o]&&(o<r&&(r=o),i<e&&(e=i),o>a&&(a=o),i>n&&(n=i));return a<r||n<e?{Width:1,Height:1,Data:new Uint8Array([0])}:g(t,{X:r,Y:e,Width:a-r+1,Height:n-e+1})}(t),a=Math.max(e.Width,e.Height),n=new Uint8Array(a*a),i=Math.floor((a-e.Width)/2),o=Math.floor((a-e.Height)/2),h=0;h<e.Height;h++)for(var l=0;l<e.Width;l++)n[(h+o)*a+(l+i)]=e.Data[h*e.Width+l];return function(t,r,e){for(var a=new Uint8Array(r*e),n=0;n<e;n++)for(var i=0;i<r;i++){var o=Math.min(t.Width-1,Math.floor(i/r*t.Width)),h=Math.min(t.Height-1,Math.floor(n/e*t.Height));a[n*r+i]=t.Data[h*t.Width+o]}return{Width:r,Height:e,Data:a}}({Width:a,Height:a,Data:n},r,r)}self.addEventListener("message",function(t){""===t.origin&&i(function(){var r,e,n,W,m,p;return o(this,function(b){var H,w,D;switch(b.label){case 0:if(!(r=t.data)||"detect"!==r.Kind)return[2];b.label=1;case 1:return b.trys.push([1,3,,4]),[4,(H=r,i(function(){var t,r,e,n,i,W,m,p,b,w,D,x,S,A,M,I,X,Y,k,U,R,B,C,E,j,O,P,T,q,K;return o(this,function(o){e=!function(t){for(var r=t.data,e=3;e<r.length;e+=4)if(r[e]<255)return!0;return!1}(H.ImageData)?H.BackgroundCandidates.slice(0,1):H.BackgroundCandidates,n=null!=(t=H.FontCandidates)?t:l,i=null!=(r=H.ScoreThreshold)?r:.32,W=null,m=!0,p=!1,b=void 0;try{for(w=e[Symbol.iterator]();!(m=(D=w.next()).done);m=!0){var G,N;if(x=D.value,S=function(t,r){var e=c(u(t.width,t.height));return e.fillStyle=r,e.fillRect(0,0,t.width,t.height),e.putImageData(t,0,0),e.getImageData(0,0,t.width,t.height)}(H.ImageData,x),A=function(t){for(var r=t.width,e=t.height,a=t.data,n=new Uint8ClampedArray(r*e),i=0,o=0;i<a.length;i+=4,o++){var h=a[i],l=a[i+1],f=a[i+2];n[o]=Math.round(.299*h+.587*l+.114*f)}return{Width:r,Height:e,Data:n}}(S),G=s(A),N=M=v(function(t){for(var r=new Uint8Array(t.Width*t.Height),e=1;e<t.Height-1;e++)for(var a=1;a<t.Width-1;a++){for(var n=1,i=-1;i<=1&&n;i++)for(var o=-1;o<=1;o++)if(0===t.Data[(e+i)*t.Width+(a+o)]){n=0;break}r[e*t.Width+a]=n}return{Width:t.Width,Height:t.Height,Data:r}}(v(G))),I=(function(t){for(var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:8,e=arguments.length>2&&void 0!==arguments[2]?arguments[2]:4,n=function(t){if(Array.isArray(t))return a(t)}(t)||function(t){if("u">typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||function(t){if(t){if("string"==typeof t)return a(t,void 0);var r=Object.prototype.toString.call(t).slice(8,-1);if("Object"===r&&t.constructor&&(r=t.constructor.name),"Map"===r||"Set"===r)return Array.from(r);if("Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r))return a(t,void 0)}}(t)||function(){throw TypeError("Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}(),i=!0;i;){i=!1;t:for(var o=0;o<n.length;o++)for(var h=o+1;h<n.length;h++)if(function(t,a){var n=t.X+t.Width,i=t.Y+t.Height,o=a.X+a.Width,h=a.Y+a.Height;return!(n+r<a.X||o+r<t.X||i+e<a.Y||h+e<t.Y)}(n[o],n[h])){var l=n[o],f=n[h];n[o]={X:Math.min(l.X,f.X),Y:Math.min(l.Y,f.Y),Width:Math.max(l.X+l.Width,f.X+f.Width)-Math.min(l.X,f.X),Height:Math.max(l.Y+l.Height,f.Y+f.Height)-Math.min(l.Y,f.Y)},n.splice(h,1),i=!0;break t}}return n})(function(t){for(var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:20,e=new Uint8Array(t.Width*t.Height),a=[],n=new Int32Array(t.Width*t.Height),i=new Int32Array(t.Width*t.Height),o=0;o<t.Height;o++)for(var h=0;h<t.Width;h++){var l=o*t.Width+h;if(!e[l]&&0!==t.Data[l]){var f=0,u=0;n[0]=h,i[u]=o,u++,e[l]=1;for(var c=h,d=o,s=h,v=o,g=0;f<u;){var y=n[f],W=i[f];f++,g++,y<c&&(c=y),W<d&&(d=W),y>s&&(s=y),W>v&&(v=W);for(var m=-1;m<=1;m++)for(var p=-1;p<=1;p++){if(0!==p||0!==m){var b=y+p,H=W+m;if(!(b<0)&&!(H<0)&&!(b>=t.Width)&&!(H>=t.Height)){var w=H*t.Width+b;!e[w]&&0!==t.Data[w]&&(e[w]=1,n[u]=b,i[u]=H,u++)}}}}g>=r&&a.push({X:c,Y:d,Width:s-c+1,Height:v-d+1})}}return a}(N,16),10,6).filter(function(t){if(t.Width<8||t.Height<8)return!1;var r=t.Width/t.Height;return r>.5&&r<12}),0!==I.length){X=!0,Y=!1,k=void 0;try{for(U=I[Symbol.iterator]();!(X=(R=U.next()).done);X=!0){B=R.value,C=g(M,B),E=!0,j=!1,O=void 0;try{for(P=h[Symbol.iterator]();!(E=(T=P.next()).done);E=!0)q=T.value,K=function(t,r,e){var a=y(t),n=1/0,i=!0,o=!1,h=void 0;try{for(var l,v=e[Symbol.iterator]();!(i=(l=v.next()).done);i=!0){var g=l.value,W=function(t,r){var e="".concat(t,"__").concat(r),a=f.get(e);if(a)return a;var n=u(256,96),i=c(n);i.fillStyle="white",i.fillRect(0,0,256,96);for(var o=Math.floor(69.12);o>8;){i.clearRect(0,0,256,96),i.fillStyle="white",i.fillRect(0,0,256,96),i.fillStyle="black",i.textAlign="center",i.textBaseline="middle",i.font="700 ".concat(o,"px ").concat(r);var h=i.measureText(t),l=h.width,v=(h.actualBoundingBoxAscent||.8*o)+(h.actualBoundingBoxDescent||.2*o);if(l<=230.4&&v<=86.4){i.fillText(t,128,48);var g=y(s(d(n)));return f.set(e,g),g}o--}i.font="700 12px ".concat(r),i.fillStyle="black",i.textAlign="center",i.textBaseline="middle",i.fillText(t,128,48);var W=y(s(d(n)));return f.set(e,W),W}(r,g),m=function(t,r){if(t.Width!==r.Width||t.Height!==r.Height)throw Error("Image size mismatch");for(var e=0,a=0;a<t.Data.length;a++)t.Data[a]!==r.Data[a]&&e++;return e/t.Data.length}(a,W);m<n&&(n=m)}}catch(t){o=!0,h=t}finally{try{i||null==v.return||v.return()}finally{if(o)throw h}}return n}(C,q,n),(!W||K<W.Score)&&(W={Label:q,Score:K,Box:B})}catch(t){j=!0,O=t}finally{try{E||null==P.return||P.return()}finally{if(j)throw O}}}}catch(t){Y=!0,k=t}finally{try{X||null==U.return||U.return()}finally{if(Y)throw k}}}}}catch(t){p=!0,b=t}finally{try{m||null==w.return||w.return()}finally{if(p)throw b}}return!W||W.Score>i?[2,null]:[2,W]})})())];case 2:return e=b.sent(),n={Kind:"detect-result",RequestId:r.RequestId,Result:e},self.postMessage(n),[3,4];case 3:return w=W=b.sent(),m=(null!=(D=Error)&&"u">typeof Symbol&&D[Symbol.hasInstance]?!!D[Symbol.hasInstance](w):w instanceof D)?W.message:String(W),p={Kind:"detect-error",RequestId:r.RequestId,Error:m},self.postMessage(p),[3,4];case 4:return[2]}})})()})})();'],{type:"application/javascript"})))),i.addEventListener("vue:settled",function(t){return d(t)}),i.addEventListener("vue:url-changed",function(t){return setTimeout(function(){return d(t)},250)}),["https://fonts.googleapis.com/css2?family=Nanum Gothic&display=swap"].forEach(function(e){var r=t.document.createElement("link");r.rel="stylesheet",r.href=e,t.document.head.appendChild(r)}),[2]}})})()}("u">typeof unsafeWindow?unsafeWindow:window)})();
34
+ */
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@filteringdev/namulink",
3
- "version": "20.3.0",
3
+ "version": "20.4.0-build.9e0cb5c20b9f",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build:interface": "tsc -p userscript/tsconfig.json",
8
7
  "build:userscript": "npm run build -w builder -- --minify true --use-cache false --build-type production --SubscriptionUrl https://cdn.jsdelivr.net/npm/@filteringdev/namulink@latest/dist/NamuLink.user.js",
9
- "build": "npm run build:interface && npm run build:userscript",
8
+ "build": "npm run build:userscript",
10
9
  "debug": "npm run debug -w builder",
11
10
  "lint": "npm run lint -w builder && npm run lint -w userscript"
12
11
  },
@@ -17,12 +16,6 @@
17
16
  "files": [
18
17
  "dist/**/*"
19
18
  ],
20
- "exports": {
21
- ".": {
22
- "import": "./dist/index.js",
23
- "types": "./dist/index.d.ts"
24
- }
25
- },
26
19
  "repository": {
27
20
  "type": "git",
28
21
  "url": "git+https://github.com/FilteringDev/NamuLink.git"
@@ -33,9 +26,9 @@
33
26
  "builder"
34
27
  ],
35
28
  "devDependencies": {
36
- "@typescript-eslint/eslint-plugin": "^8.58.0",
37
- "@typescript-eslint/parser": "^8.58.0",
38
- "eslint": "^10.2.0",
39
- "typescript-eslint": "^8.58.0"
29
+ "@typescript-eslint/eslint-plugin": "^8.59.1",
30
+ "@typescript-eslint/parser": "^8.59.1",
31
+ "eslint": "^10.3.0",
32
+ "typescript-eslint": "^8.59.1"
40
33
  }
41
34
  }
@@ -1 +0,0 @@
1
- export declare function WaitForElement(Selector: string, Root?: HTMLElement | Document): Promise<HTMLElement>;
package/dist/dom-await.js DELETED
@@ -1,21 +0,0 @@
1
- export function WaitForElement(Selector, Root = document.documentElement) {
2
- return new Promise((Resolve) => {
3
- const Found = Root.querySelector(Selector);
4
- if (Found && Found instanceof HTMLElement) {
5
- Resolve(Found);
6
- return;
7
- }
8
- const Observer = new MutationObserver(() => {
9
- const El = Root.querySelector(Selector);
10
- if (El && El instanceof HTMLElement) {
11
- Observer.disconnect();
12
- Resolve(El);
13
- }
14
- });
15
- Observer.observe(Root, {
16
- subtree: true,
17
- childList: true,
18
- attributes: true
19
- });
20
- });
21
- }
package/dist/index.d.ts DELETED
@@ -1,10 +0,0 @@
1
- /*!
2
- * @license MPL-2.0
3
- * This Source Code Form is subject to the terms of the Mozilla Public
4
- * License, v. 2.0. If a copy of the MPL was not distributed with this
5
- * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
- *
7
- * Contributors:
8
- * - See Git history at https://github.com/FilteringDev/NamuLink for detailed authorship information.
9
- */
10
- export declare function RunNamuLinkUserscript(BrowserWindow: typeof window, UserscriptName?: string): Promise<void>;
package/dist/index.js DELETED
@@ -1,179 +0,0 @@
1
- /*!
2
- * @license MPL-2.0
3
- * This Source Code Form is subject to the terms of the Mozilla Public
4
- * License, v. 2.0. If a copy of the MPL was not distributed with this
5
- * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
- *
7
- * Contributors:
8
- * - See Git history at https://github.com/FilteringDev/NamuLink for detailed authorship information.
9
- */
10
- const Win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;
11
- import { AttachVueSettledEvents } from './vuejsawait.js';
12
- import { WaitForElement } from './dom-await.js';
13
- import { CreateOcrWorkerClient } from './ocr-client.js';
14
- export async function RunNamuLinkUserscript(BrowserWindow, UserscriptName = 'NamuLink') {
15
- const OriginalReflectApply = BrowserWindow.Reflect.apply;
16
- const PL2PromiseThenRegexs = [[
17
- /function *[A-Za-z0-9]+ *\([A-Za-z0-9]+ * *\) *{ *function *[A-Za-z0-9]+ *\( *[a-zA-Z]+ *, *[A-Za-z]+ *\) *{ *return *[A-Za-z0-9]+ *\( */,
18
- /{ *return *[A-Za-z0-9]+ *\( *[a-zA-Z]+[- ]*0x[a-f0-9]+ *, *[a-zA-Z]+ *\) *; *\} *[A-Za-z0-9]+ *\( *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+/,
19
- /\( *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *, *[A-Za-z0-9]+ *\( *0x[a-f0-9]+ *, *0x[a-f0-9]+ *\) *, *[A-Za-z0-9]+ *\) *;/
20
- ]];
21
- BrowserWindow.Promise.prototype.then = new Proxy(BrowserWindow.Promise.prototype.then, {
22
- apply(Target, ThisArg, Args) {
23
- if (typeof Args[0] !== 'function' || typeof Args[1] !== 'function') {
24
- return OriginalReflectApply(Target, ThisArg, Args);
25
- }
26
- const Stringified = [String(Args[0]), String(Args[1])];
27
- if (Stringified.every(Str => PL2PromiseThenRegexs.filter(Regexs => Regexs.filter(Regex => Regex.test(Str)).length === Regexs.length).length === 1)) {
28
- console.debug(`[${UserscriptName}] Detected PL2 Promise.then`, Stringified, Args);
29
- setTimeout(() => {
30
- let Targeted = [...document.querySelectorAll('#app div[class] div[class] ~ div[class]')].filter(Ele => Ele instanceof HTMLElement);
31
- Targeted = Targeted.filter(Ele => parseFloat(getComputedStyle(Ele).getPropertyValue('margin-bottom')) >= 12.5);
32
- Targeted = Targeted.filter(Ele => Ele.innerText.trim().length === 0);
33
- Targeted = Targeted.filter(Ele => [...Ele.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement).some(Child => {
34
- const Height = Child.getBoundingClientRect().height;
35
- return Height > 0 && Height <= 5;
36
- }));
37
- console.debug(`[${UserscriptName}] Detected PL2 Promise.then Targeted`, Targeted);
38
- Targeted.forEach(Ele => {
39
- Ele.style.setProperty('display', 'none', 'important');
40
- });
41
- }, 250);
42
- return;
43
- }
44
- return OriginalReflectApply(Target, ThisArg, Args);
45
- }
46
- });
47
- const ArticleHTMLElement = await WaitForElement('#app', BrowserWindow.document);
48
- const EventName = 'vue:settled';
49
- const ChangeEventName = 'vue:change';
50
- const UrlChangeEventName = 'vue:url-changed';
51
- AttachVueSettledEvents(ArticleHTMLElement, {
52
- QuietMs: 75,
53
- EventName: EventName,
54
- ChangeEventName: ChangeEventName,
55
- UrlChange: UrlChangeEventName
56
- });
57
- const OCRInstance = CreateOcrWorkerClient(BrowserWindow, new Worker(URL.createObjectURL(new Blob([__OCR_WORKER_CODE__], { type: 'application/javascript' }))));
58
- async function ExecuteOCR(Targeted) {
59
- const NextTargeted = [];
60
- for (const Parent of Targeted) {
61
- const CandidateChildren = [...Parent.querySelectorAll('*')]
62
- .filter(Child => Child instanceof HTMLElement)
63
- .filter(Child => Child instanceof HTMLImageElement ||
64
- getComputedStyle(Child).backgroundImage !== 'none').filter(Child => parseFloat(getComputedStyle(Child).getPropertyValue('width')) >= 5 && parseFloat(getComputedStyle(Child).getPropertyValue('height')) >= 5)
65
- .filter(Child => parseFloat(getComputedStyle(Child).getPropertyValue('width')) <= 50 && parseFloat(getComputedStyle(Child).getPropertyValue('height')) <= 50);
66
- let MatchedCount = 0;
67
- for (const Child of CandidateChildren) {
68
- const Result = await OCRInstance.DetectFromElement(Child, {
69
- ScoreThreshold: 0.32
70
- });
71
- if (Result !== null) {
72
- MatchedCount += 1;
73
- }
74
- if (MatchedCount >= 1) {
75
- NextTargeted.push(Parent);
76
- break;
77
- }
78
- }
79
- }
80
- return NextTargeted;
81
- }
82
- function AllParents(Ele) {
83
- let SetHTMLElement = new Set([Ele]);
84
- for (let I = 0;; I++) {
85
- let Upper = [...SetHTMLElement][I].parentElement;
86
- if (Upper === null) {
87
- break;
88
- }
89
- SetHTMLElement.add(Upper);
90
- }
91
- return SetHTMLElement;
92
- }
93
- async function Handler(EventParameter) {
94
- let Targeted = [...document.querySelectorAll('#app div[class] div[class] ~ div[class]')].filter(Ele => Ele instanceof HTMLElement);
95
- Targeted = Targeted.filter(Ele => parseFloat(getComputedStyle(Ele).getPropertyValue('padding-top')) >= 20 ||
96
- parseFloat(getComputedStyle(Ele).getPropertyValue('margin-top')) >= 20 ||
97
- parseFloat(getComputedStyle(Ele).getPropertyValue('margin-bottom')) >= 12.5);
98
- Targeted = Targeted.filter(Ele => {
99
- let Children = [...Ele.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement);
100
- // non-HTMLTableElement
101
- if (Children.filter(Child => parseFloat(getComputedStyle(Child).getPropertyValue('padding-top')) >= 5 &&
102
- parseFloat(getComputedStyle(Child).getPropertyValue('border-bottom-width')) >= 0.1).length === 1)
103
- return true;
104
- // HTMLTableElement
105
- return Children.filter(Child => (Child instanceof HTMLTableElement || Child instanceof HTMLTableCellElement) &&
106
- parseFloat(getComputedStyle(Child).getPropertyValue('padding-top')) >= 5 && parseFloat(getComputedStyle(Child).getPropertyValue('padding-bottom')) >= 5).length >= 2;
107
- });
108
- Targeted = Targeted.filter(Ele => {
109
- let Children = [...Ele.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement);
110
- return !Children.some(Child => {
111
- return parseFloat(getComputedStyle(Child).getPropertyValue('margin-bottom')) >= 10 && parseFloat(getComputedStyle(Child).getPropertyValue('padding-bottom')) >= 1 && parseFloat(getComputedStyle(Child).getPropertyValue('padding-top')) >= 1 &&
112
- parseFloat(getComputedStyle(Child).getPropertyValue('border-top-width')) >= 0.25 && parseFloat(getComputedStyle(Child).getPropertyValue('border-bottom-width')) >= 0.25;
113
- });
114
- });
115
- Targeted = Targeted.filter(Ele => {
116
- let Children = [...Ele.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement);
117
- Children = Children.filter(Child => parseFloat(getComputedStyle(Child).getPropertyValue('padding-right')) >= 10 && parseFloat(getComputedStyle(Child).getPropertyValue('padding-bottom')) >= 10);
118
- Children = Children.filter(Child => parseFloat(getComputedStyle(Child).getPropertyValue('margin-left')) >= 2.5);
119
- return Children.length === 0;
120
- });
121
- Targeted = Targeted.filter(Ele => {
122
- if (Ele.getBoundingClientRect().width < 500 && BrowserWindow.document.body.getBoundingClientRect().width > 500)
123
- return false;
124
- let Children = [...Ele.querySelectorAll('*[style]')].filter(Child => Child instanceof HTMLElement && Child.style.length > 0);
125
- return Children.filter(Child => {
126
- if (!(Child instanceof HTMLElement))
127
- return false;
128
- const ComputedStyle = getComputedStyle(Child);
129
- const MissingCount = [...Child.style].filter(Property => {
130
- const InlineValue = Child.style.getPropertyValue(Property).trim();
131
- const ComputedValue = ComputedStyle.getPropertyValue(Property).trim();
132
- return InlineValue !== ComputedValue;
133
- }).length;
134
- return MissingCount <= 1;
135
- }).length < 5;
136
- });
137
- Targeted = await ExecuteOCR(Targeted);
138
- Targeted.forEach(Ele => Targeted.push(...new Set([...Ele.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement))));
139
- Targeted = [...new Set(Targeted)];
140
- let RealTargeted = Targeted.filter(Ele => parseFloat(getComputedStyle(Ele).getPropertyValue('padding-left')) >= 5 && parseFloat(getComputedStyle(Ele).getPropertyValue('border-right-width')) >= 0.1);
141
- console.debug(`[${UserscriptName}] ${EventParameter.type} RealTargeted`, RealTargeted, EventParameter);
142
- RealTargeted.forEach(Ele => {
143
- Ele.style.setProperty('display', 'none', 'important');
144
- });
145
- let RealTabletTargeted = Targeted.filter(Ele => {
146
- if (!(Ele instanceof HTMLElement) || !(Ele instanceof HTMLTableElement))
147
- return false;
148
- let Children = [...Ele.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement);
149
- return Children.some(Child => parseFloat(getComputedStyle(Child).getPropertyValue('padding-top')) >= 5 && parseFloat(getComputedStyle(Child).getPropertyValue('padding-bottom')) >= 5);
150
- });
151
- console.debug(`[${UserscriptName}] ${EventParameter.type} RealTabletTargeted`, RealTabletTargeted, EventParameter);
152
- RealTabletTargeted.forEach(Ele => {
153
- Ele.style.setProperty('display', 'none', 'important');
154
- });
155
- // leftover
156
- const PlaceHolderCandidated = new Set([...RealTargeted, ...RealTabletTargeted]);
157
- PlaceHolderCandidated.forEach(PlaceHolder => {
158
- let Parents = [...AllParents(PlaceHolder)].filter(Ele => Ele.innerText.trim().length === 0);
159
- Parents.forEach(Ele => PlaceHolderCandidated.add(Ele));
160
- });
161
- console.debug(`[${UserscriptName}] ${EventParameter.type} PlaceHolderCandidated`, PlaceHolderCandidated, EventParameter);
162
- [...PlaceHolderCandidated].forEach(Ele => {
163
- Ele.style.setProperty('display', 'none', 'important');
164
- });
165
- }
166
- ArticleHTMLElement.addEventListener('vue:settled', (EventParameter) => Handler(EventParameter));
167
- ArticleHTMLElement.addEventListener('vue:url-changed', (EventParameter) => setTimeout(() => Handler(EventParameter), 250));
168
- // init Naver Nanum fonts
169
- const FontAddr = [
170
- 'https://fonts.googleapis.com/css2?family=Nanum Gothic&display=swap',
171
- ];
172
- FontAddr.forEach(Addr => {
173
- const Link = BrowserWindow.document.createElement('link');
174
- Link.rel = 'stylesheet';
175
- Link.href = Addr;
176
- BrowserWindow.document.head.appendChild(Link);
177
- });
178
- }
179
- void RunNamuLinkUserscript(Win);
@@ -1,15 +0,0 @@
1
- import type { MatchResult } from './ocr-types.js';
2
- type DetectElementOptions = {
3
- FontCandidates?: readonly string[];
4
- ScoreThreshold?: number;
5
- };
6
- type DetectSourceOptions = DetectElementOptions & {
7
- HostElement: HTMLElement;
8
- SourceUrl: string;
9
- };
10
- export declare function CreateOcrWorkerClient(BrowserWindow: typeof window, WorkerInstance: Worker): {
11
- DetectFromElement: (Element: HTMLElement, Options?: DetectElementOptions) => Promise<MatchResult>;
12
- DetectFromSource: (Options: DetectSourceOptions) => Promise<MatchResult>;
13
- Terminate(): void;
14
- };
15
- export {};
@@ -1,281 +0,0 @@
1
- function ParseBackgroundImageUrl(BackgroundImage) {
2
- const Trimmed = BackgroundImage.trim();
3
- if (!Trimmed || Trimmed === 'none')
4
- return null;
5
- const Match = Trimmed.match(/^url\((.*)\)$/i);
6
- if (!Match)
7
- return null;
8
- let Inner = Match[1].trim();
9
- if ((Inner.startsWith('"') && Inner.endsWith('"')) || (Inner.startsWith('\'') && Inner.endsWith('\''))) {
10
- Inner = Inner.slice(1, -1);
11
- }
12
- return Inner;
13
- }
14
- function GetElementEffectiveBackgroundColor(BrowserWindow, Element) {
15
- let Node = Element;
16
- while (Node) {
17
- const Background = BrowserWindow.getComputedStyle(Node).backgroundColor;
18
- if (Background && Background !== 'transparent' && Background !== 'rgba(0, 0, 0, 0)') {
19
- return Background;
20
- }
21
- Node = Node.parentElement;
22
- }
23
- return 'rgb(255, 255, 255)';
24
- }
25
- function GetBackgroundColorCandidates(BrowserWindow, Element, FallbackBackground) {
26
- const Candidates = new Set();
27
- function AddCandidate(BackgroundColor) {
28
- if (!BackgroundColor)
29
- return;
30
- if (BackgroundColor === 'transparent' || BackgroundColor === 'rgba(0, 0, 0, 0)')
31
- return;
32
- Candidates.add(BackgroundColor);
33
- }
34
- AddCandidate(FallbackBackground);
35
- const ElementStyle = BrowserWindow.getComputedStyle(Element);
36
- AddCandidate(ElementStyle.backgroundColor);
37
- AddCandidate(ElementStyle.color);
38
- AddCandidate(BrowserWindow.getComputedStyle(BrowserWindow.document.documentElement).backgroundColor);
39
- if (BrowserWindow.document.body) {
40
- const BodyStyle = BrowserWindow.getComputedStyle(BrowserWindow.document.body);
41
- AddCandidate(BodyStyle.backgroundColor);
42
- AddCandidate(BodyStyle.color);
43
- }
44
- AddCandidate('rgb(255, 255, 255)');
45
- AddCandidate('rgb(0, 0, 0)');
46
- return [...Candidates];
47
- }
48
- function ResolveElementSource(BrowserWindow, Element) {
49
- if (Element instanceof BrowserWindow.HTMLImageElement) {
50
- const ImageSource = Element.currentSrc || Element.src || '';
51
- return ImageSource || null;
52
- }
53
- const BackgroundImage = BrowserWindow.getComputedStyle(Element).backgroundImage;
54
- return ParseBackgroundImageUrl(BackgroundImage);
55
- }
56
- export function CreateOcrWorkerClient(BrowserWindow, WorkerInstance) {
57
- let RequestSequence = 0;
58
- const Pending = new Map();
59
- WorkerInstance.addEventListener('message', (Event) => {
60
- const Message = Event.data;
61
- if (!Message || !('RequestId' in Message))
62
- return;
63
- const PendingRequest = Pending.get(Message.RequestId);
64
- if (!PendingRequest)
65
- return;
66
- Pending.delete(Message.RequestId);
67
- if (Message.Kind === 'detect-result') {
68
- PendingRequest.Resolve(Message.Result);
69
- return;
70
- }
71
- PendingRequest.Reject(new Error(Message.Error));
72
- });
73
- function PostDetect(Request) {
74
- const RequestId = `ocr-${Date.now()}-${RequestSequence++}`;
75
- const Message = {
76
- Kind: 'detect',
77
- RequestId,
78
- ...Request,
79
- };
80
- return new Promise((Resolve, Reject) => {
81
- Pending.set(RequestId, { Resolve, Reject });
82
- WorkerInstance.postMessage(Message);
83
- });
84
- }
85
- async function DetectFromElement(Element, Options) {
86
- const SourceUrl = ResolveElementSource(BrowserWindow, Element);
87
- if (!SourceUrl)
88
- return null;
89
- const ImageDataValue = await LoadImageDataFromSourceUrl(BrowserWindow, Element, SourceUrl);
90
- const FallbackBackground = GetElementEffectiveBackgroundColor(BrowserWindow, Element);
91
- const BackgroundCandidates = GetBackgroundColorCandidates(BrowserWindow, Element, FallbackBackground);
92
- return PostDetect({
93
- ImageData: ImageDataValue,
94
- BackgroundCandidates,
95
- FontCandidates: Options?.FontCandidates,
96
- ScoreThreshold: Options?.ScoreThreshold,
97
- });
98
- }
99
- async function DetectFromSource(Options) {
100
- const ImageDataValue = await LoadImageDataFromSourceUrl(BrowserWindow, Options.HostElement, Options.SourceUrl);
101
- const FallbackBackground = GetElementEffectiveBackgroundColor(BrowserWindow, Options.HostElement);
102
- const BackgroundCandidates = GetBackgroundColorCandidates(BrowserWindow, Options.HostElement, FallbackBackground);
103
- return PostDetect({
104
- ImageData: ImageDataValue,
105
- BackgroundCandidates,
106
- FontCandidates: Options.FontCandidates,
107
- ScoreThreshold: Options.ScoreThreshold,
108
- });
109
- }
110
- return {
111
- DetectFromElement,
112
- DetectFromSource,
113
- Terminate() {
114
- for (const PendingRequest of Pending.values()) {
115
- PendingRequest.Reject(new Error('OCR worker terminated'));
116
- }
117
- Pending.clear();
118
- WorkerInstance.terminate();
119
- },
120
- };
121
- }
122
- function IsSvgDataUrl(SourceUrl) {
123
- return /^data:image\/svg\+xml(?:[;,]|$)/i.test(SourceUrl);
124
- }
125
- function DecodeBase64Utf8(BrowserWindow, Base64Text) {
126
- const Binary = BrowserWindow.atob(Base64Text);
127
- const Bytes = new Uint8Array(Binary.length);
128
- for (let Index = 0; Index < Binary.length; Index++) {
129
- Bytes[Index] = Binary.charCodeAt(Index);
130
- }
131
- return new TextDecoder().decode(Bytes);
132
- }
133
- function DecodeSvgDataUrl(BrowserWindow, SourceUrl) {
134
- const CommaIndex = SourceUrl.indexOf(',');
135
- if (CommaIndex < 0)
136
- throw new Error('Invalid SVG data URL');
137
- const Header = SourceUrl.slice(0, CommaIndex).toLowerCase();
138
- const Payload = SourceUrl.slice(CommaIndex + 1);
139
- if (Header.includes(';base64')) {
140
- return DecodeBase64Utf8(BrowserWindow, Payload);
141
- }
142
- return decodeURIComponent(Payload);
143
- }
144
- function PrepareSvgMarkupForRasterize(BrowserWindow, SvgMarkup, Width, Height) {
145
- const Parser = new BrowserWindow.DOMParser();
146
- const XmlDocument = Parser.parseFromString(SvgMarkup, 'image/svg+xml');
147
- if (XmlDocument.querySelector('parsererror')) {
148
- throw new Error('Failed to parse SVG markup');
149
- }
150
- const SvgElement = XmlDocument.documentElement;
151
- if (!SvgElement || SvgElement.nodeName.toLowerCase() !== 'svg') {
152
- throw new Error('SVG root element not found');
153
- }
154
- if (!SvgElement.getAttribute('xmlns')) {
155
- SvgElement.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
156
- }
157
- if (!SvgElement.getAttribute('width')) {
158
- SvgElement.setAttribute('width', String(Width));
159
- }
160
- if (!SvgElement.getAttribute('height')) {
161
- SvgElement.setAttribute('height', String(Height));
162
- }
163
- return new BrowserWindow.XMLSerializer().serializeToString(XmlDocument);
164
- }
165
- function WaitForImageLoad(ImageElement) {
166
- if (ImageElement.complete && ImageElement.naturalWidth > 0) {
167
- return Promise.resolve();
168
- }
169
- return new Promise((Resolve, Reject) => {
170
- function Cleanup() {
171
- ImageElement.removeEventListener('load', OnLoad);
172
- ImageElement.removeEventListener('error', OnError);
173
- }
174
- function OnLoad() {
175
- Cleanup();
176
- Resolve();
177
- }
178
- function OnError() {
179
- Cleanup();
180
- Reject(new Error('Failed to load SVG image'));
181
- }
182
- ImageElement.addEventListener('load', OnLoad);
183
- ImageElement.addEventListener('error', OnError);
184
- });
185
- }
186
- async function LoadImageElement(BrowserWindow, SourceUrl) {
187
- const ImageElement = new BrowserWindow.Image();
188
- ImageElement.decoding = 'async';
189
- ImageElement.src = SourceUrl;
190
- try {
191
- await ImageElement.decode();
192
- if (ImageElement.naturalWidth > 0) {
193
- return ImageElement;
194
- }
195
- }
196
- catch {
197
- }
198
- await WaitForImageLoad(ImageElement);
199
- return ImageElement;
200
- }
201
- function IsSvgMimeType(MimeType) {
202
- return typeof MimeType === 'string' && /^image\/svg\+xml(?:\s*;|$)/i.test(MimeType);
203
- }
204
- function GetRasterSize(BrowserWindow, HostElement) {
205
- const Rect = HostElement.getBoundingClientRect();
206
- const Scale = Math.max(1, BrowserWindow.devicePixelRatio || 1);
207
- return {
208
- Width: Math.max(1, Math.round((Rect.width || HostElement.clientWidth || 96) * Scale)),
209
- Height: Math.max(1, Math.round((Rect.height || HostElement.clientHeight || 32) * Scale)),
210
- };
211
- }
212
- async function RasterizeSvgMarkupToImageData(BrowserWindow, HostElement, SvgMarkup) {
213
- const { Width, Height } = GetRasterSize(BrowserWindow, HostElement);
214
- const PreparedSvgMarkup = PrepareSvgMarkupForRasterize(BrowserWindow, SvgMarkup, Width, Height);
215
- const SvgBlobUrl = BrowserWindow.URL.createObjectURL(new BrowserWindow.Blob([PreparedSvgMarkup], { type: 'image/svg+xml' }));
216
- try {
217
- const ImageElement = await LoadImageElement(BrowserWindow, SvgBlobUrl);
218
- const Canvas = BrowserWindow.document.createElement('canvas');
219
- Canvas.width = Width;
220
- Canvas.height = Height;
221
- const Context2D = Canvas.getContext('2d', { willReadFrequently: true });
222
- if (!Context2D)
223
- throw new Error('2D context unavailable');
224
- Context2D.clearRect(0, 0, Width, Height);
225
- Context2D.drawImage(ImageElement, 0, 0, Width, Height);
226
- return Context2D.getImageData(0, 0, Width, Height);
227
- }
228
- finally {
229
- BrowserWindow.URL.revokeObjectURL(SvgBlobUrl);
230
- }
231
- }
232
- async function RasterizeBitmapBlobToImageData(BrowserWindow, BlobData) {
233
- const Bitmap = await BrowserWindow.createImageBitmap(BlobData);
234
- try {
235
- const Canvas = BrowserWindow.document.createElement('canvas');
236
- Canvas.width = Bitmap.width;
237
- Canvas.height = Bitmap.height;
238
- const Context2D = Canvas.getContext('2d', { willReadFrequently: true });
239
- if (!Context2D)
240
- throw new Error('2D context unavailable');
241
- Context2D.drawImage(Bitmap, 0, 0);
242
- return Context2D.getImageData(0, 0, Canvas.width, Canvas.height);
243
- }
244
- finally {
245
- Bitmap.close();
246
- }
247
- }
248
- async function LoadImageDataFromSourceUrl(BrowserWindow, HostElement, SourceUrl) {
249
- if (IsSvgDataUrl(SourceUrl)) {
250
- const SvgMarkup = DecodeSvgDataUrl(BrowserWindow, SourceUrl);
251
- return await RasterizeSvgMarkupToImageData(BrowserWindow, HostElement, SvgMarkup);
252
- }
253
- const ResponseData = await new Promise((Resolve, Reject) => {
254
- GM.xmlHttpRequest({
255
- url: SourceUrl,
256
- method: 'GET',
257
- responseType: 'blob',
258
- onload: (ResponseValue) => {
259
- if (ResponseValue.status < 200 || ResponseValue.status >= 300) {
260
- Reject(new Error(`Failed to fetch image: ${ResponseValue.status} ${ResponseValue.statusText}`));
261
- return;
262
- }
263
- const BlobData = ResponseValue.response;
264
- if (!(BlobData instanceof Blob)) {
265
- Reject(new Error('Failed to fetch image: invalid blob response'));
266
- return;
267
- }
268
- const HeaderMatch = ResponseValue.responseHeaders.match(/^content-type:\s*(.+)$/im);
269
- const ContentTypeHeader = HeaderMatch ? HeaderMatch[1].trim() : null;
270
- Resolve({ BlobData, ContentTypeHeader });
271
- },
272
- onerror: Reject,
273
- ontimeout: Reject,
274
- });
275
- });
276
- if (IsSvgMimeType(ResponseData.BlobData.type) || IsSvgMimeType(ResponseData.ContentTypeHeader)) {
277
- const SvgMarkup = await ResponseData.BlobData.text();
278
- return await RasterizeSvgMarkupToImageData(BrowserWindow, HostElement, SvgMarkup);
279
- }
280
- return await RasterizeBitmapBlobToImageData(BrowserWindow, ResponseData.BlobData);
281
- }
@@ -1,32 +0,0 @@
1
- export type TargetLabel = '파워링크' | '광고' | '광고등록';
2
- export type BoundingBox = {
3
- X: number;
4
- Y: number;
5
- Width: number;
6
- Height: number;
7
- };
8
- export type MatchResult = {
9
- Label: TargetLabel;
10
- Score: number;
11
- Box: BoundingBox;
12
- } | null;
13
- export type WorkerDetectRequest = {
14
- Kind: 'detect';
15
- RequestId: string;
16
- ImageData: ImageData;
17
- BackgroundCandidates: string[];
18
- FontCandidates?: readonly string[];
19
- ScoreThreshold?: number;
20
- };
21
- export type WorkerDetectSuccessResponse = {
22
- Kind: 'detect-result';
23
- RequestId: string;
24
- Result: MatchResult;
25
- };
26
- export type WorkerDetectErrorResponse = {
27
- Kind: 'detect-error';
28
- RequestId: string;
29
- Error: string;
30
- };
31
- export type WorkerMessage = WorkerDetectRequest;
32
- export type WorkerResponse = WorkerDetectSuccessResponse | WorkerDetectErrorResponse;
package/dist/ocr-types.js DELETED
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,444 +0,0 @@
1
- const Targets = ['파워링크', '광고', '광고등록'];
2
- const DefaultFontCandidates = [
3
- 'Pretendard JP, sans-serif',
4
- 'Pretendard, sans-serif',
5
- 'system-ui, sans-serif',
6
- 'Apple SD Gothic Neo, sans-serif',
7
- 'Nanum Gothic, sans-serif',
8
- 'Noto Sans KR, sans-serif',
9
- 'Arial, sans-serif',
10
- ];
11
- const TemplateCache = new Map();
12
- function CreateCanvas(Width, Height) {
13
- return new OffscreenCanvas(Math.max(1, Math.floor(Width)), Math.max(1, Math.floor(Height)));
14
- }
15
- function Get2DContext(Canvas) {
16
- const Context2D = Canvas.getContext('2d', { willReadFrequently: true });
17
- if (!Context2D)
18
- throw new Error('2D context unavailable');
19
- return Context2D;
20
- }
21
- // function DrawImageWithBackground(
22
- // Source: CanvasImageSource,
23
- // Width: number,
24
- // Height: number,
25
- // BackgroundCssColor: string,
26
- // ): OffscreenCanvas {
27
- // const Canvas = CreateCanvas(Width, Height)
28
- // const Context2D = Get2DContext(Canvas)
29
- // Context2D.fillStyle = BackgroundCssColor
30
- // Context2D.fillRect(0, 0, Width, Height)
31
- // Context2D.drawImage(Source, 0, 0, Width, Height)
32
- // return Canvas
33
- // }
34
- function CanvasToGrayImage(Canvas) {
35
- const Context2D = Get2DContext(Canvas);
36
- const { width: Width, height: Height } = Canvas;
37
- const Rgba = Context2D.getImageData(0, 0, Width, Height).data;
38
- const Gray = new Uint8ClampedArray(Width * Height);
39
- for (let Index = 0, Pixel = 0; Index < Rgba.length; Index += 4, Pixel++) {
40
- const Red = Rgba[Index];
41
- const Green = Rgba[Index + 1];
42
- const Blue = Rgba[Index + 2];
43
- Gray[Pixel] = Math.round(0.299 * Red + 0.587 * Green + 0.114 * Blue);
44
- }
45
- return { Width, Height, Data: Gray };
46
- }
47
- function OtsuThreshold(Gray) {
48
- const Histogram = new Uint32Array(256);
49
- for (let Index = 0; Index < Gray.Data.length; Index++)
50
- Histogram[Gray.Data[Index]]++;
51
- const Total = Gray.Data.length;
52
- let Sum = 0;
53
- for (let Index = 0; Index < 256; Index++)
54
- Sum += Index * Histogram[Index];
55
- let SumBackground = 0;
56
- let WeightBackground = 0;
57
- let MaxVariance = -1;
58
- let Threshold = 127;
59
- for (let ThresholdIndex = 0; ThresholdIndex < 256; ThresholdIndex++) {
60
- WeightBackground += Histogram[ThresholdIndex];
61
- if (WeightBackground === 0)
62
- continue;
63
- const WeightForeground = Total - WeightBackground;
64
- if (WeightForeground === 0)
65
- break;
66
- SumBackground += ThresholdIndex * Histogram[ThresholdIndex];
67
- const MeanBackground = SumBackground / WeightBackground;
68
- const MeanForeground = (Sum - SumBackground) / WeightForeground;
69
- const BetweenClassVariance = WeightBackground * WeightForeground * (MeanBackground - MeanForeground) * (MeanBackground - MeanForeground);
70
- if (BetweenClassVariance > MaxVariance) {
71
- MaxVariance = BetweenClassVariance;
72
- Threshold = ThresholdIndex;
73
- }
74
- }
75
- return Threshold;
76
- }
77
- function BinarizeByContrast(Gray) {
78
- const Threshold = OtsuThreshold(Gray);
79
- let DarkCount = 0;
80
- let LightCount = 0;
81
- for (let Index = 0; Index < Gray.Data.length; Index++) {
82
- if (Gray.Data[Index] < Threshold)
83
- DarkCount++;
84
- else
85
- LightCount++;
86
- }
87
- const TextIsDark = DarkCount < LightCount;
88
- const Output = new Uint8Array(Gray.Width * Gray.Height);
89
- for (let Index = 0; Index < Gray.Data.length; Index++) {
90
- const IsText = TextIsDark ? Gray.Data[Index] < Threshold : Gray.Data[Index] > Threshold;
91
- Output[Index] = IsText ? 1 : 0;
92
- }
93
- return { Width: Gray.Width, Height: Gray.Height, Data: Output };
94
- }
95
- function Erode3x3(Source) {
96
- const Output = new Uint8Array(Source.Width * Source.Height);
97
- for (let Y = 1; Y < Source.Height - 1; Y++) {
98
- for (let X = 1; X < Source.Width - 1; X++) {
99
- let Keep = 1;
100
- for (let DeltaY = -1; DeltaY <= 1 && Keep; DeltaY++) {
101
- for (let DeltaX = -1; DeltaX <= 1; DeltaX++) {
102
- if (Source.Data[(Y + DeltaY) * Source.Width + (X + DeltaX)] === 0) {
103
- Keep = 0;
104
- break;
105
- }
106
- }
107
- }
108
- Output[Y * Source.Width + X] = Keep;
109
- }
110
- }
111
- return { Width: Source.Width, Height: Source.Height, Data: Output };
112
- }
113
- function Dilate3x3(Source) {
114
- const Output = new Uint8Array(Source.Width * Source.Height);
115
- for (let Y = 1; Y < Source.Height - 1; Y++) {
116
- for (let X = 1; X < Source.Width - 1; X++) {
117
- let Value = 0;
118
- for (let DeltaY = -1; DeltaY <= 1 && !Value; DeltaY++) {
119
- for (let DeltaX = -1; DeltaX <= 1; DeltaX++) {
120
- if (Source.Data[(Y + DeltaY) * Source.Width + (X + DeltaX)] === 1) {
121
- Value = 1;
122
- break;
123
- }
124
- }
125
- }
126
- Output[Y * Source.Width + X] = Value;
127
- }
128
- }
129
- return { Width: Source.Width, Height: Source.Height, Data: Output };
130
- }
131
- function OpenClose(Source) {
132
- return Dilate3x3(Erode3x3(Dilate3x3(Source)));
133
- }
134
- function FindConnectedComponents(Source, MinArea = 20) {
135
- const Visited = new Uint8Array(Source.Width * Source.Height);
136
- const Boxes = [];
137
- const QueueX = new Int32Array(Source.Width * Source.Height);
138
- const QueueY = new Int32Array(Source.Width * Source.Height);
139
- for (let Y = 0; Y < Source.Height; Y++) {
140
- for (let X = 0; X < Source.Width; X++) {
141
- const Index = Y * Source.Width + X;
142
- if (Visited[Index] || Source.Data[Index] === 0)
143
- continue;
144
- let Head = 0;
145
- let Tail = 0;
146
- QueueX[Tail] = X;
147
- QueueY[Tail] = Y;
148
- Tail++;
149
- Visited[Index] = 1;
150
- let MinX = X;
151
- let MinY = Y;
152
- let MaxX = X;
153
- let MaxY = Y;
154
- let Area = 0;
155
- while (Head < Tail) {
156
- const CurrentX = QueueX[Head];
157
- const CurrentY = QueueY[Head];
158
- Head++;
159
- Area++;
160
- if (CurrentX < MinX)
161
- MinX = CurrentX;
162
- if (CurrentY < MinY)
163
- MinY = CurrentY;
164
- if (CurrentX > MaxX)
165
- MaxX = CurrentX;
166
- if (CurrentY > MaxY)
167
- MaxY = CurrentY;
168
- for (let DeltaY = -1; DeltaY <= 1; DeltaY++) {
169
- for (let DeltaX = -1; DeltaX <= 1; DeltaX++) {
170
- if (DeltaX === 0 && DeltaY === 0)
171
- continue;
172
- const NextX = CurrentX + DeltaX;
173
- const NextY = CurrentY + DeltaY;
174
- if (NextX < 0 || NextY < 0 || NextX >= Source.Width || NextY >= Source.Height)
175
- continue;
176
- const NextIndex = NextY * Source.Width + NextX;
177
- if (Visited[NextIndex] || Source.Data[NextIndex] === 0)
178
- continue;
179
- Visited[NextIndex] = 1;
180
- QueueX[Tail] = NextX;
181
- QueueY[Tail] = NextY;
182
- Tail++;
183
- }
184
- }
185
- }
186
- if (Area >= MinArea) {
187
- Boxes.push({ X: MinX, Y: MinY, Width: MaxX - MinX + 1, Height: MaxY - MinY + 1 });
188
- }
189
- }
190
- }
191
- return Boxes;
192
- }
193
- function MergeNearbyBoxes(Boxes, GapX = 8, GapY = 4) {
194
- const Result = [...Boxes];
195
- let Changed = true;
196
- function OverlapsOrNear(A, B) {
197
- const AX2 = A.X + A.Width;
198
- const AY2 = A.Y + A.Height;
199
- const BX2 = B.X + B.Width;
200
- const BY2 = B.Y + B.Height;
201
- return !(AX2 + GapX < B.X
202
- || BX2 + GapX < A.X
203
- || AY2 + GapY < B.Y
204
- || BY2 + GapY < A.Y);
205
- }
206
- while (Changed) {
207
- Changed = false;
208
- outer: for (let IndexA = 0; IndexA < Result.length; IndexA++) {
209
- for (let IndexB = IndexA + 1; IndexB < Result.length; IndexB++) {
210
- if (!OverlapsOrNear(Result[IndexA], Result[IndexB]))
211
- continue;
212
- const A = Result[IndexA];
213
- const B = Result[IndexB];
214
- Result[IndexA] = {
215
- X: Math.min(A.X, B.X),
216
- Y: Math.min(A.Y, B.Y),
217
- Width: Math.max(A.X + A.Width, B.X + B.Width) - Math.min(A.X, B.X),
218
- Height: Math.max(A.Y + A.Height, B.Y + B.Height) - Math.min(A.Y, B.Y),
219
- };
220
- Result.splice(IndexB, 1);
221
- Changed = true;
222
- break outer;
223
- }
224
- }
225
- }
226
- return Result;
227
- }
228
- function CropBinary(Source, Box) {
229
- const Output = new Uint8Array(Box.Width * Box.Height);
230
- for (let Y = 0; Y < Box.Height; Y++) {
231
- for (let X = 0; X < Box.Width; X++) {
232
- Output[Y * Box.Width + X] = Source.Data[(Box.Y + Y) * Source.Width + (Box.X + X)];
233
- }
234
- }
235
- return { Width: Box.Width, Height: Box.Height, Data: Output };
236
- }
237
- function TrimBinary(Source) {
238
- let MinX = Source.Width;
239
- let MinY = Source.Height;
240
- let MaxX = -1;
241
- let MaxY = -1;
242
- for (let Y = 0; Y < Source.Height; Y++) {
243
- for (let X = 0; X < Source.Width; X++) {
244
- if (Source.Data[Y * Source.Width + X] === 0)
245
- continue;
246
- if (X < MinX)
247
- MinX = X;
248
- if (Y < MinY)
249
- MinY = Y;
250
- if (X > MaxX)
251
- MaxX = X;
252
- if (Y > MaxY)
253
- MaxY = Y;
254
- }
255
- }
256
- if (MaxX < MinX || MaxY < MinY) {
257
- return { Width: 1, Height: 1, Data: new Uint8Array([0]) };
258
- }
259
- return CropBinary(Source, { X: MinX, Y: MinY, Width: MaxX - MinX + 1, Height: MaxY - MinY + 1 });
260
- }
261
- function ResizeBinaryNearest(Source, Width, Height) {
262
- const Output = new Uint8Array(Width * Height);
263
- for (let Y = 0; Y < Height; Y++) {
264
- for (let X = 0; X < Width; X++) {
265
- const SourceX = Math.min(Source.Width - 1, Math.floor((X / Width) * Source.Width));
266
- const SourceY = Math.min(Source.Height - 1, Math.floor((Y / Height) * Source.Height));
267
- Output[Y * Width + X] = Source.Data[SourceY * Source.Width + SourceX];
268
- }
269
- }
270
- return { Width, Height, Data: Output };
271
- }
272
- function NormalizeBinary(Source, Size = 64) {
273
- const Trimmed = TrimBinary(Source);
274
- const Side = Math.max(Trimmed.Width, Trimmed.Height);
275
- const Padded = new Uint8Array(Side * Side);
276
- const OffsetX = Math.floor((Side - Trimmed.Width) / 2);
277
- const OffsetY = Math.floor((Side - Trimmed.Height) / 2);
278
- for (let Y = 0; Y < Trimmed.Height; Y++) {
279
- for (let X = 0; X < Trimmed.Width; X++) {
280
- Padded[(Y + OffsetY) * Side + (X + OffsetX)] = Trimmed.Data[Y * Trimmed.Width + X];
281
- }
282
- }
283
- return ResizeBinaryNearest({ Width: Side, Height: Side, Data: Padded }, Size, Size);
284
- }
285
- function XorDistance(Left, Right) {
286
- if (Left.Width !== Right.Width || Left.Height !== Right.Height) {
287
- throw new Error('Image size mismatch');
288
- }
289
- let Different = 0;
290
- for (let Index = 0; Index < Left.Data.length; Index++) {
291
- if (Left.Data[Index] !== Right.Data[Index])
292
- Different++;
293
- }
294
- return Different / Left.Data.length;
295
- }
296
- function GetTemplate(Text, FontFamily) {
297
- const CacheKey = `${Text}__${FontFamily}`;
298
- const Cached = TemplateCache.get(CacheKey);
299
- if (Cached)
300
- return Cached;
301
- const Width = 256;
302
- const Height = 96;
303
- const Canvas = CreateCanvas(Width, Height);
304
- const Context2D = Get2DContext(Canvas);
305
- Context2D.fillStyle = 'white';
306
- Context2D.fillRect(0, 0, Width, Height);
307
- let FontSize = Math.floor(Height * 0.72);
308
- while (FontSize > 8) {
309
- Context2D.clearRect(0, 0, Width, Height);
310
- Context2D.fillStyle = 'white';
311
- Context2D.fillRect(0, 0, Width, Height);
312
- Context2D.fillStyle = 'black';
313
- Context2D.textAlign = 'center';
314
- Context2D.textBaseline = 'middle';
315
- Context2D.font = `700 ${FontSize}px ${FontFamily}`;
316
- const Metrics = Context2D.measureText(Text);
317
- const TextWidth = Metrics.width;
318
- const TextHeight = (Metrics.actualBoundingBoxAscent || FontSize * 0.8)
319
- + (Metrics.actualBoundingBoxDescent || FontSize * 0.2);
320
- if (TextWidth <= Width * 0.9 && TextHeight <= Height * 0.9) {
321
- Context2D.fillText(Text, Width / 2, Height / 2);
322
- const Gray = CanvasToGrayImage(Canvas);
323
- const Template = NormalizeBinary(BinarizeByContrast(Gray));
324
- TemplateCache.set(CacheKey, Template);
325
- return Template;
326
- }
327
- FontSize--;
328
- }
329
- Context2D.font = `700 12px ${FontFamily}`;
330
- Context2D.fillStyle = 'black';
331
- Context2D.textAlign = 'center';
332
- Context2D.textBaseline = 'middle';
333
- Context2D.fillText(Text, Width / 2, Height / 2);
334
- const Template = NormalizeBinary(BinarizeByContrast(CanvasToGrayImage(Canvas)));
335
- TemplateCache.set(CacheKey, Template);
336
- return Template;
337
- }
338
- function ScoreRegionAgainstTarget(Region, Target, FontCandidates) {
339
- const NormalizedRegion = NormalizeBinary(Region);
340
- let Best = Number.POSITIVE_INFINITY;
341
- for (const FontFamily of FontCandidates) {
342
- const Template = GetTemplate(Target, FontFamily);
343
- const Score = XorDistance(NormalizedRegion, Template);
344
- if (Score < Best)
345
- Best = Score;
346
- }
347
- return Best;
348
- }
349
- function SelectTextRegions(Binary) {
350
- const Raw = FindConnectedComponents(Binary, 16);
351
- const Merged = MergeNearbyBoxes(Raw, 10, 6);
352
- return Merged.filter((Box) => {
353
- if (Box.Width < 8 || Box.Height < 8)
354
- return false;
355
- const Ratio = Box.Width / Box.Height;
356
- return Ratio > 0.5 && Ratio < 12;
357
- });
358
- }
359
- async function DetectFromSource(Request) {
360
- const HasTransparency = HasTransparentPixelsInImageData(Request.ImageData);
361
- const BackgroundCandidates = HasTransparency
362
- ? Request.BackgroundCandidates
363
- : Request.BackgroundCandidates.slice(0, 1);
364
- const FontCandidates = Request.FontCandidates ?? DefaultFontCandidates;
365
- const ScoreThreshold = Request.ScoreThreshold ?? 0.32;
366
- let Best = null;
367
- for (const BackgroundColor of BackgroundCandidates) {
368
- const CompositedImageData = CompositeImageDataOnBackground(Request.ImageData, BackgroundColor);
369
- const Gray = ImageDataToGrayImage(CompositedImageData);
370
- const Binary = OpenClose(BinarizeByContrast(Gray));
371
- const Regions = SelectTextRegions(Binary);
372
- if (Regions.length === 0)
373
- continue;
374
- for (const Box of Regions) {
375
- const Region = CropBinary(Binary, Box);
376
- for (const Target of Targets) {
377
- const Score = ScoreRegionAgainstTarget(Region, Target, FontCandidates);
378
- if (!Best || Score < Best.Score) {
379
- Best = { Label: Target, Score, Box };
380
- }
381
- }
382
- }
383
- }
384
- if (!Best)
385
- return null;
386
- if (Best.Score > ScoreThreshold)
387
- return null;
388
- return Best;
389
- }
390
- function ImageDataToGrayImage(Source) {
391
- const { width: Width, height: Height, data: Rgba } = Source;
392
- const Gray = new Uint8ClampedArray(Width * Height);
393
- for (let Index = 0, Pixel = 0; Index < Rgba.length; Index += 4, Pixel++) {
394
- const Red = Rgba[Index];
395
- const Green = Rgba[Index + 1];
396
- const Blue = Rgba[Index + 2];
397
- Gray[Pixel] = Math.round(0.299 * Red + 0.587 * Green + 0.114 * Blue);
398
- }
399
- return { Width, Height, Data: Gray };
400
- }
401
- function HasTransparentPixelsInImageData(Source) {
402
- const Rgba = Source.data;
403
- for (let Index = 3; Index < Rgba.length; Index += 4) {
404
- if (Rgba[Index] < 255)
405
- return true;
406
- }
407
- return false;
408
- }
409
- function CompositeImageDataOnBackground(Source, BackgroundCssColor) {
410
- const Canvas = CreateCanvas(Source.width, Source.height);
411
- const Context2D = Get2DContext(Canvas);
412
- Context2D.fillStyle = BackgroundCssColor;
413
- Context2D.fillRect(0, 0, Source.width, Source.height);
414
- Context2D.putImageData(Source, 0, 0);
415
- return Context2D.getImageData(0, 0, Source.width, Source.height);
416
- }
417
- self.addEventListener('message', (Event) => {
418
- if (Event.origin !== '')
419
- return;
420
- void (async () => {
421
- const Message = Event.data;
422
- if (!Message || Message.Kind !== 'detect')
423
- return;
424
- try {
425
- const Result = await DetectFromSource(Message);
426
- const Response = {
427
- Kind: 'detect-result',
428
- RequestId: Message.RequestId,
429
- Result,
430
- };
431
- self.postMessage(Response);
432
- }
433
- catch (ErrorValue) {
434
- const ErrorMessage = ErrorValue instanceof Error ? ErrorValue.message : String(ErrorValue);
435
- const Response = {
436
- Kind: 'detect-error',
437
- RequestId: Message.RequestId,
438
- Error: ErrorMessage,
439
- };
440
- self.postMessage(Response);
441
- }
442
- })();
443
- });
444
- export {};
@@ -1,8 +0,0 @@
1
- export declare function AttachVueSettledEvents(TargetEl: HTMLElement, Options?: {
2
- QuietMs?: number;
3
- EventName?: string;
4
- ChangeEventName?: string;
5
- UrlChange?: string;
6
- }): {
7
- Disconnect(): void;
8
- };
@@ -1,91 +0,0 @@
1
- export function AttachVueSettledEvents(TargetEl, Options = {}) {
2
- const QuietMs = Options.QuietMs ?? 120;
3
- const EventName = Options.EventName ?? 'vue:settled';
4
- const ChangeEventName = Options.ChangeEventName ?? 'vue:dom-changed';
5
- const UrlChangeEventName = Options.UrlChange ?? 'vue:url-changed';
6
- if (!(TargetEl instanceof HTMLElement)) {
7
- throw new TypeError('TargetEl must be an HTMLElement');
8
- }
9
- let Timer = -1;
10
- let Seq = 0;
11
- let Destroyed = false;
12
- let LastMutationAt = performance.now();
13
- let URLHistory = new URL(location.href);
14
- const EmitChange = (Mutations) => {
15
- TargetEl.dispatchEvent(new CustomEvent(ChangeEventName, {
16
- detail: {
17
- Seq,
18
- At: LastMutationAt,
19
- MutationCount: Mutations.length,
20
- Mutations,
21
- },
22
- }));
23
- };
24
- const EmitSettled = () => {
25
- requestAnimationFrame(() => {
26
- requestAnimationFrame(() => {
27
- if (Destroyed) {
28
- return;
29
- }
30
- TargetEl.dispatchEvent(new CustomEvent(EventName, {
31
- detail: {
32
- Seq,
33
- QuietMs,
34
- SettledAt: performance.now(),
35
- ElapsedSinceLastMutation: performance.now() - LastMutationAt,
36
- Target: TargetEl,
37
- },
38
- }));
39
- });
40
- });
41
- };
42
- const EmitUrlChange = () => {
43
- const NewURL = new URL(location.href);
44
- if (NewURL.href !== URLHistory.href) {
45
- URLHistory = NewURL;
46
- TargetEl.dispatchEvent(new CustomEvent(UrlChangeEventName, {
47
- detail: {
48
- Seq,
49
- At: performance.now(),
50
- URL: NewURL,
51
- },
52
- }));
53
- }
54
- };
55
- const ArmSettledTimer = () => {
56
- clearTimeout(Timer);
57
- Timer = setTimeout(EmitSettled, QuietMs);
58
- };
59
- const Observer = new MutationObserver((Mutations) => {
60
- Seq += 1;
61
- LastMutationAt = performance.now();
62
- EmitChange(Mutations);
63
- if (Mutations.flatMap(Mutation => [
64
- ...Mutation.addedNodes, ...Mutation.removedNodes,
65
- ...Mutation.nextSibling ? [Mutation.nextSibling] : [],
66
- ...Mutation.previousSibling ? [Mutation.previousSibling] : [],
67
- ...(Mutation.target ? [Mutation.target] : [])
68
- ]).length >= 15) {
69
- ArmSettledTimer();
70
- setTimeout(ArmSettledTimer, QuietMs * 3);
71
- }
72
- EmitUrlChange();
73
- });
74
- Observer.observe(TargetEl, {
75
- subtree: true,
76
- childList: true,
77
- attributes: true,
78
- characterData: true,
79
- });
80
- ArmSettledTimer();
81
- return {
82
- Disconnect() {
83
- Destroyed = true;
84
- clearTimeout(Timer);
85
- Observer.disconnect();
86
- TargetEl.dispatchEvent(new CustomEvent('vue:observer-disconnected', {
87
- detail: { Target: TargetEl },
88
- }));
89
- },
90
- };
91
- }