From 50850a1fc6715203e71c53cb5e610bc1d839dd90 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Tue, 17 Dec 2024 13:27:09 +0900 Subject: [PATCH] fix(YouTube Music - Spoof client): Action bar not loading as of YouTube Music 7.17.51 --- .../music/patches/misc/SpoofClientPatch.java | 54 +++++++----- .../extension/music/settings/Settings.java | 2 +- .../ReVancedPreferenceFragment.java | 4 +- .../shared/patches/BlockRequestPatch.java | 84 +++++++++++++++++++ .../shared/patches/client/AppClient.java | 6 +- .../spoof/SpoofStreamingDataPatch.java | 58 +------------ .../shared/settings/BaseSettings.java | 4 + .../utils/fix/client/SpoofClientPatch.kt | 10 ++- .../streamingdata/SpoofStreamingDataPatch.kt | 7 ++ .../shared/blockrequest/BlockRequestPatch.kt | 57 +++++++++++++ .../shared/blockrequest/Fingerprints.kt | 40 +++++++++ .../BaseSpoofStreamingDataPatch.kt | 41 +-------- .../spoof/streamingdata/Fingerprints.kt | 32 ------- .../music/settings/host/values/arrays.xml | 10 +++ .../music/settings/host/values/strings.xml | 10 ++- 15 files changed, 262 insertions(+), 157 deletions(-) create mode 100644 extensions/shared/src/main/java/app/revanced/extension/shared/patches/BlockRequestPatch.java create mode 100644 patches/src/main/kotlin/app/revanced/patches/shared/blockrequest/BlockRequestPatch.kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/shared/blockrequest/Fingerprints.kt 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 edad594b4..eb02ca092 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,25 +1,32 @@ package app.revanced.extension.music.patches.misc; -import app.revanced.extension.music.settings.Settings; +import app.revanced.extension.shared.patches.BlockRequestPatch; @SuppressWarnings("unused") -public class SpoofClientPatch { +public class SpoofClientPatch extends BlockRequestPatch { private static final int CLIENT_ID_IOS_MUSIC = 26; + /** - * The hardcoded client version of the iOS app used for InnerTube requests with this client. - * + * 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. *
- * It can be extracted by getting the latest release version of the app on - * the App - * Store page of the YouTube app, in the {@code What¡¯s New} section. - *
- */ - private static final String CLIENT_VERSION_IOS_MUSIC = "6.21"; - /** - * See this GitHub Gist for more - * information. - * + * 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_6_21 + : CLIENT_VERSION_IOS_MUSIC_7_31; 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"; @@ -31,13 +38,11 @@ public class SpoofClientPatch { USER_AGENT_VERSION_IOS_MUSIC + " like Mac OS X)"; - private static final boolean SPOOF_CLIENT_ENABLED = Settings.SPOOF_CLIENT.get(); - /** * Injection point. */ public static int getClientTypeId(int originalClientTypeId) { - if (SPOOF_CLIENT_ENABLED) { + if (SPOOF_CLIENT) { return CLIENT_ID_IOS_MUSIC; } @@ -48,7 +53,7 @@ public class SpoofClientPatch { * Injection point. */ public static String getClientVersion(String originalClientVersion) { - if (SPOOF_CLIENT_ENABLED) { + if (SPOOF_CLIENT) { return CLIENT_VERSION_IOS_MUSIC; } @@ -59,7 +64,7 @@ public class SpoofClientPatch { * Injection point. */ public static String getClientModel(String originalClientModel) { - if (SPOOF_CLIENT_ENABLED) { + if (SPOOF_CLIENT) { return DEVICE_MODEL_IOS_MUSIC; } @@ -70,7 +75,7 @@ public class SpoofClientPatch { * Injection point. */ public static String getOsVersion(String originalOsVersion) { - if (SPOOF_CLIENT_ENABLED) { + if (SPOOF_CLIENT) { return OS_VERSION_IOS_MUSIC; } @@ -81,7 +86,7 @@ public class SpoofClientPatch { * Injection point. */ public static String getUserAgent(String originalUserAgent) { - if (SPOOF_CLIENT_ENABLED) { + if (SPOOF_CLIENT) { return USER_AGENT_IOS_MUSIC; } @@ -92,16 +97,19 @@ public class SpoofClientPatch { * Injection point. */ public static boolean isClientSpoofingEnabled() { - return SPOOF_CLIENT_ENABLED; + return SPOOF_CLIENT; } /** * Injection point. + ** When spoofing the client to iOS, the playback speed menu is missing from the player response. + * This fix is required because playback speed is not available in YouTube Music Podcasts. + *
* Return true to force create the playback speed menu. */ public static boolean forceCreatePlaybackSpeedMenu(boolean original) { - if (SPOOF_CLIENT_ENABLED) { + if (SPOOF_CLIENT) { return true; } return original; 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 19d940bd0..8e56282cf 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 @@ -175,7 +175,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting DISABLE_CAIRO_SPLASH_ANIMATION = new BooleanSetting("revanced_disable_cairo_splash_animation", FALSE, true); 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 SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", FALSE, true); public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false); @@ -239,6 +238,7 @@ public class Settings extends BaseSettings { SB_API_URL.key, SETTINGS_IMPORT_EXPORT.key, SPOOF_APP_VERSION_TARGET.key, + SPOOF_STREAMING_DATA_TYPE.key, RETURN_YOUTUBE_USERNAME_ABOUT.key, RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT.key, RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY.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 70ef1de5a..f6787d62a 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 @@ -17,6 +17,7 @@ import static app.revanced.extension.music.utils.ExtendedUtils.getLayoutParams; import static app.revanced.extension.music.utils.RestartUtils.showRestartDialog; import static app.revanced.extension.shared.settings.BaseSettings.RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT; import static app.revanced.extension.shared.settings.BaseSettings.RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY; +import static app.revanced.extension.shared.settings.BaseSettings.SPOOF_STREAMING_DATA_TYPE; import static app.revanced.extension.shared.settings.Setting.getSettingFromPath; import static app.revanced.extension.shared.utils.ResourceUtils.getStringArray; import static app.revanced.extension.shared.utils.StringRef.str; @@ -158,7 +159,8 @@ public class ReVancedPreferenceFragment extends PreferenceFragment { Logger.printDebug(() -> "Failed to find the right value: " + dataString); } } else if (settings instanceof EnumSetting> enumSetting) { - if (settings.equals(RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT)) { + if (settings.equals(RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT) + || 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 new file mode 100644 index 000000000..297ad3e5d --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/BlockRequestPatch.java @@ -0,0 +1,84 @@ +package app.revanced.extension.shared.patches; + +import android.net.Uri; + +import app.revanced.extension.music.settings.Settings; +import app.revanced.extension.shared.utils.Logger; +import app.revanced.extension.shared.utils.PackageUtils; +import app.revanced.extension.shared.settings.BaseSettings; + +@SuppressWarnings("unused") +public class BlockRequestPatch { + /** + * Used in YouTube and YouTube Music. + */ + public static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_STREAMING_DATA.get(); + + /** + * Used in YouTube Music. + * Disabled by default. + */ + public static final boolean SPOOF_CLIENT = Settings.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); + + /** + * Any unreachable ip address. Used to intentionally fail requests. + */ + private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0"; + private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING); + + /** + * Injection point. + * Blocks /get_watch requests by returning an unreachable URI. + * + * @param playerRequestUri The URI of the player request. + * @return An unreachable URI if the request is a /get_watch request, otherwise the original URI. + */ + public static Uri blockGetWatchRequest(Uri playerRequestUri) { + if (BLOCK_REQUEST) { + try { + String path = playerRequestUri.getPath(); + + if (path != null && path.contains("get_watch")) { + Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri"); + + return UNREACHABLE_HOST_URI; + } + } catch (Exception ex) { + Logger.printException(() -> "blockGetWatchRequest failure", ex); + } + } + + return playerRequestUri; + } + + /** + * Injection point. + *
+ * Blocks /initplayback requests. + */ + public static String blockInitPlaybackRequest(String originalUrlString) { + if (BLOCK_REQUEST) { + try { + var originalUri = Uri.parse(originalUrlString); + String path = originalUri.getPath(); + + if (path != null && path.contains("initplayback")) { + Logger.printDebug(() -> "Blocking 'initplayback' by clearing query"); + + return originalUri.buildUpon().clearQuery().build().toString(); + } + } catch (Exception ex) { + Logger.printException(() -> "blockInitPlaybackRequest failure", ex); + } + } + + return originalUrlString; + } +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java index 80033c845..2f6102346 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/client/AppClient.java @@ -41,19 +41,19 @@ public class AppClient { USER_AGENT_VERSION_IOS + " like Mac OS X)"; - // IOS_MUSIC + // IOS MUSIC /** * The hardcoded client version of the iOS app used for InnerTube requests with this client. * *
* It can be extracted by getting the latest release version of the app on * the App - * Store page of the YouTube app, in the {@code What’s New} section. + * Store page of the YouTube Music app, in the {@code What’s New} section. *
*/ private static final String CLIENT_VERSION_IOS_MUSIC = "7.31.2"; private static final String USER_AGENT_IOS_MUSIC = "com.google.ios.youtubemusic/" + - CLIENT_VERSION_IOS + + CLIENT_VERSION_IOS_MUSIC + "(" + DEVICE_MODEL_IOS + "; U; CPU iOS " + diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java index 2bb2a233b..b3294aac3 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/SpoofStreamingDataPatch.java @@ -8,68 +8,14 @@ import androidx.annotation.Nullable; import java.nio.ByteBuffer; import java.util.Map; +import app.revanced.extension.shared.patches.BlockRequestPatch; import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.patches.spoof.requests.StreamingDataRequest; @SuppressWarnings("unused") -public class SpoofStreamingDataPatch { - private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_STREAMING_DATA.get(); - /** - * Any unreachable ip address. Used to intentionally fail requests. - */ - private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0"; - private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING); - - /** - * Injection point. - * Blocks /get_watch requests by returning an unreachable URI. - * - * @param playerRequestUri The URI of the player request. - * @return An unreachable URI if the request is a /get_watch request, otherwise the original URI. - */ - public static Uri blockGetWatchRequest(Uri playerRequestUri) { - if (SPOOF_STREAMING_DATA) { - try { - String path = playerRequestUri.getPath(); - - if (path != null && path.contains("get_watch")) { - Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri"); - - return UNREACHABLE_HOST_URI; - } - } catch (Exception ex) { - Logger.printException(() -> "blockGetWatchRequest failure", ex); - } - } - - return playerRequestUri; - } - - /** - * Injection point. - *
- * Blocks /initplayback requests.
- */
- public static String blockInitPlaybackRequest(String originalUrlString) {
- if (SPOOF_STREAMING_DATA) {
- try {
- var originalUri = Uri.parse(originalUrlString);
- String path = originalUri.getPath();
-
- if (path != null && path.contains("initplayback")) {
- Logger.printDebug(() -> "Blocking 'initplayback' by clearing query");
-
- return originalUri.buildUpon().clearQuery().build().toString();
- }
- } catch (Exception ex) {
- Logger.printException(() -> "blockInitPlaybackRequest failure", ex);
- }
- }
-
- return originalUrlString;
- }
+public class SpoofStreamingDataPatch extends BlockRequestPatch {
/**
* Injection point.
diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java b/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java
index 904465ea1..ba2c43503 100644
--- a/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java
+++ b/extensions/shared/src/main/java/app/revanced/extension/shared/settings/BaseSettings.java
@@ -37,6 +37,10 @@ public class BaseSettings {
public static final EnumSetting