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 <johan.melkonyan1@web.de>
This commit is contained in:
Zain Arbani 2024-07-28 21:51:17 +07:00 committed by GitHub
parent ab0093ff83
commit fbf629fd62
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 61 additions and 21 deletions

View File

@ -6,11 +6,13 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import app.revanced.integrations.shared.Logger; import app.revanced.integrations.shared.Logger;
import app.revanced.integrations.youtube.settings.Settings; import app.revanced.integrations.youtube.settings.Settings;
import org.chromium.net.ExperimentalUrlRequest;
@SuppressWarnings("unused") @SuppressWarnings("unused")
public class SpoofClientPatch { public class SpoofClientPatch {
private static final boolean SPOOF_CLIENT_ENABLED = Settings.SPOOF_CLIENT.get(); 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 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. * Any unreachable ip address. Used to intentionally fail requests.
@ -52,7 +54,7 @@ public class SpoofClientPatch {
/** /**
* Injection point. * Injection point.
* * <p>
* Blocks /initplayback requests. * Blocks /initplayback requests.
*/ */
public static String blockInitPlaybackRequest(String originalUrlString) { public static String blockInitPlaybackRequest(String originalUrlString) {
@ -78,33 +80,29 @@ public class SpoofClientPatch {
* Injection point. * Injection point.
*/ */
public static int getClientTypeId(int originalClientTypeId) { public static int getClientTypeId(int originalClientTypeId) {
if (SPOOF_CLIENT_ENABLED) { return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.id : originalClientTypeId;
return SPOOF_CLIENT_TYPE.id;
}
return originalClientTypeId;
} }
/** /**
* Injection point. * Injection point.
*/ */
public static String getClientVersion(String originalClientVersion) { public static String getClientVersion(String originalClientVersion) {
if (SPOOF_CLIENT_ENABLED) { return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.version : originalClientVersion;
return SPOOF_CLIENT_TYPE.version;
}
return originalClientVersion;
} }
/** /**
* Injection point. * Injection point.
*/ */
public static String getClientModel(String originalClientModel) { public static String getClientModel(String originalClientModel) {
if (SPOOF_CLIENT_ENABLED) { return SPOOF_CLIENT_ENABLED ? SPOOF_CLIENT_TYPE.model : originalClientModel;
return SPOOF_CLIENT_TYPE.model;
} }
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. * Return true to force create the playback speed menu.
*/ */
public static boolean forceCreatePlaybackSpeedMenu(boolean original) { public static boolean forceCreatePlaybackSpeedMenu(boolean original) {
if (SPOOF_CLIENT_ENABLED && SPOOF_CLIENT_TYPE == ClientType.IOS) { return SPOOFING_TO_IOS || original;
return true;
} }
return 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 builder.build();
} }
/** /**
@ -149,7 +159,12 @@ public class SpoofClientPatch {
private enum ClientType { private enum ClientType {
// https://dumps.tadiphone.dev/dumps/oculus/eureka // 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. // 11,4 = iPhone XS Max.
// 16,2 = iPhone 15 Pro Max. // 16,2 = iPhone 15 Pro Max.
// Since the 15 supports AV1 hardware decoding, only spoof that device if this // 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. // Version number should be a valid iOS release.
// https://www.ipa4fun.com/history/185230 // 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 * YouTube
@ -175,10 +195,22 @@ public class SpoofClientPatch {
*/ */
final String version; 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.id = id;
this.model = model; this.model = model;
this.version = version; this.version = version;
this.osVersion = osVersion;
this.userAgent = userAgent;
} }
} }

View File

@ -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();
}
}