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 fff1baf8..6669717f 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 @@ -81,10 +81,16 @@ public final class YoutubeParsingHelper { } /** - * The base URL of requests of the {@code WEB} client to the InnerTube internal API + * The base URL of requests of the {@code WEB} clients to the InnerTube internal API. */ public static final String YOUTUBEI_V1_URL = "https://www.youtube.com/youtubei/v1/"; + /** + * The base URL of requests of non-web clients to the InnerTube internal API. + */ + public static final String YOUTUBEI_V1_GAPIS_URL = + "https://youtubei.googleapis.com/youtubei/v1/"; + /** * A parameter to disable pretty-printed response of InnerTube requests, to reduce response * sizes. @@ -114,6 +120,26 @@ public final class YoutubeParsingHelper { public static final String CPN = "cpn"; public static final String VIDEO_ID = "videoId"; + /** + * A parameter sent by official clients named {@code contentCheckOk}. + * + *
+ * Setting it to {@code true} allows us to get streaming data on videos with a warning about + * what the sensible content they contain. + *
+ */ + public static final String CONTENT_CHECK_OK = "contentCheckOk"; + + /** + * A parameter which may be send by official clients named {@code racyCheckOk}. + * + *+ * What this parameter does is not really known, but it seems to be linked to sensitive + * contents such as age-restricted content. + *
+ */ + public static final String RACY_CHECK_OK = "racyCheckOk"; + /** * The client version for InnerTube requests with the {@code WEB} client, used as the last * fallback if the extraction of the real one failed. @@ -150,6 +176,12 @@ public final class YoutubeParsingHelper { */ private static final String MOBILE_YOUTUBE_CLIENT_VERSION = "17.10.35"; + /** + * The hardcoded client version of the Android app used for InnerTube requests with this + * client. + */ + private static final String TVHTML5_SIMPLY_EMBED_CLIENT_VERSION = "2.0"; + private static String clientVersion; private static String key; @@ -664,6 +696,9 @@ public final class YoutubeParsingHelper { return clientVersion; } + // Always extract latest client version, by trying first to extract it from the JavaScript + // service worker, then from HTML search results page as a fallback, to prevent + // fingerprinting based on the client version used try { extractClientVersionAndKeyFromSwJs(); } catch (final Exception e) { @@ -674,6 +709,7 @@ public final class YoutubeParsingHelper { return clientVersion; } + // Fallback to the hardcoded one if it's valid if (areHardcodedClientVersionAndKeyValid()) { clientVersion = HARDCODED_CLIENT_VERSION; return clientVersion; @@ -690,6 +726,9 @@ public final class YoutubeParsingHelper { return key; } + // Always extract the key used by the webiste, by trying first to extract it from the + // JavaScript service worker, then from HTML search results page as a fallback, to prevent + // fingerprinting based on the key and/or invalid key issues try { extractClientVersionAndKeyFromSwJs(); } catch (final Exception e) { @@ -700,6 +739,7 @@ public final class YoutubeParsingHelper { return key; } + // Fallback to the hardcoded one if it's valid if (areHardcodedClientVersionAndKeyValid()) { key = HARDCODED_KEY; return key; @@ -1058,8 +1098,8 @@ public final class YoutubeParsingHelper { headers.put("User-Agent", Collections.singletonList(userAgent)); headers.put("X-Goog-Api-Format-Version", Collections.singletonList("2")); - final String baseEndpointUrl = "https://youtubei.googleapis.com/youtubei/v1/" + endpoint - + "?key=" + innerTubeApiKey + DISABLE_PRETTY_PRINT_PARAMETER; + final String baseEndpointUrl = YOUTUBEI_V1_GAPIS_URL + endpoint + "?key=" + innerTubeApiKey + + DISABLE_PRETTY_PRINT_PARAMETER; final Response response = getDownloader().post(isNullOrEmpty(endPartOfUrlRequest) ? baseEndpointUrl : baseEndpointUrl + endPartOfUrlRequest, @@ -1146,30 +1186,24 @@ public final class YoutubeParsingHelper { } @Nonnull - public static JsonBuilder* This is needed for mocks in YouTube stream tests, because when they are ran, the * {@code signatureTimestamp} is known (the {@code sts} string) so a different body than the @@ -1523,19 +1464,15 @@ public class YoutubeStreamExtractor extends StreamExtractor { *
* By default, the fetch of the Android client will be made only on videos, in order to reduce * data usage, because available streams of the Android client will be almost equal to the ones - * available on the web client. + * available on the {@code WEB} client: you can get exclusively a 48kbps audio stream and a + * 3GPP very low stream (which is, most of times, a 144p8 stream). *
* - *- * Enabling this option will allow you to get a 48kbps audio - * stream on livestreams without fetching the DASH manifest returned in YouTube's player - * response. - *
- * @param forceFetchOfAndroidClientValue whether to always fetch the Android client and not - * only for videos + * @param forceFetchAndroidClientValue whether to always fetch the Android client and not only + * for videos */ - public static void forceFetchOfAndroidClient(final boolean forceFetchOfAndroidClientValue) { - isAndroidClientFetchForced = forceFetchOfAndroidClientValue; + public static void forceFetchAndroidClient(final boolean forceFetchAndroidClientValue) { + isAndroidClientFetchForced = forceFetchAndroidClientValue; } /** @@ -1543,16 +1480,19 @@ public class YoutubeStreamExtractor extends StreamExtractor { * ** By default, the fetch of the iOS client will be made only on livestreams, in order to get an - * HLS manifest with separated audio and video. + * HLS manifest with separated audio and video which has also an higher replay time (up to one + * hour, depending of the content instead of 30 seconds with non-iOS clients). *
+ * *- * Enabling this option will allow you to get an - * HLS manifest also for videos. + * Enabling this option will allow you to get an HLS manifest also for regular videos, which + * contains resolutions up to 1080p60. *
- * @param forceFetchOfIosClientValue whether to always fetch the iOS client and not only for - * livestreams + * + * @param forceFetchIosClientValue whether to always fetch the iOS client and not only for + * livestreams */ - public static void forceFetchOfIosClient(final boolean forceFetchOfIosClientValue) { - isIosClientFetchForced = forceFetchOfIosClientValue; + public static void forceFetchIosClient(final boolean forceFetchIosClientValue) { + isIosClientFetchForced = forceFetchIosClientValue; } }