Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.revanced.extension.music.patches;

import app.revanced.extension.music.settings.Settings;

@SuppressWarnings("unused")
public class ChangeMiniplayerColorPatch {

/**
* Injection point
*/
public static boolean changeMiniplayerColor() {
return Settings.CHANGE_MINIPLAYER_COLOR.get();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_NAVIGATION_BAR_LABEL = new BooleanSetting("revanced_music_hide_navigation_bar_labels", FALSE, true);

// Player
public static final BooleanSetting CHANGE_MINIPLAYER_COLOR = new BooleanSetting("revanced_music_change_miniplayer_color", FALSE, true);
public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true);

// Miscellaneous
Expand Down
4 changes: 4 additions & 0 deletions patches/api/patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,10 @@ public final class app/revanced/patches/music/layout/compactheader/HideCategoryB
public static final fun getHideCategoryBar ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/music/layout/miniplayercolor/ChangeMiniplayerColorKt {
public static final fun getChangeMiniplayerColor ()Lapp/revanced/patcher/patch/BytecodePatch;
}

public final class app/revanced/patches/music/layout/navigationbar/NavigationBarPatchKt {
public static final fun getNavigationBarPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
@file:Suppress("SpellCheckingInspection")

package app.revanced.patches.music.layout.miniplayercolor

import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
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.mapping.get
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
import app.revanced.patches.shared.misc.mapping.resourceMappings
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.util.addInstructionsAtControlFlowLabel
import app.revanced.util.findFreeRegister
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference

internal var mpp_player_bottom_sheet = -1L
private set

private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/ChangeMiniplayerColorPatch;"

@Suppress("unused")
val changeMiniplayerColor = bytecodePatch(
name = "Change miniplayer color",
description = "Adds an option to make the miniplayer match the fullscreen player color."
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
resourceMappingPatch
)

compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52",
"8.10.52"
)
)

execute {
mpp_player_bottom_sheet = resourceMappings["id", "mpp_player_bottom_sheet"]

addResources("music", "layout.miniplayercolor.changeMiniplayerColor")

PreferenceScreen.PLAYER.addPreferences(
SwitchPreference("revanced_music_change_miniplayer_color"),
)

switchToggleColorFingerprint.match(miniPlayerConstructorFingerprint.classDef).let {
val relativeIndex = it.patternMatch!!.endIndex + 1

val invokeVirtualIndex = it.method.indexOfFirstInstructionOrThrow(
relativeIndex, Opcode.INVOKE_VIRTUAL
)
val colorMathPlayerInvokeVirtualReference = it.method
.getInstruction<ReferenceInstruction>(invokeVirtualIndex).reference

val iGetIndex = it.method.indexOfFirstInstructionOrThrow(
relativeIndex, Opcode.IGET
)
val colorMathPlayerIGetReference = it.method
.getInstruction<ReferenceInstruction>(iGetIndex).reference as FieldReference

val colorGreyIndex = miniPlayerConstructorFingerprint.method.indexOfFirstInstructionReversedOrThrow {
getReference<MethodReference>()?.name == "getColor"
}
val iPutIndex = miniPlayerConstructorFingerprint.method.indexOfFirstInstructionOrThrow(
colorGreyIndex, Opcode.IPUT
)
val colorMathPlayerIPutReference = miniPlayerConstructorFingerprint.method
.getInstruction<ReferenceInstruction>(iPutIndex).reference

miniPlayerConstructorFingerprint.classDef.methods.single { method ->
method.accessFlags == AccessFlags.PUBLIC.value or AccessFlags.FINAL.value &&
method.returnType == "V" &&
method.parameters == it.originalMethod.parameters
}.apply {
val invokeDirectIndex = indexOfFirstInstructionReversedOrThrow(Opcode.INVOKE_DIRECT)

val insertIndex = invokeDirectIndex + 1
val freeRegister = findFreeRegister(insertIndex)

addInstructionsAtControlFlowLabel(
insertIndex,
"""
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->changeMiniplayerColor()Z
move-result v$freeRegister
if-eqz v$freeRegister, :off
invoke-virtual { p1 }, $colorMathPlayerInvokeVirtualReference
move-result-object v$freeRegister
check-cast v$freeRegister, ${colorMathPlayerIGetReference.definingClass}
iget v$freeRegister, v$freeRegister, $colorMathPlayerIGetReference
iput v$freeRegister, p0, $colorMathPlayerIPutReference
:off
nop
"""
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package app.revanced.patches.music.layout.miniplayercolor

import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

internal val miniPlayerConstructorFingerprint = fingerprint {
returns("V")
strings("sharedToggleMenuItemMutations")
literal { mpp_player_bottom_sheet }
}

/**
* Matches to the class found in [miniPlayerConstructorFingerprint].
*/
internal val switchToggleColorFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returns("V")
parameters("L", "J")
opcodes(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.IGET
)
}
5 changes: 5 additions & 0 deletions patches/src/main/resources/addresources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,11 @@ Video playback with AV1 may stutter or drop frames."</string>
<string name="revanced_music_hide_category_bar_summary_on">Category bar is hidden</string>
<string name="revanced_music_hide_category_bar_summary_off">Category bar is shown</string>
</patch>
<patch id="layout.miniplayercolor.changeMiniplayerColor">
<string name="revanced_music_change_miniplayer_color_title">Change miniplayer color</string>
<string name="revanced_music_change_miniplayer_color_summary_on">Miniplayer matches fullscreen player color</string>
<string name="revanced_music_change_miniplayer_color_summary_off">Miniplayer uses default color</string>
</patch>
<patch id="layout.navigationbar.navigationBarPatch">
<string name="revanced_music_navigation_bar_screen_title">Navigation bar</string>
<string name="revanced_music_navigation_bar_screen_summary">Hide or change navigation bar buttons</string>
Expand Down
Loading