From 61182fe52d4f87239e10588335b76115f01fa4f3 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Sat, 21 Dec 2024 13:05:11 +0900 Subject: [PATCH] feat(YouTube Music - Spoof client): Add `Use old client` setting and `Default client` setting --- .../music/patches/misc/SpoofClientPatch.java | 46 ++-------- .../music/patches/misc/client/AppClient.java | 89 +++++++++++++++++++ .../extension/music/settings/Settings.java | 5 ++ .../ReVancedPreferenceFragment.java | 2 + .../shared/patches/BlockRequestPatch.java | 14 ++- .../extension/shared/patches/PatchStatus.java | 10 +++ .../utils/fix/client/SpoofClientPatch.kt | 22 +++++ .../BaseSpoofStreamingDataPatch.kt | 10 +++ .../music/settings/host/values/arrays.xml | 8 ++ .../music/settings/host/values/strings.xml | 13 +-- 10 files changed, 167 insertions(+), 52 deletions(-) create mode 100644 extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/client/AppClient.java diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/SpoofClientPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/SpoofClientPatch.java index 4cbd401a3..19c5b6935 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/SpoofClientPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/SpoofClientPatch.java @@ -1,49 +1,19 @@ package app.revanced.extension.music.patches.misc; +import app.revanced.extension.music.patches.misc.client.AppClient.ClientType; +import app.revanced.extension.music.settings.Settings; import app.revanced.extension.shared.patches.BlockRequestPatch; @SuppressWarnings("unused") public class SpoofClientPatch extends BlockRequestPatch { - private static final int CLIENT_ID_IOS_MUSIC = 26; - - /** - * 1. {@link BlockRequestPatch} is not required, as the litho component is not applied to the video action bar and flyout menu. - * 2. Audio codec is MP4A. - */ - private static final String CLIENT_VERSION_IOS_MUSIC_6_21 = "6.21"; - - /** - * 1. {@link BlockRequestPatch} is required, as the layout used in iOS should be prevented from being applied to the video action bar and flyout menu. - * 2. Audio codec is OPUS. - */ - private static final String CLIENT_VERSION_IOS_MUSIC_7_31 = "7.31.2"; - - /** - * Starting with YouTube Music 7.17.51+, the litho component has been applied to the video action bar. - *

- * So if {@code CLIENT_VERSION_IOS_MUSIC_6_21} is used in YouTube Music 7.17.51+, - * the video action bar will not load properly. - */ - private static final String CLIENT_VERSION_IOS_MUSIC = IS_7_17_OR_GREATER - ? CLIENT_VERSION_IOS_MUSIC_7_31 - : CLIENT_VERSION_IOS_MUSIC_6_21; - private static final String DEVICE_MODEL_IOS_MUSIC = "iPhone16,2"; - private static final String OS_VERSION_IOS_MUSIC = "17.7.2.21H221"; - private static final String USER_AGENT_VERSION_IOS_MUSIC = "17_7_2"; - private static final String USER_AGENT_IOS_MUSIC = "com.google.ios.youtubemusic/" + - CLIENT_VERSION_IOS_MUSIC + - "(" + - DEVICE_MODEL_IOS_MUSIC + - "; U; CPU iOS " + - USER_AGENT_VERSION_IOS_MUSIC + - " like Mac OS X)"; + private static final ClientType CLIENT_TYPE = Settings.SPOOF_CLIENT_TYPE.get(); /** * Injection point. */ public static int getClientTypeId(int originalClientTypeId) { if (SPOOF_CLIENT) { - return CLIENT_ID_IOS_MUSIC; + return CLIENT_TYPE.id; } return originalClientTypeId; @@ -54,7 +24,7 @@ public class SpoofClientPatch extends BlockRequestPatch { */ public static String getClientVersion(String originalClientVersion) { if (SPOOF_CLIENT) { - return CLIENT_VERSION_IOS_MUSIC; + return CLIENT_TYPE.clientVersion; } return originalClientVersion; @@ -65,7 +35,7 @@ public class SpoofClientPatch extends BlockRequestPatch { */ public static String getClientModel(String originalClientModel) { if (SPOOF_CLIENT) { - return DEVICE_MODEL_IOS_MUSIC; + return CLIENT_TYPE.deviceModel; } return originalClientModel; @@ -76,7 +46,7 @@ public class SpoofClientPatch extends BlockRequestPatch { */ public static String getOsVersion(String originalOsVersion) { if (SPOOF_CLIENT) { - return OS_VERSION_IOS_MUSIC; + return CLIENT_TYPE.osVersion; } return originalOsVersion; @@ -87,7 +57,7 @@ public class SpoofClientPatch extends BlockRequestPatch { */ public static String getUserAgent(String originalUserAgent) { if (SPOOF_CLIENT) { - return USER_AGENT_IOS_MUSIC; + return CLIENT_TYPE.userAgent; } return originalUserAgent; diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/client/AppClient.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/client/AppClient.java new file mode 100644 index 000000000..0a21f6196 --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/misc/client/AppClient.java @@ -0,0 +1,89 @@ +package app.revanced.extension.music.patches.misc.client; + +import android.os.Build; + +import app.revanced.extension.music.settings.Settings; + +public class AppClient { + private static final String CLIENT_VERSION_ANDROID_MUSIC = Settings.SPOOF_CLIENT_LEGACY.get() + ? "4.27.53" // Audio codec is MP4A. + : "5.29.53"; // Audio codec is OPUS. + private static final String OS_VERSION_ANDROID_MUSIC = Build.VERSION.RELEASE; + private static final String USER_AGENT_ANDROID_MUSIC = "com.google.android.apps.youtube.music/" + + CLIENT_VERSION_ANDROID_MUSIC + + " (Linux; U; Android " + + OS_VERSION_ANDROID_MUSIC + + "; GB) gzip"; + + private static final String CLIENT_VERSION_IOS_MUSIC = Settings.SPOOF_CLIENT_LEGACY.get() + ? "4.27" // Audio codec is MP4A. + : "7.31.2"; // Audio codec is OPUS. + private static final String DEVICE_MODEL_IOS_MUSIC = "iPhone14,3"; + private static final String OS_VERSION_IOS_MUSIC = "15.7.1.19H117"; + private static final String USER_AGENT_VERSION_IOS_MUSIC = "15_7_1"; + private static final String USER_AGENT_IOS_MUSIC = "com.google.ios.youtubemusic/" + + CLIENT_VERSION_IOS_MUSIC + + "(" + + DEVICE_MODEL_IOS_MUSIC + + "; U; CPU iOS " + + USER_AGENT_VERSION_IOS_MUSIC + + " like Mac OS X)"; + + private AppClient() { + } + + public enum ClientType { + ANDROID_MUSIC(21, + Build.MODEL, + OS_VERSION_ANDROID_MUSIC, + USER_AGENT_ANDROID_MUSIC, + CLIENT_VERSION_ANDROID_MUSIC + ), + IOS_MUSIC( + 26, + DEVICE_MODEL_IOS_MUSIC, + OS_VERSION_IOS_MUSIC, + USER_AGENT_IOS_MUSIC, + CLIENT_VERSION_IOS_MUSIC + ); + + /** + * YouTube + * client type + */ + public final int id; + + /** + * Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model) + */ + public final String deviceModel; + + /** + * Device OS version. + */ + public final String osVersion; + + /** + * Player user-agent. + */ + public final String userAgent; + + /** + * App version. + */ + public final String clientVersion; + + ClientType(int id, + String deviceModel, + String osVersion, + String userAgent, + String clientVersion + ) { + this.id = id; + this.deviceModel = deviceModel; + this.clientVersion = clientVersion; + this.osVersion = osVersion; + this.userAgent = userAgent; + } + } +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java index 50b9c8f35..dfdedc6d2 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -6,10 +6,12 @@ import static app.revanced.extension.music.sponsorblock.objects.CategoryBehaviou import androidx.annotation.NonNull; +import app.revanced.extension.music.patches.misc.client.AppClient.ClientType; import app.revanced.extension.music.patches.utils.PatchStatus; import app.revanced.extension.music.sponsorblock.SponsorBlockSettings; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BooleanSetting; +import app.revanced.extension.shared.settings.EnumSetting; import app.revanced.extension.shared.settings.FloatSetting; import app.revanced.extension.shared.settings.IntegerSetting; import app.revanced.extension.shared.settings.LongSetting; @@ -178,6 +180,8 @@ public class Settings extends BaseSettings { public static final BooleanSetting DISABLE_DRC_AUDIO = new BooleanSetting("revanced_disable_drc_audio", FALSE, true); public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true); public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false); + public static final BooleanSetting SPOOF_CLIENT_LEGACY = new BooleanSetting("revanced_spoof_client_legacy", FALSE, true); + public static final EnumSetting SPOOF_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_client_type", ClientType.ANDROID_MUSIC, true); // PreferenceScreen: Return YouTube Dislike @@ -248,6 +252,7 @@ public class Settings extends BaseSettings { SB_API_URL.key, SETTINGS_IMPORT_EXPORT.key, SPOOF_APP_VERSION_TARGET.key, + SPOOF_CLIENT_TYPE.key, SPOOF_STREAMING_DATA_TYPE.key, RETURN_YOUTUBE_USERNAME_ABOUT.key, RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT.key, diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java b/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java index 615551f59..313588ef9 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/settings/preference/ReVancedPreferenceFragment.java @@ -12,6 +12,7 @@ import static app.revanced.extension.music.settings.Settings.RETURN_YOUTUBE_USER import static app.revanced.extension.music.settings.Settings.SB_API_URL; import static app.revanced.extension.music.settings.Settings.SETTINGS_IMPORT_EXPORT; import static app.revanced.extension.music.settings.Settings.SPOOF_APP_VERSION_TARGET; +import static app.revanced.extension.music.settings.Settings.SPOOF_CLIENT_TYPE; import static app.revanced.extension.music.utils.ExtendedUtils.getDialogBuilder; import static app.revanced.extension.music.utils.ExtendedUtils.getLayoutParams; import static app.revanced.extension.music.utils.RestartUtils.showRestartDialog; @@ -160,6 +161,7 @@ public class ReVancedPreferenceFragment extends PreferenceFragment { } } else if (settings instanceof EnumSetting enumSetting) { if (settings.equals(RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT) + || settings.equals(SPOOF_CLIENT_TYPE) || settings.equals(SPOOF_STREAMING_DATA_TYPE)) { ResettableListPreference.showDialog(mActivity, enumSetting, 0); } diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BlockRequestPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BlockRequestPatch.java index 8e7837e1d..d4c1c458e 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BlockRequestPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BlockRequestPatch.java @@ -1,11 +1,12 @@ package app.revanced.extension.shared.patches; +import static app.revanced.extension.shared.patches.PatchStatus.SpoofClient; +import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingData; + import android.net.Uri; -import app.revanced.extension.music.settings.Settings; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.utils.Logger; -import app.revanced.extension.shared.utils.PackageUtils; @SuppressWarnings("unused") public class BlockRequestPatch { @@ -18,14 +19,9 @@ public class BlockRequestPatch { * Used in YouTube Music. * Disabled by default. */ - public static final boolean SPOOF_CLIENT = Settings.SPOOF_CLIENT.get(); + public static final boolean SPOOF_CLIENT = BaseSettings.SPOOF_CLIENT.get(); - /** - * Used in YouTube Music. - */ - public static final boolean IS_7_17_OR_GREATER = PackageUtils.getAppVersionName().compareTo("7.17.00") >= 0; - - private static final boolean BLOCK_REQUEST = SPOOF_STREAMING_DATA || (SPOOF_CLIENT && IS_7_17_OR_GREATER); + private static final boolean BLOCK_REQUEST = (SpoofStreamingData() && SPOOF_STREAMING_DATA) || (SpoofClient() && SPOOF_CLIENT); /** * Any unreachable ip address. Used to intentionally fail requests. diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java index 5006cb9cd..a90ce4e62 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/PatchStatus.java @@ -11,4 +11,14 @@ public class PatchStatus { public static ClientType SpoofStreamingDataDefaultClient() { return ClientType.IOS; } + + public static boolean SpoofClient() { + // Replace this with true If the Spoof client patch succeeds + return false; + } + + public static boolean SpoofStreamingData() { + // Replace this with true If the Spoof streaming data patch succeeds + return false; + } } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt index e0001e9e9..d22922baf 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/fix/client/SpoofClientPatch.kt @@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstruction import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable @@ -13,11 +14,14 @@ import app.revanced.patches.music.utils.patch.PatchList.SPOOF_CLIENT import app.revanced.patches.music.utils.playbackSpeedBottomSheetFingerprint import app.revanced.patches.music.utils.settings.CategoryType import app.revanced.patches.music.utils.settings.ResourceUtils.updatePatchStatus +import app.revanced.patches.music.utils.settings.addPreferenceWithIntent import app.revanced.patches.music.utils.settings.addSwitchPreference import app.revanced.patches.music.utils.settings.settingsPatch import app.revanced.patches.shared.blockrequest.blockRequestPatch import app.revanced.patches.shared.createPlayerRequestBodyWithModelFingerprint +import app.revanced.patches.shared.extension.Constants.PATCHES_PATH import app.revanced.patches.shared.indexOfModelInstruction +import app.revanced.util.findMethodOrThrow import app.revanced.util.fingerprint.matchOrThrow import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.mutableClassOrThrow @@ -258,11 +262,29 @@ val spoofClientPatch = bytecodePatch( // endregion + findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { + name == "SpoofClient" + }.replaceInstruction( + 0, + "const/4 v0, 0x1" + ) + addSwitchPreference( CategoryType.MISC, "revanced_spoof_client", "false" ) + addSwitchPreference( + CategoryType.MISC, + "revanced_spoof_client_legacy", + "false", + "revanced_spoof_client" + ) + addPreferenceWithIntent( + CategoryType.MISC, + "revanced_spoof_client_type", + "revanced_spoof_client", + ) updatePatchStatus(SPOOF_CLIENT) diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt index 35c06d749..81da85344 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/spoof/streamingdata/BaseSpoofStreamingDataPatch.kt @@ -5,15 +5,18 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.BytecodePatchBuilder import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.shared.blockrequest.blockRequestPatch +import app.revanced.patches.shared.extension.Constants.PATCHES_PATH import app.revanced.patches.shared.extension.Constants.SPOOF_PATH import app.revanced.patches.shared.formatStreamModelConstructorFingerprint import app.revanced.util.findInstructionIndicesReversedOrThrow +import app.revanced.util.findMethodOrThrow import app.revanced.util.fingerprint.definingClassOrThrow import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.matchOrThrow @@ -269,6 +272,13 @@ fun baseSpoofStreamingDataPatch( // endregion + findMethodOrThrow("$PATCHES_PATH/PatchStatus;") { + name == "SpoofStreamingData" + }.replaceInstruction( + 0, + "const/4 v0, 0x1" + ) + executeBlock() } diff --git a/patches/src/main/resources/music/settings/host/values/arrays.xml b/patches/src/main/resources/music/settings/host/values/arrays.xml index d388339a5..c0fcf769b 100644 --- a/patches/src/main/resources/music/settings/host/values/arrays.xml +++ b/patches/src/main/resources/music/settings/host/values/arrays.xml @@ -55,6 +55,14 @@ 6.11.52 4.27.53 + + @string/revanced_spoof_client_type_entry_android_music + @string/revanced_spoof_client_type_entry_ios_music + + + ANDROID_MUSIC + IOS_MUSIC + @string/revanced_spoof_streaming_data_type_entry_android_vr @string/revanced_spoof_streaming_data_type_entry_ios diff --git a/patches/src/main/resources/music/settings/host/values/strings.xml b/patches/src/main/resources/music/settings/host/values/strings.xml index 797cd1aa1..9278a9f5c 100644 --- a/patches/src/main/resources/music/settings/host/values/strings.xml +++ b/patches/src/main/resources/music/settings/host/values/strings.xml @@ -451,12 +451,15 @@ Tap the continue button and allow optimization changes." Spoof client "Spoof the client to prevent playback issues. -Limitations: -• OPUS audio codec may not be supported. -• Seekbar thumbnail may not be present. -• Watch history does not work with a brand account. - ※ When used with 'Spoofing streaming data', playback issues may occur." + Use old client + "Spoofing with version 4.27.53. + +OPUS codec may not work." + Default client + Defines a default client to spoofing. + Android Music + iOS Music Spoof streaming data "Spoof the streaming data to prevent playback issues.