diff --git a/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/ConnectionTrackerFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/ConnectionTrackerFingerprint.kt
new file mode 100644
index 000000000..4d048efa3
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/ConnectionTrackerFingerprint.kt
@@ -0,0 +1,10 @@
+package app.revanced.patches.music.layout.sharebuttonhook.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object ConnectionTrackerFingerprint : MethodFingerprint(
+ returnType = "Z",
+ opcodes = listOf(Opcode.THROW),
+ strings = listOf("ConnectionTracker")
+)
diff --git a/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/MusicSettingsFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/MusicSettingsFingerprint.kt
new file mode 100644
index 000000000..d07b31945
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/MusicSettingsFingerprint.kt
@@ -0,0 +1,9 @@
+package app.revanced.patches.music.layout.sharebuttonhook.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+
+object MusicSettingsFingerprint : MethodFingerprint(
+ customFingerprint = {
+ it.definingClass.endsWith("MusicSettings;") && it.name == "getDownloaderPackageName"
+ }
+)
diff --git a/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/SharePanelFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/SharePanelFingerprint.kt
new file mode 100644
index 000000000..9e9ac05c6
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/SharePanelFingerprint.kt
@@ -0,0 +1,10 @@
+package app.revanced.patches.music.layout.sharebuttonhook.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object SharePanelFingerprint : MethodFingerprint(
+ returnType = "V",
+ opcodes = listOf(Opcode.INVOKE_VIRTUAL),
+ strings = listOf("share/get_share_panel")
+)
diff --git a/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/ShowToastFingerprint.kt b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/ShowToastFingerprint.kt
new file mode 100644
index 000000000..813d83495
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/fingerprints/ShowToastFingerprint.kt
@@ -0,0 +1,10 @@
+package app.revanced.patches.music.layout.sharebuttonhook.fingerprints
+
+import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
+import org.jf.dexlib2.Opcode
+
+object ShowToastFingerprint : MethodFingerprint(
+ returnType = "V",
+ parameters = listOf("Landroid/content/Context;","Ljava/lang/CharSequence;","I"),
+ opcodes = listOf(Opcode.IF_EQZ)
+)
diff --git a/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/patch/ShareButtonHookPatch.kt b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/patch/ShareButtonHookPatch.kt
new file mode 100644
index 000000000..c34474d9b
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/music/layout/sharebuttonhook/patch/ShareButtonHookPatch.kt
@@ -0,0 +1,83 @@
+package app.revanced.patches.music.layout.sharebuttonhook.patch
+
+import app.revanced.extensions.toErrorResult
+import app.revanced.patcher.annotation.Description
+import app.revanced.patcher.annotation.Name
+import app.revanced.patcher.annotation.Version
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.addInstruction
+import app.revanced.patcher.extensions.addInstructions
+import app.revanced.patcher.extensions.instruction
+import app.revanced.patcher.extensions.replaceInstruction
+import app.revanced.patcher.patch.BytecodePatch
+import app.revanced.patcher.patch.PatchResult
+import app.revanced.patcher.patch.PatchResultSuccess
+import app.revanced.patcher.patch.annotations.DependsOn
+import app.revanced.patcher.patch.annotations.Patch
+import app.revanced.patcher.util.smali.ExternalLabel
+import app.revanced.patches.music.layout.sharebuttonhook.fingerprints.*
+import app.revanced.patches.music.misc.settings.patch.MusicSettingsPatch
+import app.revanced.patches.music.misc.videoid.patch.MusicVideoIdPatch
+import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
+import app.revanced.patches.shared.patch.options.PatchOptions
+import app.revanced.patches.shared.patch.options.PatchOptions.Companion.MusicDownloaderPackageName
+import app.revanced.util.integrations.Constants.MUSIC_PATH
+
+@Patch
+@Name("share-button-hook")
+@Description("Replace share button with external download button.")
+@DependsOn(
+ [
+ MusicSettingsPatch::class,
+ MusicVideoIdPatch::class,
+ PatchOptions::class
+ ]
+)
+@YouTubeMusicCompatibility
+@Version("0.0.1")
+class ShareButtonHookPatch : BytecodePatch(
+ listOf(
+ ConnectionTrackerFingerprint,
+ MusicSettingsFingerprint,
+ SharePanelFingerprint,
+ ShowToastFingerprint
+ )
+) {
+ override fun execute(context: BytecodeContext): PatchResult {
+ SharePanelFingerprint.result?.let {
+ with (it.mutableMethod) {
+ val targetIndex = it.scanResult.patternScanResult!!.startIndex
+
+ addInstructions(
+ targetIndex,"""
+ invoke-static {}, $MUSIC_PATH/HookShareButtonPatch;->overrideSharePanel()Z
+ move-result p1
+ if-eqz p1, :default
+ return-void
+ """, listOf(ExternalLabel("default", instruction(targetIndex)))
+ )
+ }
+ } ?: return SharePanelFingerprint.toErrorResult()
+
+ ConnectionTrackerFingerprint.result?.mutableMethod?.addInstruction(
+ 0,
+ "sput-object p1, $MUSIC_PATH/HookShareButtonPatch;->context:Landroid/content/Context;"
+ ) ?: return ConnectionTrackerFingerprint.toErrorResult()
+
+ ShowToastFingerprint.result?.mutableMethod?.addInstructions(
+ 0,"""
+ invoke-static {p0}, $MUSIC_PATH/HookShareButtonPatch;->dismissContext(Landroid/content/Context;)Landroid/content/Context;
+ move-result-object p0
+ """
+ ) ?: return ShowToastFingerprint.toErrorResult()
+
+ MusicSettingsFingerprint.result?.mutableMethod?.replaceInstruction(
+ 0,
+ "const-string v0, \"$MusicDownloaderPackageName\""
+ )?: return MusicSettingsFingerprint.toErrorResult()
+
+ MusicSettingsPatch.addMusicPreference("navigation", "revanced_hook_share_button", "false")
+
+ return PatchResultSuccess()
+ }
+}
diff --git a/src/main/kotlin/app/revanced/patches/shared/patch/options/PatchOptions.kt b/src/main/kotlin/app/revanced/patches/shared/patch/options/PatchOptions.kt
index b11b77a70..3760b8278 100644
--- a/src/main/kotlin/app/revanced/patches/shared/patch/options/PatchOptions.kt
+++ b/src/main/kotlin/app/revanced/patches/shared/patch/options/PatchOptions.kt
@@ -60,6 +60,18 @@ class PatchOptions : ResourcePatch {
)
)
+ /**
+ * Downloader Package Name (YouTube Music)
+ */
+ internal var MusicDownloaderPackageName: String? by option(
+ PatchOption.StringOption(
+ key = "MusicDownloaderPackageName",
+ default = "ussr.razar.youtube_dl",
+ title = "Downloader Package Name for YouTube Music",
+ description = "Downloader package name of the YouTube Music. (default: PowerTube)"
+ )
+ )
+
/**
* Custom Speed Values
*/
diff --git a/src/main/kotlin/app/revanced/util/integrations/Constants.kt b/src/main/kotlin/app/revanced/util/integrations/Constants.kt
index ec61c525f..a7b044cfa 100644
--- a/src/main/kotlin/app/revanced/util/integrations/Constants.kt
+++ b/src/main/kotlin/app/revanced/util/integrations/Constants.kt
@@ -19,6 +19,8 @@ internal object Constants {
const val MISC_PATH = "$PATCHES_PATH/misc"
+ const val MUSIC_PATH = "$PATCHES_PATH/music"
+
const val BUTTON_PATH = "$PATCHES_PATH/button"
const val VIDEO_PATH = "$PATCHES_PATH/video"
diff --git a/src/main/resources/music/settings/host/values/strings.xml b/src/main/resources/music/settings/host/values/strings.xml
index 49d048c7a..659fd100e 100644
--- a/src/main/resources/music/settings/host/values/strings.xml
+++ b/src/main/resources/music/settings/host/values/strings.xml
@@ -6,6 +6,7 @@
Navigation
Disable forced captions from automatically enabling in video player.
Disable auto captions
+ %s is not installed. Please install it.
Sets the navigation bar color to black.
Enable black navbar
Matches the fullscreen player color with the minimized one.
@@ -41,4 +42,7 @@
"Hides the playlist card from homepage.
(requires an app restart)"
Hide playlist card
+ "Replace share button with external download button.
+(Experimental Flags)"
+ Hook share button