From e2a0fae0fbdecebd704574f3f4cfca2eee8c549c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ho=C3=A0ng=20Gia=20B=E1=BA=A3o?= <70064328+YT-Advanced@users.noreply.github.com> Date: Mon, 16 Dec 2024 12:15:30 +0700 Subject: [PATCH] fix(Disable Music playback speed): Use `microformat` to fetch --- .../shared/patches/client/AppClient.java | 56 +++++++++++++-- .../patches/spoof/requests/PlayerRoutes.java | 23 +++---- .../patches/video/PlaybackSpeedPatch.java | 25 ++++--- ...ylistRequest.java => CategoryRequest.java} | 68 +++++-------------- .../extension/youtube/settings/Settings.java | 1 - .../youtube/settings/host/values/strings.xml | 7 +- .../youtube/settings/xml/revanced_prefs.xml | 1 - 7 files changed, 93 insertions(+), 88 deletions(-) rename extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/{PlaylistRequest.java => CategoryRequest.java} (69%) 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 80033c845a..5e2f863a46 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 @@ -7,6 +7,19 @@ import androidx.annotation.Nullable; public class AppClient { + + // WEB + private static final String CLIENT_VERSION_WEB = "2.20240726.00.00"; + private static final String DEVICE_MODEL_WEB = "Surface Book 3"; + private static final String OS_NAME_WEB = "Windows"; + private static final String OS_VERSION_WEB = "10"; + private static final String USER_AGENT_WEB = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:129.0)" + + " Gecko/20100101" + + " Firefox/129.0"; + + // ANDROID + private static final String OS_NAME_ANDROID = "Android"; + // IOS /** * The hardcoded client version of the iOS app used for InnerTube requests with this client. @@ -18,6 +31,7 @@ public class AppClient { *
*/ private static final String CLIENT_VERSION_IOS = "19.49.5"; + private static final String DEVICE_MAKE_IOS = "Apple"; /** * The device machine id for the iPhone 16 Pro Max (iPhone17,2), used to get HDR with AV1 hardware decoding. * @@ -27,6 +41,7 @@ public class AppClient { * */ private static final String DEVICE_MODEL_IOS = "iPhone17,2"; + private static final String OS_NAME_IOS = "iOS"; /** * The minimum supported OS version for the iOS YouTube client is iOS 14.0. * Using an invalid OS version will use the AVC codec. @@ -71,6 +86,7 @@ public class AppClient { * */ private static final String CLIENT_VERSION_ANDROID_VR = "1.61.47"; + private static final String DEVICE_MAKE_ANDROID_VR = "Oculus"; /** * The device machine id for the Meta Quest 3, used to get opus codec with the Android VR client. * @@ -80,7 +96,7 @@ public class AppClient { * */ private static final String DEVICE_MODEL_ANDROID_VR = "Quest 3"; - private static final String OS_VERSION_ANDROID_VR = "12"; + private static final String OS_VERSION_ANDROID_VR = "12L"; /** * The SDK version for Android 12 is 31, * but for some reason the build.props for the {@code Quest 3} state that the SDK version is 32. @@ -95,7 +111,7 @@ public class AppClient { CLIENT_VERSION_ANDROID_VR + " (Linux; U; Android " + OS_VERSION_ANDROID_VR + - "; GB) gzip"; + "; eureka-user Build/SQ3A.220605.009.A1) gzip"; // ANDROID UNPLUGGED private static final String CLIENT_VERSION_ANDROID_UNPLUGGED = "8.49.0"; @@ -120,8 +136,20 @@ private AppClient() { } public enum ClientType { + WEB(1, + null, + DEVICE_MODEL_WEB, + OS_NAME_WEB, + OS_VERSION_WEB, + USER_AGENT_WEB, + null, + CLIENT_VERSION_WEB, + true + ), IOS(5, + DEVICE_MAKE_IOS, DEVICE_MODEL_IOS, + OS_NAME_IOS, OS_VERSION_IOS, USER_AGENT_IOS, null, @@ -129,7 +157,9 @@ public enum ClientType { false ), ANDROID_VR(28, + DEVICE_MAKE_ANDROID_VR, DEVICE_MODEL_ANDROID_VR, + OS_NAME_ANDROID, OS_VERSION_ANDROID_VR, USER_AGENT_ANDROID_VR, ANDROID_SDK_VERSION_ANDROID_VR, @@ -137,16 +167,19 @@ public enum ClientType { true ), ANDROID_UNPLUGGED(29, + null, DEVICE_MODEL_ANDROID_UNPLUGGED, + OS_NAME_ANDROID, OS_VERSION_ANDROID_UNPLUGGED, USER_AGENT_ANDROID_UNPLUGGED, ANDROID_SDK_VERSION_ANDROID_UNPLUGGED, CLIENT_VERSION_ANDROID_UNPLUGGED, true ), - IOS_MUSIC( - 26, + IOS_MUSIC(26, + DEVICE_MAKE_IOS, DEVICE_MODEL_IOS, + OS_NAME_IOS, OS_VERSION_IOS, USER_AGENT_IOS_MUSIC, null, @@ -162,11 +195,22 @@ public enum ClientType { public final String clientName; + /** + * Device manufacturer. + */ + @Nullable + public final String deviceMake; + /** * Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model) */ public final String deviceModel; + /** + * Device OS name. + */ + public final String osName; + /** * Device OS version. */ @@ -195,7 +239,9 @@ public enum ClientType { public final boolean canLogin; ClientType(int id, + String deviceMake, String deviceModel, + String osName, String osVersion, String userAgent, @Nullable String androidSdkVersion, @@ -204,8 +250,10 @@ public enum ClientType { ) { this.id = id; this.clientName = name(); + this.deviceMake = deviceMake; this.deviceModel = deviceModel; this.clientVersion = clientVersion; + this.osName = osName; this.osVersion = osVersion; this.androidSdkVersion = androidSdkVersion; this.userAgent = userAgent; diff --git a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java index f42e5443c9..1983bbeb43 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java +++ b/extensions/shared/src/main/java/app/revanced/extension/shared/patches/spoof/requests/PlayerRoutes.java @@ -14,10 +14,10 @@ @SuppressWarnings({"ExtractMethodRecommender", "deprecation"}) public final class PlayerRoutes { - public static final Route.CompiledRoute GET_PLAYLIST_PAGE = new Route( + public static final Route.CompiledRoute GET_CATEGORY = new Route( Route.Method.POST, - "next" + - "?fields=contents.singleColumnWatchNextResults.playlist.playlist" + "player" + + "?fields=microformat.playerMicroformatRenderer" ).compile(); static final Route.CompiledRoute GET_STREAMING_DATA = new Route( Route.Method.POST, @@ -38,21 +38,21 @@ private PlayerRoutes() { } public static String createInnertubeBody(ClientType clientType) { - return createInnertubeBody(clientType, false); - } - - public static String createInnertubeBody(ClientType clientType, boolean playlistId) { JSONObject innerTubeBody = new JSONObject(); try { JSONObject client = new JSONObject(); client.put("clientName", clientType.clientName); client.put("clientVersion", clientType.clientVersion); - client.put("deviceModel", clientType.deviceModel); - client.put("osVersion", clientType.osVersion); if (clientType.androidSdkVersion != null) { client.put("androidSdkVersion", clientType.androidSdkVersion); } + if (clientType.deviceMake != null) { + client.put("deviceMake", clientType.deviceMake); + } + client.put("deviceModel", clientType.deviceModel); + client.put("osName", clientType.osName); + client.put("osVersion", clientType.osVersion); client.put("hl", LOCALE_LANGUAGE); JSONObject context = new JSONObject(); @@ -62,9 +62,6 @@ public static String createInnertubeBody(ClientType clientType, boolean playlist innerTubeBody.put("contentCheckOk", true); innerTubeBody.put("racyCheckOk", true); innerTubeBody.put("videoId", "%s"); - if (playlistId) { - innerTubeBody.put("playlistId", "%s"); - } } catch (JSONException e) { Logger.printException(() -> "Failed to create innerTubeBody", e); } @@ -88,4 +85,4 @@ public static HttpURLConnection getPlayerResponseConnectionFromRoute(Route.Compi connection.setReadTimeout(CONNECTION_TIMEOUT_MILLISECONDS); return connection; } -} \ No newline at end of file +} diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java index 99b658d0ac..8db52e1958 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/PlaybackSpeedPatch.java @@ -10,7 +10,7 @@ import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.youtube.patches.utils.PatchStatus; -import app.revanced.extension.youtube.patches.video.requests.PlaylistRequest; +import app.revanced.extension.youtube.patches.video.requests.CategoryRequest; import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.VideoInformation; import app.revanced.extension.youtube.whitelist.Whitelist; @@ -50,7 +50,7 @@ public static void fetchPlaylistData(@NonNull String videoId, boolean isShortAnd return; } - PlaylistRequest.fetchRequestIfNeeded(videoId); + CategoryRequest.fetchRequestIfNeeded(videoId); } catch (Exception ex) { Logger.printException(() -> "fetchPlaylistData failure", ex); } @@ -114,23 +114,22 @@ public static void userSelectedPlaybackSpeed(float playbackSpeed) { } private static float getDefaultPlaybackSpeed(@NonNull String channelId, @Nullable String videoId) { - return (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_LIVE.get() && isLiveStream) || - Whitelist.isChannelWhitelistedPlaybackSpeed(channelId) || - getPlaylistData(videoId) - ? 1.0f - : Settings.DEFAULT_PLAYBACK_SPEED.get(); + return (isLiveStream || + Whitelist.isChannelWhitelistedPlaybackSpeed(channelId) || + getCategory(videoId) + ) ? 1.0f : Settings.DEFAULT_PLAYBACK_SPEED.get(); } - private static boolean getPlaylistData(@Nullable String videoId) { + private static boolean getCategory(@Nullable String videoId) { if (Settings.DISABLE_DEFAULT_PLAYBACK_SPEED_MUSIC.get() && videoId != null) { try { - PlaylistRequest request = PlaylistRequest.getRequestForVideoId(videoId); - final boolean isPlaylist = request != null && BooleanUtils.toBoolean(request.getStream()); - Logger.printDebug(() -> "isPlaylist: " + isPlaylist); + CategoryRequest request = CategoryRequest.getRequestForVideoId(videoId); + final boolean isMusic = request != null && BooleanUtils.toBoolean(request.getStream()); + Logger.printDebug(() -> "isMusic: " + isMusic); - return isPlaylist; + return isMusic; } catch (Exception ex) { - Logger.printException(() -> "getPlaylistData failure", ex); + Logger.printException(() -> "getCategoryData failure", ex); } } diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/CategoryRequest.java similarity index 69% rename from extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java rename to extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/CategoryRequest.java index b7c69cd0a1..9b2591126e 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/PlaylistRequest.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/video/requests/CategoryRequest.java @@ -1,6 +1,6 @@ package app.revanced.extension.youtube.patches.video.requests; -import static app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.GET_PLAYLIST_PAGE; +import static app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.GET_CATEGORY; import android.annotation.SuppressLint; @@ -16,7 +16,6 @@ import java.net.SocketTimeoutException; import java.nio.charset.StandardCharsets; import java.util.HashMap; -import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutionException; @@ -29,9 +28,8 @@ import app.revanced.extension.shared.requests.Requester; import app.revanced.extension.shared.utils.Logger; import app.revanced.extension.shared.utils.Utils; -import app.revanced.extension.youtube.shared.VideoInformation; -public class PlaylistRequest { +public class CategoryRequest { /** * How long to keep fetches until they are expired. @@ -41,7 +39,7 @@ public class PlaylistRequest { private static final long MAX_MILLISECONDS_TO_WAIT_FOR_FETCH = 20 * 1000; // 20 seconds @GuardedBy("itself") - private static final Map