From d9000113a905c14f8409aa75008f1ef6a1aecd0c Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 4 Mar 2024 20:36:25 +0100 Subject: [PATCH] feat(YouTube - External downloader): Add ability to use in-app download button --- api/revanced-patches.api | 4 +- .../copyvideourl/CopyVideoUrlBytecodePatch.kt | 1 - .../interaction/downloads/DownloadsPatch.kt | 67 +++++++++++++++++++ ...urcePatch.kt => DownloadsResourcePatch.kt} | 3 +- .../ExternalDownloadsBytecodePatch.kt | 54 --------------- .../DownloadButtonActionFingerprint.kt | 7 ++ .../resources/addresources/values/strings.xml | 5 +- 7 files changed, 82 insertions(+), 59 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/DownloadsPatch.kt rename src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/{ExternalDownloadsResourcePatch.kt => DownloadsResourcePatch.kt} (92%) delete mode 100644 src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/ExternalDownloadsBytecodePatch.kt create mode 100644 src/main/kotlin/app/revanced/patches/youtube/interaction/downloads/fingerprints/DownloadButtonActionFingerprint.kt diff --git a/api/revanced-patches.api b/api/revanced-patches.api index f0d4cd1a..9de9da57 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 894d3085..56c2b337 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 00000000..82e46f5d --- /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 e24b7e6c..bef29f94 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 fdda9fdb..00000000 --- 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 00000000..4246f4b8 --- /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 c7461f62..4801f8e9 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