From 21e579b8868899dd95d730bcb1dc05852536b3ca Mon Sep 17 00:00:00 2001 From: AudricV <74829229+AudricV@users.noreply.github.com> Date: Mon, 18 Nov 2024 04:00:36 +0530 Subject: [PATCH 1/4] [PATCH] [YouTube] Remove age-restricted videos workaround, start poTokens support --- .../services/youtube/PoTokenProvider.java | 41 +++ .../services/youtube/PoTokenResult.java | 22 ++ .../youtube/YoutubeParsingHelper.java | 35 +- .../services/youtube/YoutubeStreamHelper.java | 153 +++++++++ .../extractors/YoutubeStreamExtractor.java | 298 +++++++----------- 5 files changed, 342 insertions(+), 207 deletions(-) create mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenProvider.java create mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenResult.java create mode 100644 extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/YoutubeStreamHelper.java diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenProvider.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenProvider.java new file mode 100644 index 0000000000..d3d2a64552 --- /dev/null +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenProvider.java @@ -0,0 +1,41 @@ +package org.schabi.newpipe.extractor.services.youtube; + +import javax.annotation.Nullable; + +/** + * An interface to provide poTokens to YouTube player requests. + * + *
+ * On some major clients, YouTube requires that the integrity of the device passes some checks to + * allow playback. + *
+ * + *+ * These checks involve running codes to verify the integrity and using their result to generate a + * poToken (which likely stands for proof of origin token), using a visitor data ID for logged-out + * users. + *
+ * + *+ * These tokens may have a role in triggering the sign in requirement. + *
+ */ +public interface PoTokenProvider { + + /** + * Get a {@link PoTokenResult} specific to the desktop website, a.k.a. the WEB InnerTube client. + * + *+ * To be generated and valid, poTokens from this client must be generated using Google's + * BotGuard machine, which requires a JavaScript engine with a good DOM implementation. They + * must be added to adaptive/DASH streaming URLs with the {@code pot} parameter. + *
+ * + * @return a {@link PoTokenResult} specific to the WEB InnerTube client + */ + @Nullable + PoTokenResult getWebClientPoToken(); + + @Nullable + PoTokenResult getAndroidClientPoToken(); +} diff --git a/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenResult.java b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenResult.java new file mode 100644 index 0000000000..af2520870e --- /dev/null +++ b/extractor/src/main/java/org/schabi/newpipe/extractor/services/youtube/PoTokenResult.java @@ -0,0 +1,22 @@ +package org.schabi.newpipe.extractor.services.youtube; + +import javax.annotation.Nonnull; +import java.util.Objects; + +public final class PoTokenResult { + + /** + * The visitor data associated with a poToken. + */ + public final String visitorData; + + /** + * The poToken, a Protobuf object encoded as a base 64 string. + */ + public final String poToken; + + public PoTokenResult(@Nonnull final String visitorData, @Nonnull final String poToken) { + this.visitorData = Objects.requireNonNull(visitorData); + this.poToken = Objects.requireNonNull(poToken); + } +} 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 f514b61d61..deb6c92c04 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 @@ -1200,9 +1200,10 @@ public static JsonBuilder
* On some major clients, YouTube requires that the integrity of the device passes some checks to
* allow playback.
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 f2c0a3d114..ac60cd10ac 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
@@ -116,6 +116,8 @@ public class YoutubeStreamExtractor extends StreamExtractor {
private String androidCpn;
private String tvHtml5SimplyEmbedCpn;
+ private static boolean forceFetchIosClient;
+
public YoutubeStreamExtractor(final StreamingService service, final LinkHandler linkHandler) {
super(service, linkHandler);
}
@@ -781,9 +783,7 @@ public void onFetchPage(@Nonnull final Downloader downloader)
checkPlayabilityStatus(playerResponse, playerResponse.getObject("playabilityStatus"));
- if (webPoTokenResult == null) {
- // TODO: add ability to force fetch iOS player response even if
- // webPoTokenResult != null
+ if (forceFetchIosClient || webPoTokenResult == null) {
iosCpn = generateContentPlaybackNonce();
final JsonObject iosPlayerResponse = YoutubeStreamHelper.getIosPlayerResponse(
contentCountry, localization, videoId, iosCpn);
@@ -795,10 +795,10 @@ public void onFetchPage(@Nonnull final Downloader downloader)
final JsonObject iosStreamingData = iosPlayerResponse.getObject(STREAMING_DATA);
if (!isNullOrEmpty(iosStreamingData)) {
this.iosStreamingData = iosStreamingData;
- // TODO: only assign playerCaptionsTracklistRenderer when iOS client
- // fetching is not forced
- playerCaptionsTracklistRenderer = iosPlayerResponse.getObject("captions")
- .getObject("playerCaptionsTracklistRenderer");
+ if (!forceFetchIosClient) {
+ playerCaptionsTracklistRenderer = iosPlayerResponse.getObject("captions")
+ .getObject("playerCaptionsTracklistRenderer");
+ }
}
}
@@ -1515,8 +1515,33 @@ public List
+ * This method allows setting an implementation of {@link PoTokenProvider} which will be used
+ * to obtain poTokens required for YouTube player requests. These tokens are used by YouTube to verify the
+ * integrity of the device and may be necessary for playback at times.
+ *
+ * This method allows setting a flag to force the fetching of the iOS player response, even if a
+ * valid webPoTokenResult is available. This can be useful in scenarios where streams from the iOS player
+ * response is preferred.
+ *
* On some major clients, YouTube requires that the integrity of the device passes some checks to
@@ -21,6 +20,9 @@
*
* These tokens may have a role in triggering the sign in requirement.
*
- * This method allows setting an implementation of {@link PoTokenProvider} which will be used
- * to obtain poTokens required for YouTube player requests. These tokens are used by YouTube to verify the
- * integrity of the device and may be necessary for playback at times.
+ * This method allows setting an implementation of {@link PoTokenProvider} which will
+ * be used to obtain poTokens required for YouTube player requests. These tokens are
+ * used by YouTube to verify the integrity of the device and may be necessary for
+ * playback at times.
*
* This method allows setting a flag to force the fetching of the iOS player response, even if a
- * valid webPoTokenResult is available. This can be useful in scenarios where streams from the iOS player
- * response is preferred.
+ * valid webPoTokenResult is available. This can be useful in scenarios where streams from the
+ * iOS player response is preferred.
*