@@ -201,6 +201,7 @@ private YoutubeParsingHelper() {
201201    private  static  String [] youtubeMusicKey ;
202202
203203    private  static  boolean  keyAndVersionExtracted  = false ;
204+     private  static  final  Object  KEY_AND_VERSION_EXTRACTED_LOCK  = new  Object ();
204205    @ SuppressWarnings ("OptionalUsedAsFieldOrParameterType" )
205206    private  static  Optional <Boolean > hardcodedClientVersionAndKeyValid  = Optional .empty ();
206207
@@ -619,82 +620,89 @@ public static boolean areHardcodedClientVersionAndKeyValid()
619620
620621    private  static  void  extractClientVersionAndKeyFromSwJs ()
621622            throws  IOException , ExtractionException  {
622-         if  (keyAndVersionExtracted ) {
623-             return ;
624-         }
625-         final  String  url  = "https://www.youtube.com/sw.js" ;
626-         final  Map <String , List <String >> headers  = new  HashMap <>();
627-         headers .put ("Origin" , singletonList ("https://www.youtube.com" ));
628-         headers .put ("Referer" , singletonList ("https://www.youtube.com" ));
629-         final  String  response  = getDownloader ().get (url , headers ).responseBody ();
630-         try  {
631-             clientVersion  = getStringResultFromRegexArray (response ,
632-                     INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
633-             key  = getStringResultFromRegexArray (response , INNERTUBE_API_KEY_REGEXES , 1 );
634-         } catch  (final  Parser .RegexException  e ) {
635-             throw  new  ParsingException ("Could not extract YouTube WEB InnerTube client version " 
636-                     + "and API key from sw.js" , e );
623+         synchronized  (KEY_AND_VERSION_EXTRACTED_LOCK ) {
624+             if  (keyAndVersionExtracted ) {
625+                 return ;
626+             }
627+             final  String  url  = "https://www.youtube.com/sw.js" ;
628+             final  Map <String , List <String >> headers  = new  HashMap <>();
629+             headers .put ("Origin" , singletonList ("https://www.youtube.com" ));
630+             headers .put ("Referer" , singletonList ("https://www.youtube.com" ));
631+             final  String  response  = getDownloader ().get (url , headers ).responseBody ();
632+             try  {
633+                 clientVersion  = getStringResultFromRegexArray (response ,
634+                         INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
635+                 key  = getStringResultFromRegexArray (response , INNERTUBE_API_KEY_REGEXES , 1 );
636+             } catch  (final  Parser .RegexException  e ) {
637+                 throw  new  ParsingException ("Could not extract YouTube WEB InnerTube client version " 
638+                         + "and API key from sw.js" , e );
639+             }
640+             keyAndVersionExtracted  = true ;
637641        }
638-         keyAndVersionExtracted  = true ;
639642    }
640643
641644    private  static  void  extractClientVersionAndKeyFromHtmlSearchResultsPage ()
642645            throws  IOException , ExtractionException  {
643-         // Don't extract the client version and the InnerTube key if it has been already extracted 
644-         if  (keyAndVersionExtracted ) {
645-             return ;
646-         }
647646
648-         // Don't provide a search term in order to have a smaller response 
649-         final  String  url  = "https://www.youtube.com/results?search_query=&ucbcb=1" ;
650-         final  String  html  = getDownloader ().get (url , getCookieHeader ()).responseBody ();
651-         final  JsonObject  initialData  = getInitialData (html );
652-         final  JsonArray  serviceTrackingParams  = initialData .getObject ("responseContext" )
653-                 .getArray ("serviceTrackingParams" );
647+         synchronized  (KEY_AND_VERSION_EXTRACTED_LOCK ) {
654648
655-         // Try to get version from initial data first 
656-         final  Stream <JsonObject > serviceTrackingParamsStream  = serviceTrackingParams .stream ()
657-                 .filter (JsonObject .class ::isInstance )
658-                 .map (JsonObject .class ::cast );
649+             // Don't extract the client version and the InnerTube key 
650+             // if it has been already extracted 
651+             if  (keyAndVersionExtracted ) {
652+                 return ;
653+             }
659654
660-         clientVersion  = getClientVersionFromServiceTrackingParam (
661-                 serviceTrackingParamsStream , "CSI" , "cver" );
655+             // Don't provide a search term in order to have a smaller response 
656+             final  String  url  = "https://www.youtube.com/results?search_query=&ucbcb=1" ;
657+             final  String  html  = getDownloader ().get (url , getCookieHeader ()).responseBody ();
658+             final  JsonObject  initialData  = getInitialData (html );
659+             final  JsonArray  serviceTrackingParams  = initialData .getObject ("responseContext" )
660+                     .getArray ("serviceTrackingParams" );
661+ 
662+             // Try to get version from initial data first 
663+             final  Stream <JsonObject > serviceTrackingParamsStream  = serviceTrackingParams .stream ()
664+                     .filter (JsonObject .class ::isInstance )
665+                     .map (JsonObject .class ::cast );
666+ 
667+             clientVersion  = getClientVersionFromServiceTrackingParam (
668+                     serviceTrackingParamsStream , "CSI" , "cver" );
669+ 
670+             if  (clientVersion  == null ) {
671+                 try  {
672+                     clientVersion  = getStringResultFromRegexArray (html ,
673+                             INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
674+                 } catch  (final  Parser .RegexException  ignored ) {
675+                 }
676+             }
677+ 
678+             // Fallback to get a shortened client version which does not contain the last two 
679+             // digits 
680+             if  (isNullOrEmpty (clientVersion )) {
681+                 clientVersion  = getClientVersionFromServiceTrackingParam (
682+                         serviceTrackingParamsStream , "ECATCHER" , "client.version" );
683+             }
662684
663-         if  (clientVersion  == null ) {
664685            try  {
665-                 clientVersion  = getStringResultFromRegexArray (html ,
666-                         INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
686+                 key  = getStringResultFromRegexArray (html , INNERTUBE_API_KEY_REGEXES , 1 );
667687            } catch  (final  Parser .RegexException  ignored ) {
668688            }
669-         }
670689
671-         // Fallback to get a shortened client version which does not contain the last two 
672-         // digits 
673-         if  (isNullOrEmpty (clientVersion )) {
674-             clientVersion  = getClientVersionFromServiceTrackingParam (
675-                     serviceTrackingParamsStream , "ECATCHER" , "client.version" );
676-         }
677- 
678-         try  {
679-             key  = getStringResultFromRegexArray (html , INNERTUBE_API_KEY_REGEXES , 1 );
680-         } catch  (final  Parser .RegexException  ignored ) {
681-         }
690+             if  (isNullOrEmpty (key )) {
691+                 throw  new  ParsingException (
692+                         // CHECKSTYLE:OFF 
693+                         "Could not extract YouTube WEB InnerTube API key from HTML search results page" );
694+                 // CHECKSTYLE:ON 
695+             }
682696
683-         if  (isNullOrEmpty ( key ) ) {
684-             throw  new  ParsingException (
685-                     // CHECKSTYLE:OFF 
686-                     "Could not extract YouTube WEB InnerTube API key  from HTML search results page" );
687-                      // CHECKSTYLE:ON 
688-         }
697+              if  (clientVersion  ==  null ) {
698+                  throw  new  ParsingException (
699+                          // CHECKSTYLE:OFF 
700+                          "Could not extract YouTube WEB InnerTube client version  from HTML search results page" );
701+                 // CHECKSTYLE:ON 
702+              }
689703
690-         if  (clientVersion  == null ) {
691-             throw  new  ParsingException (
692-                     // CHECKSTYLE:OFF 
693-                     "Could not extract YouTube WEB InnerTube client version from HTML search results page" );
694-                     // CHECKSTYLE:ON 
704+             keyAndVersionExtracted  = true ;
695705        }
696- 
697-         keyAndVersionExtracted  = true ;
698706    }
699707
700708    @ Nullable 
0 commit comments