Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(YouTube - Downloads): Use new task context #2841

Merged
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions api/revanced-patches.api
Original file line number Diff line number Diff line change
Expand Up @@ -1748,6 +1748,7 @@ public final class app/revanced/util/BytecodeUtilsKt {
public static final fun indexOfFirstInstruction (Lcom/android/tools/smali/dexlib2/iface/Method;Lkotlin/jvm/functions/Function1;)I
public static final fun indexOfFirstWideLiteralInstructionValue (Lcom/android/tools/smali/dexlib2/iface/Method;J)I
public static final fun injectHideViewCall (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableMethod;IILjava/lang/String;Ljava/lang/String;)V
public static final fun resultOrThrow (Lapp/revanced/patcher/fingerprint/MethodFingerprint;)Lapp/revanced/patcher/fingerprint/MethodFingerprintResult;
public static final fun returnEarly (Ljava/util/List;Z)V
public static synthetic fun returnEarly$default (Ljava/util/List;ZILjava/lang/Object;)V
public static final fun transformMethods (Lapp/revanced/patcher/util/proxy/mutableTypes/MutableClass;Lkotlin/jvm/functions/Function1;)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ abstract class BaseIntegrationsPatch(

method.addInstruction(
0,
"sput-object v$contextRegister, " +
"$integrationsDescriptor->context:Landroid/content/Context;",
"invoke-static/range { v$contextRegister .. v$contextRegister }, " +
"$integrationsDescriptor->setContext(Landroid/content/Context;)V",
)
} ?: throw PatchException("Could not find hook target fingerprint.")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package app.revanced.patches.youtube.interaction.downloads

import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
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.interaction.downloads.fingerprints.DownloadActionCommandResolverFingerprint
import app.revanced.patches.youtube.interaction.downloads.fingerprints.DownloadActionCommandResolverParentFingerprint
import app.revanced.patches.youtube.interaction.downloads.fingerprints.LegacyDownloadCommandResolverFingerprint
import app.revanced.patches.youtube.misc.playercontrols.PlayerControlsBytecodePatch
import app.revanced.patches.youtube.shared.fingerprints.MainActivityFingerprint
import app.revanced.patches.youtube.video.information.VideoInformationPatch
import app.revanced.util.exception
import app.revanced.util.resultOrThrow

@Patch(
name = "Downloads",
Expand Down Expand Up @@ -39,8 +41,10 @@ import app.revanced.util.exception
@Suppress("unused")
object DownloadsPatch : BytecodePatch(
setOf(
DownloadButtonActionFingerprint,
),
DownloadActionCommandResolverParentFingerprint,
LegacyDownloadCommandResolverFingerprint,
MainActivityFingerprint
)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/DownloadsPatch;"
private const val BUTTON_DESCRIPTOR = "Lapp/revanced/integrations/youtube/videoplayer/ExternalDownloadButton;"
Expand All @@ -49,19 +53,44 @@ object DownloadsPatch : BytecodePatch(
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
// Main activity is used to launch downloader intent.
MainActivityFingerprint.resultOrThrow().mutableMethod.apply {
LisoUseInAIKyrios marked this conversation as resolved.
Show resolved Hide resolved
addInstruction(
implementation!!.instructions.lastIndex,
"invoke-static { p0 }, $INTEGRATIONS_CLASS_DESCRIPTOR->activityCreated(Landroid/app/Activity;)V"
)
}

val commonInstructions = """
move-result v0
if-eqz v0, :show_native_downloader
return-void
:show_native_downloader
nop
"""

DownloadActionCommandResolverFingerprint.resolve(context,
DownloadActionCommandResolverParentFingerprint.resultOrThrow().classDef)
DownloadActionCommandResolverFingerprint.resultOrThrow().mutableMethod.apply {
addInstructionsWithLabels(
0,
"""
invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppDownloadButtonOnClick()Z
$commonInstructions
"""
)
}

// Legacy fingerprint is used for old spoofed versions,
// or if download playlist is pressed on any version.
LegacyDownloadCommandResolverFingerprint.resultOrThrow().mutableMethod.apply {
addInstructionsWithLabels(
0,
"""
invoke-static/range {p1 .. p1}, $INTEGRATIONS_CLASS_DESCRIPTOR->inAppDownloadPlaylistLegacyOnClick(Ljava/lang/String;)Z
$commonInstructions
"""
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ internal object DownloadsResourcePatch : ResourcePatch() {
sorting = Sorting.UNSORTED,
preferences = setOf(
SwitchPreference("revanced_external_downloader"),
SwitchPreference("revanced_external_downloader_action_button"),
TextPreference("revanced_external_downloader_name", inputType = InputType.TEXT),
SwitchPreference("revanced_use_in_app_download_button"),
),
),
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package app.revanced.patches.youtube.interaction.downloads.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

/**
* Resolves to the class found in [DownloadActionCommandResolverParentFingerprint].
*/
internal object DownloadActionCommandResolverFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V",
parameters = listOf("L", "Ljava/util/Map;")
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package app.revanced.patches.youtube.interaction.downloads.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.util.patch.LiteralValueFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

internal object DownloadActionCommandResolverParentFingerprint : LiteralValueFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V",
parameters = listOf("L", "L"),
strings = listOf(
// Strings are not unique and found in other methods.
"com.google.android.libraries.youtube.logging.interaction_logger",
"Unknown command"
),
literalSupplier = { 16 }
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package app.revanced.patches.youtube.interaction.downloads.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode

/**
* For spoofing to older versions.
*/
internal object LegacyDownloadCommandResolverFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "V",
parameters = listOf("Ljava/lang/String;", "Ljava/lang/String;", "L", "L"),
strings = listOf(""),
opcodes = listOf(
Opcode.MOVE_OBJECT_FROM16,
Opcode.MOVE_OBJECT_FROM16,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IGET_OBJECT,
Opcode.IF_NEZ,
)
)
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import app.revanced.patches.youtube.video.videoid.VideoIdPatch
import app.revanced.util.exception
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
Expand Down Expand Up @@ -88,8 +89,6 @@ object ReturnYouTubeDislikePatch : BytecodePatch(
private const val FILTER_CLASS_DESCRIPTOR =
"Lapp/revanced/integrations/youtube/patches/components/ReturnYouTubeDislikeFilterPatch;"

private fun MethodFingerprint.resultOrThrow() = result ?: throw exception

override fun execute(context: BytecodeContext) {
// region Inject newVideoLoaded event handler to update dislikes when a new video is loaded.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.reques
import app.revanced.patches.youtube.layout.thumbnails.fingerprints.cronet.request.callback.OnSucceededFingerprint
import app.revanced.patches.youtube.misc.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.settings.SettingsPatch
import app.revanced.util.exception
import app.revanced.util.resultOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
Expand Down Expand Up @@ -144,11 +144,8 @@ object AlternativeThumbnailsPatch : BytecodePatch(
NonInteractivePreference("revanced_alt_thumbnail_stills_about"),
)

fun MethodFingerprint.getResultOrThrow() =
result ?: throw exception

fun MethodFingerprint.alsoResolve(fingerprint: MethodFingerprint) =
also { resolve(context, fingerprint.getResultOrThrow().classDef) }.getResultOrThrow()
also { resolve(context, fingerprint.resultOrThrow().classDef) }.resultOrThrow()

fun MethodFingerprint.resolveAndLetMutableMethod(
fingerprint: MethodFingerprint,
Expand All @@ -172,7 +169,7 @@ object AlternativeThumbnailsPatch : BytecodePatch(

// The URL is required for the failure callback hook, but the URL field is obfuscated.
// Add a helper get method that returns the URL field.
RequestFingerprint.getResultOrThrow().apply {
RequestFingerprint.resultOrThrow().apply {
// The url is the only string field that is set inside the constructor.
val urlFieldInstruction = mutableMethod.getInstructions().first {
if (it.opcode != Opcode.IPUT_OBJECT) return@first false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@ package app.revanced.patches.youtube.misc.playeroverlay
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
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.integrations.IntegrationsPatch
import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint
import app.revanced.util.exception

@Patch(
description = "Hook for adding custom overlays to the video player.",
description = "Hook for the video player overlay",
dependencies = [IntegrationsPatch::class],
compatiblePackages = [
CompatiblePackage("com.google.android.youtube", [
"18.32.39"
])
]
)

/**
* Edit: This patch is not in use and may not work.
*/
@Suppress("unused")
object PlayerOverlaysHookPatch : BytecodePatch( // TODO: delete this unused outdated patch and its integration code.
object PlayerOverlaysHookPatch : BytecodePatch(
setOf(PlayerOverlaysOnFinishInflateFingerprint)
) {
private const val INTEGRATIONS_CLASS_DESCRIPTOR = "Lapp/revanced/integrations/youtube/patches/PlayerOverlaysHookPatch;"

override fun execute(context: BytecodeContext) {
// hook YouTubePlayerOverlaysLayout.onFinishInflate()
val method = PlayerOverlaysOnFinishInflateFingerprint.result!!.mutableMethod
method.addInstruction(
method.implementation!!.instructions.size - 2,
"invoke-static { p0 }, Lapp/revanced/integrations/youtube/patches/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V"
)
PlayerOverlaysOnFinishInflateFingerprint.result?.mutableMethod?.apply {
addInstruction(
implementation!!.instructions.lastIndex,
"invoke-static { p0 }, $INTEGRATIONS_CLASS_DESCRIPTOR->playerOverlayInflated(Landroid/view/ViewGroup;)V"
)
} ?: throw PlayerOverlaysOnFinishInflateFingerprint.exception
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package app.revanced.patches.youtube.misc.playeroverlay.fingerprint


import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.AccessFlags

internal object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "V",
customFingerprint = { methodDef, _ ->
methodDef.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && methodDef.name == "onFinishInflate"
}
methodDef.definingClass.endsWith("/YouTubePlayerOverlaysLayout;")
&& methodDef.name == "onFinishInflate"
},
)
3 changes: 3 additions & 0 deletions src/main/kotlin/app/revanced/util/BytecodeUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ import com.android.tools.smali.dexlib2.iface.instruction.WideLiteralInstruction
import com.android.tools.smali.dexlib2.iface.reference.Reference
import com.android.tools.smali.dexlib2.util.MethodUtil


fun MethodFingerprint.resultOrThrow() = result ?: throw exception

/**
* The [PatchException] of failing to resolve a [MethodFingerprint].
*
Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/addresources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -232,12 +232,12 @@
<string name="revanced_external_downloader_title">Show external download button</string>
<string name="revanced_external_downloader_summary_on">Download button shown in player</string>
<string name="revanced_external_downloader_summary_off">Download button not shown in player</string>
<string name="revanced_external_downloader_action_button_title">Override player action button</string>
LisoUseInAIKyrios marked this conversation as resolved.
Show resolved Hide resolved
<string name="revanced_external_downloader_action_button_summary_on">Download action button will launch the external downloader</string>
<string name="revanced_external_downloader_action_button_summary_off">Download action button will launch the native in-app downloader</string>
<string name="revanced_external_downloader_name_title">Downloader package name</string>
<string name="revanced_external_downloader_name_summary">Package name of your installed external downloader app, such as NewPipe or Seal</string>
<string name="revanced_external_downloader_not_installed_warning">%s is not installed. Please install it.</string>
<string name="revanced_use_in_app_download_button_title">Use in-app download button</string>
<string name="revanced_use_in_app_download_button_summary_on">Button will launch the external downloader</string>
<string name="revanced_use_in_app_download_button_summary_off">Button will launch the native in-app downloader</string>
</patch>
<patch id="interaction.seekbar.DisablePreciseSeekingGesturePatch">
<string name="revanced_disable_precise_seeking_gesture_title">Disable precise seeking gesture</string>
Expand Down
Loading