From e7196e54b06d52ae8fd3f759f570c31c457dc04d Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 11 Mar 2026 11:02:56 +0100 Subject: [PATCH] feat(YouTube Music): Add `Forcibly enable miniplayer` patch Co-Authored-By: ILoveOpenSourceApplications <117499019+iloveopensourceapplications@users.noreply.github.com> --- .../ForciblyEnableMiniplayerPatch.java | 13 ++++ .../extension/music/settings/Settings.java | 1 + .../ChangeMiniplayerColor.kt | 2 +- .../Fingerprints.kt | 9 ++- .../ForciblyEnableMiniplayerPatch.kt | 68 +++++++++++++++++++ .../resources/addresources/values/strings.xml | 7 +- 6 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 extensions/music/src/main/java/app/revanced/extension/music/patches/ForciblyEnableMiniplayerPatch.java rename patches/src/main/kotlin/app/revanced/patches/music/layout/{miniplayercolor => miniplayer}/ChangeMiniplayerColor.kt (98%) rename patches/src/main/kotlin/app/revanced/patches/music/layout/{miniplayercolor => miniplayer}/Fingerprints.kt (77%) create mode 100644 patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ForciblyEnableMiniplayerPatch.kt diff --git a/extensions/music/src/main/java/app/revanced/extension/music/patches/ForciblyEnableMiniplayerPatch.java b/extensions/music/src/main/java/app/revanced/extension/music/patches/ForciblyEnableMiniplayerPatch.java new file mode 100644 index 0000000000..8b6b9c10a1 --- /dev/null +++ b/extensions/music/src/main/java/app/revanced/extension/music/patches/ForciblyEnableMiniplayerPatch.java @@ -0,0 +1,13 @@ +package app.revanced.extension.music.patches; + +import app.revanced.extension.music.settings.Settings; + +@SuppressWarnings("unused") +public class ForciblyEnableMiniplayerPatch { + /** + * Injection point + */ + public static boolean enableForcedMiniplayerPatch(boolean original) { + return Settings.FORCIBLY_ENABLE_MINIPLAYER.get() || original; + } +} \ No newline at end of file diff --git a/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java b/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java index 2e057681d6..395f4e7c21 100644 --- a/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java +++ b/extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java @@ -35,6 +35,7 @@ public class Settings extends YouTubeAndMusicSettings { // Player public static final BooleanSetting CHANGE_MINIPLAYER_COLOR = new BooleanSetting("revanced_music_change_miniplayer_color", FALSE, true); + public static final BooleanSetting FORCIBLY_ENABLE_MINIPLAYER = new BooleanSetting("revanced_music_forcibly_enable_miniplayer", FALSE, true); public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true); // Miscellaneous diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/ChangeMiniplayerColor.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ChangeMiniplayerColor.kt similarity index 98% rename from patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/ChangeMiniplayerColor.kt rename to patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ChangeMiniplayerColor.kt index 34bb8e04f1..608a33e319 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/ChangeMiniplayerColor.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ChangeMiniplayerColor.kt @@ -1,6 +1,6 @@ @file:Suppress("SpellCheckingInspection") -package app.revanced.patches.music.layout.miniplayercolor +package app.revanced.patches.music.layout.miniplayer import app.revanced.patcher.accessFlags import app.revanced.patcher.extensions.getInstruction diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/Fingerprints.kt similarity index 77% rename from patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/Fingerprints.kt rename to patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/Fingerprints.kt index cd621ba5ed..552dde0c3d 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayercolor/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/Fingerprints.kt @@ -1,4 +1,4 @@ -package app.revanced.patches.music.layout.miniplayercolor +package app.revanced.patches.music.layout.miniplayer import app.revanced.patcher.* import app.revanced.patcher.patch.BytecodePatchContext @@ -28,3 +28,10 @@ internal val ClassDef.switchToggleColorMethodMatch by ClassDefComposing.composin Opcode.IGET, ) } + +internal val BytecodePatchContext.minimizedPlayerMethod by gettingFirstMethodDeclaratively { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returnType("V") + parameterTypes("L", "L") + instructions("w_st"()) +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ForciblyEnableMiniplayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ForciblyEnableMiniplayerPatch.kt new file mode 100644 index 0000000000..4fa3fa0677 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/miniplayer/ForciblyEnableMiniplayerPatch.kt @@ -0,0 +1,68 @@ +@file:Suppress("SpellCheckingInspection") + +package app.revanced.patches.music.layout.miniplayer + +import app.revanced.patcher.extensions.addInstructions +import app.revanced.patcher.extensions.getInstruction +import app.revanced.patcher.extensions.methodReference +import app.revanced.patcher.patch.bytecodePatch +import app.revanced.patches.all.misc.resources.addResources +import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.music.misc.extension.sharedExtensionPatch +import app.revanced.patches.music.misc.settings.PreferenceScreen +import app.revanced.patches.music.misc.settings.settingsPatch +import app.revanced.patches.shared.misc.settings.preference.SwitchPreference +import app.revanced.util.indexOfFirstInstructionOrThrow +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction + +private const val EXTENSION_CLASS_DESCRIPTOR = + "Lapp/revanced/extension/music/patches/ForciblyEnableMiniplayerPatch;" + +@Suppress("unused") +val forciblyEnableMiniplayerPatch = bytecodePatch( + name = "Forcibly enable miniplayer", + description = "Adds an option to forcibly enable the miniplayer when switching between music videos, podcasts, or songs." +) { + dependsOn( + sharedExtensionPatch, + settingsPatch, + addResourcesPatch, + ) + + compatibleWith( + "com.google.android.apps.youtube.music"( + "7.29.52", + "8.10.52", + "8.37.56", + "8.40.54", + "8.44.54" + ), + ) + + apply { + addResources("music", "layout.miniplayer.forciblyEnableMiniplayer") + + PreferenceScreen.PLAYER.addPreferences( + SwitchPreference("revanced_music_forcibly_enable_miniplayer") + ) + + minimizedPlayerMethod.apply { + val invokeIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.INVOKE_VIRTUAL && methodReference?.name == "booleanValue" + } + + val moveResultIndex = invokeIndex + 1 + val moveResultInstr = getInstruction(moveResultIndex) + val targetRegister = moveResultInstr.registerA + + addInstructions( + moveResultIndex + 1, + """ + invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->forciblyEnableMiniplayerPatch(Z)Z + move-result v$targetRegister + """ + ) + } + } +} \ No newline at end of file diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 9a7d953248..6bf4dba82d 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1862,11 +1862,16 @@ Video playback with AV1 may stutter or drop frames." Category bar is hidden Category bar is shown - + Change miniplayer color Miniplayer color matches fullscreen player Miniplayer uses default color + + Forcibly enable miniplayer + Miniplayer stays minimized when playback changes + Miniplayer expands to fullscreen when playback changes + Navigation bar Hide or change navigation bar buttons