@@ -144,6 +144,11 @@ private YoutubeParsingHelper() {
144144 */
145145 public static final String RACY_CHECK_OK = "racyCheckOk" ;
146146
147+ /**
148+ * The hardcoded client ID used for InnerTube requests with the {@code WEB} client.
149+ */
150+ private static final String WEB_CLIENT_ID = "1" ;
151+
147152 /**
148153 * The client version for InnerTube requests with the {@code WEB} client, used as the last
149154 * fallback if the extraction of the real one failed.
@@ -177,6 +182,11 @@ private YoutubeParsingHelper() {
177182 */
178183 private static final String TVHTML5_SIMPLY_EMBED_CLIENT_VERSION = "2.0" ;
179184
185+ /**
186+ * The hardcoded client ID used for InnerTube requests with the YouTube Music desktop client.
187+ */
188+ private static final String YOUTUBE_MUSIC_CLIENT_ID = "67" ;
189+
180190 /**
181191 * The hardcoded client version used for InnerTube requests with the YouTube Music desktop
182192 * client.
@@ -212,6 +222,30 @@ private YoutubeParsingHelper() {
212222 */
213223 private static final String IOS_DEVICE_MODEL = "iPhone15,4" ;
214224
225+ /**
226+ * Spoofing an iPhone 15 running iOS 17.4.1 with the hardcoded version of the iOS app. To be
227+ * used for the {@code "osVersion"} field in JSON POST requests.
228+ * <p>
229+ * The value of this field seems to use the following structure:
230+ * "iOS major version.minor version.patch version.build version", where
231+ * "patch version" is equal to 0 if it isn't set
232+ * The build version corresponding to the iOS version used can be found on
233+ * <a href="https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15">
234+ * https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15</a>
235+ * </p>
236+ *
237+ * @see #IOS_USER_AGENT_VERSION
238+ */
239+ private static final String IOS_OS_VERSION = "17.4.1.21E237" ;
240+
241+ /**
242+ * Spoofing an iPhone 15 running iOS 17.4.1 with the hardcoded version of the iOS app. To be
243+ * used in the user agent for requests.
244+ *
245+ * @see #IOS_OS_VERSION
246+ */
247+ private static final String IOS_USER_AGENT_VERSION = "17_4_1" ;
248+
215249 private static Random numberGenerator = new Random ();
216250
217251 private static final String FEED_BASE_CHANNEL_ID =
@@ -529,7 +563,7 @@ public static boolean isHardcodedClientVersionValid()
529563 .end ().done ().getBytes (StandardCharsets .UTF_8 );
530564 // @formatter:on
531565
532- final var headers = getClientHeaders ("1" , HARDCODED_CLIENT_VERSION );
566+ final var headers = getClientHeaders (WEB_CLIENT_ID , HARDCODED_CLIENT_VERSION );
533567
534568 // This endpoint is fetched by the YouTube website to get the items of its main menu and is
535569 // pretty lightweight (around 30kB)
@@ -723,7 +757,8 @@ public static boolean isHardcodedYoutubeMusicClientVersionValid() throws IOExcep
723757 // @formatter:on
724758
725759 final var headers = new HashMap <>(getOriginReferrerHeaders (YOUTUBE_MUSIC_URL ));
726- headers .putAll (getClientHeaders ("67" , HARDCODED_YOUTUBE_MUSIC_CLIENT_VERSION ));
760+ headers .putAll (getClientHeaders (YOUTUBE_MUSIC_CLIENT_ID ,
761+ HARDCODED_YOUTUBE_MUSIC_CLIENT_VERSION ));
727762
728763 final Response response = getDownloader ().postWithContentTypeJson (url , headers , json );
729764 // Ensure to have a valid response
@@ -1217,14 +1252,7 @@ public static JsonBuilder<JsonObject> prepareIosMobileJsonBuilder(
12171252 .value ("deviceModel" , IOS_DEVICE_MODEL )
12181253 .value ("platform" , "MOBILE" )
12191254 .value ("osName" , "iOS" )
1220- /*
1221- The value of this field seems to use the following structure:
1222- "iOS major version.minor version.patch version.build version", where
1223- "patch version" is equal to 0 if it isn't set
1224- The build version corresponding to the iOS version used can be found on
1225- https://theapplewiki.com/wiki/Firmware/iPhone/17.x#iPhone_15
1226- */
1227- .value ("osVersion" , "17.4.1.21E237" )
1255+ .value ("osVersion" , IOS_OS_VERSION )
12281256 .value ("hl" , localization .getLocalizationCode ())
12291257 .value ("gl" , contentCountry .getCountryCode ())
12301258 .value ("utcOffsetMinutes" , 0 )
@@ -1345,7 +1373,8 @@ public static String getAndroidUserAgent(@Nullable final Localization localizati
13451373 public static String getIosUserAgent (@ Nullable final Localization localization ) {
13461374 // Spoofing an iPhone 15 running iOS 17.4.1 with the hardcoded version of the iOS app
13471375 return "com.google.ios.youtube/" + IOS_YOUTUBE_CLIENT_VERSION
1348- + "(" + IOS_DEVICE_MODEL + "; U; CPU iOS 17_4_1 like Mac OS X; "
1376+ + "(" + IOS_DEVICE_MODEL + "; U; CPU iOS "
1377+ + IOS_USER_AGENT_VERSION + " like Mac OS X; "
13491378 + (localization != null ? localization : Localization .DEFAULT ).getCountryCode ()
13501379 + ")" ;
13511380 }
@@ -1356,7 +1385,8 @@ public static String getIosUserAgent(@Nullable final Localization localization)
13561385 @ Nonnull
13571386 public static Map <String , List <String >> getYoutubeMusicHeaders () {
13581387 final var headers = new HashMap <>(getOriginReferrerHeaders (YOUTUBE_MUSIC_URL ));
1359- headers .putAll (getClientHeaders ("67" , youtubeMusicClientVersion ));
1388+ headers .putAll (getClientHeaders (YOUTUBE_MUSIC_CLIENT_ID ,
1389+ youtubeMusicClientVersion ));
13601390 return headers ;
13611391 }
13621392
@@ -1378,7 +1408,7 @@ public static Map<String, List<String>> getYouTubeHeaders()
13781408 public static Map <String , List <String >> getClientInfoHeaders ()
13791409 throws ExtractionException , IOException {
13801410 final var headers = new HashMap <>(getOriginReferrerHeaders ("https://www.youtube.com" ));
1381- headers .putAll (getClientHeaders ("1" , getClientVersion ()));
1411+ headers .putAll (getClientHeaders (WEB_CLIENT_ID , getClientVersion ()));
13821412 return headers ;
13831413 }
13841414
0 commit comments