@filteringdev/namulink 17.5.1 → 18.0.1

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 MIT
10
10
  //
11
- // @version 17.5.1
11
+ // @version 18.0.1
12
12
  // @author PiQuark6046 and contributors
13
13
  //
14
14
  // @match https://namu.wiki/*
@@ -20,7 +20,15 @@
20
20
  // @run-at document-start
21
21
  // ==/UserScript==
22
22
  // Used libraries:
23
- (()=>{var y=typeof unsafeWindow<"u"?unsafeWindow:window;function d(f,l="NamuLink"){let r=f.Function.prototype.toString;function p(t){let e=[];for(;t.parentElement;)e.push(t.parentElement),t=t.parentElement;return e}setInterval(()=>{if(location.href.startsWith("https://namu.wiki/w/")){let t=Array.from(document.querySelectorAll('div[class*=" "] div[class]')).filter(e=>e instanceof HTMLElement);t=t.filter(e=>{let a=Number(getComputedStyle(e).getPropertyValue("padding-left").replaceAll("px","")),n=Number(getComputedStyle(e).getPropertyValue("padding-right").replaceAll("px","")),i=Number(getComputedStyle(e).getPropertyValue("padding-top").replaceAll("px","")),o=Number(getComputedStyle(e).getPropertyValue("padding-bottom").replaceAll("px",""));return a>5&&n>5&&i>5&&o>5}),t=t.filter(e=>Array.from(e.querySelectorAll("*")).filter(a=>a instanceof HTMLElement&&getComputedStyle(a).getPropertyValue("animation-timing-function")==="ease-in-out").length>=3),t=t.filter(e=>p(e).some(a=>Number(getComputedStyle(a).getPropertyValue("margin-top").replaceAll("px",""))>10)),t=t.filter(e=>e.innerText.length<1e3),t=t.filter(e=>Array.from(e.querySelectorAll('*[href="/RecentChanges"]')).filter(a=>a instanceof HTMLElement&&getComputedStyle(a).getPropertyValue("display")!=="none").length===0),t=t.filter(e=>!e.innerText.includes((new URL(location.href).searchParams.get("from")||"")+"\uC5D0\uC11C \uB118\uC5B4\uC634")),t=t.filter(e=>!/\[[0-9]+\] .+/.test(e.innerText)),t.forEach(e=>e.remove())}},1e3);let x=[[/for *\( *; *; *\) *switch *\( *_[a-z0-9]+\[_[a-z0-9]+\([a-z0-9]+\)\] *=_[a-z0-9]+/,/_[a-z0-9]+\[('|")[A-Z]+('|")\]\)\(\[ *\]\)/,/0x[a-z0-9]+ *\) *; *case/],[/; *return *this\[_0x[a-z0-9]+\( *0x[0-9a-z]+ *\)/,/; *if *\( *_0x[a-z0-9]+ *&& *\( *_0x[a-z0-9]+ *= *_0x[a-z0-9]+/,/\) *, *void *\( *this *\[ *_0x[a-z0-9]+\( *0x[0-9a-z]+ *\) *\] *= *_0x[a-z0-9]+ *\[/]];f.Function.prototype.bind=new Proxy(f.Function.prototype.bind,{apply(t,e,a){let n=Reflect.apply(r,e,a);return x.filter(i=>i.filter(o=>o.test(n)).length>=3).length===1?(console.debug(`[${l}]: Function.prototype.bind:`,e),Reflect.apply(t,()=>{},[])):Reflect.apply(t,e,a)}});let u=[[/\( *\) *=> *{ *var *_0x[0-9a-z]+ *= *a0_0x[0-9a-f]+ *; *this\[ *_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\]\(\); *}/,/\( *\) *=> *{ *var *_0x[0-9a-z]+ *= *a0_0x[0-9a-f]+ *; *this\[ *_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\]\(\); *}/],[/\( *\) *=> *{ *var _0x[a-z0-9]+ *= *_0x[a-z0-9]+ *; *if *\( *this\[ *_0x[a-z0-9]+ *\( *0x[0-9a-f]+ *\) *\] *\) *return *clearTimeout/,/\( *0x[0-9a-f]+ *\) *\] *\) *, *void *\( *this\[ *_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\] *= *void *\([x0-9a-f*+-]+ *\) *\) *; *this\[_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\] *\(\) *;/]];f.setTimeout=new Proxy(f.setTimeout,{apply(t,e,a){let n=Reflect.apply(r,a[0],a);if(u.filter(i=>i.filter(o=>o.test(n)).length>=1).length===1){console.debug(`[${l}]: setTimeout:`,a[0]);return}return Reflect.apply(t,e,a)}});let c=[[/function\( *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+\) *\{ *var *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *; *const *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *= *_0x[a-f0-9]+/,/\[ *('|")[a-zA-Z0-9-_]+('|") *\] *\) *\( *\( *\) *=> *\[*\( *\( *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+/,/ *, *{ *('|")[a-zA-Z0-9-_]+('|") *: *0x[a-f0-9]+ *, *('|")[a-zA-Z0-9-_]+('|") *: *\( *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+/,/('|")innerHTML('|") *: *_0x[a-f0-9]+ *\[ *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *\] *\} *, *null *, *-? *0x[a-f0-9]+ *\* *0x[a-f0-9]+/,/\( *_0x[a-f0-9]+ *\[ *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *\] *\) *&& *-?0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+ *\* *-? *0x[a-f0-9]+ *!== *_0x[a-f0-9]+/,/{ *('|")[A-Za-z0-9-_]+('|") *: *\( *0x[a-f0-9]+ *\* *-? *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *-? *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *, *_0x[a-f0-9]+ *\[ *('|")[A-Za-z0-9-_]+('|") *\] *\) *\( *\( *\) *=> *\[/,/\[ *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *, *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *\] *\) *\] *, *-? *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *-?0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *\) *; *\}/]];f.Function.prototype.call=new Proxy(f.Function.prototype.call,{apply(t,e,a){let n=Reflect.apply(r,e,a);return n.length<=25e3&&c.filter(i=>i.filter(o=>o.test(n)).length>=5).length===1?(console.debug(`[${l}]: Function.prototype.call:`,e),Reflect.apply(t,()=>{},[])):Reflect.apply(t,e,a)}})}d(y);})();
23
+ (()=>{function M(o={}){let e=R(o),d=e.Events.Navigate,l=e.Events.Rendered,h=g=>{window.dispatchEvent(new CustomEvent(d,{detail:g}))},i=g=>{window.dispatchEvent(new CustomEvent(l,{detail:g}))},s=window.location.href,r=0,n=!1,a=g=>{if(n)return;let c=window.location.href;if(c===s)return;let f=s;s=c;let m=++r;h({Seq:m,From:f,To:c,Cause:g}),(async()=>{let p=e.Root();if(!p){if(m!==r||n)return;i({Seq:m,Url:c,Ok:!0});return}let w=await y({Root:p,StableForMs:e.StableForMs,SampleWindowMs:e.SampleWindowMs,Threshold:e.Threshold,TimeoutMs:e.TimeoutMs,Ignore:e.IgnoreMutation});m!==r||n||i({Seq:m,Url:c,Ok:w})})()},t=g=>{let c=history[g].bind(history);Object.defineProperty(history,g,{value:(...m)=>{let p=c(...m);return queueMicrotask(()=>a(g)),p},configurable:!0,writable:!0})};t("pushState"),t("replaceState");let u=()=>a("popstate");window.addEventListener("popstate",u);let S=()=>a("hashchange");return e.WatchHashChange&&window.addEventListener("hashchange",S),queueMicrotask(()=>{if(n)return;let g=++r;h({Seq:g,From:null,To:window.location.href,Cause:"init"}),(async()=>{let c=e.Root();if(!c){if(g!==r||n)return;i({Seq:g,Url:window.location.href,Ok:!0});return}let f=await y({Root:c,StableForMs:e.StableForMs,SampleWindowMs:e.SampleWindowMs,Threshold:e.Threshold,TimeoutMs:e.TimeoutMs,Ignore:e.IgnoreMutation});g!==r||n||i({Seq:g,Url:window.location.href,Ok:f})})()}),()=>{n=!0,window.removeEventListener("popstate",u),e.WatchHashChange&&window.removeEventListener("hashchange",S)}}function b(o){if(o.type==="attributes"){let e=o.attributeName??"";if(e==="class"||e==="style"||e.startsWith("aria-")||e.startsWith("data-"))return!0}return!1}function R(o){return{Root:o.Root??(()=>document.querySelector("#app")??document.body),StableForMs:o.StableForMs??900,SampleWindowMs:o.SampleWindowMs??900,Threshold:o.Threshold??3,TimeoutMs:o.TimeoutMs??12e3,IgnoreMutation:o.IgnoreMutation??b,WatchHashChange:o.WatchHashChange??!0,Events:{Navigate:o.Events?.Navigate??"SpaNavigate",Rendered:o.Events?.Rendered??"SpaRendered"}}}async function y(o){let e=[],d=performance.now(),l=!1,h=new MutationObserver(s=>{let r=performance.now();for(let t of s){if(o.Ignore?.(t))continue;let u=1;t.type==="childList"&&(u=2),e.push({T:r,Score:u})}let n=r-o.SampleWindowMs;for(;e.length&&e[0].T<n;)e.shift();e.reduce((t,u)=>t+u.Score,0)>o.Threshold&&(d=r)});h.observe(o.Root,{subtree:!0,childList:!0,attributes:!0,characterData:!0});let i=performance.now();return await new Promise(s=>{let r=()=>{if(l)return;let n=performance.now();if(n-d>=o.StableForMs){l=!0,h.disconnect(),s(!0);return}if(n-i>=o.TimeoutMs){l=!0,h.disconnect(),s(!1);return}setTimeout(r,100)};setTimeout(r,0)})}function E(){let o=`
24
+ self.onmessage = (e) => {
25
+ const { entries, jobId } = e.data;
26
+ // entries: Array<[string, number]>
27
+ // \uB0B4\uB9BC\uCC28\uC21C \uC815\uB82C
28
+ entries.sort((a, b) => b[1] - a[1]);
29
+ self.postMessage({ jobId, sorted: entries });
30
+ };
31
+ `;return URL.createObjectURL(new Blob([o],{type:"text/javascript"}))}function C(o){let e=E(),d=Array.from({length:o},()=>new Worker(e));return{Workers:d,dispose(){d.forEach(l=>l.terminate()),URL.revokeObjectURL(e)}}}function v(o=document){let e=Object.create(null),d=o.createTreeWalker(o.documentElement||o,NodeFilter.SHOW_ELEMENT),l=d.currentNode;for(;l;){if(l instanceof Element)for(let h of l.attributes){let i=h.name;i.startsWith("data-v-")&&(e[i]=(e[i]||0)+1)}l=d.nextNode()}return e}function k(o){let e=[];function d(i){e.push(i);let s=e.length-1;for(;s>0;){let r=s-1>>1;if(e[r].count>=e[s].count)break;[e[r],e[s]]=[e[s],e[r]],s=r}}function l(){let i=e[0],s=e.pop();if(e.length){e[0]=s;let r=0;for(;;){let n=r*2+1,a=n+1,t=r;if(n<e.length&&e[n].count>e[t].count&&(t=n),a<e.length&&e[a].count>e[t].count&&(t=a),t===r)break;[e[r],e[t]]=[e[t],e[r]],r=t}}return i}for(let i=0;i<o.length;i++){let s=o[i];if(s&&s.length){let[r,n]=s[0];d({Count:n,Attr:r,ChunkIndex:i,IndexInChunk:0})}}let h=[];for(;e.length;){let{Attr:i,Count:s,ChunkIndex:r,IndexInChunk:n}=l();h.push([i,s]);let a=n+1,t=o[r];if(a<t.length){let[u,S]=t[a];d({Count:S,Attr:u,ChunkIndex:r,IndexInChunk:a})}}return h}async function W(o){let e=Object.entries(o),d=Math.max(1,navigator.hardwareConcurrency||1),l=Math.min(8,Math.max(1,d-1)),i=e.length>=5e3&&l>1?l:1,s=C(i);try{let r=Array.from({length:i},()=>[]);for(let t=0;t<e.length;t++)r[t%i].push(e[t]);let n=await Promise.all(r.map((t,u)=>new Promise((S,g)=>{let c=s.Workers[u],f=u+":"+Date.now(),m=w=>{w.data?.jobId===f&&(c.removeEventListener("message",m),c.removeEventListener("error",p),S(w.data.sorted))},p=w=>{c.removeEventListener("message",m),c.removeEventListener("error",p),g(w)};c.addEventListener("message",m),c.addEventListener("error",p),c.postMessage({entries:t,jobId:f})}))),a=n.length===1?n[0]:k(n);return{Result:a,TotalKeys:a.length,WorkerCount:i,HardwareConcurrency:d}}finally{s.dispose()}}var L=typeof unsafeWindow<"u"?unsafeWindow:window;function N(o,e="NamuLink"){let d=o.Function.prototype.toString;document.readyState==="loading"?window.addEventListener("DOMContentLoaded",()=>{M({Root:()=>document.getElementById("#app"),StableForMs:900,SampleWindowMs:900,Threshold:3,TimeoutMs:12e3,IgnoreMutation:b,WatchHashChange:!0})}):window.addEventListener("DOMContentLoaded",()=>{M({Root:()=>document.getElementById("#app"),StableForMs:900,SampleWindowMs:900,Threshold:3,TimeoutMs:12e3,IgnoreMutation:b,WatchHashChange:!0})}),window.addEventListener("SpaRendered",async()=>{let l=v(document),{Result:h,TotalKeys:i,WorkerCount:s,HardwareConcurrency:r}=await W(l),n=[];h.filter(([,a])=>a<=30).forEach(([a,t])=>{n.push(...[...document.querySelectorAll(`[${a}]`)].filter(u=>u instanceof HTMLElement))}),n=n.filter(a=>getComputedStyle(a).getPropertyValue("display")==="flex"),n=n.filter(a=>[...a.querySelectorAll("*")].some(t=>t instanceof HTMLElement&&typeof t.click=="function")),n=n.filter(a=>[...a.querySelectorAll("*")].filter(t=>t instanceof HTMLElement&&t.getBoundingClientRect().bottom-t.getBoundingClientRect().top>100&&t.getBoundingClientRect().right-t.getBoundingClientRect().left>100).length<=50),n=n.filter(a=>{let t=[...a.querySelectorAll("*")].filter(u=>u.getBoundingClientRect().bottom-u.getBoundingClientRect().top>25&&u.getBoundingClientRect().right-u.getBoundingClientRect().left>25&&u instanceof SVGPathElement&&u.getAttribute("d")!==null||u instanceof HTMLImageElement&&u.src.includes("//i.namu.wiki/i/")).length;return 1<=t&&t<=6}),n=n.filter(a=>[...a.querySelectorAll("*")].some(t=>t instanceof HTMLElement&&getComputedStyle(t,"::after").getPropertyValue("content").includes(":")&&t.getBoundingClientRect().right-t.getBoundingClientRect().left>100)===!1),console.debug(`[${e}]`,n),n.forEach(a=>{setTimeout(()=>{a.setAttribute("style","display: none !important; visibility: hidden !important;")},250)})})}N(L);})();
24
32
  /*!
25
33
  * @license MPL-2.0
26
34
  * This Source Code Form is subject to the terms of the Mozilla Public
package/dist/interface.js CHANGED
@@ -1,94 +1,348 @@
1
- // sources/src/index.ts
2
- var Win = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
3
- function RunNamuLinkUserscript(BrowserWindow, UserscriptName = "NamuLink") {
4
- const ProtectedFunctionPrototypeToString = BrowserWindow.Function.prototype.toString;
5
- function GetParents(Ele) {
6
- let Parents = [];
7
- while (Ele.parentElement) {
8
- Parents.push(Ele.parentElement);
9
- Ele = Ele.parentElement;
10
- }
11
- return Parents;
12
- }
13
- setInterval(() => {
14
- if (location.href.startsWith("https://namu.wiki/w/")) {
15
- let AdContainers = Array.from(document.querySelectorAll('div[class*=" "] div[class]')).filter((AdContainer) => AdContainer instanceof HTMLElement);
16
- AdContainers = AdContainers.filter((AdContainer) => {
17
- let AdContainerPaddingLeft = Number(getComputedStyle(AdContainer).getPropertyValue("padding-left").replaceAll("px", ""));
18
- let AdContainerPaddingRight = Number(getComputedStyle(AdContainer).getPropertyValue("padding-right").replaceAll("px", ""));
19
- let AdContainerPaddingTop = Number(getComputedStyle(AdContainer).getPropertyValue("padding-top").replaceAll("px", ""));
20
- let AdContainerPaddingBottom = Number(getComputedStyle(AdContainer).getPropertyValue("padding-bottom").replaceAll("px", ""));
21
- return AdContainerPaddingLeft > 5 && AdContainerPaddingRight > 5 && AdContainerPaddingTop > 5 && AdContainerPaddingBottom > 5;
1
+ // sources/src/spa.ts
2
+ function InstallSpaNavigationBridge(Options = {}) {
3
+ const Opts = NormalizeOptions(Options);
4
+ const EventNavigate = Opts.Events.Navigate;
5
+ const EventRendered = Opts.Events.Rendered;
6
+ const FireNavigate = (Detail) => {
7
+ window.dispatchEvent(new CustomEvent(EventNavigate, { detail: Detail }));
8
+ };
9
+ const FireRendered = (Detail) => {
10
+ window.dispatchEvent(new CustomEvent(EventRendered, { detail: Detail }));
11
+ };
12
+ let LastUrl = window.location.href;
13
+ let NavSeq = 0;
14
+ let Disposed = false;
15
+ const OnUrlMaybeChanged = (Cause) => {
16
+ if (Disposed) return;
17
+ const Url = window.location.href;
18
+ if (Url === LastUrl) return;
19
+ const From = LastUrl;
20
+ LastUrl = Url;
21
+ const Seq = ++NavSeq;
22
+ FireNavigate({ Seq, From, To: Url, Cause });
23
+ void (async () => {
24
+ const Root = Opts.Root();
25
+ if (!Root) {
26
+ if (Seq !== NavSeq || Disposed) return;
27
+ FireRendered({ Seq, Url, Ok: true });
28
+ return;
29
+ }
30
+ const Ok = await WaitForDomMostlyStable({
31
+ Root,
32
+ StableForMs: Opts.StableForMs,
33
+ SampleWindowMs: Opts.SampleWindowMs,
34
+ Threshold: Opts.Threshold,
35
+ TimeoutMs: Opts.TimeoutMs,
36
+ Ignore: Opts.IgnoreMutation
22
37
  });
23
- AdContainers = AdContainers.filter((AdContainer) => {
24
- return Array.from(AdContainer.querySelectorAll("*")).filter((Ele) => Ele instanceof HTMLElement && getComputedStyle(Ele).getPropertyValue("animation-timing-function") === "ease-in-out").length >= 3;
38
+ if (Seq !== NavSeq || Disposed) return;
39
+ FireRendered({ Seq, Url, Ok });
40
+ })();
41
+ };
42
+ const PatchHistory = (MethodName) => {
43
+ const Original = history[MethodName].bind(history);
44
+ const Patched = (...Args) => {
45
+ const Ret = Original(...Args);
46
+ queueMicrotask(() => OnUrlMaybeChanged(MethodName));
47
+ return Ret;
48
+ };
49
+ Object.defineProperty(history, MethodName, {
50
+ value: Patched,
51
+ configurable: true,
52
+ writable: true
53
+ });
54
+ };
55
+ PatchHistory("pushState");
56
+ PatchHistory("replaceState");
57
+ const OnPopState = () => OnUrlMaybeChanged("popstate");
58
+ window.addEventListener("popstate", OnPopState);
59
+ const OnHashChange = () => OnUrlMaybeChanged("hashchange");
60
+ if (Opts.WatchHashChange) window.addEventListener("hashchange", OnHashChange);
61
+ queueMicrotask(() => {
62
+ if (Disposed) return;
63
+ const Seq = ++NavSeq;
64
+ FireNavigate({ Seq, From: null, To: window.location.href, Cause: "init" });
65
+ void (async () => {
66
+ const Root = Opts.Root();
67
+ if (!Root) {
68
+ if (Seq !== NavSeq || Disposed) return;
69
+ FireRendered({ Seq, Url: window.location.href, Ok: true });
70
+ return;
71
+ }
72
+ const Ok = await WaitForDomMostlyStable({
73
+ Root,
74
+ StableForMs: Opts.StableForMs,
75
+ SampleWindowMs: Opts.SampleWindowMs,
76
+ Threshold: Opts.Threshold,
77
+ TimeoutMs: Opts.TimeoutMs,
78
+ Ignore: Opts.IgnoreMutation
25
79
  });
26
- AdContainers = AdContainers.filter((AdContainer) => GetParents(AdContainer).some((Parent) => Number(getComputedStyle(Parent).getPropertyValue("margin-top").replaceAll("px", "")) > 10));
27
- AdContainers = AdContainers.filter((AdContainer) => AdContainer.innerText.length < 1e3);
28
- AdContainers = AdContainers.filter((AdContainer) => Array.from(AdContainer.querySelectorAll('*[href="/RecentChanges"]')).filter((Ele) => Ele instanceof HTMLElement && getComputedStyle(Ele).getPropertyValue("display") !== "none").length === 0);
29
- AdContainers = AdContainers.filter((AdContainer) => !AdContainer.innerText.includes((new URL(location.href).searchParams.get("from") || "") + "\uC5D0\uC11C \uB118\uC5B4\uC634"));
30
- AdContainers = AdContainers.filter((AdContainer) => !/\[[0-9]+\] .+/.test(AdContainer.innerText));
31
- AdContainers.forEach((Ele) => Ele.remove());
80
+ if (Seq !== NavSeq || Disposed) return;
81
+ FireRendered({ Seq, Url: window.location.href, Ok });
82
+ })();
83
+ });
84
+ return () => {
85
+ Disposed = true;
86
+ window.removeEventListener("popstate", OnPopState);
87
+ if (Opts.WatchHashChange) window.removeEventListener("hashchange", OnHashChange);
88
+ };
89
+ }
90
+ function DefaultIgnoreMutation(Mutation) {
91
+ if (Mutation.type === "attributes") {
92
+ const Name = Mutation.attributeName ?? "";
93
+ if (Name === "class" || Name === "style") return true;
94
+ if (Name.startsWith("aria-") || Name.startsWith("data-")) return true;
95
+ }
96
+ return false;
97
+ }
98
+ function NormalizeOptions(Options) {
99
+ return {
100
+ Root: Options.Root ?? (() => document.querySelector("#app") ?? document.body),
101
+ StableForMs: Options.StableForMs ?? 900,
102
+ SampleWindowMs: Options.SampleWindowMs ?? 900,
103
+ Threshold: Options.Threshold ?? 3,
104
+ TimeoutMs: Options.TimeoutMs ?? 12e3,
105
+ IgnoreMutation: Options.IgnoreMutation ?? DefaultIgnoreMutation,
106
+ WatchHashChange: Options.WatchHashChange ?? true,
107
+ Events: {
108
+ Navigate: Options.Events?.Navigate ?? "SpaNavigate",
109
+ Rendered: Options.Events?.Rendered ?? "SpaRendered"
32
110
  }
33
- }, 1e3);
34
- let PowerLinkGenerationPositiveRegExps = [[
35
- /for *\( *; *; *\) *switch *\( *_[a-z0-9]+\[_[a-z0-9]+\([a-z0-9]+\)\] *=_[a-z0-9]+/,
36
- /_[a-z0-9]+\[('|")[A-Z]+('|")\]\)\(\[ *\]\)/,
37
- /0x[a-z0-9]+ *\) *; *case/
38
- ], [
39
- /; *return *this\[_0x[a-z0-9]+\( *0x[0-9a-z]+ *\)/,
40
- /; *if *\( *_0x[a-z0-9]+ *&& *\( *_0x[a-z0-9]+ *= *_0x[a-z0-9]+/,
41
- /\) *, *void *\( *this *\[ *_0x[a-z0-9]+\( *0x[0-9a-z]+ *\) *\] *= *_0x[a-z0-9]+ *\[/
42
- ]];
43
- BrowserWindow.Function.prototype.bind = new Proxy(BrowserWindow.Function.prototype.bind, {
44
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
45
- apply(Target, ThisArg, Args) {
46
- let StringifiedFunc = Reflect.apply(ProtectedFunctionPrototypeToString, ThisArg, Args);
47
- if (PowerLinkGenerationPositiveRegExps.filter((PowerLinkGenerationPositiveRegExp) => PowerLinkGenerationPositiveRegExp.filter((Index) => Index.test(StringifiedFunc)).length >= 3).length === 1) {
48
- console.debug(`[${UserscriptName}]: Function.prototype.bind:`, ThisArg);
49
- return Reflect.apply(Target, () => {
50
- }, []);
51
- }
52
- return Reflect.apply(Target, ThisArg, Args);
111
+ };
112
+ }
113
+ async function WaitForDomMostlyStable(Opts) {
114
+ const Events = [];
115
+ let LastAboveAt = performance.now();
116
+ let Done = false;
117
+ const Observer = new MutationObserver((List) => {
118
+ const Now = performance.now();
119
+ for (const M of List) {
120
+ if (Opts.Ignore?.(M)) continue;
121
+ let Score = 1;
122
+ if (M.type === "childList") Score = 2;
123
+ Events.push({ T: Now, Score });
53
124
  }
125
+ const Cutoff = Now - Opts.SampleWindowMs;
126
+ while (Events.length && Events[0].T < Cutoff) Events.shift();
127
+ const WindowScore = Events.reduce((Sum, E) => Sum + E.Score, 0);
128
+ if (WindowScore > Opts.Threshold) LastAboveAt = Now;
129
+ });
130
+ Observer.observe(Opts.Root, {
131
+ subtree: true,
132
+ childList: true,
133
+ attributes: true,
134
+ characterData: true
54
135
  });
55
- let PowerLinkGenerationSkeletionPositiveRegExps = [[
56
- /\( *\) *=> *{ *var *_0x[0-9a-z]+ *= *a0_0x[0-9a-f]+ *; *this\[ *_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\]\(\); *}/,
57
- /\( *\) *=> *{ *var *_0x[0-9a-z]+ *= *a0_0x[0-9a-f]+ *; *this\[ *_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\]\(\); *}/
58
- ], [
59
- /\( *\) *=> *{ *var _0x[a-z0-9]+ *= *_0x[a-z0-9]+ *; *if *\( *this\[ *_0x[a-z0-9]+ *\( *0x[0-9a-f]+ *\) *\] *\) *return *clearTimeout/,
60
- /\( *0x[0-9a-f]+ *\) *\] *\) *, *void *\( *this\[ *_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\] *= *void *\([x0-9a-f*+-]+ *\) *\) *; *this\[_0x[a-z0-9]+\( *0x[0-9a-f]+ *\) *\] *\(\) *;/
61
- ]];
62
- BrowserWindow.setTimeout = new Proxy(BrowserWindow.setTimeout, {
63
- apply(Target, ThisArg, Args) {
64
- let StringifiedFunc = Reflect.apply(ProtectedFunctionPrototypeToString, Args[0], Args);
65
- if (PowerLinkGenerationSkeletionPositiveRegExps.filter((PowerLinkGenerationSkeletionPositiveRegExp) => PowerLinkGenerationSkeletionPositiveRegExp.filter((Index) => Index.test(StringifiedFunc)).length >= 1).length === 1) {
66
- console.debug(`[${UserscriptName}]: setTimeout:`, Args[0]);
136
+ const Start = performance.now();
137
+ return await new Promise((Resolve) => {
138
+ const Tick = () => {
139
+ if (Done) return;
140
+ const Now = performance.now();
141
+ if (Now - LastAboveAt >= Opts.StableForMs) {
142
+ Done = true;
143
+ Observer.disconnect();
144
+ Resolve(true);
67
145
  return;
68
146
  }
69
- return Reflect.apply(Target, ThisArg, Args);
70
- }
147
+ if (Now - Start >= Opts.TimeoutMs) {
148
+ Done = true;
149
+ Observer.disconnect();
150
+ Resolve(false);
151
+ return;
152
+ }
153
+ setTimeout(Tick, 100);
154
+ };
155
+ setTimeout(Tick, 0);
71
156
  });
72
- let PowerLinkGenerationSurfingPositiveRegExps = [[
73
- /function\( *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+\) *\{ *var *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *; *const *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *= *_0x[a-f0-9]+/,
74
- /\[ *('|")[a-zA-Z0-9-_]+('|") *\] *\) *\( *\( *\) *=> *\[*\( *\( *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+/,
75
- / *, *{ *('|")[a-zA-Z0-9-_]+('|") *: *0x[a-f0-9]+ *, *('|")[a-zA-Z0-9-_]+('|") *: *\( *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+/,
76
- /('|")innerHTML('|") *: *_0x[a-f0-9]+ *\[ *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *\] *\} *, *null *, *-? *0x[a-f0-9]+ *\* *0x[a-f0-9]+/,
77
- /\( *_0x[a-f0-9]+ *\[ *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *\] *\) *&& *-?0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\+ *-? *0x[a-f0-9]+ *\* *-? *0x[a-f0-9]+ *!== *_0x[a-f0-9]+/,
78
- /{ *('|")[A-Za-z0-9-_]+('|") *: *\( *0x[a-f0-9]+ *\* *-? *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *-? *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *, *_0x[a-f0-9]+ *\[ *('|")[A-Za-z0-9-_]+('|") *\] *\) *\( *\( *\) *=> *\[/,
79
- /\[ *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *, *_0x[a-f0-9]+ *\( *0x[a-f0-9]+ *\) *\] *\) *\] *, *-? *0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *-?0x[a-f0-9]+ *\+ *0x[a-f0-9]+ *\* *0x[a-f0-9]+ *\) *; *\}/
80
- ]];
81
- BrowserWindow.Function.prototype.call = new Proxy(BrowserWindow.Function.prototype.call, {
82
- // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
83
- apply(Target, ThisArg, Args) {
84
- let StringifiedFunc = Reflect.apply(ProtectedFunctionPrototypeToString, ThisArg, Args);
85
- if (StringifiedFunc.length <= 25e3 && PowerLinkGenerationSurfingPositiveRegExps.filter((PowerLinkGenerationSurfingPositiveRegExp) => PowerLinkGenerationSurfingPositiveRegExp.filter((Index) => Index.test(StringifiedFunc)).length >= 5).length === 1) {
86
- console.debug(`[${UserscriptName}]: Function.prototype.call:`, ThisArg);
87
- return Reflect.apply(Target, () => {
88
- }, []);
157
+ }
158
+
159
+ // sources/src/sort.ts
160
+ function CreateSortWorkerURL() {
161
+ const WorkerCode = `
162
+ self.onmessage = (e) => {
163
+ const { entries, jobId } = e.data;
164
+ // entries: Array<[string, number]>
165
+ // \uB0B4\uB9BC\uCC28\uC21C \uC815\uB82C
166
+ entries.sort((a, b) => b[1] - a[1]);
167
+ self.postMessage({ jobId, sorted: entries });
168
+ };
169
+ `;
170
+ return URL.createObjectURL(new Blob([WorkerCode], { type: "text/javascript" }));
171
+ }
172
+ function MakeWorkerPool(Size) {
173
+ const Url = CreateSortWorkerURL();
174
+ const Workers = Array.from({ length: Size }, () => new Worker(Url));
175
+ return {
176
+ Workers,
177
+ dispose() {
178
+ Workers.forEach((W) => W.terminate());
179
+ URL.revokeObjectURL(Url);
180
+ }
181
+ };
182
+ }
183
+ function CollectDataVAttributes(Root = document) {
184
+ const Counts = /* @__PURE__ */ Object.create(null);
185
+ const Walker = Root.createTreeWalker(
186
+ Root.documentElement || Root,
187
+ NodeFilter.SHOW_ELEMENT
188
+ );
189
+ let Node = Walker.currentNode;
190
+ while (Node) {
191
+ if (Node instanceof Element) {
192
+ for (const Attr of Node.attributes) {
193
+ const Name = Attr.name;
194
+ if (Name.startsWith("data-v-")) {
195
+ Counts[Name] = (Counts[Name] || 0) + 1;
196
+ }
197
+ }
198
+ }
199
+ Node = Walker.nextNode();
200
+ }
201
+ return Counts;
202
+ }
203
+ function MergeSortedChunks(Chunks) {
204
+ const Heap = [];
205
+ function Push(Item) {
206
+ Heap.push(Item);
207
+ let I = Heap.length - 1;
208
+ while (I > 0) {
209
+ const P = I - 1 >> 1;
210
+ if (Heap[P].count >= Heap[I].count) break;
211
+ [Heap[P], Heap[I]] = [Heap[I], Heap[P]];
212
+ I = P;
213
+ }
214
+ }
215
+ ;
216
+ function Pop() {
217
+ const Top = Heap[0];
218
+ const Last = Heap.pop();
219
+ if (Heap.length) {
220
+ Heap[0] = Last;
221
+ let I = 0;
222
+ while (true) {
223
+ const L = I * 2 + 1;
224
+ const R = L + 1;
225
+ let M = I;
226
+ if (L < Heap.length && Heap[L].count > Heap[M].count) M = L;
227
+ if (R < Heap.length && Heap[R].count > Heap[M].count) M = R;
228
+ if (M === I) break;
229
+ [Heap[I], Heap[M]] = [Heap[M], Heap[I]];
230
+ I = M;
89
231
  }
90
- return Reflect.apply(Target, ThisArg, Args);
91
232
  }
233
+ return Top;
234
+ }
235
+ for (let C = 0; C < Chunks.length; C++) {
236
+ const Arr = Chunks[C];
237
+ if (Arr && Arr.length) {
238
+ const [Attr, Count] = Arr[0];
239
+ Push({ Count, Attr, ChunkIndex: C, IndexInChunk: 0 });
240
+ }
241
+ }
242
+ const Out = [];
243
+ while (Heap.length) {
244
+ const { Attr, Count, ChunkIndex, IndexInChunk } = Pop();
245
+ Out.push([Attr, Count]);
246
+ const NextIndex = IndexInChunk + 1;
247
+ const Arr = Chunks[ChunkIndex];
248
+ if (NextIndex < Arr.length) {
249
+ const [NAttr, NCount] = Arr[NextIndex];
250
+ Push({ Count: NCount, Attr: NAttr, ChunkIndex, IndexInChunk: NextIndex });
251
+ }
252
+ }
253
+ return Out;
254
+ }
255
+ async function RankCountsWithWorkersParallel(Counts) {
256
+ const Entries = Object.entries(Counts);
257
+ const Hc = Math.max(1, navigator.hardwareConcurrency || 1);
258
+ const WorkerCount = Math.min(8, Math.max(1, Hc - 1));
259
+ const ShouldParallel = Entries.length >= 5e3 && WorkerCount > 1;
260
+ const ActualWorkers = ShouldParallel ? WorkerCount : 1;
261
+ const Pool = MakeWorkerPool(ActualWorkers);
262
+ try {
263
+ const Chunks = Array.from({ length: ActualWorkers }, () => []);
264
+ for (let I = 0; I < Entries.length; I++) {
265
+ Chunks[I % ActualWorkers].push(Entries[I]);
266
+ }
267
+ const SortedChunks = await Promise.all(
268
+ Chunks.map((ChunkEntries, Idx) => {
269
+ return new Promise((Resolve, Reject) => {
270
+ const Worker2 = Pool.Workers[Idx];
271
+ const JobId = Idx + ":" + Date.now();
272
+ const OnMsg = (E) => {
273
+ if (E.data?.jobId !== JobId) return;
274
+ Worker2.removeEventListener("message", OnMsg);
275
+ Worker2.removeEventListener("error", OnErr);
276
+ Resolve(E.data.sorted);
277
+ };
278
+ const OnErr = (Err) => {
279
+ Worker2.removeEventListener("message", OnMsg);
280
+ Worker2.removeEventListener("error", OnErr);
281
+ Reject(Err);
282
+ };
283
+ Worker2.addEventListener("message", OnMsg);
284
+ Worker2.addEventListener("error", OnErr);
285
+ Worker2.postMessage({ entries: ChunkEntries, jobId: JobId });
286
+ });
287
+ })
288
+ );
289
+ const Merged = SortedChunks.length === 1 ? SortedChunks[0] : MergeSortedChunks(SortedChunks);
290
+ return { Result: Merged, TotalKeys: Merged.length, WorkerCount: ActualWorkers, HardwareConcurrency: Hc };
291
+ } finally {
292
+ Pool.dispose();
293
+ }
294
+ }
295
+
296
+ // sources/src/index.ts
297
+ var Win = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
298
+ function RunNamuLinkUserscript(BrowserWindow, UserscriptName = "NamuLink") {
299
+ const ProtectedFunctionPrototypeToString = BrowserWindow.Function.prototype.toString;
300
+ if (document.readyState === "loading") {
301
+ window.addEventListener("DOMContentLoaded", () => {
302
+ InstallSpaNavigationBridge({
303
+ Root: () => document.getElementById("#app"),
304
+ StableForMs: 900,
305
+ SampleWindowMs: 900,
306
+ Threshold: 3,
307
+ TimeoutMs: 12e3,
308
+ IgnoreMutation: DefaultIgnoreMutation,
309
+ WatchHashChange: true
310
+ });
311
+ });
312
+ } else {
313
+ window.addEventListener("DOMContentLoaded", () => {
314
+ InstallSpaNavigationBridge({
315
+ Root: () => document.getElementById("#app"),
316
+ StableForMs: 900,
317
+ SampleWindowMs: 900,
318
+ Threshold: 3,
319
+ TimeoutMs: 12e3,
320
+ IgnoreMutation: DefaultIgnoreMutation,
321
+ WatchHashChange: true
322
+ });
323
+ });
324
+ }
325
+ window.addEventListener("SpaRendered", async () => {
326
+ let HTMLEle = CollectDataVAttributes(document);
327
+ const { Result, TotalKeys, WorkerCount, HardwareConcurrency } = await RankCountsWithWorkersParallel(HTMLEle);
328
+ let TargetedAttrsDOMs = [];
329
+ Result.filter(([, Count]) => Count <= 30).forEach(([Attr, Count]) => {
330
+ TargetedAttrsDOMs.push(...[...document.querySelectorAll(`[${Attr}]`)].filter((El) => El instanceof HTMLElement));
331
+ });
332
+ TargetedAttrsDOMs = TargetedAttrsDOMs.filter((El) => getComputedStyle(El).getPropertyValue("display") === "flex");
333
+ TargetedAttrsDOMs = TargetedAttrsDOMs.filter((El) => [...El.querySelectorAll("*")].some((Child) => Child instanceof HTMLElement && typeof Child.click === "function"));
334
+ TargetedAttrsDOMs = TargetedAttrsDOMs.filter((El) => [...El.querySelectorAll("*")].filter((Child) => Child instanceof HTMLElement && Child.getBoundingClientRect().bottom - Child.getBoundingClientRect().top > 100 && Child.getBoundingClientRect().right - Child.getBoundingClientRect().left > 100).length <= 50);
335
+ TargetedAttrsDOMs = TargetedAttrsDOMs.filter((El) => {
336
+ let Count = [...El.querySelectorAll("*")].filter((Child) => Child.getBoundingClientRect().bottom - Child.getBoundingClientRect().top > 25 && Child.getBoundingClientRect().right - Child.getBoundingClientRect().left > 25 && (Child instanceof SVGPathElement && Child.getAttribute("d") !== null) || Child instanceof HTMLImageElement && Child.src.includes("//i.namu.wiki/i/")).length;
337
+ return 1 <= Count && Count <= 6;
338
+ });
339
+ TargetedAttrsDOMs = TargetedAttrsDOMs.filter((El) => [...El.querySelectorAll("*")].some((Child) => Child instanceof HTMLElement && getComputedStyle(Child, "::after").getPropertyValue("content").includes(":") && Child.getBoundingClientRect().right - Child.getBoundingClientRect().left > 100) === false);
340
+ console.debug(`[${UserscriptName}]`, TargetedAttrsDOMs);
341
+ TargetedAttrsDOMs.forEach((El) => {
342
+ setTimeout(() => {
343
+ El.setAttribute("style", "display: none !important; visibility: hidden !important;");
344
+ }, 250);
345
+ });
92
346
  });
93
347
  }
94
348
  RunNamuLinkUserscript(Win);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../sources/src/index.ts"],
4
- "sourcesContent": ["/*!\n * @license MPL-2.0\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n *\n * Contributors:\n * - See Git history at https://github.com/FilteringDev/tinyShield for detailed authorship information.\n */\n\ntype unsafeWindow = typeof window\n// eslint-disable-next-line @typescript-eslint/naming-convention\ndeclare const unsafeWindow: unsafeWindow\n\nconst Win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window\n\nexport function RunNamuLinkUserscript(BrowserWindow: typeof window, UserscriptName: string = 'NamuLink'): void {\n const ProtectedFunctionPrototypeToString = BrowserWindow.Function.prototype.toString\n\n function GetParents(Ele: HTMLElement) {\n let Parents: HTMLElement[] = []\n while (Ele.parentElement) {\n Parents.push(Ele.parentElement)\n Ele = Ele.parentElement\n }\n return Parents\n }\n\n setInterval(() => {\n if (location.href.startsWith('https://namu.wiki/w/')) {\n let AdContainers = Array.from(document.querySelectorAll('div[class*=\" \"] div[class]')).filter(AdContainer => AdContainer instanceof HTMLElement)\n\n AdContainers = AdContainers.filter((AdContainer) => {\n let AdContainerPaddingLeft = Number(getComputedStyle(AdContainer).getPropertyValue('padding-left').replaceAll('px', ''))\n let AdContainerPaddingRight = Number(getComputedStyle(AdContainer).getPropertyValue('padding-right').replaceAll('px', ''))\n let AdContainerPaddingTop = Number(getComputedStyle(AdContainer).getPropertyValue('padding-top').replaceAll('px', ''))\n let AdContainerPaddingBottom = Number(getComputedStyle(AdContainer).getPropertyValue('padding-bottom').replaceAll('px', ''))\n return AdContainerPaddingLeft > 5 && AdContainerPaddingRight > 5 && AdContainerPaddingTop > 5 && AdContainerPaddingBottom > 5\n })\n\n AdContainers = AdContainers.filter(AdContainer => {\n return Array.from(AdContainer.querySelectorAll('*')).filter(Ele => Ele instanceof HTMLElement &&\n getComputedStyle(Ele).getPropertyValue('animation-timing-function') === 'ease-in-out').length >= 3\n })\n\n AdContainers = AdContainers.filter(AdContainer => GetParents(AdContainer).some(Parent => Number(getComputedStyle(Parent).getPropertyValue('margin-top').replaceAll('px', '')) > 10 ))\n\n AdContainers = AdContainers.filter(AdContainer => AdContainer.innerText.length < 1000)\n\n AdContainers = AdContainers.filter(AdContainer => Array.from(AdContainer.querySelectorAll('*[href=\"/RecentChanges\"]')).filter(Ele => Ele instanceof HTMLElement && getComputedStyle(Ele).getPropertyValue('display') !== 'none').length === 0)\n\n AdContainers = AdContainers.filter(AdContainer => !AdContainer.innerText.includes((new URL(location.href).searchParams.get('from') || '') + '\uC5D0\uC11C \uB118\uC5B4\uC634'))\n\n AdContainers = AdContainers.filter(AdContainer => !/\\[[0-9]+\\] .+/.test(AdContainer.innerText))\n\n AdContainers.forEach(Ele => Ele.remove())\n }\n }, 1000)\n\n let PowerLinkGenerationPositiveRegExps: RegExp[][] = [[\n /for *\\( *; *; *\\) *switch *\\( *_[a-z0-9]+\\[_[a-z0-9]+\\([a-z0-9]+\\)\\] *=_[a-z0-9]+/,\n /_[a-z0-9]+\\[('|\")[A-Z]+('|\")\\]\\)\\(\\[ *\\]\\)/,\n /0x[a-z0-9]+ *\\) *; *case/\n ], [\n /; *return *this\\[_0x[a-z0-9]+\\( *0x[0-9a-z]+ *\\)/,\n /; *if *\\( *_0x[a-z0-9]+ *&& *\\( *_0x[a-z0-9]+ *= *_0x[a-z0-9]+/,\n /\\) *, *void *\\( *this *\\[ *_0x[a-z0-9]+\\( *0x[0-9a-z]+ *\\) *\\] *= *_0x[a-z0-9]+ *\\[/\n ]]\n\n BrowserWindow.Function.prototype.bind = new Proxy(BrowserWindow.Function.prototype.bind, {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n apply(Target: typeof Function.prototype.bind, ThisArg: Function, Args: Parameters<typeof Function.prototype.bind>) {\n let StringifiedFunc = Reflect.apply(ProtectedFunctionPrototypeToString, ThisArg, Args) as string\n if (PowerLinkGenerationPositiveRegExps.filter(PowerLinkGenerationPositiveRegExp => PowerLinkGenerationPositiveRegExp.filter(Index => Index.test(StringifiedFunc)).length >= 3).length === 1) {\n console.debug(`[${UserscriptName}]: Function.prototype.bind:`, ThisArg)\n return Reflect.apply(Target, () => {}, [])\n }\n return Reflect.apply(Target, ThisArg, Args)\n }\n })\n\n let PowerLinkGenerationSkeletionPositiveRegExps: RegExp[][] = [[\n /\\( *\\) *=> *{ *var *_0x[0-9a-z]+ *= *a0_0x[0-9a-f]+ *; *this\\[ *_0x[a-z0-9]+\\( *0x[0-9a-f]+ *\\) *\\]\\(\\); *}/,\n /\\( *\\) *=> *{ *var *_0x[0-9a-z]+ *= *a0_0x[0-9a-f]+ *; *this\\[ *_0x[a-z0-9]+\\( *0x[0-9a-f]+ *\\) *\\]\\(\\); *}/\n ], [\n /\\( *\\) *=> *{ *var _0x[a-z0-9]+ *= *_0x[a-z0-9]+ *; *if *\\( *this\\[ *_0x[a-z0-9]+ *\\( *0x[0-9a-f]+ *\\) *\\] *\\) *return *clearTimeout/,\n /\\( *0x[0-9a-f]+ *\\) *\\] *\\) *, *void *\\( *this\\[ *_0x[a-z0-9]+\\( *0x[0-9a-f]+ *\\) *\\] *= *void *\\([x0-9a-f*+-]+ *\\) *\\) *; *this\\[_0x[a-z0-9]+\\( *0x[0-9a-f]+ *\\) *\\] *\\(\\) *;/\n ]]\n\n BrowserWindow.setTimeout = new Proxy(BrowserWindow.setTimeout, {\n apply(Target: typeof setTimeout, ThisArg: undefined, Args: Parameters<typeof setTimeout>) {\n let StringifiedFunc = Reflect.apply(ProtectedFunctionPrototypeToString, Args[0], Args) as string\n if (PowerLinkGenerationSkeletionPositiveRegExps.filter(PowerLinkGenerationSkeletionPositiveRegExp => PowerLinkGenerationSkeletionPositiveRegExp.filter(Index => Index.test(StringifiedFunc)).length >= 1).length === 1) {\n console.debug(`[${UserscriptName}]: setTimeout:`, Args[0])\n return\n }\n\n return Reflect.apply(Target, ThisArg, Args)\n }\n })\n\n let PowerLinkGenerationSurfingPositiveRegExps: RegExp[][] = [[\n /function\\( *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *, *_0x[a-f0-9]+\\) *\\{ *var *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *; *const *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *= *_0x[a-f0-9]+ *, *_0x[a-f0-9]+ *= *_0x[a-f0-9]+/,\n /\\[ *('|\")[a-zA-Z0-9-_]+('|\") *\\] *\\) *\\( *\\( *\\) *=> *\\[*\\( *\\( *0x[a-f0-9]+ *\\* *0x[a-f0-9]+ *\\+ *-? *0x[a-f0-9]+ *\\+ *-? *0x[a-f0-9]+/,\n / *, *{ *('|\")[a-zA-Z0-9-_]+('|\") *: *0x[a-f0-9]+ *, *('|\")[a-zA-Z0-9-_]+('|\") *: *\\( *0x[a-f0-9]+ *\\* *0x[a-f0-9]+ *\\+ *0x[a-f0-9]+ *\\+ *-? *0x[a-f0-9]+/,\n /('|\")innerHTML('|\") *: *_0x[a-f0-9]+ *\\[ *_0x[a-f0-9]+ *\\( *0x[a-f0-9]+ *\\) *\\] *\\} *, *null *, *-? *0x[a-f0-9]+ *\\* *0x[a-f0-9]+/,\n /\\( *_0x[a-f0-9]+ *\\[ *_0x[a-f0-9]+ *\\( *0x[a-f0-9]+ *\\) *\\] *\\) *&& *-?0x[a-f0-9]+ *\\+ *0x[a-f0-9]+ *\\+ *-? *0x[a-f0-9]+ *\\* *-? *0x[a-f0-9]+ *!== *_0x[a-f0-9]+/,\n /{ *('|\")[A-Za-z0-9-_]+('|\") *: *\\( *0x[a-f0-9]+ *\\* *-? *0x[a-f0-9]+ *\\+ *0x[a-f0-9]+ *\\* *-? *0x[a-f0-9]+ *\\+ *0x[a-f0-9]+ *\\* *0x[a-f0-9]+ *, *_0x[a-f0-9]+ *\\[ *('|\")[A-Za-z0-9-_]+('|\") *\\] *\\) *\\( *\\( *\\) *=> *\\[/,\n /\\[ *_0x[a-f0-9]+ *\\( *0x[a-f0-9]+ *\\) *, *_0x[a-f0-9]+ *\\( *0x[a-f0-9]+ *\\) *\\] *\\) *\\] *, *-? *0x[a-f0-9]+ *\\+ *0x[a-f0-9]+ *\\* *-?0x[a-f0-9]+ *\\+ *0x[a-f0-9]+ *\\* *0x[a-f0-9]+ *\\) *; *\\}/\n ]]\n\n BrowserWindow.Function.prototype.call = new Proxy(BrowserWindow.Function.prototype.call, {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n apply(Target: typeof Function.prototype.call, ThisArg: Function, Args: Parameters<typeof Function.prototype.call>) {\n let StringifiedFunc = Reflect.apply(ProtectedFunctionPrototypeToString, ThisArg, Args) as string\n if ( StringifiedFunc.length <= 25000\n && PowerLinkGenerationSurfingPositiveRegExps.filter(PowerLinkGenerationSurfingPositiveRegExp => PowerLinkGenerationSurfingPositiveRegExp.filter(Index => Index.test(StringifiedFunc)).length >= 5).length === 1) {\n console.debug(`[${UserscriptName}]: Function.prototype.call:`, ThisArg)\n return Reflect.apply(Target, () => {}, [])\n }\n return Reflect.apply(Target, ThisArg, Args)\n }\n })\n}\n\nRunNamuLinkUserscript(Win)"],
5
- "mappings": "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",
6
- "names": []
3
+ "sources": ["../sources/src/spa.ts", "../sources/src/sort.ts", "../sources/src/index.ts"],
4
+ "sourcesContent": ["/*!\n * @license MPL-2.0\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n *\n * Contributors:\n * - See Git history at https://github.com/FilteringDev/tinyShield for detailed authorship information.\n */\n\ntype SpaNavigateCause =\n | 'init'\n | 'pushState'\n | 'replaceState'\n | 'popstate'\n | 'hashchange'\n\nexport type SpaNavigateDetail = {\n Seq: number\n From: string | null\n To: string\n Cause: SpaNavigateCause\n}\n\nexport type SpaRenderedDetail = {\n Seq: number\n Url: string\n Ok: boolean\n}\n\nexport type IgnoreMutation = (Mutation: MutationRecord) => boolean\n\nexport type SpaBridgeOptions = {\n Root?: () => Node | null\n StableForMs?: number\n SampleWindowMs?: number\n Threshold?: number\n TimeoutMs?: number\n IgnoreMutation?: IgnoreMutation\n WatchHashChange?: boolean\n Events?: {\n Navigate?: 'SpaNavigate'\n Rendered?: 'SpaRendered'\n }\n}\n\ntype WaitStableOptions = {\n Root: Node\n StableForMs: number\n SampleWindowMs: number\n Threshold: number\n TimeoutMs: number\n Ignore?: IgnoreMutation\n}\n\n/**\n * SPA \uB77C\uC6B0\uD305(URL \uBCC0\uACBD)\uC744 \uAC10\uC9C0\uD574 \uCEE4\uC2A4\uD140 \uC774\uBCA4\uD2B8\uB97C \uBC1C\uD589\uD558\uACE0,\n * DOM\uC774 \uCDA9\uBD84\uD788 \uC548\uC815\uD654\uB418\uBA74 'Rendered' \uC774\uBCA4\uD2B8\uAE4C\uC9C0 \uBC1C\uD589\uD558\uB294 \uBE0C\uB9BF\uC9C0\n *\n * Events (PascalCase):\n * - 'SpaNavigate' => CustomEvent<SpaNavigateDetail>\n * - 'SpaRendered' => CustomEvent<SpaRenderedDetail>\n */\nexport function InstallSpaNavigationBridge(Options: SpaBridgeOptions = {}): () => void {\n\n const Opts = NormalizeOptions(Options)\n\n const EventNavigate = Opts.Events.Navigate\n const EventRendered = Opts.Events.Rendered\n\n const FireNavigate = (Detail: SpaNavigateDetail) => {\n window.dispatchEvent(new CustomEvent<SpaNavigateDetail>(EventNavigate, { detail: Detail }))\n }\n\n const FireRendered = (Detail: SpaRenderedDetail) => {\n window.dispatchEvent(new CustomEvent<SpaRenderedDetail>(EventRendered, { detail: Detail }))\n }\n\n let LastUrl = window.location.href\n let NavSeq = 0\n let Disposed = false\n\n const OnUrlMaybeChanged = (Cause: SpaNavigateCause) => {\n if (Disposed) return\n\n const Url = window.location.href\n if (Url === LastUrl) return\n\n const From = LastUrl\n LastUrl = Url\n\n const Seq = ++NavSeq\n FireNavigate({ Seq, From, To: Url, Cause })\n\n void (async () => {\n const Root = Opts.Root()\n if (!Root) {\n if (Seq !== NavSeq || Disposed) return\n FireRendered({ Seq, Url, Ok: true })\n return\n }\n\n const Ok = await WaitForDomMostlyStable({\n Root: Root,\n StableForMs: Opts.StableForMs,\n SampleWindowMs: Opts.SampleWindowMs,\n Threshold: Opts.Threshold,\n TimeoutMs: Opts.TimeoutMs,\n Ignore: Opts.IgnoreMutation,\n })\n\n if (Seq !== NavSeq || Disposed) return\n FireRendered({ Seq, Url, Ok })\n })()\n }\n\n const PatchHistory = (MethodName: 'pushState' | 'replaceState') => {\n const Original = history[MethodName].bind(history)\n\n const Patched = (...Args: Parameters<History['pushState']>): ReturnType<History['pushState']> => {\n const Ret = Original(...Args)\n queueMicrotask(() => OnUrlMaybeChanged(MethodName))\n return Ret\n }\n\n Object.defineProperty(history, MethodName, {\n value: Patched,\n configurable: true,\n writable: true,\n })\n }\n\n PatchHistory('pushState')\n PatchHistory('replaceState')\n\n const OnPopState = () => OnUrlMaybeChanged('popstate')\n window.addEventListener('popstate', OnPopState)\n\n const OnHashChange = () => OnUrlMaybeChanged('hashchange')\n if (Opts.WatchHashChange) window.addEventListener('hashchange', OnHashChange)\n\n queueMicrotask(() => {\n if (Disposed) return\n\n const Seq = ++NavSeq\n FireNavigate({ Seq, From: null, To: window.location.href, Cause: 'init' })\n\n void (async () => {\n const Root = Opts.Root()\n if (!Root) {\n if (Seq !== NavSeq || Disposed) return\n FireRendered({ Seq, Url: window.location.href, Ok: true })\n return\n }\n\n const Ok = await WaitForDomMostlyStable({\n Root: Root,\n StableForMs: Opts.StableForMs,\n SampleWindowMs: Opts.SampleWindowMs,\n Threshold: Opts.Threshold,\n TimeoutMs: Opts.TimeoutMs,\n Ignore: Opts.IgnoreMutation,\n })\n\n if (Seq !== NavSeq || Disposed) return\n FireRendered({ Seq, Url: window.location.href, Ok: Ok })\n })()\n })\n\n return () => {\n Disposed = true\n window.removeEventListener('popstate', OnPopState)\n if (Opts.WatchHashChange) window.removeEventListener('hashchange', OnHashChange)\n }\n}\n\nexport function DefaultIgnoreMutation(Mutation: MutationRecord): boolean {\n if (Mutation.type === 'attributes') {\n const Name = Mutation.attributeName ?? ''\n if (Name === 'class' || Name === 'style') return true\n if (Name.startsWith('aria-') || Name.startsWith('data-')) return true\n }\n return false\n}\n\nfunction NormalizeOptions(Options: SpaBridgeOptions) {\n return {\n Root: Options.Root ?? (() => document.querySelector('#app') ?? document.body),\n StableForMs: Options.StableForMs ?? 900,\n SampleWindowMs: Options.SampleWindowMs ?? 900,\n Threshold: Options.Threshold ?? 3,\n TimeoutMs: Options.TimeoutMs ?? 12000,\n IgnoreMutation: Options.IgnoreMutation ?? DefaultIgnoreMutation,\n WatchHashChange: Options.WatchHashChange ?? true,\n Events: {\n Navigate: Options.Events?.Navigate ?? 'SpaNavigate',\n Rendered: Options.Events?.Rendered ?? 'SpaRendered',\n },\n }\n}\n\nasync function WaitForDomMostlyStable(Opts: WaitStableOptions): Promise<boolean> {\n const Events: Array<{ T: number; Score: number }> = []\n let LastAboveAt = performance.now()\n let Done = false\n\n const Observer = new MutationObserver((List) => {\n const Now = performance.now()\n\n for (const M of List) {\n if (Opts.Ignore?.(M)) continue\n\n let Score = 1\n if (M.type === 'childList') Score = 2\n Events.push({ T: Now, Score })\n }\n\n const Cutoff = Now - Opts.SampleWindowMs\n while (Events.length && Events[0].T < Cutoff) Events.shift()\n\n const WindowScore = Events.reduce((Sum, E) => Sum + E.Score, 0)\n if (WindowScore > Opts.Threshold) LastAboveAt = Now\n })\n\n Observer.observe(Opts.Root, {\n subtree: true,\n childList: true,\n attributes: true,\n characterData: true,\n })\n\n const Start = performance.now()\n\n return await new Promise<boolean>((Resolve) => {\n const Tick = () => {\n if (Done) return\n\n const Now = performance.now()\n\n if (Now - LastAboveAt >= Opts.StableForMs) {\n Done = true\n Observer.disconnect()\n Resolve(true)\n return\n }\n\n if (Now - Start >= Opts.TimeoutMs) {\n Done = true\n Observer.disconnect()\n Resolve(false)\n return\n }\n\n setTimeout(Tick, 100)\n }\n\n setTimeout(Tick, 0)\n })\n}", "export function CreateSortWorkerURL() {\n const WorkerCode = `\nself.onmessage = (e) => {\n const { entries, jobId } = e.data;\n // entries: Array<[string, number]>\n // \uB0B4\uB9BC\uCC28\uC21C \uC815\uB82C\n entries.sort((a, b) => b[1] - a[1]);\n self.postMessage({ jobId, sorted: entries });\n};\n`\n return URL.createObjectURL(new Blob([WorkerCode], { type: 'text/javascript' }))\n}\n\nexport function MakeWorkerPool(Size: number) {\n const Url = CreateSortWorkerURL()\n const Workers = Array.from({ length: Size }, () => new Worker(Url))\n return {\n Workers,\n dispose() {\n Workers.forEach(W => W.terminate())\n URL.revokeObjectURL(Url)\n }\n }\n}\n\nexport function CollectDataVAttributes(Root = document): Record<string, number> {\n const Counts = Object.create(null)\n\n const Walker = Root.createTreeWalker(\n Root.documentElement || Root,\n NodeFilter.SHOW_ELEMENT\n )\n\n let Node = Walker.currentNode\n while (Node) {\n if (Node instanceof Element) {\n for (const Attr of Node.attributes) {\n const Name = Attr.name\n if (Name.startsWith('data-v-')) {\n Counts[Name] = (Counts[Name] || 0) + 1\n }\n }\n }\n Node = Walker.nextNode()\n }\n return Counts\n}\n\nexport function MergeSortedChunks(Chunks: Array<Array<[string, number]>>): Array<[string, number]> {\n // chunks: Array<Array<[string, number]>> \uAC01\uAC01 \uB0B4\uB9BC\uCC28\uC21C\n // \uACB0\uACFC: \uC804\uCCB4 \uB0B4\uB9BC\uCC28\uC21C\n\n // \uAC04\uB2E8\uD55C max-heap (count \uAE30\uC900)\n const Heap = []\n function Push(Item) {\n Heap.push(Item)\n let I = Heap.length - 1\n while (I > 0) {\n const P = (I - 1) >> 1\n if (Heap[P].count >= Heap[I].count) break\n [Heap[P], Heap[I]] = [Heap[I], Heap[P]]\n I = P\n }\n };\n function Pop() {\n const Top = Heap[0]\n const Last = Heap.pop()\n if (Heap.length) {\n Heap[0] = Last\n let I = 0\n while (true) {\n const L = I * 2 + 1\n const R = L + 1\n let M = I\n if (L < Heap.length && Heap[L].count > Heap[M].count) M = L\n if (R < Heap.length && Heap[R].count > Heap[M].count) M = R\n if (M === I) break\n [Heap[I], Heap[M]] = [Heap[M], Heap[I]]\n I = M\n }\n }\n return Top\n }\n\n for (let C = 0; C < Chunks.length; C++) {\n const Arr = Chunks[C]\n if (Arr && Arr.length) {\n const [Attr, Count] = Arr[0]\n Push({ Count, Attr, ChunkIndex: C, IndexInChunk: 0 })\n }\n }\n\n const Out = []\n while (Heap.length) {\n const { Attr, Count, ChunkIndex, IndexInChunk } = Pop()\n Out.push([Attr, Count])\n\n const NextIndex = IndexInChunk + 1\n const Arr = Chunks[ChunkIndex]\n if (NextIndex < Arr.length) {\n const [NAttr, NCount] = Arr[NextIndex]\n Push({ Count: NCount, Attr: NAttr, ChunkIndex, IndexInChunk: NextIndex })\n }\n }\n\n return Out\n}\n\nexport async function RankCountsWithWorkersParallel(Counts: Record<string, number>) {\n const Entries = Object.entries(Counts) // [attr, count][]\n\n // \uB17C\uB9AC \uCF54\uC5B4 \uC218 \uAE30\uBC18 \uC6CC\uCEE4 \uAC1C\uC218 \uACB0\uC815\n // - \uB108\uBB34 \uB9CE\uC774 \uB9CC\uB4E4\uBA74 \uC624\uD788\uB824 \uC5ED\uD6A8\uACFC\uB77C \uC0C1\uD55C\uC744 \uB460\n const Hc = Math.max(1, navigator.hardwareConcurrency || 1)\n const WorkerCount = Math.min(8, Math.max(1, Hc - 1))\n\n // entries\uAC00 \uC801\uC73C\uBA74 \uBCD1\uB82C\uD654 \uC774\uB4DD\uC774 \uAC70\uC758 \uC5C6\uC74C \u2192 1\uAC1C\uB85C\n const ShouldParallel = Entries.length >= 5000 && WorkerCount > 1\n const ActualWorkers = ShouldParallel ? WorkerCount : 1\n const Pool = MakeWorkerPool(ActualWorkers)\n\n try {\n // chunks \uBD84\uD560\n const Chunks = Array.from({ length: ActualWorkers }, () => [])\n for (let I = 0; I < Entries.length; I++) {\n Chunks[I % ActualWorkers].push(Entries[I])\n }\n\n // \uAC01 \uC6CC\uCEE4\uC5D0 \uC815\uB82C \uC694\uCCAD\n const SortedChunks = await Promise.all(\n Chunks.map((ChunkEntries, Idx) => {\n return new Promise<Array<[string, number]>>((Resolve, Reject) => {\n const Worker = Pool.Workers[Idx]\n const JobId = Idx + ':' + Date.now()\n\n const OnMsg = (E) => {\n if (E.data?.jobId !== JobId) return\n Worker.removeEventListener('message', OnMsg)\n Worker.removeEventListener('error', OnErr)\n Resolve(E.data.sorted)\n }\n const OnErr = (Err) => {\n Worker.removeEventListener('message', OnMsg)\n Worker.removeEventListener('error', OnErr)\n Reject(Err)\n }\n\n Worker.addEventListener('message', OnMsg)\n Worker.addEventListener('error', OnErr)\n Worker.postMessage({ entries: ChunkEntries, jobId: JobId })\n })\n })\n )\n // \uBCD1\uD569\uD574\uC11C \uC804\uCCB4 \uC21C\uC704 \uC0DD\uC131\n const Merged = (SortedChunks.length === 1)\n ? SortedChunks[0]\n : MergeSortedChunks(SortedChunks)\n\n return { Result: Merged, TotalKeys: Merged.length, WorkerCount: ActualWorkers, HardwareConcurrency: Hc }\n } finally {\n Pool.dispose()\n }\n}", "/*!\n * @license MPL-2.0\n * This Source Code Form is subject to the terms of the Mozilla Public\n * License, v. 2.0. If a copy of the MPL was not distributed with this\n * file, You can obtain one at https://mozilla.org/MPL/2.0/.\n *\n * Contributors:\n * - See Git history at https://github.com/FilteringDev/tinyShield for detailed authorship information.\n */\n\ntype unsafeWindow = typeof window\n// eslint-disable-next-line @typescript-eslint/naming-convention\ndeclare const unsafeWindow: unsafeWindow\nimport * as SPA from './spa.js'\nimport * as Sort from './sort.js'\n\nconst Win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window\n\nexport function RunNamuLinkUserscript(BrowserWindow: typeof window, UserscriptName: string = 'NamuLink'): void {\n const ProtectedFunctionPrototypeToString = BrowserWindow.Function.prototype.toString\n\n if (document.readyState === 'loading') {\n window.addEventListener('DOMContentLoaded', () => {\n SPA.InstallSpaNavigationBridge({\n Root: () => document.getElementById('#app'),\n StableForMs: 900,\n SampleWindowMs: 900,\n Threshold: 3,\n TimeoutMs: 12000,\n IgnoreMutation: SPA.DefaultIgnoreMutation,\n WatchHashChange: true\n })\n })\n } else {\n // \uC774\uBBF8 DOMContentLoaded \uC774\uD6C4\n window.addEventListener('DOMContentLoaded', () => {\n SPA.InstallSpaNavigationBridge({\n Root: () => document.getElementById('#app'),\n StableForMs: 900,\n SampleWindowMs: 900,\n Threshold: 3,\n TimeoutMs: 12000,\n IgnoreMutation: SPA.DefaultIgnoreMutation,\n WatchHashChange: true\n })\n })\n }\n\n window.addEventListener('SpaRendered', async () => {\n let HTMLEle = Sort.CollectDataVAttributes(document)\n const { Result, TotalKeys, WorkerCount, HardwareConcurrency } = await Sort.RankCountsWithWorkersParallel(HTMLEle)\n let TargetedAttrsDOMs: HTMLElement[] = []\n Result.filter(([, Count]) => Count <= 30).forEach(([Attr, Count]) => {\n TargetedAttrsDOMs.push(...[...document.querySelectorAll(`[${Attr}]`)].filter((El) => El instanceof HTMLElement))\n })\n TargetedAttrsDOMs = TargetedAttrsDOMs.filter(El => getComputedStyle(El).getPropertyValue('display') === 'flex')\n TargetedAttrsDOMs = TargetedAttrsDOMs.filter(El => [...El.querySelectorAll('*')].some(Child => Child instanceof HTMLElement && typeof Child.click === 'function'))\n TargetedAttrsDOMs = TargetedAttrsDOMs.filter(El => [...El.querySelectorAll('*')].filter(Child => Child instanceof HTMLElement && Child.getBoundingClientRect().bottom - Child.getBoundingClientRect().top > 100 && Child.getBoundingClientRect().right - Child.getBoundingClientRect().left > 100).length <= 50)\n TargetedAttrsDOMs = TargetedAttrsDOMs.filter(El => {\n let Count = [...El.querySelectorAll('*')].filter(Child => (Child.getBoundingClientRect().bottom - Child.getBoundingClientRect().top > 25 && Child.getBoundingClientRect().right - Child.getBoundingClientRect().left > 25 && (Child instanceof SVGPathElement && Child.getAttribute('d') !== null) || (Child instanceof HTMLImageElement && Child.src.includes('//i.namu.wiki/i/')))).length\n return 1 <= Count && Count <= 6\n })\n TargetedAttrsDOMs = TargetedAttrsDOMs.filter(El => [...El.querySelectorAll('*')].some(Child => Child instanceof HTMLElement && getComputedStyle(Child, '::after').getPropertyValue('content').includes(':') && Child.getBoundingClientRect().right - Child.getBoundingClientRect().left > 100) === false)\n console.debug(`[${UserscriptName}]`, TargetedAttrsDOMs)\n TargetedAttrsDOMs.forEach(El => {\n setTimeout(() => {\n El.setAttribute('style', 'display: none !important; visibility: hidden !important;')\n }, 250)\n })\n })\n}\n\nRunNamuLinkUserscript(Win)"],
5
+ "mappings": "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",
6
+ "names": ["Worker"]
7
7
  }
@@ -0,0 +1,13 @@
1
+ export declare function CreateSortWorkerURL(): string;
2
+ export declare function MakeWorkerPool(Size: number): {
3
+ Workers: Worker[];
4
+ dispose(): void;
5
+ };
6
+ export declare function CollectDataVAttributes(Root?: Document): Record<string, number>;
7
+ export declare function MergeSortedChunks(Chunks: Array<Array<[string, number]>>): Array<[string, number]>;
8
+ export declare function RankCountsWithWorkersParallel(Counts: Record<string, number>): Promise<{
9
+ Result: [string, number][];
10
+ TotalKeys: number;
11
+ WorkerCount: number;
12
+ HardwareConcurrency: number;
13
+ }>;
@@ -0,0 +1,46 @@
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/tinyShield for detailed authorship information.
9
+ */
10
+ type SpaNavigateCause = 'init' | 'pushState' | 'replaceState' | 'popstate' | 'hashchange';
11
+ export type SpaNavigateDetail = {
12
+ Seq: number;
13
+ From: string | null;
14
+ To: string;
15
+ Cause: SpaNavigateCause;
16
+ };
17
+ export type SpaRenderedDetail = {
18
+ Seq: number;
19
+ Url: string;
20
+ Ok: boolean;
21
+ };
22
+ export type IgnoreMutation = (Mutation: MutationRecord) => boolean;
23
+ export type SpaBridgeOptions = {
24
+ Root?: () => Node | null;
25
+ StableForMs?: number;
26
+ SampleWindowMs?: number;
27
+ Threshold?: number;
28
+ TimeoutMs?: number;
29
+ IgnoreMutation?: IgnoreMutation;
30
+ WatchHashChange?: boolean;
31
+ Events?: {
32
+ Navigate?: 'SpaNavigate';
33
+ Rendered?: 'SpaRendered';
34
+ };
35
+ };
36
+ /**
37
+ * SPA 라우팅(URL 변경)을 감지해 커스텀 이벤트를 발행하고,
38
+ * DOM이 충분히 안정화되면 'Rendered' 이벤트까지 발행하는 브릿지
39
+ *
40
+ * Events (PascalCase):
41
+ * - 'SpaNavigate' => CustomEvent<SpaNavigateDetail>
42
+ * - 'SpaRendered' => CustomEvent<SpaRenderedDetail>
43
+ */
44
+ export declare function InstallSpaNavigationBridge(Options?: SpaBridgeOptions): () => void;
45
+ export declare function DefaultIgnoreMutation(Mutation: MutationRecord): boolean;
46
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@filteringdev/namulink",
3
- "version": "17.5.1",
3
+ "version": "18.0.1",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -8,7 +8,7 @@
8
8
  "build:userscript": "esbuild sources/src/index.ts --bundle --minify --define:global=window --inject:./sources/esbuild.inject.ts --banner:js=\"$(cat ./sources/banner.txt)\" --target=es2024,chrome119,safari17,firefox121 --outfile=./dist/NamuLink.user.js",
9
9
  "build": "npm run build:interface && npm run build:userscript",
10
10
  "debug": "esbuild sources/src/index.ts --bundle --define:global=window --inject:./sources/esbuild.inject.ts --banner:js=\"$(cat ./sources/banner.txt)\" --target=es2024,chrome119,safari17,firefox121 --outfile=./dist/NamuLink-debug.user.js",
11
- "lint": "tsc && eslint sources --ext .ts"
11
+ "lint": "tsc --noEmit && eslint sources --ext .ts"
12
12
  },
13
13
  "keywords": [],
14
14
  "author": {