diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java index ece76ecef..6b8742531 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeParsingHelper.java @@ -155,11 +155,6 @@ public final class YoutubeParsingHelper { */ public static final String RACY_CHECK_OK = "racyCheckOk"; - /** - * The hardcoded client version used for InnerTube requests with the TV HTML5 embed client. - */ - private static final String TVHTML5_SIMPLY_EMBED_CLIENT_VERSION = "2.0"; - private static String clientVersion; private static String youtubeMusicClientVersion; @@ -1065,43 +1060,6 @@ public final class YoutubeParsingHelper { + DISABLE_PRETTY_PRINT_PARAMETER, headers, body, localization))); } - public static JsonObject getJsonAndroidPostResponse( - final String endpoint, - final byte[] body, - @Nonnull final Localization localization, - @Nullable final String endPartOfUrlRequest) throws IOException, ExtractionException { - return getMobilePostResponse(endpoint, body, localization, - getAndroidUserAgent(localization), endPartOfUrlRequest); - } - - public static JsonObject getJsonIosPostResponse( - final String endpoint, - final byte[] body, - @Nonnull final Localization localization, - @Nullable final String endPartOfUrlRequest) throws IOException, ExtractionException { - return getMobilePostResponse(endpoint, body, localization, getIosUserAgent(localization), - endPartOfUrlRequest); - } - - private static JsonObject getMobilePostResponse( - final String endpoint, - final byte[] body, - @Nonnull final Localization localization, - @Nonnull final String userAgent, - @Nullable final String endPartOfUrlRequest) throws IOException, ExtractionException { - final var headers = Map.of("User-Agent", List.of(userAgent), - "X-Goog-Api-Format-Version", List.of("2")); - - final String baseEndpointUrl = YOUTUBEI_V1_GAPIS_URL + endpoint + "?" - + DISABLE_PRETTY_PRINT_PARAMETER; - - return JsonUtils.toJsonObject(getValidJsonResponseBody( - getDownloader().postWithContentTypeJson(isNullOrEmpty(endPartOfUrlRequest) - ? baseEndpointUrl - : baseEndpointUrl + endPartOfUrlRequest, - headers, body, localization))); - } - @Nonnull public static JsonBuilder prepareDesktopJsonBuilder( @Nonnull final Localization localization, @@ -1148,165 +1106,6 @@ public final class YoutubeParsingHelper { // @formatter:on } - @Nonnull - public static JsonBuilder prepareAndroidMobileJsonBuilder( - @Nonnull final Localization localization, - @Nonnull final ContentCountry contentCountry) { - // @formatter:off - return JsonObject.builder() - .object("context") - .object("client") - .value("clientName", "ANDROID") - .value("clientVersion", ANDROID_YOUTUBE_CLIENT_VERSION) - .value("platform", "MOBILE") - .value("osName", "Android") - .value("osVersion", "14") - /* - A valid Android SDK version is required to be sure to get a valid player - response - If this parameter is not provided, the player response is replaced by an - error saying the message "The following content is not available on this - app. Watch this content on the latest version on YouTube" (it was - previously a 5-minute video with this message) - See https://github.com/TeamNewPipe/NewPipe/issues/8713 - The Android SDK version corresponding to the Android version used in - requests is sent - */ - .value("androidSdkVersion", 34) - .value("hl", localization.getLocalizationCode()) - .value("gl", contentCountry.getCountryCode()) - .value("utcOffsetMinutes", 0) - .end() - .object("request") - .array("internalExperimentFlags") - .end() - .value("useSsl", true) - .end() - .object("user") - // TODO: provide a way to enable restricted mode with: - // .value("enableSafetyMode", boolean) - .value("lockedSafetyMode", false) - .end() - .end(); - // @formatter:on - } - - @Nonnull - public static JsonBuilder prepareIosMobileJsonBuilder( - @Nonnull final Localization localization, - @Nonnull final ContentCountry contentCountry) { - // @formatter:off - return JsonObject.builder() - .object("context") - .object("client") - .value("clientName", "IOS") - .value("clientVersion", IOS_YOUTUBE_CLIENT_VERSION) - .value("deviceMake", "Apple") - // Device model is required to get 60fps streams - .value("deviceModel", IOS_DEVICE_MODEL) - .value("platform", "MOBILE") - .value("osName", "iOS") - .value("osVersion", IOS_OS_VERSION) - .value("visitorData", randomVisitorData(contentCountry)) - .value("hl", localization.getLocalizationCode()) - .value("gl", contentCountry.getCountryCode()) - .value("utcOffsetMinutes", 0) - .end() - .object("request") - .array("internalExperimentFlags") - .end() - .value("useSsl", true) - .end() - .object("user") - // TODO: provide a way to enable restricted mode with: - // .value("enableSafetyMode", boolean) - .value("lockedSafetyMode", false) - .end() - .end(); - // @formatter:on - } - - @Nonnull - public static JsonBuilder prepareTvHtml5EmbedJsonBuilder( - @Nonnull final Localization localization, - @Nonnull final ContentCountry contentCountry, - @Nonnull final String videoId) { - // @formatter:off - return JsonObject.builder() - .object("context") - .object("client") - .value("clientName", "TVHTML5_SIMPLY_EMBEDDED_PLAYER") - .value("clientVersion", TVHTML5_SIMPLY_EMBED_CLIENT_VERSION) - .value("clientScreen", "EMBED") - .value("platform", "TV") - .value("hl", localization.getLocalizationCode()) - .value("gl", contentCountry.getCountryCode()) - .value("utcOffsetMinutes", 0) - .end() - .object("thirdParty") - .value("embedUrl", "https://www.youtube.com/watch?v=" + videoId) - .end() - .object("request") - .array("internalExperimentFlags") - .end() - .value("useSsl", true) - .end() - .object("user") - // TODO: provide a way to enable restricted mode with: - // .value("enableSafetyMode", boolean) - .value("lockedSafetyMode", false) - .end() - .end(); - // @formatter:on - } - - @Nonnull - public static JsonObject getWebPlayerResponse( - @Nonnull final Localization localization, - @Nonnull final ContentCountry contentCountry, - @Nonnull final String videoId) throws IOException, ExtractionException { - final byte[] body = JsonWriter.string( - prepareDesktopJsonBuilder(localization, contentCountry) - .value(VIDEO_ID, videoId) - .value(CONTENT_CHECK_OK, true) - .value(RACY_CHECK_OK, true) - .done()) - .getBytes(StandardCharsets.UTF_8); - final String url = YOUTUBEI_V1_URL + "player" + "?" + DISABLE_PRETTY_PRINT_PARAMETER - + "&$fields=microformat,playabilityStatus,storyboards,videoDetails"; - - return JsonUtils.toJsonObject(getValidJsonResponseBody( - getDownloader().postWithContentTypeJson( - url, getYouTubeHeaders(), body, localization))); - } - - @Nonnull - public static byte[] createTvHtml5EmbedPlayerBody( - @Nonnull final Localization localization, - @Nonnull final ContentCountry contentCountry, - @Nonnull final String videoId, - @Nonnull final Integer sts, - @Nonnull final String contentPlaybackNonce) { - // @formatter:off - return JsonWriter.string( - prepareTvHtml5EmbedJsonBuilder(localization, contentCountry, videoId) - .object("playbackContext") - .object("contentPlaybackContext") - // Signature timestamp from the JavaScript base player is needed to get - // working obfuscated URLs - .value("signatureTimestamp", sts) - .value("referer", "https://www.youtube.com/watch?v=" + videoId) - .end() - .end() - .value(CPN, contentPlaybackNonce) - .value(VIDEO_ID, videoId) - .value(CONTENT_CHECK_OK, true) - .value(RACY_CHECK_OK, true) - .done()) - .getBytes(StandardCharsets.UTF_8); - // @formatter:on - } - /** * Get the user-agent string used as the user-agent for InnerTube requests with the Android * client.