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