From 0479dd265e09b0accdf6ff6b00c8e938dc5b96c7 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:58:27 +0100 Subject: [PATCH] fix(YouTube - Spoof video streams): Add 'Android Creator' (#4262) --- .../extension/shared/spoof/ClientType.java | 50 ++++++++++++++++--- .../shared/spoof/SpoofVideoStreamsPatch.java | 6 ++- .../shared/spoof/requests/PlayerRoutes.java | 3 ++ .../spoof/requests/StreamingDataRequest.java | 4 +- ...oofStreamingDataSideEffectsPreference.java | 17 ++++++- .../resources/addresources/values/arrays.xml | 2 + .../resources/addresources/values/strings.xml | 2 + 7 files changed, 72 insertions(+), 12 deletions(-) diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java index fde8a67fd..2a1e4868e 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/ClientType.java @@ -11,7 +11,9 @@ public enum ClientType { ANDROID_VR_NO_AUTH( 28, "ANDROID_VR", + "Oculus", "Quest 3", + "Android", "12", "com.google.android.apps.youtube.vr.oculus/1.56.21 (Linux; U; Android 12; GB) gzip", "32", // Android 12.1 @@ -19,10 +21,14 @@ public enum ClientType { false, "Android VR No auth" ), + // Chromecast with Google TV 4K. + // https://dumps.tadiphone.dev/dumps/google/kirkwood ANDROID_UNPLUGGED( 29, "ANDROID_UNPLUGGED", + "Google", "Google TV Streamer", + "Android", "14", "com.google.android.apps.youtube.unplugged/8.49.0 (Linux; U; Android 14; GB) gzip", "34", @@ -33,7 +39,9 @@ public enum ClientType { ANDROID_VR( ANDROID_VR_NO_AUTH.id, ANDROID_VR_NO_AUTH.clientName, + ANDROID_VR_NO_AUTH.deviceMake, ANDROID_VR_NO_AUTH.deviceModel, + ANDROID_VR_NO_AUTH.osName, ANDROID_VR_NO_AUTH.osVersion, ANDROID_VR_NO_AUTH.userAgent, ANDROID_VR_NO_AUTH.androidSdkVersion, @@ -41,18 +49,21 @@ public enum ClientType { true, "Android VR" ), - IOS_UNPLUGGED(33, + IOS_UNPLUGGED( + 33, "IOS_UNPLUGGED", + "Apple", forceAVC() ? "iPhone12,5" // 11 Pro Max (last device with iOS 13) : "iPhone16,2", // 15 Pro Max + "iOS", // iOS 13 and earlier uses only AVC. 14+ adds VP9 and AV1. forceAVC() ? "13.7.17H35" // Last release of iOS 13. - : "18.1.1.22B91", + : "18.2.22C152", forceAVC() - ? "com.google.ios.youtubeunplugged/6.45 (iPhone; U; CPU iOS 13_7 like Mac OS X)" - : "com.google.ios.youtubeunplugged/8.33 (iPhone; U; CPU iOS 18_1_1 like Mac OS X)", + ? "com.google.ios.youtubeunplugged/6.45 (iPhone12,5; U; CPU iOS 13_7 like Mac OS X)" + : "com.google.ios.youtubeunplugged/8.49 (iPhone16,2; U; CPU iOS 18_2_22 like Mac OS X)", null, // Version number should be a valid iOS release. // https://www.ipa4fun.com/history/152043/ @@ -60,11 +71,24 @@ public enum ClientType { // but 6.45 is the last version that supports iOS 13. forceAVC() ? "6.45" - : "8.33", + : "8.49", true, forceAVC() ? "iOS TV Force AVC" : "iOS TV" + ), + ANDROID_CREATOR( + 14, + "ANDROID_CREATOR", + Build.MANUFACTURER, + Build.MODEL, + "Android", + "11", + "com.google.android.apps.youtube.creator/24.45.100 (Linux; U; Android 11) gzip", + "30", + "24.45.100", + true, + "Android Creator" ); private static boolean forceAVC() { @@ -80,10 +104,20 @@ public enum ClientType { public final String clientName; /** - * Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model) + * Device model, equivalent to {@link Build#MANUFACTURER} (System property: ro.product.vendor.manufacturer) + */ + public final String deviceMake; + + /** + * Device model, equivalent to {@link Build#MODEL} (System property: ro.product.vendor.model) */ public final String deviceModel; + /** + * Device OS name. + */ + public final String osName; + /** * Device OS version. */ @@ -118,7 +152,9 @@ public enum ClientType { ClientType(int id, String clientName, + String deviceMake, String deviceModel, + String osName, String osVersion, String userAgent, @Nullable String androidSdkVersion, @@ -127,7 +163,9 @@ public enum ClientType { String friendlyName) { this.id = id; this.clientName = clientName; + this.deviceMake = deviceMake; this.deviceModel = deviceModel; + this.osName = osName; this.osVersion = osVersion; this.userAgent = userAgent; this.androidSdkVersion = androidSdkVersion; diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java index f2c0df925..c014f53e2 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java @@ -119,17 +119,19 @@ public class SpoofVideoStreamsPatch { return; } + // 'get_drm_license' has no video id and appears to happen when waiting for a paid video to start. // 'heartbeat' has no video id and appears to be only after playback has started. // 'refresh' has no video id and appears to happen when waiting for a livestream to start. // 'ad_break' has no video id. - if (path.contains("heartbeat") || path.contains("refresh") || path.contains("ad_break")) { + if (path.contains("get_drm_license") || path.contains("heartbeat") + || path.contains("refresh") || path.contains("ad_break")) { Logger.printDebug(() -> "Ignoring path: " + path); return; } String id = uri.getQueryParameter("id"); if (id == null) { - Logger.printException(() -> "Ignoring request with no id. Url: " + url); + Logger.printException(() -> "Ignoring request with no id: " + url); return; } diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java index 0f51009d8..bae0c07a3 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/PlayerRoutes.java @@ -50,7 +50,9 @@ final class PlayerRoutes { client.put("hl", language.getLanguage()); client.put("clientName", clientType.clientName); client.put("clientVersion", clientType.clientVersion); + client.put("deviceMake", clientType.deviceMake); client.put("deviceModel", clientType.deviceModel); + client.put("osName", clientType.osName); client.put("osVersion", clientType.osVersion); if (clientType.androidSdkVersion != null) { client.put("androidSdkVersion", clientType.androidSdkVersion); @@ -76,6 +78,7 @@ final class PlayerRoutes { connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("User-Agent", clientType.userAgent); + connection.setRequestProperty("X-YouTube-Client-Version", String.valueOf(clientType.id)); connection.setUseCaches(false); connection.setDoOutput(true); diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java index 0cf361bfd..5daa4b6e8 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/requests/StreamingDataRequest.java @@ -191,8 +191,8 @@ public class StreamingDataRequest { // gzip encoding doesn't response with content length (-1), // but empty response body does. if (connection.getContentLength() == 0) { - if (BaseSettings.DEBUG.get()) { - Logger.printException(() -> "Ignoring empty client: " + clientType); + if (BaseSettings.DEBUG.get() && BaseSettings.DEBUG_TOAST_ON_ERROR.get()) { + Utils.showToastShort("Ignoring empty spoof stream client: " + clientType); } } else { try (InputStream inputStream = new BufferedInputStream(connection.getInputStream()); diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java index a7fef50f9..0fc4283e2 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java @@ -81,7 +81,20 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference { (clientType == ClientType.IOS_UNPLUGGED ? "ios_tv" : "android"); - setTitle(str(key + "_title")); - setSummary(str(key + "_summary")); + String title = str(key + "_title"); + String summary = str(key + "_summary"); + + // Android VR supports AV1 but all other clients do not. + if (clientType != ClientType.ANDROID_VR && clientType != ClientType.ANDROID_VR_NO_AUTH) { + summary += '\n' + str("revanced_spoof_video_streams_about_no_av1"); + + // Android Creator does not support HDR. + if (clientType == ClientType.ANDROID_CREATOR) { + summary += '\n' + str("revanced_spoof_video_streams_about_no_hdr"); + } + } + + setTitle(title); + setSummary(summary); } } diff --git a/patches/src/main/resources/addresources/values/arrays.xml b/patches/src/main/resources/addresources/values/arrays.xml index a8bf565d9..3165e0a47 100644 --- a/patches/src/main/resources/addresources/values/arrays.xml +++ b/patches/src/main/resources/addresources/values/arrays.xml @@ -116,6 +116,7 @@ Android VR @string/revanced_spoof_video_streams_client_type_android_vr_no_auth + Android Creator Android TV iOS TV @@ -123,6 +124,7 @@ ANDROID_VR ANDROID_VR_NO_AUTH + ANDROID_CREATOR ANDROID_UNPLUGGED IOS_UNPLUGGED diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 9ffd95837..2e4a803d7 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1395,6 +1395,8 @@ AVC has a maximum resolution of 1080p, Opus audio codec is not available, and vi "• Audio track menu is missing • Stable volume is not available • Force original audio is not available" + • No AV1 video codec + • No HDR video Show in Stats for nerds Client type is shown in Stats for nerds Client is hidden in Stats for nerds