feat(YouTube): add Hook YouTube Music actions patch

This commit is contained in:
inotia00
2024-09-23 22:24:13 +09:00
parent 9bd51f7df8
commit ce5561732e
8 changed files with 199 additions and 16 deletions

View File

@ -176,7 +176,7 @@ object DownloadActionsPatch : BaseBytecodePatch(
SettingsPatch.addPreference( SettingsPatch.addPreference(
arrayOf( arrayOf(
"PREFERENCE_SCREEN: GENERAL", "PREFERENCE_SCREEN: GENERAL",
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS", "SETTINGS: HOOK_BUTTONS",
"SETTINGS: HOOK_DOWNLOAD_ACTIONS" "SETTINGS: HOOK_DOWNLOAD_ACTIONS"
) )
) )

View File

@ -0,0 +1,108 @@
package app.revanced.patches.youtube.general.music
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
import app.revanced.patches.youtube.general.music.fingerprints.AppDeepLinkFingerprint
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.gms.GmsCoreSupportResourcePatch.PackageNameYouTubeMusic
import app.revanced.patches.youtube.utils.integrations.Constants.GENERAL_PATH
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addEntryValues
import app.revanced.patches.youtube.utils.settings.SettingsBytecodePatch
import app.revanced.patches.youtube.utils.settings.SettingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.patch.BaseBytecodePatch
import app.revanced.util.resultOrThrow
import app.revanced.util.valueOrThrow
import com.android.tools.smali.dexlib2.Opcode
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.FieldReference
import java.io.Closeable
@Suppress("unused")
object YouTubeMusicActionsPatch : BaseBytecodePatch(
name = "Hook YouTube Music actions",
description = "Adds support for opening music in RVX Music using the in-app YouTube Music button.",
dependencies = setOf(SettingsPatch::class),
compatiblePackages = COMPATIBLE_PACKAGE,
fingerprints = setOf(AppDeepLinkFingerprint)
), Closeable {
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$GENERAL_PATH/YouTubeMusicActionsPatch;"
override fun execute(context: BytecodeContext) {
AppDeepLinkFingerprint.resultOrThrow().let {
it.mutableMethod.apply {
val packageNameIndex = it.scanResult.patternScanResult!!.startIndex
val packageNameField = getInstruction<ReferenceInstruction>(packageNameIndex).reference.toString()
implementation!!.instructions
.withIndex()
.filter { (_, instruction) ->
instruction.opcode == Opcode.IGET_OBJECT &&
instruction.getReference<FieldReference>()?.toString() == packageNameField
}
.map { (index, _) -> index }
.reversed()
.forEach { index ->
val register = getInstruction<TwoRegisterInstruction>(index).registerA
addInstructions(
index + 1, """
invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->overridePackageName(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register
"""
)
}
}
}
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE_SCREEN: GENERAL",
"SETTINGS: HOOK_BUTTONS",
"SETTINGS: HOOK_YOUTUBE_MUSIC_ACTIONS"
)
)
SettingsPatch.updatePatchStatus(this)
}
override fun close() {
if (SettingsPatch.containsPatch("GmsCore support")) {
SettingsPatch.contexts.addEntryValues(
"revanced_third_party_youtube_music_label",
"RVX Music"
)
SettingsPatch.contexts.addEntryValues(
"revanced_third_party_youtube_music_package_name",
PackageNameYouTubeMusic.valueOrThrow()
)
SettingsBytecodePatch.contexts
.findClass { classDef -> classDef.type == INTEGRATIONS_CLASS_DESCRIPTOR }
?.mutableClass
?.methods
?.first { method -> method.name == "getRVXMusicPackageName" }
?.apply {
val replaceIndex = indexOfFirstInstructionOrThrow(Opcode.CONST_STRING)
val replaceRegister =
getInstruction<OneRegisterInstruction>(replaceIndex).registerA
replaceInstruction(
replaceIndex,
"const-string v$replaceRegister, \"${PackageNameYouTubeMusic.valueOrThrow()}\""
)
}
}
}
}

View File

