From d2ea46a613d407aad58617b31521415e7d49afab Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 10 Feb 2025 17:41:51 +0900 Subject: [PATCH] feat(YouTube Music - Player components): Add settings `Change seekbar position` and `Enable thick seekbar` (YouTube Music 7.29.51+, close https://github.com/inotia00/ReVanced_Extended/issues/2770) --- .../music/patches/player/PlayerPatch.java | 16 ++++++ .../extension/music/settings/Settings.java | 2 + .../music/player/components/Fingerprints.kt | 28 +++++++++ .../components/PlayerComponentsPatch.kt | 57 +++++++++++++++++++ .../utils/resourceid/SharedResourceIdPatch.kt | 6 ++ .../music/settings/host/values/strings.xml | 4 ++ 6 files changed, 113 insertions(+) diff --git a/extensions/shared/src/main/java/app/revanced/extension/music/patches/player/PlayerPatch.java b/extensions/shared/src/main/java/app/revanced/extension/music/patches/player/PlayerPatch.java index ffc217e14..ed34d5cb1 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/music/patches/player/PlayerPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/music/patches/player/PlayerPatch.java @@ -29,10 +29,14 @@ public class PlayerPatch { Settings.ADD_MINIPLAYER_PREVIOUS_BUTTON.get(); private static final boolean CHANGE_PLAYER_BACKGROUND_COLOR = Settings.CHANGE_PLAYER_BACKGROUND_COLOR.get(); + private static final boolean CHANGE_SEEK_BAR_POSITION = + Settings.CHANGE_SEEK_BAR_POSITION.get(); private static final boolean DISABLE_PLAYER_GESTURE = Settings.DISABLE_PLAYER_GESTURE.get(); private static final boolean ENABLE_SWIPE_TO_DISMISS_MINIPLAYER = Settings.ENABLE_SWIPE_TO_DISMISS_MINIPLAYER.get(); + private static final boolean ENABLE_THICK_SEEKBAR = + Settings.ENABLE_THICK_SEEKBAR.get(); private static final boolean ENABLE_ZEN_MODE = Settings.ENABLE_ZEN_MODE.get(); private static final boolean ENABLE_ZEN_MODE_PODCAST = @@ -108,6 +112,12 @@ public class PlayerPatch { return colors; } + public static boolean changeSeekBarPosition(boolean original) { + return SETTINGS_INITIALIZED + ? CHANGE_SEEK_BAR_POSITION + : original; + } + public static boolean disableMiniPlayerGesture() { return Settings.DISABLE_MINIPLAYER_GESTURE.get(); } @@ -186,6 +196,12 @@ public class PlayerPatch { return ENABLE_SWIPE_TO_DISMISS_MINIPLAYER ? null : object; } + public static boolean enableThickSeekBar(boolean original) { + return SETTINGS_INITIALIZED + ? ENABLE_THICK_SEEKBAR + : original; + } + public static int enableZenMode(int originalColor) { if (ENABLE_ZEN_MODE && originalColor == MUSIC_VIDEO_BACKGROUND_COLOR) { final VideoType videoType = VideoType.getCurrent(); 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 0b1d92971..ff66390b8 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 @@ -139,10 +139,12 @@ public class Settings extends BaseSettings { public static final BooleanSetting CHANGE_PLAYER_BACKGROUND_COLOR = new BooleanSetting("revanced_change_player_background_color", FALSE, true); public static final StringSetting CUSTOM_PLAYER_BACKGROUND_COLOR_PRIMARY = new StringSetting("revanced_custom_player_background_color_primary", "#000000", true); public static final StringSetting CUSTOM_PLAYER_BACKGROUND_COLOR_SECONDARY = new StringSetting("revanced_custom_player_background_color_secondary", "#000000", true); + public static final BooleanSetting CHANGE_SEEK_BAR_POSITION = new BooleanSetting("revanced_change_seekbar_position", FALSE, true); public static final BooleanSetting DISABLE_MINIPLAYER_GESTURE = new BooleanSetting("revanced_disable_miniplayer_gesture", FALSE, true); public static final BooleanSetting DISABLE_PLAYER_GESTURE = new BooleanSetting("revanced_disable_player_gesture", FALSE, true); public static final BooleanSetting ENABLE_FORCED_MINIPLAYER = new BooleanSetting("revanced_enable_forced_miniplayer", TRUE); public static final BooleanSetting ENABLE_SWIPE_TO_DISMISS_MINIPLAYER = new BooleanSetting("revanced_enable_swipe_to_dismiss_miniplayer", TRUE, true); + public static final BooleanSetting ENABLE_THICK_SEEKBAR = new BooleanSetting("revanced_enable_thick_seekbar", TRUE, true); public static final BooleanSetting ENABLE_ZEN_MODE = new BooleanSetting("revanced_enable_zen_mode", FALSE, true); public static final BooleanSetting ENABLE_ZEN_MODE_PODCAST = new BooleanSetting("revanced_enable_zen_mode_podcast", FALSE, true); public static final BooleanSetting HIDE_COMMENT_CHANNEL_GUIDELINES = new BooleanSetting("revanced_hide_comment_channel_guidelines", TRUE); diff --git a/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt index 96d619c3d..0182bc141 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/player/components/Fingerprints.kt @@ -4,6 +4,7 @@ import app.revanced.patches.music.utils.extension.Constants.PLAYER_CLASS_DESCRIP import app.revanced.patches.music.utils.playservice.is_7_18_or_greater import app.revanced.patches.music.utils.resourceid.colorGrey import app.revanced.patches.music.utils.resourceid.darkBackground +import app.revanced.patches.music.utils.resourceid.inlineTimeBarProgressColor import app.revanced.patches.music.utils.resourceid.miniPlayerDefaultText import app.revanced.patches.music.utils.resourceid.miniPlayerMdxPlaying import app.revanced.patches.music.utils.resourceid.miniPlayerPlayPauseReplayButton @@ -359,6 +360,33 @@ internal val switchToggleColorFingerprint = legacyFingerprint( ) ) +internal val thickSeekBarColorFingerprint = legacyFingerprint( + name = "thickSeekBarColorFingerprint", + returnType = "V", + parameters = listOf("L"), + literals = listOf(inlineTimeBarProgressColor), + customFingerprint = { method, _ -> + method.definingClass.endsWith("/MusicPlaybackControls;") + } +) + +internal val thickSeekBarFeatureFlagFingerprint = legacyFingerprint( + name = "thickSeekBarFeatureFlagFingerprint", + returnType = "Z", + parameters = emptyList(), + literals = listOf(45659062L), +) + +internal val thickSeekBarInflateFingerprint = legacyFingerprint( + name = "thickSeekBarInflateFingerprint", + returnType = "V", + parameters = emptyList(), + customFingerprint = { method, _ -> + method.definingClass.endsWith("/MusicPlaybackControls;") && + method.name == "onFinishInflate" + } +) + internal val zenModeFingerprint = legacyFingerprint( name = "zenModeFingerprint", returnType = "V", diff --git a/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt index 21c8a727b..c39664845 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/player/components/PlayerComponentsPatch.kt @@ -24,6 +24,7 @@ import app.revanced.patches.music.utils.playservice.is_6_27_or_greater import app.revanced.patches.music.utils.playservice.is_6_42_or_greater import app.revanced.patches.music.utils.playservice.is_7_18_or_greater import app.revanced.patches.music.utils.playservice.is_7_25_or_greater +import app.revanced.patches.music.utils.playservice.is_7_29_or_greater import app.revanced.patches.music.utils.playservice.is_8_03_or_greater import app.revanced.patches.music.utils.playservice.versionCheckPatch import app.revanced.patches.music.utils.resourceid.colorGrey @@ -55,6 +56,7 @@ import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.injectLiteralInstructionViewCall import app.revanced.util.fingerprint.matchOrNull import app.revanced.util.fingerprint.matchOrThrow +import app.revanced.util.fingerprint.methodCall import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.mutableClassOrThrow import app.revanced.util.fingerprint.resolvable @@ -71,6 +73,7 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.Instruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @@ -488,6 +491,52 @@ val playerComponentsPatch = bytecodePatch( // endregion + // region patch for enable thick seek bar + + var thickSeekBar = false + + fun MutableMethod.thickSeekBarHook(index: Int, methodName: String = "enableThickSeekBar") { + val register = getInstruction(index + 1).registerA + + addInstructions( + index + 2, """ + invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->$methodName(Z)Z + move-result v$register + """ + ) + } + + if (is_7_25_or_greater) { + val thickSeekBarMethodCall = thickSeekBarFeatureFlagFingerprint.methodCall() + val filter: Instruction.() -> Boolean = { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.toString() == thickSeekBarMethodCall + } + + thickSeekBarInflateFingerprint.methodOrThrow().apply { + val indexes = findInstructionIndicesReversed(filter) + + thickSeekBarHook(indexes.first(), "changeSeekBarPosition") + thickSeekBarHook(indexes.last()) + } + + if (is_7_29_or_greater) { + thickSeekBarColorFingerprint.methodOrThrow().apply { + findInstructionIndicesReversed(filter).forEach { thickSeekBarHook(it) } + } + } + + addSwitchPreference( + CategoryType.PLAYER, + "revanced_change_seekbar_position", + "false" + ) + + thickSeekBar = true + } + + // endregion + // region patch for disable gesture in player val playerViewPagerConstructorMethod = @@ -721,6 +770,14 @@ val playerComponentsPatch = bytecodePatch( // endregion + if (thickSeekBar) { + addSwitchPreference( + CategoryType.PLAYER, + "revanced_enable_thick_seekbar", + "true" + ) + } + // region patch for enable zen mode (~ 6.34) // this method is used for old player background (deprecated since YT Music v6.34.51) diff --git a/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt index d0c1c9cc4..f8ffbd8be 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/utils/resourceid/SharedResourceIdPatch.kt @@ -43,6 +43,8 @@ var historyMenuItem = -1L private set var inlineTimeBarAdBreakMarkerColor = -1L private set +var inlineTimeBarProgressColor = -1L + private set var interstitialsContainer = -1L private set var isTablet = -1L @@ -174,6 +176,10 @@ internal val sharedResourceIdPatch = resourcePatch( COLOR, "inline_time_bar_ad_break_marker_color" ] + inlineTimeBarProgressColor = resourceMappings[ + COLOR, + "inline_time_bar_progress_color" + ] interstitialsContainer = resourceMappings[ ID, "interstitials_container" 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 56955b6bf..cf9ffdaab 100644 --- a/patches/src/main/resources/music/settings/host/values/strings.xml +++ b/patches/src/main/resources/music/settings/host/values/strings.xml @@ -250,6 +250,8 @@ Use dark colors if possible, as the app does not support light themes." Use dark colors if possible, as the app does not support light themes." Invalid player background color. + Change seekbar position + Moves the seekbar below the play button. Disable miniplayer gesture Disables swipe to change tracks in the miniplayer. Disable player gesture @@ -258,6 +260,8 @@ Use dark colors if possible, as the app does not support light themes." Enables forced miniplayer when switching to a new track. Enable swipe to dismiss miniplayer Enables swipe down to dismiss miniplayer. + Enable thick seekbar + Enables the thick seekbar. Enable Zen mode Enables a light grey color for the player background to reduce eye strain. Enable Zen mode in podcasts