feat(YouTube Music): Add Hide cast button and Navigation bar patches (#5934)

This commit is contained in:
MarcaD
2025-09-20 14:26:14 +03:00
committed by GitHub
parent 0d15c5f338
commit 651d358096
10 changed files with 383 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
package app.revanced.extension.music.patches;
import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition;
import android.view.View;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class HideCastButtonPatch {
/**
* Injection point
*/
public static int hideCastButton(int original) {
return Settings.HIDE_CAST_BUTTON.get() ? View.GONE : original;
}
/**
* Injection point
*/
public static void hideCastButton(View view) {
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view);
}
}

View File

@@ -0,0 +1,74 @@
package app.revanced.extension.music.patches;
import static app.revanced.extension.shared.Utils.hideViewUnderCondition;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.revanced.extension.music.settings.Settings;
@SuppressWarnings("unused")
public class NavigationBarPatch {
@NonNull
private static String lastYTNavigationEnumName = "";
public static void setLastAppNavigationEnum(@Nullable Enum<?> ytNavigationEnumName) {
if (ytNavigationEnumName != null) {
lastYTNavigationEnumName = ytNavigationEnumName.name();
}
}
public static void hideNavigationLabel(TextView textview) {
hideViewUnderCondition(Settings.HIDE_NAVIGATION_BAR_LABEL.get(), textview);
}
public static void hideNavigationButton(@NonNull View view) {
// Hide entire navigation bar.
if (Settings.HIDE_NAVIGATION_BAR.get() && view.getParent() != null) {
hideViewUnderCondition(true, (View) view.getParent());
return;
}
// Hide navigation buttons based on their type.
for (NavigationButton button : NavigationButton.values()) {
if (button.ytEnumNames.equals(lastYTNavigationEnumName)) {
hideViewUnderCondition(button.hidden, view);
break;
}
}
}
private enum NavigationButton {
HOME(
"TAB_HOME",
Settings.HIDE_NAVIGATION_BAR_HOME_BUTTON.get()
),
SAMPLES(
"TAB_SAMPLES",
Settings.HIDE_NAVIGATION_BAR_SAMPLES_BUTTON.get()
),
EXPLORE(
"TAB_EXPLORE",
Settings.HIDE_NAVIGATION_BAR_EXPLORE_BUTTON.get()
),
LIBRARY(
"LIBRARY_MUSIC",
Settings.HIDE_NAVIGATION_BAR_LIBRARY_BUTTON.get()
),
UPGRADE(
"TAB_MUSIC_PREMIUM",
Settings.HIDE_NAVIGATION_BAR_UPGRADE_BUTTON.get()
);
private final String ytEnumNames;
private final boolean hidden;
NavigationButton(@NonNull String ytEnumNames, boolean hidden) {
this.ytEnumNames = ytEnumNames;
this.hidden = hidden;
}
}
}

View File

@@ -18,7 +18,15 @@ public class Settings extends BaseSettings {
public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true);
// General
public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_music_hide_cast_button", FALSE, false);
public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR_HOME_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_home_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR_SAMPLES_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_samples_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR_EXPLORE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_explore_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR_LIBRARY_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_library_button", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_upgrade_button", TRUE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_music_hide_navigation_bar", FALSE, true);
public static final BooleanSetting HIDE_NAVIGATION_BAR_LABEL = new BooleanSetting("revanced_music_hide_navigation_bar_labels", FALSE, true);
// Player
public static final BooleanSetting PERMANENT_REPEAT = new BooleanSetting("revanced_music_play_permanent_repeat", FALSE, true);

View File

@@ -372,10 +372,18 @@ public final class app/revanced/patches/music/interaction/permanentshuffle/Perma
public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt {
public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch;
}
public final class app/revanced/patches/music/layout/compactheader/HideCategoryBarKt {
public static final fun getHideCategoryBar ()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;
}
public final class app/revanced/patches/music/layout/premium/HideGetPremiumPatchKt {
public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
}

View File

