@@ -155,11 +155,6 @@ private YoutubeParsingHelper() {
155155 */
156156 public static final String RACY_CHECK_OK = "racyCheckOk" ;
157157
158- /**
159- * The hardcoded client version used for InnerTube requests with the TV HTML5 embed client.
160- */
161- private static final String TVHTML5_SIMPLY_EMBED_CLIENT_VERSION = "2.0" ;
162-
163158 private static String clientVersion ;
164159
165160 private static String youtubeMusicClientVersion ;
@@ -1065,43 +1060,6 @@ public static JsonObject getJsonPostResponse(final String endpoint,
10651060 + DISABLE_PRETTY_PRINT_PARAMETER , headers , body , localization )));
10661061 }
10671062
1068- public static JsonObject getJsonAndroidPostResponse (
1069- final String endpoint ,
1070- final byte [] body ,
1071- @ Nonnull final Localization localization ,
1072- @ Nullable final String endPartOfUrlRequest ) throws IOException , ExtractionException {
1073- return getMobilePostResponse (endpoint , body , localization ,
1074- getAndroidUserAgent (localization ), endPartOfUrlRequest );
1075- }
1076-
1077- public static JsonObject getJsonIosPostResponse (
1078- final String endpoint ,
1079- final byte [] body ,
1080- @ Nonnull final Localization localization ,
1081- @ Nullable final String endPartOfUrlRequest ) throws IOException , ExtractionException {
1082- return getMobilePostResponse (endpoint , body , localization , getIosUserAgent (localization ),
1083- endPartOfUrlRequest );
1084- }
1085-
1086- private static JsonObject getMobilePostResponse (
1087- final String endpoint ,
1088- final byte [] body ,
1089- @ Nonnull final Localization localization ,
1090- @ Nonnull final String userAgent ,
1091- @ Nullable final String endPartOfUrlRequest ) throws IOException , ExtractionException {
1092- final var headers = Map .of ("User-Agent" , List .of (userAgent ),
1093- "X-Goog-Api-Format-Version" , List .of ("2" ));
1094-
1095- final String baseEndpointUrl = YOUTUBEI_V1_GAPIS_URL + endpoint + "?"
1096- + DISABLE_PRETTY_PRINT_PARAMETER ;
1097-
1098- return JsonUtils .toJsonObject (getValidJsonResponseBody (
1099- getDownloader ().postWithContentTypeJson (isNullOrEmpty (endPartOfUrlRequest )
1100- ? baseEndpointUrl
1101- : baseEndpointUrl + endPartOfUrlRequest ,
1102- headers , body , localization )));
1103- }
1104-
11051063 @ Nonnull
11061064 public static JsonBuilder <JsonObject > prepareDesktopJsonBuilder (
11071065 @ Nonnull final Localization localization ,
@@ -1148,165 +1106,6 @@ public static JsonBuilder<JsonObject> prepareDesktopJsonBuilder(
11481106 // @formatter:on
11491107 }
11501108
1151- @ Nonnull
1152- public static JsonBuilder <JsonObject > prepareAndroidMobileJsonBuilder (
1153- @ Nonnull final Localization localization ,
1154- @ Nonnull final ContentCountry contentCountry ) {
1155- // @formatter:off
1156- return JsonObject .builder ()
1157- .object ("context" )
1158- .object ("client" )
1159- .value ("clientName" , "ANDROID" )
1160- .value ("clientVersion" , ANDROID_YOUTUBE_CLIENT_VERSION )
1161- .value ("platform" , "MOBILE" )
1162- .value ("osName" , "Android" )
1163- .value ("osVersion" , "14" )
1164- /*
1165- A valid Android SDK version is required to be sure to get a valid player
1166- response
1167- If this parameter is not provided, the player response is replaced by an
1168- error saying the message "The following content is not available on this
1169- app. Watch this content on the latest version on YouTube" (it was
1170- previously a 5-minute video with this message)
1171- See https://github.com/TeamNewPipe/NewPipe/issues/8713
1172- The Android SDK version corresponding to the Android version used in
1173- requests is sent
1174- */
1175- .value ("androidSdkVersion" , 34 )
1176- .value ("hl" , localization .getLocalizationCode ())
1177- .value ("gl" , contentCountry .getCountryCode ())
1178- .value ("utcOffsetMinutes" , 0 )
1179- .end ()
1180- .object ("request" )
1181- .array ("internalExperimentFlags" )
1182- .end ()
1183- .value ("useSsl" , true )
1184- .end ()
1185- .object ("user" )
1186- // TODO: provide a way to enable restricted mode with:
1187- // .value("enableSafetyMode", boolean)
1188- .value ("lockedSafetyMode" , false )
1189- .end ()
1190- .end ();
1191- // @formatter:on
1192- }
1193-
1194- @ Nonnull
1195- public static JsonBuilder <JsonObject > prepareIosMobileJsonBuilder (
1196- @ Nonnull final Localization localization ,
1197- @ Nonnull final ContentCountry contentCountry ) {
1198- // @formatter:off
1199- return JsonObject .builder ()
1200- .object ("context" )
1201- .object ("client" )
1202- .value ("clientName" , "IOS" )
1203- .value ("clientVersion" , IOS_YOUTUBE_CLIENT_VERSION )
1204- .value ("deviceMake" , "Apple" )
1205- // Device model is required to get 60fps streams
1206- .value ("deviceModel" , IOS_DEVICE_MODEL )
1207- .value ("platform" , "MOBILE" )
1208- .value ("osName" , "iOS" )
1209- .value ("osVersion" , IOS_OS_VERSION )
1210- .value ("visitorData" , randomVisitorData (contentCountry ))
1211- .value ("hl" , localization .getLocalizationCode ())
1212- .value ("gl" , contentCountry .getCountryCode ())
1213- .value ("utcOffsetMinutes" , 0 )
1214- .end ()
1215- .object ("request" )
1216- .array ("internalExperimentFlags" )
1217- .end ()
1218- .value ("useSsl" , true )
1219- .end ()
1220- .object ("user" )
1221- // TODO: provide a way to enable restricted mode with:
1222- // .value("enableSafetyMode", boolean)
1223- .value ("lockedSafetyMode" , false )
1224- .end ()
1225- .end ();
1226- // @formatter:on
1227- }
1228-
1229- @ Nonnull
1230- public static JsonBuilder <JsonObject > prepareTvHtml5EmbedJsonBuilder (
1231- @ Nonnull final Localization localization ,
1232- @ Nonnull final ContentCountry contentCountry ,
1233- @ Nonnull final String videoId ) {
1234- // @formatter:off
1235- return JsonObject .builder ()
1236- .object ("context" )
1237- .object ("client" )
1238- .value ("clientName" , "TVHTML5_SIMPLY_EMBEDDED_PLAYER" )
1239- .value ("clientVersion" , TVHTML5_SIMPLY_EMBED_CLIENT_VERSION )
1240- .value ("clientScreen" , "EMBED" )
1241- .value ("platform" , "TV" )
1242- .value ("hl" , localization .getLocalizationCode ())
1243- .value ("gl" , contentCountry .getCountryCode ())
1244- .value ("utcOffsetMinutes" , 0 )
1245- .end ()
1246- .object ("thirdParty" )
1247- .value ("embedUrl" , "https://www.youtube.com/watch?v=" + videoId )
1248- .end ()
1249- .object ("request" )
1250- .array ("internalExperimentFlags" )
1251- .end ()
1252- .value ("useSsl" , true )
1253- .end ()
1254- .object ("user" )
1255- // TODO: provide a way to enable restricted mode with:
1256- // .value("enableSafetyMode", boolean)
1257- .value ("lockedSafetyMode" , false )
1258- .end ()
1259- .end ();
1260- // @formatter:on
1261- }
1262-
1263- @ Nonnull
1264- public static JsonObject getWebPlayerResponse (
1265- @ Nonnull final Localization localization ,
1266- @ Nonnull final ContentCountry contentCountry ,
1267- @ Nonnull final String videoId ) throws IOException , ExtractionException {
1268- final byte [] body = JsonWriter .string (
1269- prepareDesktopJsonBuilder (localization , contentCountry )
1270- .value (VIDEO_ID , videoId )
1271- .value (CONTENT_CHECK_OK , true )
1272- .value (RACY_CHECK_OK , true )
1273- .done ())
1274- .getBytes (StandardCharsets .UTF_8 );
1275- final String url = YOUTUBEI_V1_URL + "player" + "?" + DISABLE_PRETTY_PRINT_PARAMETER
1276- + "&$fields=microformat,playabilityStatus,storyboards,videoDetails" ;
1277-
1278- return JsonUtils .toJsonObject (getValidJsonResponseBody (
1279- getDownloader ().postWithContentTypeJson (
1280- url , getYouTubeHeaders (), body , localization )));
1281- }
1282-
1283- @ Nonnull
1284- public static byte [] createTvHtml5EmbedPlayerBody (
1285- @ Nonnull final Localization localization ,
1286- @ Nonnull final ContentCountry contentCountry ,
1287- @ Nonnull final String videoId ,
1288- @ Nonnull final Integer sts ,
1289- @ Nonnull final String contentPlaybackNonce ) {
1290- // @formatter:off
1291- return JsonWriter .string (
1292- prepareTvHtml5EmbedJsonBuilder (localization , contentCountry , videoId )
1293- .object ("playbackContext" )
1294- .object ("contentPlaybackContext" )
1295- // Signature timestamp from the JavaScript base player is needed to get
1296- // working obfuscated URLs
1297- .value ("signatureTimestamp" , sts )
1298- .value ("referer" , "https://www.youtube.com/watch?v=" + videoId )
1299- .end ()
1300- .end ()
1301- .value (CPN , contentPlaybackNonce )
1302- .value (VIDEO_ID , videoId )
1303- .value (CONTENT_CHECK_OK , true )
1304- .value (RACY_CHECK_OK , true )
1305- .done ())
1306- .getBytes (StandardCharsets .UTF_8 );
1307- // @formatter:on
1308- }
1309-
13101109 /**
13111110 * Get the user-agent string used as the user-agent for InnerTube requests with the Android
13121111 * client.
0 commit comments