feat(YouTube Music/Hide action bar component): add Hide add to playlist button, Hide comment button, Hide download button, Hide share button settings

This commit is contained in:
inotia00 2023-12-19 17:27:44 +09:00
parent 5afb86545f
commit ae412c337b
11 changed files with 204 additions and 252 deletions

View File

@ -0,0 +1,169 @@
package app.revanced.patches.music.actionbar.component
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.actionbar.component.fingerprints.ActionBarComponentFingerprint
import app.revanced.patches.music.utils.integrations.Constants.ACTIONBAR
import app.revanced.patches.music.utils.intenthook.IntentHookPatch
import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.video.information.VideoInformationPatch
import app.revanced.util.exception
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
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import kotlin.math.min
@Patch(
name = "Hide action bar component",
description = "Hides action bar components or replaces the offline download button with an external download button.",
dependencies = [
IntentHookPatch::class,
SettingsPatch::class,
VideoInformationPatch::class
],
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
)
@Suppress("unused")
object ActionBarComponentPatch : BytecodePatch(
setOf(ActionBarComponentFingerprint)
) {
private var spannedReference = ""
override fun execute(context: BytecodeContext) {
ActionBarComponentFingerprint.result?.let {
it.mutableMethod.apply {
val instructions = implementation!!.instructions
// hook download button
val addViewIndex = instructions.indexOfLast { instruction ->
((instruction as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addView"
}
val addViewRegister = getInstruction<FiveRegisterInstruction>(addViewIndex).registerD
addInstruction(
addViewIndex + 1,
"invoke-static {v$addViewRegister}, $ACTIONBAR->hookDownloadButton(Landroid/view/View;)V"
)
// hide action button label
val noLabelIndex = instructions.indexOfFirst { instruction ->
val reference = (instruction as? ReferenceInstruction)?.reference.toString()
instruction.opcode == Opcode.INVOKE_DIRECT
&& reference.endsWith("<init>(Landroid/content/Context;)V")
&& !reference.contains("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;")
} - 2
val replaceIndex = instructions.indexOfFirst { instruction ->
val reference = (instruction as? ReferenceInstruction)?.reference.toString()
instruction.opcode == Opcode.INVOKE_DIRECT
&& reference.endsWith("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;-><init>(Landroid/content/Context;)V")
} - 2
val replaceInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
val replaceReference = getInstruction<ReferenceInstruction>(replaceIndex).reference
addInstructionsWithLabels(
replaceIndex + 1, """
invoke-static {}, $ACTIONBAR->hideActionBarLabel()Z
move-result v${replaceInstruction.registerA}
if-nez v${replaceInstruction.registerA}, :hidden
iget-object v${replaceInstruction.registerA}, v${replaceInstruction.registerB}, $replaceReference
""", ExternalLabel("hidden", getInstruction(noLabelIndex))
)
removeInstruction(replaceIndex)
// hide action button
val hasNextIndex = instructions.indexOfFirst { instruction ->
((instruction as? ReferenceInstruction)?.reference as? MethodReference)?.name == "hasNext"
}
val freeRegister = min(implementation!!.registerCount - parameters.size - 2, 15)
val spannedIndex = instructions.indexOfFirst { instruction ->
spannedReference = (instruction as? ReferenceInstruction)?.reference.toString()
spannedReference.endsWith("Landroid/text/Spanned;")
}
val spannedRegister = getInstruction<FiveRegisterInstruction>(spannedIndex).registerC
addInstructionsWithLabels(
spannedIndex + 1, """
invoke-static {}, $ACTIONBAR->hideActionButton()Z
move-result v$freeRegister
if-nez v$freeRegister, :hidden
invoke-static {v$spannedRegister}, $spannedReference
""", ExternalLabel("hidden", getInstruction(hasNextIndex))
)
removeInstruction(spannedIndex)
// set action button identifier
val buttonTypeDownloadIndex = it.scanResult.patternScanResult!!.startIndex + 1
val buttonTypeDownloadRegister = getInstruction<OneRegisterInstruction>(buttonTypeDownloadIndex).registerA
val buttonTypeIndex = it.scanResult.patternScanResult!!.endIndex - 1
val buttonTypeRegister = getInstruction<OneRegisterInstruction>(buttonTypeIndex).registerA
addInstruction(
buttonTypeIndex + 2,
"invoke-static {v$buttonTypeRegister}, $ACTIONBAR->setButtonType(Ljava/lang/Object;)V"
)
addInstruction(
buttonTypeDownloadIndex,
"invoke-static {v$buttonTypeDownloadRegister}, $ACTIONBAR->setButtonTypeDownload(I)V"
)
}
} ?: throw ActionBarComponentFingerprint.exception
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_button_add_to_playlist",
"false"
)
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_button_comment",
"false"
)
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_button_download",
"false"
)
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_button_label",
"false"
)
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_button_radio",
"false"
)
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_button_share",
"false"
)
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hook_action_button_download",
"false"
)
SettingsPatch.addMusicPreferenceWithIntent(
CategoryType.ACTION_BAR,
"revanced_external_downloader_package_name",
"revanced_hook_action_button_download"
)
}
}

