diff --git a/api/revanced-patches.api b/api/revanced-patches.api index 262eb3e94..10956e60c 100644 --- a/api/revanced-patches.api +++ b/api/revanced-patches.api @@ -1065,6 +1065,12 @@ public final class app/revanced/patches/twitch/misc/settings/SettingsResourcePat public static final field INSTANCE Lapp/revanced/patches/twitch/misc/settings/SettingsResourcePatch; } +public final class app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch : app/revanced/patcher/patch/BytecodePatch { + public static final field INSTANCE Lapp/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch; + public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V + public synthetic fun execute (Lapp/revanced/patcher/data/Context;)V +} + public final class app/revanced/patches/twitter/layout/viewcount/HideViewCountPatch : app/revanced/patcher/patch/BytecodePatch { public static final field INSTANCE Lapp/revanced/patches/twitter/layout/viewcount/HideViewCountPatch; public fun execute (Lapp/revanced/patcher/data/BytecodeContext;)V diff --git a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt new file mode 100644 index 000000000..ee13fab68 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/UnlockDownloadsPatch.kt @@ -0,0 +1,50 @@ +package app.revanced.patches.twitter.interaction.downloads + +import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.getInstructions +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.fingerprint.MethodFingerprintResult +import app.revanced.patcher.patch.BytecodePatch +import app.revanced.patcher.patch.annotation.CompatiblePackage +import app.revanced.patcher.patch.annotation.Patch +import app.revanced.patches.twitter.interaction.downloads.fingerprints.ConstructMediaOptionsSheetFingerprint +import app.revanced.patches.twitter.interaction.downloads.fingerprints.ShowDownloadVideoUpsellBottomSheetFingerprint +import app.revanced.util.exception +import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction + +@Patch( + name = "Unlock downloads", + description = "Unlocks the ability to download any video.", + compatiblePackages = [CompatiblePackage("com.twitter.android")] +) +@Suppress("unused") +object UnlockDownloadsPatch : BytecodePatch( + setOf(ConstructMediaOptionsSheetFingerprint, ShowDownloadVideoUpsellBottomSheetFingerprint) +) { + override fun execute(context: BytecodeContext) { + fun MethodFingerprint.patch(getRegisterAndIndex: MethodFingerprintResult.() -> Pair) = result?.let { + getRegisterAndIndex(it).let { (index, register) -> + it.mutableMethod.addInstruction(index, "const/4 v$register, 0x1") + } + } ?: throw exception + + // Allow downloads for non-premium users. + ShowDownloadVideoUpsellBottomSheetFingerprint.patch { + val checkIndex = scanResult.patternScanResult!!.startIndex + val register = mutableMethod.getInstruction(checkIndex).registerA + + checkIndex to register + } + + // Force show the download menu item. + ConstructMediaOptionsSheetFingerprint.patch { + val showDownloadButtonIndex = mutableMethod.getInstructions().lastIndex - 1 + val register = mutableMethod.getInstruction(showDownloadButtonIndex).registerA + + showDownloadButtonIndex to register + } + } +} diff --git a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ConstructMediaOptionsSheetFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ConstructMediaOptionsSheetFingerprint.kt new file mode 100644 index 000000000..86b2a247b --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ConstructMediaOptionsSheetFingerprint.kt @@ -0,0 +1,12 @@ +package app.revanced.patches.twitter.interaction.downloads.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.AccessFlags + + +internal object ConstructMediaOptionsSheetFingerprint : MethodFingerprint( + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, + strings = listOf("captionsState") +) diff --git a/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt new file mode 100644 index 000000000..1257d0f58 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/twitter/interaction/downloads/fingerprints/ShowDownloadVideoUpsellBottomSheetFingerprint.kt @@ -0,0 +1,10 @@ +package app.revanced.patches.twitter.interaction.downloads.fingerprints + +import app.revanced.patcher.fingerprint.MethodFingerprint +import com.android.tools.smali.dexlib2.Opcode + +internal object ShowDownloadVideoUpsellBottomSheetFingerprint : MethodFingerprint( + returnType = "Z", + strings = listOf("variantToDownload.url"), + opcodes = listOf(Opcode.IF_EQZ) +)