From 6533a333fa840d25f56d3ed4670cbe0f322ef033 Mon Sep 17 00:00:00 2001 From: AudricV <74829229+AudricV@users.noreply.github.com> Date: Fri, 31 Jan 2025 10:51:07 +0100 Subject: [PATCH] [YouTube] Add ability to get a visitorData from InnerTube --- .../youtube/YoutubeParsingHelper.java | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) 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 d6efbfb94..8e9643efc 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 @@ -1495,4 +1495,90 @@ public final class YoutubeParsingHelper { return null; } } + + public static String getVisitorDataFromInnertube( + @Nonnull final InnertubeClientRequestInfo innertubeClientRequestInfo, + @Nonnull final Localization localization, + @Nonnull final ContentCountry contentCountry, + @Nonnull final Map> httpHeaders, + @Nonnull final String innerTubeDomain, + @Nullable final String embedUrl) throws IOException, ExtractionException { + final JsonBuilder builder = prepareJsonBuilder( + localization, contentCountry, innertubeClientRequestInfo, embedUrl); + + final byte[] body = JsonWriter.string(builder.done()) + .getBytes(StandardCharsets.UTF_8); + + final String visitorData = JsonUtils.toJsonObject(getValidJsonResponseBody(getDownloader() + .postWithContentTypeJson(innerTubeDomain + "visitor_id", httpHeaders, body))) + .getObject("responseContext") + .getString("visitorData"); + + if (isNullOrEmpty(visitorData)) { + throw new ParsingException("Could not get visitorData"); + } + + return visitorData; + } + + @Nonnull + static JsonBuilder prepareJsonBuilder( + @Nonnull final Localization localization, + @Nonnull final ContentCountry contentCountry, + @Nonnull final InnertubeClientRequestInfo innertubeClientRequestInfo, + @Nullable final String embedUrl) { + final JsonBuilder builder = JsonObject.builder() + .object("context") + .object("client") + .value("clientName", innertubeClientRequestInfo.clientInfo.clientName) + .value("clientVersion", innertubeClientRequestInfo.clientInfo.clientVersion) + .value("clientScreen", innertubeClientRequestInfo.clientInfo.clientScreen) + .value("platform", innertubeClientRequestInfo.deviceInfo.platform); + + if (innertubeClientRequestInfo.clientInfo.visitorData != null) { + builder.value("visitorData", innertubeClientRequestInfo.clientInfo.visitorData); + } + + if (innertubeClientRequestInfo.deviceInfo.deviceMake != null) { + builder.value("deviceMake", innertubeClientRequestInfo.deviceInfo.deviceMake); + } + if (innertubeClientRequestInfo.deviceInfo.deviceModel != null) { + builder.value("deviceModel", innertubeClientRequestInfo.deviceInfo.deviceModel); + } + if (innertubeClientRequestInfo.deviceInfo.osName != null) { + builder.value("osName", innertubeClientRequestInfo.deviceInfo.osName); + } + if (innertubeClientRequestInfo.deviceInfo.osVersion != null) { + builder.value("osVersion", innertubeClientRequestInfo.deviceInfo.osVersion); + } + if (innertubeClientRequestInfo.deviceInfo.androidSdkVersion > 0) { + builder.value("androidSdkVersion", + innertubeClientRequestInfo.deviceInfo.androidSdkVersion); + } + + builder.value("hl", localization.getLocalizationCode()) + .value("gl", contentCountry.getCountryCode()) + .value("utcOffsetMinutes", 0) + .end(); + + if (embedUrl != null) { + builder.object("thirdParty") + .value("embedUrl", embedUrl) + .end(); + } + + builder.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(); + + return builder; + } }