@ -0,0 +1,27 @@
package app.revanced.patches.youtube.general.music.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal object AppDeepLinkFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "Ljava/util/Map;"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.CONST_STRING,
),
strings = listOf("android.intent.action.VIEW"),
customFingerprint = { methodDef, _ ->
methodDef.indexOfFirstInstruction {
getReference<FieldReference>()?.name == "appDeepLinkEndpoint"
} >= 0
}
)

View File

@ -318,6 +318,7 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
"revanced_preference_screen_feed_flyout_menu", "revanced_preference_screen_feed_flyout_menu",
"revanced_preference_screen_fullscreen", "revanced_preference_screen_fullscreen",
"revanced_preference_screen_haptic_feedback", "revanced_preference_screen_haptic_feedback",
"revanced_preference_screen_hook_buttons",
"revanced_preference_screen_import_export", "revanced_preference_screen_import_export",
"revanced_preference_screen_miniplayer", "revanced_preference_screen_miniplayer",
"revanced_preference_screen_navigation_buttons", "revanced_preference_screen_navigation_buttons",
@ -430,6 +431,7 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
"revanced_preference_screen_comments" -> "revanced_hide_quick_actions_comment_button_icon" "revanced_preference_screen_comments" -> "revanced_hide_quick_actions_comment_button_icon"
"revanced_preference_screen_feed_flyout_menu" -> "revanced_preference_screen_player_flyout_menu_icon" "revanced_preference_screen_feed_flyout_menu" -> "revanced_preference_screen_player_flyout_menu_icon"
"revanced_preference_screen_haptic_feedback" -> "revanced_enable_swipe_haptic_feedback_icon" "revanced_preference_screen_haptic_feedback" -> "revanced_enable_swipe_haptic_feedback_icon"
"revanced_preference_screen_hook_buttons" -> "revanced_preference_screen_import_export_icon"
"revanced_preference_screen_miniplayer" -> "offline_key_icon" "revanced_preference_screen_miniplayer" -> "offline_key_icon"
"revanced_preference_screen_patch_information" -> "about_key_icon" "revanced_preference_screen_patch_information" -> "about_key_icon"
"revanced_preference_screen_shorts_player" -> "revanced_preference_screen_shorts_icon" "revanced_preference_screen_shorts_player" -> "revanced_preference_screen_shorts_icon"

View File

@ -316,7 +316,13 @@ object SettingsPatch : BaseResourcePatch(
updatePatchStatus(patch.name!!) updatePatchStatus(patch.name!!)
} }
private val patchList = ArrayList<String>()
internal fun updatePatchStatus(patchName: String) { internal fun updatePatchStatus(patchName: String) {
patchList.add(patchName)
contexts.updatePatchStatus(patchName) contexts.updatePatchStatus(patchName)
} }
internal fun containsPatch(patchName: String) =
patchList.contains(patchName)
} }

View File

@ -185,6 +185,12 @@
<item>17.41.37</item> <item>17.41.37</item>
<item>17.33.42</item> <item>17.33.42</item>
</string-array> </string-array>
<string-array name="revanced_third_party_youtube_music_label">
<item>YouTube Music</item>
</string-array>
<string-array name="revanced_third_party_youtube_music_package_name">
<item>com.google.android.apps.youtube.music</item>
</string-array>
<string-array name="revanced_watch_history_type_entries"> <string-array name="revanced_watch_history_type_entries">
<item>@string/revanced_watch_history_type_entry_1</item> <item>@string/revanced_watch_history_type_entry_1</item>
<item>@string/revanced_watch_history_type_entry_2</item> <item>@string/revanced_watch_history_type_entry_2</item>

View File