View File

@ -0,0 +1,21 @@
package app.revanced.patches.music.actionbar.component.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object ActionBarComponentFingerprint : LiteralValueFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L"),
opcodes = listOf(
Opcode.AND_INT_LIT16,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.SGET_OBJECT
),
literalSupplier = { 99180 }
)

View File

@ -1,40 +0,0 @@
package app.revanced.patches.music.actionbar.downloadbuttonhook
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.utils.actionbarhook.ActionBarHookPatch
import app.revanced.patches.music.utils.intenthook.IntentHookPatch
import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.patches.music.video.information.VideoInformationPatch
@Patch(
name = "Hook download button",
description = "Replaces the offline download button with an external download button.",
dependencies = [
ActionBarHookPatch::class,
IntentHookPatch::class,
SettingsPatch::class,
VideoInformationPatch::class
],
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
)
@Suppress("unused")
object DownloadButtonHookPatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hook_action_bar_download",
"false"
)
SettingsPatch.addMusicPreferenceWithIntent(
CategoryType.ACTION_BAR,
"revanced_external_downloader_package_name",
"revanced_hook_action_bar_download"
)
}
}

View File

@ -1,77 +0,0 @@
package app.revanced.patches.music.actionbar.label
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.actionbar.label.fingerprints.ActionBarLabelFingerprint
import app.revanced.patches.music.utils.fingerprints.ActionsBarParentFingerprint
import app.revanced.patches.music.utils.integrations.Constants.ACTIONBAR
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch(
name = "Hide action bar label",
description = "Hide labels in action bar.",
dependencies = [
SettingsPatch::class,
SharedResourceIdPatch::class
],
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
)
@Suppress("unused")
object ActionBarLabelPatch : BytecodePatch(
setOf(ActionsBarParentFingerprint)
) {
override fun execute(context: BytecodeContext) {
ActionsBarParentFingerprint.result?.classDef?.let { parentClassDef ->
ActionBarLabelFingerprint.resolve(context, parentClassDef)
ActionBarLabelFingerprint.result?.let {
it.mutableMethod.apply {
val instructions = implementation!!.instructions
val noLabelIndex = instructions.indexOfFirst { instruction ->
val reference = (instruction as? ReferenceInstruction)?.reference.toString()
instruction.opcode == Opcode.INVOKE_DIRECT
&& reference.endsWith("<init>(Landroid/content/Context;)V")
&& !reference.contains("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;")
} - 2
val replaceIndex = instructions.indexOfFirst { instruction ->
val reference = (instruction as? ReferenceInstruction)?.reference.toString()
instruction.opcode == Opcode.INVOKE_DIRECT
&& reference.endsWith("Lcom/google/android/libraries/youtube/common/ui/YouTubeButton;-><init>(Landroid/content/Context;)V")
} - 2
val replaceInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
val replaceReference = getInstruction<ReferenceInstruction>(replaceIndex).reference
addInstructionsWithLabels(
replaceIndex + 1, """
invoke-static {}, $ACTIONBAR->hideActionBarLabel()Z
move-result v${replaceInstruction.registerA}
if-nez v${replaceInstruction.registerA}, :hidden
iget-object v${replaceInstruction.registerA}, v${replaceInstruction.registerB}, $replaceReference
""", ExternalLabel("hidden", getInstruction(noLabelIndex))
)
removeInstruction(replaceIndex)
}
} ?: throw ActionBarLabelFingerprint.exception
} ?: throw ActionsBarParentFingerprint.exception
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_bar_label",
"false"
)
}
}

View File

@ -1,19 +0,0 @@
package app.revanced.patches.music.actionbar.label.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object ActionBarLabelFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L"),
opcodes = listOf(
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
)
)

View File

@ -1,31 +0,0 @@
package app.revanced.patches.music.actionbar.radio
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.utils.actionbarhook.ActionBarHookPatch
import app.revanced.patches.music.utils.settings.CategoryType
import app.revanced.patches.music.utils.settings.SettingsPatch
@Patch(
name = "Hide radio button",
description = "Hides start radio button.",
dependencies = [
ActionBarHookPatch::class,
SettingsPatch::class
],
compatiblePackages = [CompatiblePackage("com.google.android.apps.youtube.music")]
)
@Suppress("unused")
object HideRadioButtonPatch : BytecodePatch(emptySet()) {
override fun execute(context: BytecodeContext) {
SettingsPatch.addMusicPreference(
CategoryType.ACTION_BAR,
"revanced_hide_action_bar_radio",
"false"
)
}
}

View File

