@@ -504,6 +504,18 @@ applyScrollingFix();
504504 } ) ;
505505} ) ( ) ;
506506
507+ const fnStr = ( f ) => {
508+ try {
509+ return f . toString ( ) ;
510+ } catch {
511+ try {
512+ return Function . prototype . toString . call ( f ) ;
513+ } catch {
514+ return "" ;
515+ }
516+ }
517+ } ;
518+
507519( async function hotloadWebpackModules ( ) {
508520 while ( ! window ?. webpackChunkclient_web ) {
509521 await new Promise ( ( r ) => setTimeout ( r , 50 ) ) ;
@@ -554,7 +566,14 @@ applyScrollingFix();
554566 return a ;
555567 } , { } ) ;
556568 } ;
557- const functionModules = modules . filter ( ( module ) => typeof module === "function" ) ;
569+ const webpackFactories = new Set ( Object . values ( require . m ) ) ;
570+ const functionModules = modules . flatMap ( ( module ) =>
571+ typeof module === "function"
572+ ? [ module ]
573+ : typeof module === "object" && module
574+ ? Object . values ( module ) . filter ( ( v ) => typeof v === "function" && ! webpackFactories . has ( v ) )
575+ : [ ]
576+ ) ;
558577 const exportedReactObjects = groupBy ( modules . filter ( Boolean ) , ( x ) => x . $$typeof ) ;
559578 const exportedMemos = exportedReactObjects [ Symbol . for ( "react.memo" ) ] ;
560579 const exportedForwardRefs = exportedReactObjects [ Symbol . for ( "react.forward_ref" ) ] ;
@@ -564,17 +583,18 @@ applyScrollingFix();
564583 const componentRegexes = componentNames . map ( ( n ) => new RegExp ( `"data-encore-id":(?:[a-zA-Z_\$][\w\$]*\\.){2}${ n } \\b` ) ) ;
565584 const componentPairs = [ functionModules . map ( ( f ) => [ f , f ] ) , exportedForwardRefs . map ( ( f ) => [ f . render , f ] ) ]
566585 . flat ( )
567- . map ( ( [ s , f ] ) => [ componentNames . find ( ( _ , i ) => s . toString ( ) . match ( componentRegexes [ i ] ) ) , f ] ) ;
586+ . map ( ( [ s , f ] ) => [ componentNames . find ( ( _ , i ) => fnStr ( s ) ?. match ( componentRegexes [ i ] ) ) , f ] ) ;
587+
568588 return Object . fromEntries ( componentPairs ) ;
569589 } ;
570590 const reactComponentsUI = exposeReactComponentsUI ( { modules, functionModules, exportedForwardRefs } ) ;
571591
572592 const knownMenuTypes = [ "album" , "show" , "artist" , "track" , "playlist" ] ;
573593 const menus = modules
574594 . map ( ( m ) => {
575- const valueMatch = m ?. type ?. toString ( ) . match ( / v a l u e : " ( [ \w - ] + ) " / ) ;
595+ const valueMatch = ( m ?. type ? fnStr ( m . type ) : "" ) . match ( / v a l u e : " ( [ \w - ] + ) " / ) ;
576596 if ( valueMatch ) return [ m , valueMatch [ 1 ] ] ;
577- const typeMatch = m ?. type ?. toString ( ) . match ( / t y p e : [ \w $ ] + \. [ \w $ ] + \. ( [ A - Z _ ] + ) / ) ;
597+ const typeMatch = ( m ?. type ? fnStr ( m . type ) : "" ) . match ( / t y p e : [ \w $ ] + \. [ \w $ ] + \. ( [ A - Z _ ] + ) / ) ;
578598 if ( typeMatch ) return [ m , typeMatch [ 1 ] . toLowerCase ( ) ] ;
579599 return null ;
580600 } )
@@ -599,7 +619,7 @@ applyScrollingFix();
599619 ...functionModules
600620 . flatMap ( ( m ) => {
601621 return cardTypesToFind . map ( ( type ) => {
602- if ( m . toString ( ) . includes ( `featureIdentifier:"${ type } "` ) ) {
622+ if ( fnStr ( m ) . includes ( `featureIdentifier:"${ type } "` ) ) {
603623 cardTypesToFind . splice ( cardTypesToFind . indexOf ( type ) , 1 ) ;
604624 return [ type [ 0 ] . toUpperCase ( ) + type . slice ( 1 ) , m ] ;
605625 }
@@ -610,7 +630,7 @@ applyScrollingFix();
610630 . flatMap ( ( m ) => {
611631 return cardTypesToFind . map ( ( type ) => {
612632 try {
613- if ( m ?. type ?. toString ( ) . includes ( `featureIdentifier:"${ type } "` ) ) {
633+ if ( ( m ?. type ? fnStr ( m . type ) : "" ) . includes ( `featureIdentifier:"${ type } "` ) ) {
614634 cardTypesToFind . splice ( cardTypesToFind . indexOf ( type ) , 1 ) ;
615635 return [ type [ 0 ] . toUpperCase ( ) + type . slice ( 1 ) , m ] ;
616636 }
@@ -630,7 +650,7 @@ applyScrollingFix();
630650 . filter ( ( [ _ , v ] ) => v . toString ( ) . includes ( "[native code]" ) )
631651 . map ( ( [ i ] ) => require ( i ) )
632652 . find ( ( e ) => typeof e === "function" ) ,
633- Color : functionModules . find ( ( m ) => m . toString ( ) . includes ( "static fromHex" ) || m . toString ( ) . includes ( "this.rgb" ) ) ,
653+ Color : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "static fromHex" ) || fnStr ( m ) . includes ( "this.rgb" ) ) ,
634654 Player : {
635655 ...Spicetify . Player ,
636656 get origin ( ) {
@@ -642,79 +662,74 @@ applyScrollingFix();
642662 get Request ( ) {
643663 return Spicetify . Platform ?. GraphQLLoader || Spicetify . GraphQL . Handler ?. ( Spicetify . GraphQL . Context ) ;
644664 } ,
645- Context : functionModules . find ( ( m ) => m . toString ( ) . includes ( "subscription" ) && m . toString ( ) . includes ( "mutation" ) ) ,
646- Handler : functionModules . find ( ( m ) => m . toString ( ) . includes ( "GraphQL subscriptions are not supported" ) ) ,
665+ Context : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "subscription" ) && fnStr ( m ) . includes ( "mutation" ) ) ,
666+ Handler : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "GraphQL subscriptions are not supported" ) ) ,
647667 } ,
648668 ReactComponent : {
649669 ...Spicetify . ReactComponent ,
650670 TextComponent : modules . find ( ( m ) => m ?. h1 && m ?. render ) ,
651- Menu : functionModules . find ( ( m ) => m . toString ( ) . includes ( "getInitialFocusElement" ) && m . toString ( ) . includes ( "children" ) ) ,
652- MenuItem : functionModules . find ( ( m ) => m . toString ( ) . includes ( "handleMouseEnter" ) && m . toString ( ) . includes ( "onClick" ) ) ,
653- MenuSubMenuItem : functionModules . find ( ( f ) => f . toString ( ) . includes ( "subMenuIcon" ) ) ,
654- Slider : wrapProvider ( functionModules . find ( ( m ) => m . toString ( ) . includes ( "progressBarRef" ) ) ) ,
655- RemoteConfigProvider : functionModules . find ( ( m ) => m . toString ( ) . includes ( "resolveSuspense" ) && m . toString ( ) . includes ( "configuration" ) ) ,
671+ Menu : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "getInitialFocusElement" ) && fnStr ( m ) . includes ( "children" ) ) ,
672+ MenuItem : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "handleMouseEnter" ) && fnStr ( m ) . includes ( "onClick" ) ) ,
673+ MenuSubMenuItem : functionModules . find ( ( f ) => fnStr ( f ) . includes ( "subMenuIcon" ) ) ,
674+ Slider : wrapProvider ( functionModules . find ( ( m ) => fnStr ( m ) . includes ( "progressBarRef" ) ) ) ,
675+ RemoteConfigProvider : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "resolveSuspense" ) && fnStr ( m ) . includes ( "configuration" ) ) ,
656676 RightClickMenu : functionModules . find (
657- ( m ) =>
658- m . toString ( ) . includes ( "action" ) && m . toString ( ) . includes ( "open" ) && m . toString ( ) . includes ( "trigger" ) && m . toString ( ) . includes ( "right-click" )
677+ ( m ) => fnStr ( m ) . includes ( "action" ) && fnStr ( m ) . includes ( "open" ) && fnStr ( m ) . includes ( "trigger" ) && fnStr ( m ) . includes ( "right-click" )
659678 ) ,
660- TooltipWrapper : functionModules . find ( ( m ) => m . toString ( ) . includes ( "renderInline" ) && m . toString ( ) . includes ( "showDelay" ) ) ,
679+ TooltipWrapper : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "renderInline" ) && fnStr ( m ) . includes ( "showDelay" ) ) ,
661680 ButtonPrimary : reactComponentsUI . ButtonPrimary ,
662681 ButtonSecondary : reactComponentsUI . ButtonSecondary ,
663682 ButtonTertiary : reactComponentsUI . ButtonTertiary ,
664683 Snackbar : {
665- wrapper : functionModules . find ( ( m ) => m . toString ( ) . includes ( "encore-light-theme" ) && m . toString ( ) . includes ( "elevated" ) ) ,
666- simpleLayout : functionModules . find ( ( m ) => [ "leading" , "center" , "trailing" ] . every ( ( keyword ) => m . toString ( ) . includes ( keyword ) ) ) ,
667- ctaText : functionModules . find ( ( m ) => m . toString ( ) . includes ( "ctaText" ) ) ,
668- styledImage : functionModules . find ( ( m ) => m . toString ( ) . includes ( "placeholderSrc" ) ) ,
684+ wrapper : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "encore-light-theme" ) && fnStr ( m ) . includes ( "elevated" ) ) ,
685+ simpleLayout : functionModules . find ( ( m ) => [ "leading" , "center" , "trailing" ] . every ( ( keyword ) => fnStr ( m ) . includes ( keyword ) ) ) ,
686+ ctaText : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "ctaText" ) ) ,
687+ styledImage : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "placeholderSrc" ) ) ,
669688 } ,
670689 Chip : reactComponentsUI . Chip ,
671- Toggle : functionModules . find ( ( m ) => m . toString ( ) . includes ( "onSelected" ) && m . toString ( ) . includes ( 'type:"checkbox"' ) ) ,
690+ Toggle : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "onSelected" ) && fnStr ( m ) . includes ( 'type:"checkbox"' ) ) ,
672691 Cards : {
673692 Default : reactComponentsUI . Card ,
674693 FeatureCard : functionModules . find (
675- ( m ) => m . toString ( ) . includes ( "?highlight" ) && m . toString ( ) . includes ( "headerText" ) && m . toString ( ) . includes ( "imageContainer" )
694+ ( m ) => fnStr ( m ) . includes ( "?highlight" ) && fnStr ( m ) . includes ( "headerText" ) && fnStr ( m ) . includes ( "imageContainer" )
676695 ) ,
677- Hero : functionModules . find ( ( m ) => m ?. toString ( ) . includes ( '"herocard-click-handler"' ) ) ,
696+ Hero : functionModules . find ( ( m ) => fnStr ( m ) . includes ( '"herocard-click-handler"' ) ) ,
678697 CardImage : functionModules . find (
679698 ( m ) =>
680- m . toString ( ) . includes ( "isHero" ) &&
681- ( m . toString ( ) . includes ( "withWaves" ) || m . toString ( ) . includes ( "isCircular" ) ) &&
682- m . toString ( ) . includes ( "imageWrapper" )
699+ fnStr ( m ) . includes ( "isHero" ) && ( fnStr ( m ) . includes ( "withWaves" ) || fnStr ( m ) . includes ( "isCircular" ) ) && fnStr ( m ) . includes ( "imageWrapper" )
683700 ) ,
684701 ...Object . fromEntries ( cards ) ,
685702 } ,
686- Router : functionModules . find ( ( m ) => m . toString ( ) . includes ( "navigationType" ) && m . toString ( ) . includes ( "static" ) ) ,
687- Routes : functionModules . find ( ( m ) => m . toString ( ) . match ( / \( [ \w $ ] + \) \{ l e t \{ c h i l d r e n : [ \w $ ] + , l o c a t i o n : [ \w $ ] + \} = [ \w $ ] + / ) ) ,
688- Route : functionModules . find ( ( m ) => m . toString ( ) . match ( / ^ f u n c t i o n [ \w $ ] + \( [ \w $ ] + \) \{ \( 0 , [ \w $ ] + \. [ \w $ ] + \) \( ! 1 \) \} $ / ) ) ,
689- StoreProvider : functionModules . find ( ( m ) => m . toString ( ) . includes ( "notifyNestedSubs" ) && m . toString ( ) . includes ( "serverState" ) ) ,
690- ScrollableContainer : functionModules . find ( ( m ) => m . toString ( ) . includes ( "scrollLeft" ) && m . toString ( ) . includes ( "showButtons" ) ) ,
703+ Router : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "navigationType" ) && fnStr ( m ) . includes ( "static" ) ) ,
704+ Routes : functionModules . find ( ( m ) => fnStr ( m ) . match ( / \( [ \w $ ] + \) \{ l e t \{ c h i l d r e n : [ \w $ ] + , l o c a t i o n : [ \w $ ] + \} = [ \w $ ] + / ) ) ,
705+ Route : functionModules . find ( ( m ) => fnStr ( m ) . match ( / ^ f u n c t i o n [ \w $ ] + \( [ \w $ ] + \) \{ \( 0 , [ \w $ ] + \. [ \w $ ] + \) \( ! 1 \) \} $ / ) ) ,
706+ StoreProvider : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "notifyNestedSubs" ) && fnStr ( m ) . includes ( "serverState" ) ) ,
707+ ScrollableContainer : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "scrollLeft" ) && fnStr ( m ) . includes ( "showButtons" ) ) ,
691708 IconComponent : reactComponentsUI . Icon ,
692709 ...Object . fromEntries ( menus ) ,
693710 } ,
694711 ReactHook : {
695- DragHandler : functionModules . find ( ( m ) => m . toString ( ) . includes ( "dataTransfer" ) && m . toString ( ) . includes ( "data-dragging" ) ) ,
712+ DragHandler : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "dataTransfer" ) && fnStr ( m ) . includes ( "data-dragging" ) ) ,
696713 useExtractedColor : functionModules . find (
697- ( m ) => m . toString ( ) . includes ( "extracted-color" ) || ( m . toString ( ) . includes ( "colorRaw" ) && m . toString ( ) . includes ( "useEffect" ) )
714+ ( m ) => fnStr ( m ) . includes ( "extracted-color" ) || ( fnStr ( m ) . includes ( "colorRaw" ) && fnStr ( m ) . includes ( "useEffect" ) )
698715 ) ,
699716 } ,
700717 // React Query
701718 // https://github.com/TanStack/query
702719 // v3 until Spotify v1.2.29
703720 // v5 since Spotify v1.2.30
704721 ReactQuery : cache . find ( ( module ) => module . useQuery ) || {
705- PersistQueryClientProvider : functionModules . find ( ( m ) => m . toString ( ) . includes ( "persistOptions" ) ) ,
706- QueryClient : functionModules . find ( ( m ) => m . toString ( ) . includes ( "defaultMutationOptions" ) ) ,
707- QueryClientProvider : functionModules . find ( ( m ) => m . toString ( ) . includes ( "use QueryClientProvider" ) ) ,
722+ PersistQueryClientProvider : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "persistOptions" ) ) ,
723+ QueryClient : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "defaultMutationOptions" ) ) ,
724+ QueryClientProvider : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "use QueryClientProvider" ) ) ,
708725 notifyManager : modules . find ( ( m ) => m ?. setBatchNotifyFunction ) ,
709- useMutation : functionModules . find ( ( m ) => m . toString ( ) . includes ( "mutateAsync" ) ) ,
726+ useMutation : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "mutateAsync" ) ) ,
710727 useQuery : functionModules . find ( ( m ) =>
711- m . toString ( ) . match ( / ^ f u n c t i o n [ \w _ $ ] + \( ( [ \w _ $ ] + ) , ( [ \w _ $ ] + ) \) \{ r e t u r n \( 0 , [ \w _ $ ] + \. [ \w _ $ ] + \) \( \1, [ \w _ $ ] + \. [ \w _ $ ] + , \2\) \} $ / )
712- ) ,
713- useQueryClient : functionModules . find (
714- ( m ) => m . toString ( ) . includes ( "client" ) && m . toString ( ) . includes ( "Provider" ) && m . toString ( ) . includes ( "mount" )
728+ fnStr ( m ) . match ( / ^ f u n c t i o n [ \w _ $ ] + \( ( [ \w _ $ ] + ) , ( [ \w _ $ ] + ) \) \{ r e t u r n \( 0 , [ \w _ $ ] + \. [ \w _ $ ] + \) \( \1, [ \w _ $ ] + \. [ \w _ $ ] + , \2\) \} $ / )
715729 ) ,
730+ useQueryClient : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "client" ) && fnStr ( m ) . includes ( "Provider" ) && fnStr ( m ) . includes ( "mount" ) ) ,
716731 useSuspenseQuery : functionModules . find (
717- ( m ) => m . toString ( ) . includes ( "throwOnError" ) && m . toString ( ) . includes ( "suspense" ) && m . toString ( ) . includes ( "enabled" )
732+ ( m ) => fnStr ( m ) . includes ( "throwOnError" ) && fnStr ( m ) . includes ( "suspense" ) && fnStr ( m ) . includes ( "enabled" )
718733 ) ,
719734 } ,
720735 ReactFlipToolkit : {
@@ -729,7 +744,7 @@ applyScrollingFix();
729744
730745 if ( ! Spicetify . ContextMenuV2 . _context ) Spicetify . ContextMenuV2 . _context = Spicetify . React . createContext ( { } ) ;
731746 if ( ! Spicetify . ReactComponent . Navigation )
732- Spicetify . ReactComponent . Navigation = exportedMemoFRefs . find ( ( m ) => m . type . render . toString ( ) . includes ( "navigationalRoot" ) ) ;
747+ Spicetify . ReactComponent . Navigation = exportedMemoFRefs . find ( ( m ) => fnStr ( m . type . render ) . includes ( "navigationalRoot" ) ) ;
733748
734749 ( function waitForChunks ( ) {
735750 const listOfComponents = [
@@ -743,7 +758,7 @@ applyScrollingFix();
743758 // "Cards.Show",
744759 // "Cards.Track",
745760 ] ;
746- if ( listOfComponents . every ( ( component ) => Spicetify . ReactComponent [ component ] !== undefined ) ) return ;
761+ if ( listOfComponents . every ( ( component ) => component . split ( "." ) . reduce ( ( o , k ) => o ?. [ k ] , Spicetify . ReactComponent ) !== undefined ) ) return ;
747762 const cache = Object . keys ( require . m ) . map ( ( id ) => require ( id ) ) ;
748763 const modules = cache
749764 . filter ( ( module ) => typeof module === "object" )
@@ -798,7 +813,7 @@ applyScrollingFix();
798813 Spicetify . ReactComponent . Toggle = Object . values ( require ( toggleChunk [ 0 ] ) ) [ 0 ] . render ;
799814 }
800815
801- if ( ! listOfComponents . every ( ( component ) => Spicetify . ReactComponent [ component ] !== undefined ) ) {
816+ if ( ! listOfComponents . every ( ( component ) => component . split ( "." ) . reduce ( ( o , k ) => o ?. [ k ] , Spicetify . ReactComponent ) !== undefined ) ) {
802817 setTimeout ( waitForChunks , 100 ) ;
803818 return ;
804819 }
@@ -815,16 +830,14 @@ applyScrollingFix();
815830 // https://github.com/iamhosseindhv/notistack
816831 Spicetify . Snackbar = {
817832 ...Spicetify . Snackbar ,
818- SnackbarProvider : functionModules . find ( ( m ) => m . toString ( ) . includes ( "enqueueSnackbar called with invalid argument" ) ) ,
819- useSnackbar : functionModules . find ( ( m ) => m . toString ( ) . match ( / ^ f u n c t i o n \( \) \{ r e t u r n \( 0 , [ \w $ ] + \. u s e C o n t e x t \) \( [ \w $ ] + \) \} $ / ) ) ,
833+ SnackbarProvider : functionModules . find ( ( m ) => fnStr ( m ) . includes ( "enqueueSnackbar called with invalid argument" ) ) ,
834+ useSnackbar : functionModules . find ( ( m ) => fnStr ( m ) . match ( / ^ f u n c t i o n \( \) \{ r e t u r n \( 0 , [ \w $ ] + \. u s e C o n t e x t \) \( [ \w $ ] + \) \} $ / ) ) ,
820835 } ;
821836 } ) ( ) ;
822837
823838 const localeModule = modules . find ( ( m ) => m ?. getTranslations ) ;
824839 if ( localeModule ) {
825- const createUrlLocale = functionModules . find (
826- ( m ) => m . toString ( ) . includes ( "has" ) && m . toString ( ) . includes ( "baseName" ) && m . toString ( ) . includes ( "language" )
827- ) ;
840+ const createUrlLocale = functionModules . find ( ( m ) => fnStr ( m ) . includes ( "has" ) && fnStr ( m ) . includes ( "baseName" ) && fnStr ( m ) . includes ( "language" ) ) ;
828841 Spicetify . Locale = {
829842 get _relativeTimeFormat ( ) {
830843 return localeModule . _relativeTimeFormat ;
@@ -892,7 +905,7 @@ applyScrollingFix();
892905 Spicetify . ReactComponent . ConfirmDialog = Object . values ( require ( confirmDialogChunk [ 0 ] ) ) . find ( ( m ) => typeof m === "object" ) ;
893906 } else {
894907 Spicetify . ReactComponent . ConfirmDialog = functionModules . find (
895- ( m ) => m . toString ( ) . includes ( "isOpen" ) && m . toString ( ) . includes ( "shouldCloseOnEsc" ) && m . toString ( ) . includes ( "onClose" )
908+ ( m ) => fnStr ( m ) . includes ( "isOpen" ) && fnStr ( m ) . includes ( "shouldCloseOnEsc" ) && fnStr ( m ) . includes ( "onClose" )
896909 ) ;
897910 }
898911
0 commit comments