Skip to content

Commit 651d358

Browse files
authored
feat(YouTube Music): Add Hide cast button and Navigation bar patches (#5934)
1 parent 0d15c5f commit 651d358

File tree

10 files changed

+383
-1
lines changed

10 files changed

+383
-1
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition;
4+
5+
import android.view.View;
6+
import app.revanced.extension.music.settings.Settings;
7+
8+
@SuppressWarnings("unused")
9+
public class HideCastButtonPatch {
10+
11+
/**
12+
* Injection point
13+
*/
14+
public static int hideCastButton(int original) {
15+
return Settings.HIDE_CAST_BUTTON.get() ? View.GONE : original;
16+
}
17+
18+
/**
19+
* Injection point
20+
*/
21+
public static void hideCastButton(View view) {
22+
hideViewBy0dpUnderCondition(Settings.HIDE_CAST_BUTTON.get(), view);
23+
}
24+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import static app.revanced.extension.shared.Utils.hideViewUnderCondition;
4+
5+
import android.view.View;
6+
import android.widget.TextView;
7+
8+
import androidx.annotation.NonNull;
9+
import androidx.annotation.Nullable;
10+
11+
import app.revanced.extension.music.settings.Settings;
12+
13+
@SuppressWarnings("unused")
14+
public class NavigationBarPatch {
15+
@NonNull
16+
private static String lastYTNavigationEnumName = "";
17+
18+
public static void setLastAppNavigationEnum(@Nullable Enum<?> ytNavigationEnumName) {
19+
if (ytNavigationEnumName != null) {
20+
lastYTNavigationEnumName = ytNavigationEnumName.name();
21+
}
22+
}
23+
24+
public static void hideNavigationLabel(TextView textview) {
25+
hideViewUnderCondition(Settings.HIDE_NAVIGATION_BAR_LABEL.get(), textview);
26+
}
27+
28+
public static void hideNavigationButton(@NonNull View view) {
29+
// Hide entire navigation bar.
30+
if (Settings.HIDE_NAVIGATION_BAR.get() && view.getParent() != null) {
31+
hideViewUnderCondition(true, (View) view.getParent());
32+
return;
33+
}
34+
35+
// Hide navigation buttons based on their type.
36+
for (NavigationButton button : NavigationButton.values()) {
37+
if (button.ytEnumNames.equals(lastYTNavigationEnumName)) {
38+
hideViewUnderCondition(button.hidden, view);
39+
break;
40+
}
41+
}
42+
}
43+
44+
private enum NavigationButton {
45+
HOME(
46+
"TAB_HOME",
47+
Settings.HIDE_NAVIGATION_BAR_HOME_BUTTON.get()
48+
),
49+
SAMPLES(
50+
"TAB_SAMPLES",
51+
Settings.HIDE_NAVIGATION_BAR_SAMPLES_BUTTON.get()
52+
),
53+
EXPLORE(
54+
"TAB_EXPLORE",
55+
Settings.HIDE_NAVIGATION_BAR_EXPLORE_BUTTON.get()
56+
),
57+
LIBRARY(
58+
"LIBRARY_MUSIC",
59+
Settings.HIDE_NAVIGATION_BAR_LIBRARY_BUTTON.get()
60+
),
61+
UPGRADE(
62+
"TAB_MUSIC_PREMIUM",
63+
Settings.HIDE_NAVIGATION_BAR_UPGRADE_BUTTON.get()
64+
);
65+
66+
private final String ytEnumNames;
67+
private final boolean hidden;
68+
69+
NavigationButton(@NonNull String ytEnumNames, boolean hidden) {
70+
this.ytEnumNames = ytEnumNames;
71+
this.hidden = hidden;
72+
}
73+
}
74+
}

extensions/music/src/main/java/app/revanced/extension/music/settings/Settings.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,15 @@ public class Settings extends BaseSettings {
1818
public static final BooleanSetting HIDE_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_upgrade_button", TRUE, true);
1919

2020
// General
21+
public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_music_hide_cast_button", FALSE, false);
2122
public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true);
23+
public static final BooleanSetting HIDE_NAVIGATION_BAR_HOME_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_home_button", FALSE, true);
24+
public static final BooleanSetting HIDE_NAVIGATION_BAR_SAMPLES_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_samples_button", FALSE, true);
25+
public static final BooleanSetting HIDE_NAVIGATION_BAR_EXPLORE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_explore_button", FALSE, true);
26+
public static final BooleanSetting HIDE_NAVIGATION_BAR_LIBRARY_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_library_button", FALSE, true);
27+
public static final BooleanSetting HIDE_NAVIGATION_BAR_UPGRADE_BUTTON = new BooleanSetting("revanced_music_hide_navigation_bar_upgrade_button", TRUE, true);
28+
public static final BooleanSetting HIDE_NAVIGATION_BAR = new BooleanSetting("revanced_music_hide_navigation_bar", FALSE, true);
29+
public static final BooleanSetting HIDE_NAVIGATION_BAR_LABEL = new BooleanSetting("revanced_music_hide_navigation_bar_labels", FALSE, true);
2230

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

patches/api/patches.api

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,10 +372,18 @@ public final class app/revanced/patches/music/interaction/permanentshuffle/Perma
372372
public static final fun getPermanentShufflePatch ()Lapp/revanced/patcher/patch/BytecodePatch;
373373
}
374374

375+
public final class app/revanced/patches/music/layout/castbutton/HideCastButtonKt {
376+
public static final fun getHideCastButton ()Lapp/revanced/patcher/patch/BytecodePatch;
377+
}
378+
375379
public final class app/revanced/patches/music/layout/compactheader/HideCategoryBarKt {
376380
public static final fun getHideCategoryBar ()Lapp/revanced/patcher/patch/BytecodePatch;
377381
}
378382

383+
public final class app/revanced/patches/music/layout/navigationbar/NavigationBarPatchKt {
384+
public static final fun getNavigationBarPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
385+
}
386+
379387
public final class app/revanced/patches/music/layout/premium/HideGetPremiumPatchKt {
380388
public static final fun getHideGetPremiumPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
381389
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package app.revanced.patches.music.layout.castbutton
2+
3+
import com.android.tools.smali.dexlib2.AccessFlags
4+
import app.revanced.patcher.fingerprint
5+
import app.revanced.util.literal
6+
7+
internal val mediaRouteButtonFingerprint = fingerprint {
8+
accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL)
9+
returns("Z")
10+
strings("MediaRouteButton")
11+
}
12+
13+
internal val playerOverlayChipFingerprint = fingerprint {
14+
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
15+
returns("L")
16+
literal { playerOverlayChip }
17+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package app.revanced.patches.music.layout.castbutton
2+
3+
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
4+
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
5+
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
6+
import app.revanced.patcher.patch.bytecodePatch
7+
import app.revanced.patches.all.misc.resources.addResources
8+
import app.revanced.patches.all.misc.resources.addResourcesPatch
9+
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
10+
import app.revanced.patches.music.misc.settings.PreferenceScreen
11+
import app.revanced.patches.music.misc.settings.settingsPatch
12+
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
13+
import app.revanced.util.indexOfFirstInstructionOrThrow
14+
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
15+
import com.android.tools.smali.dexlib2.Opcode
16+
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
17+
18+
internal var playerOverlayChip = -1L
19+
private set
20+
21+
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCastButtonPatch;"
22+
23+
@Suppress("unused")
24+
val hideCastButton = bytecodePatch(
25+
name = "Hide cast button",
26+
description = "Adds an option to hide the cast button."
27+
) {
28+
dependsOn(
29+
sharedExtensionPatch,
30+
settingsPatch,
31+
addResourcesPatch,
32+
)
33+
34+
compatibleWith(
35+
"com.google.android.apps.youtube.music"(
36+
"7.29.52"
37+
)
38+
)
39+
40+
execute {
41+
addResources("music", "layout.castbutton.hideCastButton")
42+
43+
PreferenceScreen.GENERAL.addPreferences(
44+
SwitchPreference("revanced_music_hide_cast_button"),
45+
)
46+
47+
mediaRouteButtonFingerprint.classDef.apply {
48+
val setVisibilityMethod = methods.first { method -> method.name == "setVisibility" }
49+
50+
setVisibilityMethod.addInstructions(
51+
0,
52+
"""
53+
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(I)I
54+
move-result p1
55+
"""
56+
)
57+
}
58+
59+
playerOverlayChipFingerprint.method.apply {
60+
val resourceIndex = indexOfFirstLiteralInstructionOrThrow(playerOverlayChip)
61+
val targetIndex = indexOfFirstInstructionOrThrow(resourceIndex, Opcode.MOVE_RESULT)
62+
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
63+
64+
addInstruction(
65+
targetIndex + 1,
66+
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(Landroid/view/View;)V"
67+
)
68+
}
69+
}
70+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package app.revanced.patches.music.layout.navigationbar
2+
3+
import com.android.tools.smali.dexlib2.Opcode
4+
import com.android.tools.smali.dexlib2.AccessFlags
5+
import app.revanced.patcher.fingerprint
6+
import app.revanced.util.getReference
7+
import app.revanced.util.indexOfFirstInstruction
8+
import app.revanced.util.literal
9+
import com.android.tools.smali.dexlib2.iface.Method
10+
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
11+
12+
internal val tabLayoutTextFingerprint = fingerprint {
13+
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
14+
returns("V")
15+
parameters("L")
16+
opcodes(
17+
Opcode.IGET,
18+
Opcode.INVOKE_STATIC,
19+
Opcode.MOVE_RESULT_OBJECT,
20+
Opcode.IF_NEZ,
21+
Opcode.SGET_OBJECT,
22+
Opcode.INVOKE_INTERFACE,
23+
Opcode.MOVE_RESULT
24+
)
25+
strings("FEmusic_search")
26+
literal { text1 }
27+
custom { method, _ ->
28+
indexOfGetVisibilityInstruction(method) >= 0
29+
}
30+
}
31+
32+
internal fun indexOfGetVisibilityInstruction(method: Method) =
33+
method.indexOfFirstInstruction {
34+
opcode == Opcode.INVOKE_VIRTUAL &&
35+
getReference<MethodReference>()?.name == "getVisibility"
36+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package app.revanced.patches.music.layout.navigationbar
2+
3+
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
4+
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
5+
import app.revanced.patcher.patch.PatchException
6+
import app.revanced.patcher.patch.bytecodePatch
7+
import app.revanced.patches.all.misc.resources.addResources
8+
import app.revanced.patches.all.misc.resources.addResourcesPatch
9+
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
10+
import app.revanced.patches.music.misc.settings.PreferenceScreen
11+
import app.revanced.patches.music.misc.settings.settingsPatch
12+
import app.revanced.patches.shared.misc.mapping.get
13+
import app.revanced.patches.shared.misc.mapping.resourceMappingPatch
14+
import app.revanced.patches.shared.misc.mapping.resourceMappings
15+
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPreference
16+
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
17+
import app.revanced.util.indexOfFirstInstructionOrThrow
18+
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
19+
import com.android.tools.smali.dexlib2.Opcode
20+
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
21+
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
22+
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
23+
24+
internal var text1 = -1L
25+
private set
26+
27+
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/NavigationBarPatch;"
28+
29+
@Suppress("unused")
30+
val navigationBarPatch = bytecodePatch(
31+
name = "Navigation bar",
32+
description = "Adds options to hide navigation bar, labels and buttons."
33+
) {
34+
dependsOn(
35+
resourceMappingPatch,
36+
sharedExtensionPatch,
37+
settingsPatch,
38+
addResourcesPatch
39+
)
40+
41+
compatibleWith(
42+
"com.google.android.apps.youtube.music"(
43+
"7.29.52"
44+
)
45+
)
46+
47+
execute {
48+
text1 = resourceMappings[
49+
"id",
50+
"text1",
51+
]
52+
53+
addResources("music", "layout.navigationbar.navigationBarPatch")
54+
55+
PreferenceScreen.GENERAL.addPreferences(
56+
PreferenceScreenPreference(
57+
key = "revanced_music_navigation_bar_screen",
58+
sorting = PreferenceScreenPreference.Sorting.UNSORTED,
59+
preferences = setOf(
60+
SwitchPreference("revanced_music_hide_navigation_bar_home_button"),
61+
SwitchPreference("revanced_music_hide_navigation_bar_samples_button"),
62+
SwitchPreference("revanced_music_hide_navigation_bar_explore_button"),
63+
SwitchPreference("revanced_music_hide_navigation_bar_library_button"),
64+
SwitchPreference("revanced_music_hide_navigation_bar_upgrade_button"),
65+
66+
SwitchPreference("revanced_music_hide_navigation_bar"),
67+
SwitchPreference("revanced_music_hide_navigation_bar_labels"),
68+
)
69+
)
70+
)
71+
72+
tabLayoutTextFingerprint.method.apply {
73+
/**
74+
* Hide navigation labels.
75+
*/
76+
val constIndex = indexOfFirstLiteralInstructionOrThrow(text1)
77+
val targetIndex = indexOfFirstInstructionOrThrow(constIndex, Opcode.CHECK_CAST)
78+
val targetParameter = getInstruction<ReferenceInstruction>(targetIndex).reference
79+
val targetRegister = getInstruction<OneRegisterInstruction>(targetIndex).registerA
80+
81+
if (!targetParameter.toString().endsWith("Landroid/widget/TextView;"))
82+
throw PatchException("Method signature parameter did not match: $targetParameter")
83+
84+
addInstruction(
85+
targetIndex + 1,
86+
"invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationLabel(Landroid/widget/TextView;)V"
87+
)
88+
89+
/**
90+
* Set navigation enum and hide navigation buttons.
91+
*/
92+
val enumIndex = tabLayoutTextFingerprint.patternMatch!!.startIndex + 3
93+
val enumRegister = getInstruction<OneRegisterInstruction>(enumIndex).registerA
94+
val insertEnumIndex = indexOfFirstInstructionOrThrow(Opcode.AND_INT_LIT8) - 2
95+
96+
val pivotTabIndex = indexOfGetVisibilityInstruction(this)
97+
val pivotTabRegister = getInstruction<FiveRegisterInstruction>(pivotTabIndex).registerC
98+
99+
addInstruction(
100+
pivotTabIndex,
101+
"invoke-static { v$pivotTabRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideNavigationButton(Landroid/view/View;)V"
102+
)
103+
104+
addInstruction(
105+
insertEnumIndex,
106+
"invoke-static { v$enumRegister }, $EXTENSION_CLASS_DESCRIPTOR->setLastAppNavigationEnum(Ljava/lang/Enum;)V"
107+
)
108+
}
109+
}
110+
}

patches/src/main/kotlin/app/revanced/patches/music/layout/upgradebutton/HideUpgradeButtonPatch.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
2121

2222
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideUpgradeButtonPatch;"
2323

24+
@Deprecated("This patch will be removed in the future.")
2425
@Suppress("unused")
2526
val hideUpgradeButton = bytecodePatch(
26-
name = "Hide upgrade button",
2727
description = "Hides the upgrade tab from the pivot bar.",
2828
) {
2929
dependsOn(

0 commit comments

Comments
 (0)