@@ -66,15 +66,15 @@ private YoutubeParsingHelper() {
6666
6767 public static final String YOUTUBEI_V1_URL = "https://www.youtube.com/youtubei/v1/" ;
6868
69- private static final String HARDCODED_CLIENT_VERSION = "2.20210603.07 .00" ;
69+ private static final String HARDCODED_CLIENT_VERSION = "2.20210622.10 .00" ;
7070 private static final String HARDCODED_KEY = "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8" ;
7171 private static final String MOBILE_YOUTUBE_KEY = "AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w" ;
72- private static final String MOBILE_YOUTUBE_CLIENT_VERSION = "16.20 .36" ;
72+ private static final String MOBILE_YOUTUBE_CLIENT_VERSION = "16.23 .36" ;
7373 private static String clientVersion ;
7474 private static String key ;
7575
7676 private static final String [] HARDCODED_YOUTUBE_MUSIC_KEY =
77- {"AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30" , "67" , "0.1 " };
77+ {"AIzaSyC9XL3ZjWddXya6X74dJoCTL-WEYFDNX30" , "67" , "1.20210621.00.00 " };
7878 private static String [] youtubeMusicKey ;
7979
8080 private static boolean keyAndVersionExtracted = false ;
@@ -102,7 +102,8 @@ private static boolean isGoogleURL(String url) {
102102 try {
103103 final URL u = new URL (url );
104104 final String host = u .getHost ();
105- return host .startsWith ("google." ) || host .startsWith ("m.google." )
105+ return host .startsWith ("google." )
106+ || host .startsWith ("m.google." )
106107 || host .startsWith ("www.google." );
107108 } catch (final MalformedURLException e ) {
108109 return false ;
@@ -111,7 +112,8 @@ private static boolean isGoogleURL(String url) {
111112
112113 public static boolean isYoutubeURL (@ Nonnull final URL url ) {
113114 final String host = url .getHost ();
114- return host .equalsIgnoreCase ("youtube.com" ) || host .equalsIgnoreCase ("www.youtube.com" )
115+ return host .equalsIgnoreCase ("youtube.com" )
116+ || host .equalsIgnoreCase ("www.youtube.com" )
115117 || host .equalsIgnoreCase ("m.youtube.com" )
116118 || host .equalsIgnoreCase ("music.youtube.com" );
117119 }
@@ -234,7 +236,7 @@ public static OffsetDateTime parseDateFrom(final String textualUploadDate)
234236 * Checks if the given playlist id is a YouTube Mix (auto-generated playlist)
235237 * Ids from a YouTube Mix start with "RD"
236238 *
237- * @param playlistId the id of the playlist
239+ * @param playlistId the playlist id
238240 * @return Whether given id belongs to a YouTube Mix
239241 */
240242 public static boolean isYoutubeMixId (@ Nonnull final String playlistId ) {
@@ -306,8 +308,8 @@ public static JsonObject getInitialData(final String html) throws ParsingExcepti
306308 }
307309 }
308310
309- public static boolean areHardcodedClientVersionAndKeyValid () throws IOException ,
310- ExtractionException {
311+ public static boolean areHardcodedClientVersionAndKeyValid ()
312+ throws IOException , ExtractionException {
311313 if (areHardcodedClientVersionAndKeyValidValue != null ) {
312314 return areHardcodedClientVersionAndKeyValidValue ;
313315 }
@@ -316,11 +318,17 @@ public static boolean areHardcodedClientVersionAndKeyValid() throws IOException,
316318 .object ()
317319 .object ("context" )
318320 .object ("client" )
319- .value ("hl" , "en" )
321+ .value ("hl" , "en-GB " )
320322 .value ("gl" , "GB" )
321- .value ("clientName" , "1 " )
323+ .value ("clientName" , "WEB " )
322324 .value ("clientVersion" , HARDCODED_CLIENT_VERSION )
323325 .end ()
326+ .object ("user" )
327+ // TO DO: provide a way to enable restricted mode with:
328+ // .value("enableSafetyMode", boolean)
329+ .value ("lockedSafetyMode" , false )
330+ .end ()
331+ .value ("fetchLiveState" , true )
324332 .end ()
325333 .end ().done ().getBytes (UTF_8 );
326334 // @formatter:on
@@ -337,9 +345,8 @@ public static boolean areHardcodedClientVersionAndKeyValid() throws IOException,
337345 final String responseBody = response .responseBody ();
338346 final int responseCode = response .responseCode ();
339347
340- areHardcodedClientVersionAndKeyValidValue = responseBody .length () > 5000
348+ return areHardcodedClientVersionAndKeyValidValue = responseBody .length () > 5000
341349 && responseCode == 200 ; // Ensure to have a valid response
342- return areHardcodedClientVersionAndKeyValidValue ;
343350 }
344351
345352 private static void extractClientVersionAndKey () throws IOException , ExtractionException {
@@ -485,8 +492,7 @@ public static boolean isHardcodedYoutubeMusicKeyValid() throws IOException,
485492 .value ("hl" , "en-GB" )
486493 .value ("gl" , "GB" )
487494 .array ("experimentIds" ).end ()
488- .value ("experimentsToken" , "" )
489- .value ("utcOffsetMinutes" , 0 )
495+ .value ("experimentsToken" , EMPTY_STRING )
490496 .object ("locationInfo" ).end ()
491497 .object ("musicAppInfo" ).end ()
492498 .end ()
@@ -802,10 +808,13 @@ public static JsonBuilder<JsonObject> prepareJsonBuilder(@Nonnull final Localiza
802808 return JsonObject .builder ()
803809 .object ("context" )
804810 .object ("client" )
805- .value ("clientName" , "WEB" )
806- .value ("clientVersion" , getClientVersion ())
807811 .value ("hl" , localization .getLocalizationCode ())
808812 .value ("gl" , contentCountry .getCountryCode ())
813+ .value ("clientName" , "WEB" )
814+ .value ("clientVersion" , getClientVersion ())
815+ .end ()
816+ .object ("user" )
817+ .value ("lockedSafetyMode" , false )
809818 .end ()
810819 .end ();
811820 // @formatter:on
@@ -826,6 +835,11 @@ public static JsonBuilder<JsonObject> prepareMobileJsonBuilder(@Nonnull final Lo
826835 .value ("hl" , localization .getLocalizationCode ())
827836 .value ("gl" , contentCountry .getCountryCode ())
828837 .end ()
838+ .object ("user" )
839+ // TO DO: provide a way to enable restricted mode with:
840+ // .value("enableSafetyMode", boolean)
841+ .value ("lockedSafetyMode" , false )
842+ .end ()
829843 .end ();
830844 // @formatter:on
831845 }
@@ -848,15 +862,11 @@ public static void addYouTubeHeaders(final Map<String, List<String>> headers)
848862 */
849863 public static void addClientInfoHeaders (@ Nonnull final Map <String , List <String >> headers )
850864 throws IOException , ExtractionException {
851- if (headers .get ("Origin" ) == null ) {
852- headers .put ("Origin" , Collections .singletonList ("https://www.youtube.com" ));
853- }
854- if (headers .get ("Referer" ) == null ) {
855- headers .put ("Referer" , Collections .singletonList ("https://www.youtube.com" ));
856- }
857- if (headers .get ("X-YouTube-Client-Name" ) == null ) {
858- headers .put ("X-YouTube-Client-Name" , Collections .singletonList ("1" ));
859- }
865+ headers .computeIfAbsent ("Origin" , k -> Collections .singletonList (
866+ "https://www.youtube.com" ));
867+ headers .computeIfAbsent ("Referer" , k -> Collections .singletonList (
868+ "https://www.youtube.com" ));
869+ headers .computeIfAbsent ("X-YouTube-Client-Name" , k -> Collections .singletonList ("1" ));
860870 if (headers .get ("X-YouTube-Client-Version" ) == null ) {
861871 headers .put ("X-YouTube-Client-Version" , Collections .singletonList (getClientVersion ()));
862872 }
@@ -867,7 +877,7 @@ public static void addClientInfoHeaders(@Nonnull final Map<String, List<String>>
867877 * @see #CONSENT_COOKIE
868878 * @param headers the headers which should be completed
869879 */
870- public static void addCookieHeader (@ Nonnull final Map <String , List <String >> headers ) {
880+ public static void addCookieHeader (final Map <String , List <String >> headers ) {
871881 if (headers .get ("Cookie" ) == null ) {
872882 headers .put ("Cookie" , Arrays .asList (generateConsentCookie ()));
873883 } else {
@@ -1092,5 +1102,4 @@ public static String unescapeDocument(@Nonnull final String doc) {
10921102 .replaceAll ("\\ \\ x5b" , "[" )
10931103 .replaceAll ("\\ \\ x5d" , "]" );
10941104 }
1095-
10961105}
0 commit comments