@@ -0,0 +1,17 @@
package app.revanced.patches.music.layout.castbutton
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
import app.revanced.util.literal
internal val mediaRouteButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
returns("Z")
strings("MediaRouteButton")
}
internal val playerOverlayChipFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
literal { playerOverlayChip }
}

View File

@@ -0,0 +1,70 @@
package app.revanced.patches.music.layout.castbutton
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
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.settings.preference.SwitchPreference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
internal var playerOverlayChip = -1L
private set
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCastButtonPatch;"
@Suppress("unused")
val hideCastButton = bytecodePatch(
name = "Hide cast button",
description = "Adds an option to hide the cast button."
) {
dependsOn(
sharedExtensionPatch,
settingsPatch,
addResourcesPatch,
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
)
)
execute {
addResources("music", "layout.castbutton.hideCastButton")
PreferenceScreen.GENERAL.addPreferences(
SwitchPreference("revanced_music_hide_cast_button"),
)
mediaRouteButtonFingerprint.classDef.apply {
val setVisibilityMethod = methods.first { method -> method.name == "setVisibility" }
setVisibilityMethod.addInstructions(
0,
"""
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(I)I
move-result p1
"""
)
}
playerOverlayChipFingerprint.method.apply {
val resourceIndex = indexOfFirstLiteralInstructionOrThrow(playerOverlayChip)
val targetIndex = indexOfFirstInstructionOrThrow(resourceIndex, Opcode.MOVE_RESULT)
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(Landroid/view/View;)V"
)
}
}
}

View File

@@ -0,0 +1,36 @@
package app.revanced.patches.music.layout.navigationbar
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.AccessFlags
import app.revanced.patcher.fingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
internal val tabLayoutTextFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters("L")
opcodes(
Opcode.IGET,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT
)
strings("FEmusic_search")
literal { text1 }
custom { method, _ ->
indexOfGetVisibilityInstruction(method) >= 0
}
}
internal fun indexOfGetVisibilityInstruction(method: Method) =
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "getVisibility"
}

View File

@@ -0,0 +1,110 @@
package app.revanced.patches.music.layout.navigationbar
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchException
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.PreferenceScreenPreference
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
internal var text1 = -1L
private set
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/NavigationBarPatch;"
@Suppress("unused")
val navigationBarPatch = bytecodePatch(
name = "Navigation bar",
description = "Adds options to hide navigation bar, labels and buttons."
) {
dependsOn(
resourceMappingPatch,
sharedExtensionPatch,
settingsPatch,
addResourcesPatch
)
compatibleWith(
"com.google.android.apps.youtube.music"(
"7.29.52"
)
)
execute {
text1 = resourceMappings[
"id",
"text1",
]
addResources("music", "layout.navigationbar.navigationBarPatch")
PreferenceScreen.GENERAL.addPreferences(
PreferenceScreenPreference(
key = "revanced_music_navigation_bar_screen",
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_music_hide_navigation_bar_home_button"),
SwitchPreference("revanced_music_hide_navigation_bar_samples_button"),
SwitchPreference("revanced_music_hide_navigation_bar_explore_button"),
SwitchPreference("revanced_music_hide_navigation_bar_library_button"),
SwitchPreference("revanced_music_hide_navigation_bar_upgrade_button"),
SwitchPreference("revanced_music_hide_navigation_bar"),
SwitchPreference("revanced_music_hide_navigation_bar_labels"),
)
)
)
tabLayoutTextFingerprint.method.apply {
/**
* Hide navigation labels.
*/
val constIndex = indexOfFirstLiteralInstructionOrThrow(text1)
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
val targetParameter = getInstruction<ReferenceInstruction>(targetIndex).reference
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
if (!targetParameter.toString().endsWith("Landroid/widget/TextView;"))
throw PatchException("Method signature parameter did not match: $targetParameter")
addInstruction(
targetIndex + 1,
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationLabel(Landroid/widget/TextView;)V"
)
/**
* Set navigation enum and hide navigation buttons.
*/
val enumIndex = tabLayoutTextFingerprint.patternMatch!!.startIndex + 3
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2
val pivotTabIndex = indexOfGetVisibilityInstruction(this)
val pivotTabRegister = getInstruction<FiveRegisterInstruction>(pivotTabIndex).registerC
addInstruction(
pivotTabIndex,
"invoke-static { v$pivotTabRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationButton(Landroid/view/View;)V"
)
addInstruction(
insertEnumIndex,
"invoke-static { v$enumRegister }, $EXTENSION_CLASS_DESCRIPTOR->setLastAppNavigationEnum(Ljava/lang/Enum;)V"
)
}
}
}

