diff --git a/api/revanced-patches.api b/api/revanced-patches.api
index f0d4cd1a3..9de9da570 100644
--- a/api/revanced-patches.api
+++ b/api/revanced-patches.api
@@ -1194,8 +1194,8 @@ public final class app/revanced/patches/youtube/interaction/dialog/RemoveViewerD
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
-public final class app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch : app/revanced/patcher/patch/BytecodePatch {
- public static final field INSTANCE Lapp/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch;
+public final class app/revanced/patches/youtube/interaction/downloads/DownloadsPatch : app/revanced/patcher/patch/BytecodePatch {
+ public static final field INSTANCE Lapp/revanced/patches/youtube/interaction/downloads/DownloadsPatch;
public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V
public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V
}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt
index 894d30855..56c2b337d 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/copyvideourl/CopyVideoUrlBytecodePatch.kt
@@ -39,7 +39,6 @@ object CopyVideoUrlBytecodePatch : BytecodePatch(emptySet()) {
)
override fun execute(context: BytecodeContext) {
- // Initialize buttons and inject visibility control
BUTTONS_DESCRIPTORS.forEach { descriptor ->
PlayerControlsBytecodePatch.initializeControl("$descriptor->initializeButton(Landroid/view/View;)V")
PlayerControlsBytecodePatch.injectVisibilityCheckCall("$descriptor->changeVisibility(Z)V")
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt
new file mode 100644
index 000000000..82e46f5d8
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt
@@ -0,0 +1,67 @@
+package app.revanced.patches.youtube.interaction.downloads
+
+import app.revanced.patcher.data.BytecodeContext
+import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
+import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
+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.youtube.interaction.downloads.fingerprints.DownloadButtonActionFingerprint
+import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsBytecodePatch
+import app.revanced.patches.youtube.video.information.VideoInformationPatch
+import app.revanced.util.exception
+
+@Patch(
+ name = "Downloads",
+ description = "Adds support to download videos with an external downloader app" +
+ "using the in-app download button or a video player action button.",
+ dependencies = [
+ DownloadsResourcePatch::class,
+ PlayerControlsBytecodePatch::class,
+ VideoInformationPatch::class,
+ ],
+ compatiblePackages = [
+ CompatiblePackage(
+ "com.google.android.youtube",
+ [
+ "18.48.39",
+ "18.49.37",
+ "19.01.34",
+ "19.02.39",
+ "19.03.35",
+ "19.03.36",
+ "19.04.37",
+ ],
+ ),
+ ],
+)
+@Suppress("unused")
+object DownloadsPatch : BytecodePatch(
+ setOf(
+ DownloadButtonActionFingerprint,
+ ),
+) {
+ private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/DownloadsPatch;"
+ private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
+
+ override fun execute(context: BytecodeContext) {
+ PlayerControlsBytecodePatch.initializeControl("$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V")
+ PlayerControlsBytecodePatch.injectVisibilityCheckCall("$BUTTON_DESCRIPTOR->changeVisibility(Z)V")
+
+ DownloadButtonActionFingerprint.result?.let {
+ it.mutableMethod.apply {
+ addInstructionsWithLabels(
+ 2,
+ """
+ invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppDownloadButtonOnClick()Z
+ move-result v0
+ if-eqz v0, :show_dialog
+ return-void
+ """,
+ ExternalLabel("show_dialog", getInstruction(2)),
+ )
+ }
+ } ?: throw DownloadButtonActionFingerprint.exception
+ }
+}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsResourcePatch.kt
similarity index 92%
rename from src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt
rename to src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsResourcePatch.kt
index e24b7e6c1..bef29f946 100644
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsResourcePatch.kt
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsResourcePatch.kt
@@ -21,7 +21,7 @@ import app.revanced.util.copyResources
AddResourcesPatch::class,
],
)
-internal object ExternalDownloadsResourcePatch : ResourcePatch() {
+internal object DownloadsResourcePatch : ResourcePatch() {
override fun execute(context: ResourceContext) {
AddResourcesPatch(this::class)
@@ -32,6 +32,7 @@ internal object ExternalDownloadsResourcePatch : ResourcePatch() {
preferences = setOf(
SwitchPreference("revanced_external_downloader"),
TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT),
+ SwitchPreference("revanced_use_in_app_download_button"),
),
),
)
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt
deleted file mode 100644
index fdda9fdbe..000000000
--- a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package app.revanced.patches.youtube.interaction.downloads
-
-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.youtube.misc.playercontrols.PlayerControlsBytecodePatch
-import app.revanced.patches.youtube.video.information.VideoInformationPatch
-
-@Patch(
- name = "External downloads",
- description = "Adds support to download and save YouTube videos using an external downloader app.",
- dependencies = [
- ExternalDownloadsResourcePatch::class,
- PlayerControlsBytecodePatch::class,
- VideoInformationPatch::class,
- ],
- compatiblePackages = [
- CompatiblePackage(
- "com.google.android.youtube",
- [
- "18.48.39",
- "18.49.37",
- "19.01.34",
- "19.02.39",
- "19.03.35",
- "19.03.36",
- "19.04.37",
- ],
- ),
- ],
-)
-@Suppress("unused")
-object ExternalDownloadsBytecodePatch : BytecodePatch(emptySet()) {
- private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
-
- override fun execute(context: BytecodeContext) {
- /*
- initialize the control
- */
-
- PlayerControlsBytecodePatch.initializeControl(
- "$BUTTON_DESCRIPTOR->initializeButton(Landroid/view/View;)V",
- )
-
- /*
- add code to change the visibility of the control
- */
-
- PlayerControlsBytecodePatch.injectVisibilityCheckCall(
- "$BUTTON_DESCRIPTOR->changeVisibility(Z)V",
- )
- }
-}
diff --git a/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/fingerprints/DownloadButtonActionFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/fingerprints/DownloadButtonActionFingerprint.kt
new file mode 100644
index 000000000..4246f4b8a
--- /dev/null
+++ b/src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/fingerprints/DownloadButtonActionFingerprint.kt
@@ -0,0 +1,7 @@
+package app.revanced.patches.youtube.interaction.downloads.fingerprints
+
+import app.revanced.patcher.fingerprint.MethodFingerprint
+
+internal object DownloadButtonActionFingerprint : MethodFingerprint(
+ strings = listOf("offline/get_download_action"),
+)
diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml
index c7461f621..4801f8e94 100644
--- a/src/main/resources/addresources/values/strings.xml
+++ b/src/main/resources/addresources/values/strings.xml
@@ -226,7 +226,7 @@
Dialog will be shown
This does not bypass the age restriction. It just accepts it automatically.
-
+
External downloads
Settings for using an external downloader
Show external download button
@@ -235,6 +235,9 @@
Downloader package name
Package name of your installed external downloader app, such as NewPipe or Seal
%s is not installed. Please install it.
+ Use in-app download button
+ Button will launch the external downloader
+ Button will launch the native in-app downloader
Disable precise seeking gesture