@@ -205,6 +205,7 @@ private YoutubeParsingHelper() {
205205    private  static  String [] youtubeMusicKey ;
206206
207207    private  static  boolean  keyAndVersionExtracted  = false ;
208+     private  static  final  Object  KEY_AND_VERSION_EXTRACTED_LOCK  = new  Object ();
208209    @ SuppressWarnings ("OptionalUsedAsFieldOrParameterType" )
209210    private  static  Optional <Boolean > hardcodedClientVersionAndKeyValid  = Optional .empty ();
210211
@@ -575,80 +576,84 @@ public static boolean areHardcodedClientVersionAndKeyValid()
575576
576577    private  static  void  extractClientVersionAndKeyFromSwJs ()
577578            throws  IOException , ExtractionException  {
578-         if  (keyAndVersionExtracted ) {
579-             return ;
580-         }
581-         final  String  url  = "https://www.youtube.com/sw.js" ;
582-         final  var  headers  = getOriginReferrerHeaders ("https://www.youtube.com" );
583-         final  String  response  = getDownloader ().get (url , headers ).responseBody ();
584-         try  {
585-             clientVersion  = getStringResultFromRegexArray (response ,
586-                     INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
587-             key  = getStringResultFromRegexArray (response , INNERTUBE_API_KEY_REGEXES , 1 );
588-         } catch  (final  Parser .RegexException  e ) {
589-             throw  new  ParsingException ("Could not extract YouTube WEB InnerTube client version " 
590-                     + "and API key from sw.js" , e );
579+         synchronized  (KEY_AND_VERSION_EXTRACTED_LOCK ) {
580+             if  (keyAndVersionExtracted ) {
581+                 return ;
582+             }
583+             final  String  url  = "https://www.youtube.com/sw.js" ;
584+             final  var  headers  = getOriginReferrerHeaders ("https://www.youtube.com" );
585+             final  String  response  = getDownloader ().get (url , headers ).responseBody ();
586+             try  {
587+                 clientVersion  = getStringResultFromRegexArray (response ,
588+                         INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
589+                 key  = getStringResultFromRegexArray (response , INNERTUBE_API_KEY_REGEXES , 1 );
590+             } catch  (final  Parser .RegexException  e ) {
591+                 throw  new  ParsingException ("Could not extract YouTube WEB InnerTube client version " 
592+                         + "and API key from sw.js" , e );
593+             }
594+             keyAndVersionExtracted  = true ;
591595        }
592-         keyAndVersionExtracted  = true ;
593596    }
594597
595598    private  static  void  extractClientVersionAndKeyFromHtmlSearchResultsPage ()
596599            throws  IOException , ExtractionException  {
597-         // Don't extract the client version and the InnerTube key if it has been already extracted 
598-         if  (keyAndVersionExtracted ) {
599-             return ;
600-         }
600+         synchronized  (KEY_AND_VERSION_EXTRACTED_LOCK ) {
601+             // Don't extract the client version and the InnerTube key if it has been already extracted 
602+             if  (keyAndVersionExtracted ) {
603+                 return ;
604+             }
601605
602-         // Don't provide a search term in order to have a smaller response 
603-         final  String  url  = "https://www.youtube.com/results?search_query=&ucbcb=1" ;
604-         final  String  html  = getDownloader ().get (url , getCookieHeader ()).responseBody ();
605-         final  JsonObject  initialData  = getInitialData (html );
606-         final  JsonArray  serviceTrackingParams  = initialData .getObject ("responseContext" )
607-                 .getArray ("serviceTrackingParams" );
606+              // Don't provide a search term in order to have a smaller response 
607+              final  String  url  = "https://www.youtube.com/results?search_query=&ucbcb=1" ;
608+              final  String  html  = getDownloader ().get (url , getCookieHeader ()).responseBody ();
609+              final  JsonObject  initialData  = getInitialData (html );
610+              final  JsonArray  serviceTrackingParams  = initialData .getObject ("responseContext" )
611+                      .getArray ("serviceTrackingParams" );
608612
609-         // Try to get version from initial data first 
610-         final  Stream <JsonObject > serviceTrackingParamsStream  = serviceTrackingParams .stream ()
611-                 .filter (JsonObject .class ::isInstance )
612-                 .map (JsonObject .class ::cast );
613+             // Try to get version from initial data first 
614+             final  Stream <JsonObject > serviceTrackingParamsStream  = serviceTrackingParams .stream ()
615+                     .filter (JsonObject .class ::isInstance )
616+                     .map (JsonObject .class ::cast );
617+ 
618+             clientVersion  = getClientVersionFromServiceTrackingParam (
619+                     serviceTrackingParamsStream , "CSI" , "cver" );
613620
614-         clientVersion  = getClientVersionFromServiceTrackingParam (
615-                 serviceTrackingParamsStream , "CSI" , "cver" );
621+             if  (clientVersion  == null ) {
622+                 try  {
623+                     clientVersion  = getStringResultFromRegexArray (html ,
624+                             INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
625+                 } catch  (final  Parser .RegexException  ignored ) {
626+                 }
627+             }
628+ 
629+             // Fallback to get a shortened client version which does not contain the last two 
630+             // digits 
631+             if  (isNullOrEmpty (clientVersion )) {
632+                 clientVersion  = getClientVersionFromServiceTrackingParam (
633+                         serviceTrackingParamsStream , "ECATCHER" , "client.version" );
634+             }
616635
617-         if  (clientVersion  == null ) {
618636            try  {
619-                 clientVersion  = getStringResultFromRegexArray (html ,
620-                         INNERTUBE_CONTEXT_CLIENT_VERSION_REGEXES , 1 );
637+                 key  = getStringResultFromRegexArray (html , INNERTUBE_API_KEY_REGEXES , 1 );
621638            } catch  (final  Parser .RegexException  ignored ) {
622639            }
623-         }
624- 
625-         // Fallback to get a shortened client version which does not contain the last two 
626-         // digits 
627-         if  (isNullOrEmpty (clientVersion )) {
628-             clientVersion  = getClientVersionFromServiceTrackingParam (
629-                     serviceTrackingParamsStream , "ECATCHER" , "client.version" );
630-         }
631640
632-         try  {
633-             key  = getStringResultFromRegexArray (html , INNERTUBE_API_KEY_REGEXES , 1 );
634-         } catch  (final  Parser .RegexException  ignored ) {
635-         }
641+             if  (isNullOrEmpty (key )) {
642+                 throw  new  ParsingException (
643+                         // CHECKSTYLE:OFF 
644+                         "Could not extract YouTube WEB InnerTube API key from HTML search results page" );
645+                 // CHECKSTYLE:ON 
646+             }
636647
637-         if  (isNullOrEmpty ( key ) ) {
638-             throw  new  ParsingException (
639-                     // CHECKSTYLE:OFF 
640-                     "Could not extract YouTube WEB InnerTube API key  from HTML search results page" );
641-                      // CHECKSTYLE:ON 
642-         }
648+              if  (clientVersion  ==  null ) {
649+                  throw  new  ParsingException (
650+                          // CHECKSTYLE:OFF 
651+                          "Could not extract YouTube WEB InnerTube client version  from HTML search results page" );
652+                 // CHECKSTYLE:ON 
653+              }
643654
644-         if  (clientVersion  == null ) {
645-             throw  new  ParsingException (
646-                     // CHECKSTYLE:OFF 
647-                     "Could not extract YouTube WEB InnerTube client version from HTML search results page" );
648-                     // CHECKSTYLE:ON 
655+             keyAndVersionExtracted  = true ;
649656        }
650- 
651-         keyAndVersionExtracted  = true ;
652657    }
653658
654659    @ Nullable 
0 commit comments