@ -351,15 +351,6 @@ This does not bypass the age restriction. It just accepts it automatically."</st
<string name="revanced_enable_tablet_layout_title">Enable tablet layout</string> <string name="revanced_enable_tablet_layout_title">Enable tablet layout</string>
<string name="revanced_enable_tablet_layout_summary">Spoofs the dpi to use some tablet layouts.</string> <string name="revanced_enable_tablet_layout_summary">Spoofs the dpi to use some tablet layouts.</string>
<string name="revanced_override_video_download_button_title">Override video download button</string>
<string name="revanced_override_video_download_button_summary_on">Native video download button opens your external downloader.</string>
<string name="revanced_override_video_download_button_summary_off">Native video download button opens the native in-app downloader.</string>
<string name="revanced_override_playlist_download_button_title">Override playlist download button</string>
<string name="revanced_override_playlist_download_button_summary_on">Native playlist download button is always shown, and in public playlists, it opens your external downloader.</string>
<string name="revanced_override_playlist_download_button_summary_off">If shown, the native playlist download button opens the native in-app downloader.</string>
<string name="revanced_external_downloader_package_name_playlist_title">Playlist downloader package name</string>
<string name="revanced_external_downloader_package_name_playlist_summary">Package name of your installed external downloader app, such as YTDLnis.</string>
<string name="revanced_spoof_app_version_title">Spoof app version</string> <string name="revanced_spoof_app_version_title">Spoof app version</string>
<string name="revanced_spoof_app_version_summary_on">Version spoofed</string> <string name="revanced_spoof_app_version_summary_on">Version spoofed</string>
<string name="revanced_spoof_app_version_summary_off">Version not spoofed</string> <string name="revanced_spoof_app_version_summary_off">Version not spoofed</string>
@ -404,6 +395,34 @@ Some components may not be hidden."</string>
<string name="revanced_custom_filter_strings_summary">List of component path builder strings to filter, separated by new lines.</string> <string name="revanced_custom_filter_strings_summary">List of component path builder strings to filter, separated by new lines.</string>
<string name="revanced_custom_filter_toast_invalid_syntax">Invalid custom filter: %s.</string> <string name="revanced_custom_filter_toast_invalid_syntax">Invalid custom filter: %s.</string>
<!-- PreferenceScreen: General, PreferenceCategory: General, PreferenceScreen: Hook buttons -->
<string name="revanced_preference_screen_hook_buttons_title">Hook buttons</string>
<string name="revanced_preference_screen_hook_buttons_summary">Overrides the click action of in-app buttons.</string>
<!-- PreferenceScreen: General, PreferenceCategory: General, PreferenceScreen: Hook buttons, PreferenceCategory: Download button -->
<string name="revanced_preference_category_download_button">Download button</string>
<string name="revanced_override_video_download_button_title">Override video download button</string>
<string name="revanced_override_video_download_button_summary_on">Native video download button opens your external downloader.</string>
<string name="revanced_override_video_download_button_summary_off">Native video download button opens the native in-app downloader.</string>
<string name="revanced_override_playlist_download_button_title">Override playlist download button</string>
<string name="revanced_override_playlist_download_button_summary_on">Native playlist download button is always shown, and in public playlists, it opens your external downloader.</string>
<string name="revanced_override_playlist_download_button_summary_off">If shown, the native playlist download button opens the native in-app downloader.</string>
<string name="revanced_external_downloader_package_name_playlist_title">Playlist downloader package name</string>
<string name="revanced_external_downloader_package_name_playlist_summary">Package name of your installed external downloader app, such as YTDLnis.</string>
<!-- PreferenceScreen: General, PreferenceCategory: General, PreferenceScreen: Hook buttons, PreferenceCategory: Experimental Flags -->
<string name="revanced_override_youtube_music_button_title">Override YouTube Music button</string>
<string name="revanced_override_youtube_music_button_summary_on">YouTube Music button opens the RVX Music.</string>
<string name="revanced_override_youtube_music_button_summary_off">YouTube Music button opens the native app.</string>
<string name="revanced_third_party_youtube_music_package_name_title">RVX Music package name</string>
<string name="revanced_third_party_youtube_music_package_name_summary">Package name of installed RVX Music.</string>
<string name="revanced_third_party_youtube_music_dialog_title">RVX Music</string>
<string name="revanced_third_party_youtube_music_not_installed_dialog_title">Warning</string>
<string name="revanced_third_party_youtube_music_not_installed_warning">%s is not installed. Please install it.</string>
<string name="revanced_override_youtube_music_button_about_prerequisite_title">Prerequisite</string>
<string name="revanced_override_youtube_music_button_about_prerequisite_summary">YouTube Music is required to override button action. Tap here to download YouTube Music.</string>
<!-- PreferenceScreen: General, PreferenceCategory: General, PreferenceScreen: Miniplayer --> <!-- PreferenceScreen: General, PreferenceCategory: General, PreferenceScreen: Miniplayer -->
<string name="revanced_preference_screen_miniplayer_title">Miniplayer</string> <string name="revanced_preference_screen_miniplayer_title">Miniplayer</string>
<string name="revanced_preference_screen_miniplayer_summary">Change the style of the in app minimized player.</string> <string name="revanced_preference_screen_miniplayer_summary">Change the style of the in app minimized player.</string>

