diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java index 17462aac35..113f2d4a3d 100644 --- a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/extractors/YoutubeStreamExtractor.java @@ -868,6 +868,10 @@ public void onFetchPage(@Nonnull final Downloader downloader) playerMicroFormatRenderer = youtubePlayerResponse.getObject("microformat") .getObject("playerMicroformatRenderer"); + if (isPlayerResponseNotValid(playerResponse, videoId)) { + throw new ExtractionException("Initial player response is not valid"); + } + final byte[] body = JsonWriter.string( prepareDesktopJsonBuilder(localization, contentCountry) .value(VIDEO_ID, videoId) @@ -1058,6 +1062,11 @@ private void fetchTvHtml5EmbedJsonPlayer(@Nonnull final ContentCountry contentCo final JsonObject tvHtml5EmbedPlayerResponse = getJsonPostResponse(PLAYER, createDesktopPlayerBody(localization, contentCountry, videoId, sts, true, html5Cpn), localization); + + if (isPlayerResponseNotValid(tvHtml5EmbedPlayerResponse, videoId)) { + return; + } + final JsonObject streamingData = tvHtml5EmbedPlayerResponse.getObject( STREAMING_DATA); if (!isNullOrEmpty(streamingData)) { @@ -1067,35 +1076,40 @@ private void fetchTvHtml5EmbedJsonPlayer(@Nonnull final ContentCountry contentCo } /** - * Checks whether an additional player response is not valid. + * Checks whether a player response is invalid. * *
* If YouTube detect that requests come from a third party client, they may replace the real * player response by another one of a video saying that this content is not available on this - * app and to watch it on the latest version of YouTube. + * app and to watch it on the latest version of YouTube. This behavior has been observed on the + * {@code ANDROID} client, see + * + * https://github.com/TeamNewPipe/NewPipe/issues/8713. *
* *- * We can detect this by checking whether the video ID of the player response returned is the - * same as the one requested by the extractor. + * YouTube may also sometimes for currently unknown reasons rate-limit an IP, and replace the + * real one by a player response with a video that says that the requested video is + * unavailable. This behaviour has been observed in Piped on the InnerTube clients used by the + * extractor ({@code ANDROID} and {@code WEB} clients) which should apply for all clients, see + * + * https://github.com/TeamPiped/Piped/issues/2487. *
* *- * This behavior has been already observed on the {@code ANDROID} client, see - * - * https://github.com/TeamNewPipe/NewPipe/issues/8713. + * We can detect this by checking whether the video ID of the player response returned is the + * same as the one requested by the extractor. *
* - * @param additionalPlayerResponse an additional response to the one of the {@code HTML5} - * client used - * @param videoId the video ID of the content requested + * @param playerResponse a player response from any client + * @param videoId the video ID of the content requested * @return whether the video ID of the player response is not equal to the one requested */ private static boolean isPlayerResponseNotValid( - @Nonnull final JsonObject additionalPlayerResponse, + @Nonnull final JsonObject playerResponse, @Nonnull final String videoId) { - return !videoId.equals(additionalPlayerResponse.getObject("videoDetails") - .getString("videoId", "")); + return !videoId.equals(playerResponse.getObject("videoDetails") + .getString("videoId")); } private static void storePlayerJs() throws ParsingException {