diff --git a/CHANGELOG.md b/CHANGELOG.md index a41650434..64b8abf31 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [5.46.0-dev.7](https://github.com/ReVanced/revanced-patches/compare/v5.46.0-dev.6...v5.46.0-dev.7) (2025-11-08) + + +### Bug Fixes + +* **YouTube - Settings:** Add additional languages to ReVanced language preference ([d390b54](https://github.com/ReVanced/revanced-patches/commit/d390b54dab92d75b4e0d3e38344eae489dd69d98)) + # [5.46.0-dev.6](https://github.com/ReVanced/revanced-patches/compare/v5.46.0-dev.5...v5.46.0-dev.6) (2025-11-08) diff --git a/extensions/music/src/main/java/app/revanced/extension/music/patches/HideButtonsPatch.java b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideButtonsPatch.java new file mode 100644 index 000000000..5794baa9b --- /dev/null +++ b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideButtonsPatch.java @@ -0,0 +1,49 @@ +package app.revanced.extension.music.patches; + +import static app.revanced.extension.shared.Utils.hideViewBy0dpUnderCondition; + +import android.view.View; +import android.view.ViewGroup; + +import app.revanced.extension.music.settings.Settings; + +@SuppressWarnings("unused") +public class HideButtonsPatch { + + /** + * 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, view); + } + + /** + * Injection point + */ + public static boolean hideHistoryButton(boolean original) { + return original && !Settings.HIDE_HISTORY_BUTTON.get(); + } + + /** + * Injection point + */ + public static void hideNotificationButton(View view) { + if (view.getParent() instanceof ViewGroup viewGroup) { + hideViewBy0dpUnderCondition(Settings.HIDE_NOTIFICATION_BUTTON, viewGroup); + } + } + + /** + * Injection point + */ + public static void hideSearchButton(View view) { + hideViewBy0dpUnderCondition(Settings.HIDE_SEARCH_BUTTON, view); + } +} diff --git a/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCastButtonPatch.java b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCastButtonPatch.java deleted file mode 100644 index ab03ba8e4..000000000 --- a/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCastButtonPatch.java +++ /dev/null @@ -1,24 +0,0 @@ -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, view); - } -} diff --git a/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCategoryBarPatch.java b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCategoryBarPatch.java index 79d772096..f0b090155 100644 --- a/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCategoryBarPatch.java +++ b/extensions/music/src/main/java/app/revanced/extension/music/patches/HideCategoryBarPatch.java @@ -3,6 +3,7 @@ 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") 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 a56fb04b9..bebb3f86c 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 @@ -16,8 +16,11 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_GET_PREMIUM_LABEL = new BooleanSetting("revanced_music_hide_get_premium_label", TRUE, true); // General - public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_music_hide_cast_button", TRUE, false); + public static final BooleanSetting HIDE_CAST_BUTTON = new BooleanSetting("revanced_music_hide_cast_button", TRUE, true); public static final BooleanSetting HIDE_CATEGORY_BAR = new BooleanSetting("revanced_music_hide_category_bar", FALSE, true); + public static final BooleanSetting HIDE_HISTORY_BUTTON = new BooleanSetting("revanced_music_hide_history_button", FALSE, true); + public static final BooleanSetting HIDE_SEARCH_BUTTON = new BooleanSetting("revanced_music_hide_search_button", FALSE, true); + public static final BooleanSetting HIDE_NOTIFICATION_BUTTON = new BooleanSetting("revanced_music_hide_notification_button", 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); diff --git a/extensions/primevideo/src/main/java/app/revanced/extension/primevideo/videoplayer/PlaybackSpeedPatch.java b/extensions/primevideo/src/main/java/app/revanced/extension/primevideo/videoplayer/PlaybackSpeedPatch.java index 10cbda63a..b11ec0875 100644 --- a/extensions/primevideo/src/main/java/app/revanced/extension/primevideo/videoplayer/PlaybackSpeedPatch.java +++ b/extensions/primevideo/src/main/java/app/revanced/extension/primevideo/videoplayer/PlaybackSpeedPatch.java @@ -204,4 +204,4 @@ class SpeedIconDrawable extends Drawable { public int getIntrinsicHeight() { return Dim.dp32; } -} \ No newline at end of file +} diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java index b1cc4fb05..fcd030fc2 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/Utils.java @@ -782,6 +782,28 @@ public class Utils { || (type == ConnectivityManager.TYPE_BLUETOOTH) ? NetworkType.MOBILE : NetworkType.OTHER; } + /** + * Hides a view by setting its layout width and height to 0dp. + * Handles null layout params safely. + * + * @param view The view to hide. If null, does nothing. + */ + public static void hideViewByLayoutParams(@Nullable View view) { + if (view == null) return; + + ViewGroup.LayoutParams params = view.getLayoutParams(); + + if (params == null) { + // Create generic 0x0 layout params accepted by all ViewGroups. + params = new ViewGroup.LayoutParams(0, 0); + } else { + params.width = 0; + params.height = 0; + } + + view.setLayoutParams(params); + } + /** * Configures the parameters of a dialog window, including its width, gravity, vertical offset and background dimming. * The width is calculated as a percentage of the screen's portrait width and the vertical offset is specified in DIP. diff --git a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ImportExportPreference.java b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ImportExportPreference.java index 6ae43018e..1044ba424 100644 --- a/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ImportExportPreference.java +++ b/extensions/shared/library/src/main/java/app/revanced/extension/shared/settings/preference/ImportExportPreference.java @@ -19,7 +19,6 @@ import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.shared.settings.Setting; import app.revanced.extension.shared.ui.CustomDialog; -import app.revanced.extension.shared.ui.Dim; @SuppressWarnings({"unused", "deprecation"}) public class ImportExportPreference extends EditTextPreference implements Preference.OnPreferenceClickListener { diff --git a/gradle.properties b/gradle.properties index 3ff864873..539c4f679 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,4 +3,4 @@ org.gradle.jvmargs = -Xms512M -Xmx2048M org.gradle.parallel = true android.useAndroidX = true kotlin.code.style = official -version = 5.46.0-dev.6 +version = 5.46.0-dev.7 diff --git a/patches/api/patches.api b/patches/api/patches.api index d5a8418b8..9105dac35 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -372,6 +372,10 @@ public final class app/revanced/patches/music/layout/branding/CustomBrandingPatc public static final fun getCustomBrandingPatch ()Lapp/revanced/patcher/patch/ResourcePatch; } +public final class app/revanced/patches/music/layout/buttons/HideButtonsKt { + public static final fun getHideButtons ()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; } diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/Fingerprints.kt new file mode 100644 index 000000000..31c844aea --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/Fingerprints.kt @@ -0,0 +1,64 @@ +package app.revanced.patches.music.layout.buttons + +import app.revanced.patcher.fingerprint +import app.revanced.util.containsLiteralInstruction +import app.revanced.util.literal +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode + +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 } +} + +internal val historyMenuItemFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("Landroid/view/Menu;") + opcodes( + Opcode.INVOKE_INTERFACE, + Opcode.RETURN_VOID + ) + literal { historyMenuItem } + custom { _, classDef -> + classDef.methods.count() == 5 + } +} + +internal val historyMenuItemOfflineTabFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters("Landroid/view/Menu;") + opcodes( + Opcode.INVOKE_INTERFACE, + Opcode.RETURN_VOID + ) + custom { method, _ -> + method.containsLiteralInstruction(historyMenuItem) && + method.containsLiteralInstruction(offlineSettingsMenuItem) + } +} + +internal val searchActionViewFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Landroid/view/View;") + parameters() + literal { searchButton } + custom { _, classDef -> + classDef.type.endsWith("/SearchActionProvider;") + } +} + +internal val topBarMenuItemImageViewFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Landroid/view/View;") + parameters() + literal { topBarMenuItemImageView } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt new file mode 100644 index 000000000..331dae93d --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/buttons/HideButtons.kt @@ -0,0 +1,121 @@ +package app.revanced.patches.music.layout.buttons + +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.mapping.ResourceType +import app.revanced.patches.shared.misc.mapping.getResourceId +import app.revanced.patches.shared.misc.mapping.resourceMappingPatch +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 + +internal var playerOverlayChip = -1L + private set +internal var historyMenuItem = -1L + private set +internal var offlineSettingsMenuItem = -1L + private set +internal var searchButton = -1L + private set +internal var topBarMenuItemImageView = -1L + private set + +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideButtonsPatch;" + +@Suppress("unused") +val hideButtons = bytecodePatch( + name = "Hide buttons", + description = "Adds options to hide the cast, history, notification, and search buttons." +) { + dependsOn( + sharedExtensionPatch, + settingsPatch, + addResourcesPatch, + resourceMappingPatch + ) + + compatibleWith( + "com.google.android.apps.youtube.music"( + "7.29.52", + "8.10.52" + ) + ) + + execute { + playerOverlayChip = getResourceId(ResourceType.ID, "player_overlay_chip") + historyMenuItem = getResourceId(ResourceType.ID, "history_menu_item") + offlineSettingsMenuItem = getResourceId(ResourceType.ID, "offline_settings_menu_item") + searchButton = getResourceId(ResourceType.ID, "search_button") + topBarMenuItemImageView = getResourceId(ResourceType.ID, "top_bar_menu_item_image_view") + + addResources("music", "layout.buttons.hideButtons") + + PreferenceScreen.GENERAL.addPreferences( + SwitchPreference("revanced_music_hide_cast_button"), + SwitchPreference("revanced_music_hide_history_button"), + SwitchPreference("revanced_music_hide_notification_button"), + SwitchPreference("revanced_music_hide_search_button") + ) + + // Region for hide history button in the top bar. + arrayOf( + historyMenuItemFingerprint, + historyMenuItemOfflineTabFingerprint + ).forEach { fingerprint -> + fingerprint.method.apply { + val targetIndex = fingerprint.patternMatch!!.startIndex + val targetRegister = getInstruction(targetIndex).registerD + + addInstructions( + targetIndex, + """ + invoke-static { v$targetRegister }, $EXTENSION_CLASS_DESCRIPTOR->hideHistoryButton(Z)Z + move-result v$targetRegister + """ + ) + } + } + + // Region for hide cast, search and notification buttons in the top bar. + arrayOf( + Triple(playerOverlayChipFingerprint, playerOverlayChip, "hideCastButton"), + Triple(searchActionViewFingerprint, searchButton, "hideSearchButton"), + Triple(topBarMenuItemImageViewFingerprint, topBarMenuItemImageView, "hideNotificationButton") + ).forEach { (fingerprint, resourceIdLiteral, methodName) -> + fingerprint.method.apply { + val resourceIndex = indexOfFirstLiteralInstructionOrThrow(resourceIdLiteral) + val targetIndex = indexOfFirstInstructionOrThrow( + resourceIndex, Opcode.MOVE_RESULT_OBJECT + ) + val targetRegister = getInstruction(targetIndex).registerA + + addInstruction( + targetIndex + 1, + "invoke-static { v$targetRegister }, " + + "$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V" + ) + } + } + + // Region for hide cast button in the player. + mediaRouteButtonFingerprint.classDef.methods.single { method -> + method.name == "setVisibility" + }.addInstructions( + 0, + """ + invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(I)I + move-result p1 + """ + ) + } +} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/Fingerprints.kt deleted file mode 100644 index 605b7bedb..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/Fingerprints.kt +++ /dev/null @@ -1,24 +0,0 @@ -package app.revanced.patches.music.layout.castbutton - -import app.revanced.patcher.fingerprint -import app.revanced.patcher.opcode -import app.revanced.patches.shared.misc.mapping.ResourceType -import app.revanced.patches.shared.misc.mapping.resourceLiteral -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import org.stringtemplate.v4.compiler.Bytecode.instructions - -internal val mediaRouteButtonFingerprint = fingerprint { - accessFlags(AccessFlags.PRIVATE, AccessFlags.FINAL) - returns("Z") - strings("MediaRouteButton") -} - -internal val playerOverlayChipFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) - returns("L") - instructions( - resourceLiteral(ResourceType.ID, "player_overlay_chip"), - opcode(Opcode.MOVE_RESULT_OBJECT) - ) -} diff --git a/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt index 89bc0fe88..bb6053f8a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/layout/castbutton/HideCastButton.kt @@ -1,66 +1,10 @@ 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.mapping.resourceMappingPatch -import app.revanced.patches.shared.misc.settings.preference.SwitchPreference -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction - -private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/HideCastButtonPatch;" +import app.revanced.patches.music.layout.buttons.hideButtons +@Deprecated("Patch was moved", ReplaceWith("hideButtons")) @Suppress("unused") -val hideCastButton = bytecodePatch( - name = "Hide cast button", - description = "Adds an option to hide the cast button." -) { - dependsOn( - sharedExtensionPatch, - settingsPatch, - addResourcesPatch, - resourceMappingPatch - ) - - compatibleWith( - "com.google.android.apps.youtube.music"( - "7.29.52", - "8.10.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 index = playerOverlayChipFingerprint.instructionMatches.last().index - val register = getInstruction(index).registerA - - addInstruction( - index + 1, - "invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->hideCastButton(Landroid/view/View;)V" - ) - } - } +val hideCastButton = bytecodePatch{ + dependsOn(hideButtons) } diff --git a/patches/src/main/resources/addresources/values/strings.xml b/patches/src/main/resources/addresources/values/strings.xml index 0d0a10147..e0fbc6432 100644 --- a/patches/src/main/resources/addresources/values/strings.xml +++ b/patches/src/main/resources/addresources/values/strings.xml @@ -1,4 +1,3 @@ -