Skip to content

Commit

Permalink
feat(YouTube): add Hook YouTube Music actions patch
Browse files Browse the repository at this point in the history
  • Loading branch information
inotia00 committed Sep 23, 2024
1 parent 9bd51f7 commit ce55617
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ object DownloadActionsPatch : BaseBytecodePatch(
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE_SCREEN: GENERAL",
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS",
"SETTINGS: HOOK_BUTTONS",
"SETTINGS: HOOK_DOWNLOAD_ACTIONS"
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -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()}\""
)
}
}

}
}
Original file line number Diff line number Diff line change
@@ -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
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
"revanced_preference_screen_feed_flyout_menu",
"revanced_preference_screen_fullscreen",
"revanced_preference_screen_haptic_feedback",
"revanced_preference_screen_hook_buttons",
"revanced_preference_screen_import_export",
"revanced_preference_screen_miniplayer",
"revanced_preference_screen_navigation_buttons",
Expand Down Expand Up @@ -430,6 +431,7 @@ object VisualPreferencesIconsPatch : BaseResourcePatch(
"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_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_patch_information" -> "about_key_icon"
"revanced_preference_screen_shorts_player" -> "revanced_preference_screen_shorts_icon"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,13 @@ object SettingsPatch : BaseResourcePatch(
updatePatchStatus(patch.name!!)
}

private val patchList = ArrayList<String>()

internal fun updatePatchStatus(patchName: String) {
patchList.add(patchName)
contexts.updatePatchStatus(patchName)
}

internal fun containsPatch(patchName: String) =
patchList.contains(patchName)
}
6 changes: 6 additions & 0 deletions src/main/resources/youtube/settings/host/values/arrays.xml
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@
<item>17.41.37</item>
<item>17.33.42</item>
</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">
<item>@string/revanced_watch_history_type_entry_1</item>
<item>@string/revanced_watch_history_type_entry_2</item>
Expand Down
37 changes: 28 additions & 9 deletions src/main/resources/youtube/settings/host/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_summary_on">Version spoofed</string>
<string name="revanced_spoof_app_version_summary_off">Version not spoofed</string>
Expand Down Expand Up @@ -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_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 -->
<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>
Expand Down
Loading

0 comments on commit ce55617

Please sign in to comment.