View File

@ -132,6 +132,27 @@
<app.revanced.integrations.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_custom_filter_strings_title" android:key="revanced_custom_filter_strings" android:summary="@string/revanced_custom_filter_strings_summary" android:inputType="textMultiLine" /> <app.revanced.integrations.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_custom_filter_strings_title" android:key="revanced_custom_filter_strings" android:summary="@string/revanced_custom_filter_strings_summary" android:inputType="textMultiLine" />
</PreferenceScreen>SETTINGS: HIDE_LAYOUT_COMPONENTS --> </PreferenceScreen>SETTINGS: HIDE_LAYOUT_COMPONENTS -->
<!-- SETTINGS: HOOK_BUTTONS
<PreferenceScreen android:title="@string/revanced_preference_screen_hook_buttons_title" android:key="revanced_preference_screen_hook_buttons" android:summary="@string/revanced_preference_screen_hook_buttons_summary">SETTINGS: HOOK_BUTTONS -->
<!-- SETTINGS: HOOK_DOWNLOAD_ACTIONS
<PreferenceCategory android:title="@string/revanced_preference_category_download_button" android:layout="@layout/revanced_settings_preferences_category" />
<SwitchPreference android:title="@string/revanced_override_video_download_button_title" android:key="revanced_override_video_download_button" android:summaryOn="@string/revanced_override_video_download_button_summary_on" android:summaryOff="@string/revanced_override_video_download_button_summary_off" />
<SwitchPreference android:title="@string/revanced_override_playlist_download_button_title" android:key="revanced_override_playlist_download_button" android:summaryOn="@string/revanced_override_playlist_download_button_summary_on" android:summaryOff="@string/revanced_override_playlist_download_button_summary_off" />
<app.revanced.integrations.youtube.settings.preference.ExternalDownloaderVideoPreference android:title="@string/revanced_external_downloader_package_name_video_title" android:key="revanced_external_downloader_package_name_video" android:summary="@string/revanced_external_downloader_package_name_video_summary" />
<app.revanced.integrations.youtube.settings.preference.ExternalDownloaderPlaylistPreference android:title="@string/revanced_external_downloader_package_name_playlist_title" android:key="revanced_external_downloader_package_name_playlist" android:summary="@string/revanced_external_downloader_package_name_playlist_summary" />SETTINGS: HOOK_DOWNLOAD_ACTIONS -->
<!-- SETTINGS: HOOK_YOUTUBE_MUSIC_ACTIONS
<PreferenceCategory android:title="@string/revanced_preference_category_experimental_flag" android:layout="@layout/revanced_settings_preferences_category" />
<SwitchPreference android:title="@string/revanced_override_youtube_music_button_title" android:key="revanced_override_youtube_music_button" android:summaryOn="@string/revanced_override_youtube_music_button_summary_on" android:summaryOff="@string/revanced_override_youtube_music_button_summary_off" />
<app.revanced.integrations.youtube.settings.preference.ThirdPartyYouTubeMusicPreference android:title="@string/revanced_third_party_youtube_music_package_name_title" android:key="revanced_third_party_youtube_music_package_name" android:summary="@string/revanced_third_party_youtube_music_package_name_summary" />
<Preference android:title="@string/revanced_override_youtube_music_button_about_prerequisite_title" android:key="revanced_override_youtube_music_button_about_prerequisite" android:summary="@string/revanced_override_youtube_music_button_about_prerequisite_summary">
<intent android:action="android.intent.action.VIEW" android:data="https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music" />
</Preference>SETTINGS: HOOK_YOUTUBE_MUSIC_ACTIONS -->
<!-- SETTINGS: HOOK_BUTTONS
</PreferenceScreen>SETTINGS: HOOK_BUTTONS -->
<!-- SETTINGS: MINIPLAYER_TYPE_MODERN <!-- SETTINGS: MINIPLAYER_TYPE_MODERN
<PreferenceScreen android:title="@string/revanced_preference_screen_miniplayer_title" android:key="revanced_preference_screen_miniplayer" android:summary="@string/revanced_preference_screen_miniplayer_summary"> <PreferenceScreen android:title="@string/revanced_preference_screen_miniplayer_title" android:key="revanced_preference_screen_miniplayer" android:summary="@string/revanced_preference_screen_miniplayer_summary">
<ListPreference android:entries="@array/revanced_miniplayer_type_19_15_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_15_entry_values" />SETTINGS: MINIPLAYER_TYPE_MODERN --> <ListPreference android:entries="@array/revanced_miniplayer_type_19_15_entries" android:title="@string/revanced_miniplayer_type_title" android:key="revanced_miniplayer_type" android:entryValues="@array/revanced_miniplayer_type_19_15_entry_values" />SETTINGS: MINIPLAYER_TYPE_MODERN -->
@ -230,12 +251,6 @@
<SwitchPreference android:title="@string/revanced_enable_phone_layout_title" android:key="revanced_enable_phone_layout" android:summary="@string/revanced_enable_phone_layout_summary" /> <SwitchPreference android:title="@string/revanced_enable_phone_layout_title" android:key="revanced_enable_phone_layout" android:summary="@string/revanced_enable_phone_layout_summary" />
<SwitchPreference android:title="@string/revanced_enable_tablet_layout_title" android:key="revanced_enable_tablet_layout" android:summary="@string/revanced_enable_tablet_layout_summary" />SETTINGS: LAYOUT_SWITCH --> <SwitchPreference android:title="@string/revanced_enable_tablet_layout_title" android:key="revanced_enable_tablet_layout" android:summary="@string/revanced_enable_tablet_layout_summary" />SETTINGS: LAYOUT_SWITCH -->
<!-- SETTINGS: HOOK_DOWNLOAD_ACTIONS
<SwitchPreference android:title="@string/revanced_override_video_download_button_title" android:key="revanced_override_video_download_button" android:summaryOn="@string/revanced_override_video_download_button_summary_on" android:summaryOff="@string/revanced_override_video_download_button_summary_off" />
<SwitchPreference android:title="@string/revanced_override_playlist_download_button_title" android:key="revanced_override_playlist_download_button" android:summaryOn="@string/revanced_override_playlist_download_button_summary_on" android:summaryOff="@string/revanced_override_playlist_download_button_summary_off" />
<app.revanced.integrations.youtube.settings.preference.ExternalDownloaderVideoPreference android:title="@string/revanced_external_downloader_package_name_video_title" android:key="revanced_external_downloader_package_name_video" android:summary="@string/revanced_external_downloader_package_name_video_summary" />
<app.revanced.integrations.youtube.settings.preference.ExternalDownloaderPlaylistPreference android:title="@string/revanced_external_downloader_package_name_playlist_title" android:key="revanced_external_downloader_package_name_playlist" android:summary="@string/revanced_external_downloader_package_name_playlist_summary" />SETTINGS: HOOK_DOWNLOAD_ACTIONS -->
<!-- SETTINGS: SPOOF_APP_VERSION <!-- SETTINGS: SPOOF_APP_VERSION
<SwitchPreference android:title="@string/revanced_spoof_app_version_title" android:key="revanced_spoof_app_version" android:summaryOn="@string/revanced_spoof_app_version_summary_on" android:summaryOff="@string/revanced_spoof_app_version_summary_off" /> <SwitchPreference android:title="@string/revanced_spoof_app_version_title" android:key="revanced_spoof_app_version" android:summaryOn="@string/revanced_spoof_app_version_summary_on" android:summaryOff="@string/revanced_spoof_app_version_summary_off" />
<ListPreference android:title="@string/revanced_spoof_app_version_target_entry_title" android:key="revanced_spoof_app_version_target" android:entries="@array/revanced_spoof_app_version_target_entries" android:entryValues="@array/revanced_spoof_app_version_target_entry_values" /> <ListPreference android:title="@string/revanced_spoof_app_version_target_entry_title" android:key="revanced_spoof_app_version_target" android:entries="@array/revanced_spoof_app_version_target_entries" android:entryValues="@array/revanced_spoof_app_version_target_entry_values" />