From fbf629fd6278440e70b0f1fb07e4cb7c412f0949 Mon Sep 17 00:00:00 2001 From: Zain Arbani Date: Sun, 28 Jul 2024 21:51:17 +0700 Subject: [PATCH] fix(YouTube - Client Spoof): Restore missing high qualities by spoofing the iOS client user agent (#668) Co-authored-by: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Co-authored-by: oSumAtrIX --- .../patches/spoof/SpoofClientPatch.java | 74 +++++++++++++------ .../chromium/net/ExperimentalUrlRequest.java | 8 ++ 2 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java diff --git a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java index 001b4137..a83bf2a6 100644 --- a/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java +++ b/app/src/main/java/app/revanced/integrations/youtube/patches/spoof/SpoofClientPatch.java @@ -6,11 +6,13 @@ import android.net.Uri; import android.os.Build; import app.revanced.integrations.shared.Logger; import app.revanced.integrations.youtube.settings.Settings; +import org.chromium.net.ExperimentalUrlRequest; @SuppressWarnings("unused") public class SpoofClientPatch { private static final boolean SPOOF_CLIENT_ENABLED = Settings.SPOOF_CLIENT.get(); private static final ClientType SPOOF_CLIENT_TYPE = Settings.SPOOF_CLIENT_USE_IOS.get() ? ClientType.IOS : ClientType.ANDROID_VR; + private static final boolean SPOOFING_TO_IOS = SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS; /** * Any unreachable ip address. Used to intentionally fail requests. @@ -52,7 +54,7 @@ public class SpoofClientPatch { /** * Injection point. - * + *

* Blocks /initplayback requests. */ public static String blockInitPlaybackRequest(String originalUrlString) { @@ -78,33 +80,29 @@ public class SpoofClientPatch { * Injection point. */ public static int getClientTypeId(int originalClientTypeId) { - if (SPOOF_CLIENT_ENABLED) { - return SPOOF_CLIENT_TYPE.id; - } - - return originalClientTypeId; + return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.id : originalClientTypeId; } /** * Injection point. */ public static String getClientVersion(String originalClientVersion) { - if (SPOOF_CLIENT_ENABLED) { - return SPOOF_CLIENT_TYPE.version; - } - - return originalClientVersion; + return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.version : originalClientVersion; } /** * Injection point. */ public static String getClientModel(String originalClientModel) { - if (SPOOF_CLIENT_ENABLED) { - return SPOOF_CLIENT_TYPE.model; - } + return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.model : originalClientModel; + } - return originalClientModel; + /** + * Injection point. + * Fix video qualities missing, if spoofing to iOS by using the correct client OS version. + */ + public static String getOsVersion(String originalOsVersion) { + return SPOOFING_TO_IOS ? ClientType.IOS.osVersion : originalOsVersion; } /** @@ -127,11 +125,23 @@ public class SpoofClientPatch { * Return true to force create the playback speed menu. */ public static boolean forceCreatePlaybackSpeedMenu(boolean original) { - if (SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS) { - return true; + return SPOOFING_TO_IOS || original; + } + + + /** + * Injection point. + * Fix video qualities missing, if spoofing to iOS by using the correct iOS user-agent. + */ + public static ExperimentalUrlRequest overrideUserAgent(ExperimentalUrlRequest.Builder builder, String url) { + if (SPOOFING_TO_IOS) { + String path = Uri.parse(url).getPath(); + if (path != null && path.contains("player")) { + return builder.addHeader("User-Agent", ClientType.IOS.userAgent).build(); + } } - return original; + return builder.build(); } /** @@ -149,7 +159,12 @@ public class SpoofClientPatch { private enum ClientType { // https://dumps.tadiphone.dev/dumps/oculus/eureka - ANDROID_VR(28, "Quest 3", "1.56.21"), + ANDROID_VR(28, + "Quest 3", + "1.56.21", + "12", + "com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip" + ), // 11,4 = iPhone XS Max. // 16,2 = iPhone 15 Pro Max. // Since the 15 supports AV1 hardware decoding, only spoof that device if this @@ -157,7 +172,12 @@ public class SpoofClientPatch { // // Version number should be a valid iOS release. // https://www.ipa4fun.com/history/185230 - IOS(5, deviceHasAV1HardwareDecoding() ? "iPhone16,2" : "iPhone11,4", "19.10.7"); + IOS(5, + deviceHasAV1HardwareDecoding() ? "iPhone16,2" : "iPhone11,4", + "19.10.7", + "17.5.1.21F90", + "com.google.ios.youtube/19.10.7 (iPhone; U; CPU iOS 17_5_1 like Mac OS X)" + ); /** * YouTube @@ -175,10 +195,22 @@ public class SpoofClientPatch { */ final String version; - ClientType(int id, String model, String version) { + /** + * Device OS version. + */ + final String osVersion; + + /** + * Player user-agent. + */ + final String userAgent; + + ClientType(int id, String model, String version, String osVersion, String userAgent) { this.id = id; this.model = model; this.version = version; + this.osVersion = osVersion; + this.userAgent = userAgent; } } diff --git a/stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java b/stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java new file mode 100644 index 00000000..cdf2593e --- /dev/null +++ b/stub/src/main/java/org/chromium/net/ExperimentalUrlRequest.java @@ -0,0 +1,8 @@ +package org.chromium.net; + +public abstract class ExperimentalUrlRequest { + public abstract class Builder { + public abstract ExperimentalUrlRequest.Builder addHeader(String name, String value); + public abstract ExperimentalUrlRequest build(); + } +}