@@ -17,14 +17,19 @@ const Win = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window
1717export function RunNamuLinkUserscript ( BrowserWindow : typeof window , UserscriptName : string = 'NamuLink' ) : void {
1818 const OriginalFunctionPrototypeCall = BrowserWindow . Function . prototype . call
1919 const OriginalReflectApply = BrowserWindow . Reflect . apply
20+ const OriginalObjectDefineProperty = BrowserWindow . Object . defineProperty
2021
2122 const PL2MajorFuncCallPatterns : RegExp [ ] [ ] = [ [
2223 / f u n c t i o n * \( * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * \) * { * r e t u r n * [ A - Z a - z . - 9 ] + / ,
2324 / , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * \) * { * r e t u r n * [ A - Z a - z . - 9 ] + * \( * [ 0 - 9 a - f x * + - ] + * , * [ A - Z a - z . - 9 ] + * , * [ A - Z a - z . - 9 ] + * , * [ 0 - 9 a - f x * + - ] + / ,
2425 / r e t u r n * [ A - Z a - z . - 9 ] + * \( * [ 0 - 9 a - f x * + - ] + * , * [ A - Z a - z . - 9 ] + * , * [ A - Z a - z . - 9 ] + * , * [ 0 - 9 a - f x * + - ] + * , [ A - Z a - z . - 9 ] + * , * [ A - Z a - z . - 9 ] + * * \) * ; * } /
26+ ] , [
27+ / f u n c t i o n * [ A - Z a - z 0 - 9 ] + * \( * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * \) * { * r e t u r n * [ A - Z a - z . - 9 ] + / ,
28+ / , * [ A - Z a - z 0 - 9 ] + * , * [ A - Z a - z 0 - 9 ] + * \) * { * r e t u r n * [ A - Z a - z . - 9 ] + * \( * [ 0 - 9 a - f x * + - ] + * , * [ A - Z a - z . - 9 ] + * , * [ A - Z a - z . - 9 ] + * , * [ 0 - 9 a - f x * + - ] + / ,
29+ / r e t u r n * [ A - Z a - z . - 9 ] + * \( * [ 0 - 9 a - f x * + - ] + * , * [ A - Z a - z . - 9 ] + * , * [ A - Z a - z . - 9 ] + * , * [ 0 - 9 a - f x * + - ] + * , [ A - Z a - z . - 9 ] + * , * [ A - Z a - z . - 9 ] + * * \) * ; * } /
2530 ] ]
2631
27- function GetPowerLinkElementFromArg ( Arg : unknown ) : HTMLElement | null {
32+ function PowerLinkElementFromArg ( Arg : unknown ) : HTMLElement | null {
2833 if ( typeof Arg !== 'object' || Arg === null ) return null
2934
3035 const Visited = new Set < object > ( )
@@ -45,6 +50,54 @@ export function RunNamuLinkUserscript(BrowserWindow: typeof window, UserscriptNa
4550
4651 return null
4752 }
53+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
54+ function PowerLinkRenderFromArg ( Arg : unknown ) : Function | null {
55+ if ( typeof Arg !== 'object' || Arg === null ) return null
56+
57+ const Visited = new Set < object > ( )
58+ let Current : unknown = ( Arg as Record < string , unknown > ) [ '_' ]
59+
60+ while ( typeof Current === 'object' && Current !== null ) {
61+ if ( Visited . has ( Current ) ) break
62+ Visited . add ( Current )
63+
64+ const Render = ( Current as Record < string , unknown > ) [ 'render' ]
65+ if ( typeof Render === 'function' ) return Render
66+
67+ Current = ( Current as Record < string , unknown > ) [ 'parent' ]
68+ }
69+
70+ return null
71+ }
72+ function PowerLinkElementFromArgParent ( Arg : unknown ) : HTMLElement | null {
73+ if ( typeof Arg !== 'object' || Arg === null ) return null
74+
75+ const Visited = new Set < object > ( )
76+ let Current = ( Arg as Record < string , unknown > ) [ '_' ]
77+
78+ while ( typeof Current === 'object' && Current !== null ) {
79+ if ( Visited . has ( Current ) ) break
80+ Visited . add ( Current )
81+
82+ const Parent = ( Current as Record < string , unknown > ) [ 'parent' ]
83+ if ( typeof Parent === 'object' && Parent !== null ) {
84+ const ParentVNode = ( Parent as Record < string , unknown > ) [ 'vnode' ]
85+ if ( typeof ParentVNode === 'object' && ParentVNode !== null ) {
86+ const ParentElement = ( ParentVNode as Record < string , unknown > ) [ 'el' ]
87+ if ( ParentElement instanceof HTMLElement ) return ParentElement
88+ }
89+ }
90+
91+ const VNode = ( Current as Record < string , unknown > ) [ 'vnode' ]
92+ if ( typeof VNode === 'object' && VNode !== null ) {
93+ const Element = ( VNode as Record < string , unknown > ) [ 'el' ]
94+ if ( Element instanceof HTMLElement ) return Element
95+ }
96+ Current = Parent
97+ }
98+ return null
99+ }
100+
48101 const MinRatio = 0.35
49102 const MaxRatio = 0.75
50103 const EpsilonRatio = 0.04
@@ -62,7 +115,7 @@ export function RunNamuLinkUserscript(BrowserWindow: typeof window, UserscriptNa
62115
63116 const Stringified = String ( ThisArg )
64117 if ( Stringified . length < 500 && PL2MajorFuncCallPatterns . filter ( Patterns => Patterns . filter ( Pattern => Pattern . test ( Stringified ) ) . length === Patterns . length ) . length === 1 ) {
65- let PL2Element : HTMLElement | null = GetPowerLinkElementFromArg ( Args [ 6 ] )
118+ let PL2Element : HTMLElement | null = PowerLinkElementFromArgParent ( Args [ 6 ] )
66119 if ( PL2Element !== null && [ ...PL2Element . querySelectorAll ( '*' ) ] . filter ( Child => {
67120 if ( ! ( Child instanceof HTMLElement ) ) return false
68121 let PL2TitleHeight = Child . getClientRects ( ) [ 0 ] ?. height ?? 0
@@ -84,6 +137,30 @@ export function RunNamuLinkUserscript(BrowserWindow: typeof window, UserscriptNa
84137 }
85138 } )
86139
140+ BrowserWindow . Object . defineProperty = new Proxy ( OriginalObjectDefineProperty , {
141+ apply ( Target : typeof Object . defineProperty , ThisArg : undefined , Args : Parameters < typeof Object . defineProperty > ) {
142+ // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
143+ let VuejsRenderer : Function | null = PowerLinkRenderFromArg ( Args [ 0 ] )
144+ let PL2Element : HTMLElement | null = PowerLinkElementFromArgParent ( Args [ 0 ] )
145+ let Stringified = String ( VuejsRenderer ?? '' )
146+ if ( VuejsRenderer !== null && PL2Element !== null && Stringified . length < 500 &&
147+ PL2MajorFuncCallPatterns . filter ( Patterns => Patterns . filter ( Pattern => Pattern . test ( Stringified ) ) . length === Patterns . length ) . length === 1 &&
148+ [ ...PL2Element . querySelectorAll ( '*' ) ] . filter ( Child => {
149+ if ( ! ( Child instanceof HTMLElement ) ) return false
150+ let PL2TitleHeight = Child . getClientRects ( ) [ 0 ] ?. height ?? 0
151+ let PL2TitleMarginBottom = Math . max ( Number ( getComputedStyle ( Child ) . getPropertyValue ( 'padding-bottom' ) . replaceAll ( / p x / g, '' ) ) ,
152+ Number ( getComputedStyle ( Child ) . getPropertyValue ( 'margin-bottom' ) . replaceAll ( / p x / g, '' ) ) )
153+ return PL2TitleHeight > 0 && PL2TitleMarginBottom >= PL2TitleHeight * ( MinRatio - EpsilonRatio ) && PL2TitleMarginBottom <= PL2TitleHeight * ( MaxRatio + EpsilonRatio )
154+ } ) . length >= 1
155+ ) {
156+ console . debug ( `[${ UserscriptName } ]: Restoring renderer.call for detected PowerLink skeleton:` , Args [ 0 ] )
157+ VuejsRenderer . call = Function . prototype . call
158+ return
159+ }
160+ return OriginalReflectApply ( Target , ThisArg , Args )
161+ }
162+ } )
163+
87164 let PL2AfterLoadInitTimerPatterns : RegExp [ ] [ ] = [ [
88165 / \( * \) * = > * { * v a r * _ 0 x [ 0 - 9 a - z ] + * = * a 0 _ 0 x [ 0 - 9 a - f ] + * ; * t h i s \[ * _ 0 x [ a - z 0 - 9 ] + \( * 0 x [ 0 - 9 a - f ] + * \) * \] \( \) ; * } / ,
89166 / \( * \) * = > * { * v a r * _ 0 x [ 0 - 9 a - z ] + * = * a 0 _ 0 x [ 0 - 9 a - f ] + * ; * t h i s \[ * _ 0 x [ a - z 0 - 9 ] + \( * 0 x [ 0 - 9 a - f ] + * \) * \] \( \) ; * } /
0 commit comments