@ -1,42 +0,0 @@
package app.revanced.patches.music.utils.actionbarhook
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patches.music.utils.actionbarhook.fingerprints.ActionBarHookFingerprint
import app.revanced.patches.music.utils.fingerprints.ActionsBarParentFingerprint
import app.revanced.patches.music.utils.integrations.Constants.ACTIONBAR
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch
import app.revanced.util.exception
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch(dependencies = [SharedResourceIdPatch::class])
object ActionBarHookPatch : BytecodePatch(
setOf(ActionsBarParentFingerprint)
) {
override fun execute(context: BytecodeContext) {
ActionsBarParentFingerprint.result?.let { parentResult ->
ActionBarHookFingerprint.also {
it.resolve(
context,
parentResult.classDef
)
}.result?.let {
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.startIndex
val targetRegister =
getInstruction<TwoRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"invoke-static {v$targetRegister}, $ACTIONBAR->hookActionBar(Landroid/view/ViewGroup;)V"
)
}
} ?: throw ActionBarHookFingerprint.exception
} ?: throw ActionsBarParentFingerprint.exception
}
}

View File

@ -1,22 +0,0 @@
package app.revanced.patches.music.utils.actionbarhook.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
object ActionBarHookFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ
)
)

View File

@ -1,13 +0,0 @@
package app.revanced.patches.music.utils.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patches.music.utils.resourceid.SharedResourceIdPatch.ActionsContainer
import app.revanced.util.fingerprint.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
object ActionsBarParentFingerprint : LiteralValueFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
literalSupplier = { ActionsContainer }
)

View File

@ -16,7 +16,6 @@ import app.revanced.patches.shared.patch.mapping.ResourceType.STYLE
@Patch(dependencies = [ResourceMappingPatch::class])
object SharedResourceIdPatch : ResourcePatch() {
var AccountSwitcherAccessibility: Long = -1
var ActionsContainer: Long = -1
var ButtonContainer: Long = -1
var ButtonIconPaddingMedium: Long = -1
var ChipCloud: Long = -1
@ -47,7 +46,6 @@ object SharedResourceIdPatch : ResourcePatch() {
?: -1
AccountSwitcherAccessibility = find(STRING, "account_switcher_accessibility_label")
ActionsContainer = find(ID, "actions_container")
ButtonContainer = find(ID, "button_container")
ButtonIconPaddingMedium = find(DIMEN, "button_icon_padding_medium")
ChipCloud = find(LAYOUT, "chip_cloud")

View File

@ -96,10 +96,18 @@ WARNING: Do not enable new player backgrounds while this is enabled."</string>
<string name="revanced_hide_account_menu_empty_component_title">Hide empty component</string>
<string name="revanced_hide_account_menu_summary">Hide account menu elements.</string>
<string name="revanced_hide_account_menu_title">Hide account menu</string>
<string name="revanced_hide_action_bar_label_summary">Hide labels in action bar.</string>
<string name="revanced_hide_action_bar_label_title">Hide action bar labels</string>
<string name="revanced_hide_action_bar_radio_summary">Hides start radio button.</string>
<string name="revanced_hide_action_bar_radio_title">Hide radio button</string>
<string name="revanced_hide_action_button_add_to_playlist_summary">Hides add to playlist button.</string>
<string name="revanced_hide_action_button_add_to_playlist_title">Hide add to playlist button</string>
<string name="revanced_hide_action_button_comment_summary">Hides comment button.</string>
<string name="revanced_hide_action_button_comment_title">Hide comment button</string>
<string name="revanced_hide_action_button_download_summary">Hides download button.</string>
<string name="revanced_hide_action_button_download_title">Hide download button</string>
<string name="revanced_hide_action_button_label_summary">Hide labels in action button.</string>
<string name="revanced_hide_action_button_label_title">Hide action button labels</string>
<string name="revanced_hide_action_button_radio_summary">Hides start radio button.</string>
<string name="revanced_hide_action_button_radio_title">Hide radio button</string>
<string name="revanced_hide_action_button_share_summary">Hides share button.</string>
<string name="revanced_hide_action_button_share_title">Hide share button</string>
<string name="revanced_hide_button_shelf_summary">Hides the button shelf from homepage and explorer.</string>
<string name="revanced_hide_button_shelf_title">Hide button shelf</string>
<string name="revanced_hide_carousel_shelf_summary">Hides the carousel shelf from homepage and explorer.</string>
@ -164,8 +172,8 @@ WARNING: Do not enable new player backgrounds while this is enabled."</string>
<string name="revanced_hide_terms_container_title">Hide terms container</string>
<string name="revanced_hide_upgrade_button_summary">Hides the upgrade button.</string>
<string name="revanced_hide_upgrade_button_title">Hide upgrade button</string>
<string name="revanced_hook_action_bar_download_summary">Replaces the offline download button with an external download button.</string>
<string name="revanced_hook_action_bar_download_title">Hook download button</string>
<string name="revanced_hook_action_button_download_summary">Replaces the offline download button with an external download button.</string>
<string name="revanced_hook_action_button_download_title">Hook download button</string>
<string name="revanced_playback_speed_normal">Normal</string>
<string name="revanced_playlist_dismiss">Already playing official music source.</string>
<string name="revanced_playlist_error">Official music source not available.</string>