View File

@@ -21,9 +21,9 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;"
@Deprecated("This patch will be removed in the future.")
@Suppress("unused")
val hideUpgradeButton = bytecodePatch(
name = "Hide upgrade button",
description = "Hides the upgrade tab from the pivot bar.",
) {
dependsOn(

View File

@@ -1663,11 +1663,46 @@ Enabling this can unlock higher video qualities"</string>
<string name="revanced_music_play_permanent_repeat_summary_on">Permanent repeat is enabled</string>
<string name="revanced_music_play_permanent_repeat_summary_off">Permanent repeat is disabled</string>
</patch>
<patch id="layout.castbutton.hideCastButton">
<string name="revanced_music_hide_cast_button_title">Hide cast button</string>
<string name="revanced_music_hide_cast_button_summary_on">Cast button is hidden</string>
<string name="revanced_music_hide_cast_button_summary_off">Cast button is shown</string>
</patch>
<patch id="layout.compactheader.hideCategoryBar">
<string name="revanced_music_hide_category_bar_title">Hide category bar</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.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>
<!-- 'Home' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_home_button_title">Hide Home button</string>
<string name="revanced_music_hide_navigation_bar_home_button_summary_on">Home button is hidden</string>
<string name="revanced_music_hide_navigation_bar_home_button_summary_off">Home button is shown</string>
<!-- 'Samples' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_samples_button_title">Hide Samples button</string>
<string name="revanced_music_hide_navigation_bar_samples_button_summary_on">Samples button is hidden</string>
<string name="revanced_music_hide_navigation_bar_samples_button_summary_off">Samples button is shown</string>
<!-- 'Explore' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_explore_button_title">Hide Explore button</string>
<string name="revanced_music_hide_navigation_bar_explore_button_summary_on">Explore button is hidden</string>
<string name="revanced_music_hide_navigation_bar_explore_button_summary_off">Explore button is shown</string>
<!-- 'Library' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_library_button_title">Hide Library button</string>
<string name="revanced_music_hide_navigation_bar_library_button_summary_on">Library button is hidden</string>
<string name="revanced_music_hide_navigation_bar_library_button_summary_off">Library button is shown</string>
<!-- 'Upgrade' should be translated using the same localized wording YouTube Music displays for the tab. -->
<string name="revanced_music_hide_navigation_bar_upgrade_button_title">Hide Upgrade button</string>
<string name="revanced_music_hide_navigation_bar_upgrade_button_summary_on">Upgrade button is hidden</string>
<string name="revanced_music_hide_navigation_bar_upgrade_button_summary_off">Upgrade button is shown</string>
<string name="revanced_music_hide_navigation_bar_title">Hide navigation bar</string>
<string name="revanced_music_hide_navigation_bar_summary_on">Navigation bar is hidden</string>
<string name="revanced_music_hide_navigation_bar_summary_off">Navigation bar is shown</string>
<string name="revanced_music_hide_navigation_bar_labels_title">Hide navigation button labels</string>
<string name="revanced_music_hide_navigation_bar_labels_summary_on">Labels are hidden</string>
<string name="revanced_music_hide_navigation_bar_labels_summary_off">Labels are shown</string>
</patch>
<patch id="layout.premium.hideGetPremiumPatch">
<string name="revanced_music_hide_get_premium_label_title">Hide \'Get Music Premium\' label</string>
<string name="revanced_music_hide_get_premium_label_summary_on">Label is hidden</string>