feat(Twitter - Unlock downloads): Unlock GIF downloads

This commit is contained in:
oSumAtrIX 2024-02-25 07:59:11 +01:00
parent 1a89dd9f8c
commit d0f91c8550
No known key found for this signature in database
GPG key ID: A9B3094ACDB604B4
2 changed files with 50 additions and 3 deletions

View file

@ -2,27 +2,36 @@ package app.revanced.patches.twitter.interaction.downloads
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction 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.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.fingerprint.MethodFingerprint import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.fingerprint.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.annotation.CompatiblePackage import app.revanced.patcher.patch.annotation.CompatiblePackage
import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.patch.annotation.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.twitter.interaction.downloads.fingerprints.BuildMediaOptionsSheetFingerprint
import app.revanced.patches.twitter.interaction.downloads.fingerprints.ConstructMediaOptionsSheetFingerprint import app.revanced.patches.twitter.interaction.downloads.fingerprints.ConstructMediaOptionsSheetFingerprint
import app.revanced.patches.twitter.interaction.downloads.fingerprints.ShowDownloadVideoUpsellBottomSheetFingerprint import app.revanced.patches.twitter.interaction.downloads.fingerprints.ShowDownloadVideoUpsellBottomSheetFingerprint
import app.revanced.util.exception import app.revanced.util.exception
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
@Patch( @Patch(
name = "Unlock downloads", name = "Unlock downloads",
description = "Unlocks the ability to download any video.", description = "Unlocks the ability to download any video. GIFs can be downloaded via the menu on long press.",
compatiblePackages = [CompatiblePackage("com.twitter.android")] compatiblePackages = [CompatiblePackage("com.twitter.android")],
) )
@Suppress("unused") @Suppress("unused")
object UnlockDownloadsPatch : BytecodePatch( object UnlockDownloadsPatch : BytecodePatch(
setOf(ConstructMediaOptionsSheetFingerprint, ShowDownloadVideoUpsellBottomSheetFingerprint) setOf(
ConstructMediaOptionsSheetFingerprint,
ShowDownloadVideoUpsellBottomSheetFingerprint,
BuildMediaOptionsSheetFingerprint,
),
) { ) {
override fun execute(context: BytecodeContext) { override fun execute(context: BytecodeContext) {
fun MethodFingerprint.patch(getRegisterAndIndex: MethodFingerprintResult.() -> Pair<Int, Int>) = result?.let { fun MethodFingerprint.patch(getRegisterAndIndex: MethodFingerprintResult.() -> Pair<Int, Int>) = result?.let {
@ -46,5 +55,29 @@ object UnlockDownloadsPatch : BytecodePatch(
showDownloadButtonIndex to register showDownloadButtonIndex to register
} }
// Make GIFs downloadable.
BuildMediaOptionsSheetFingerprint.result?.let {
val scanResult = it.scanResult.patternScanResult!!
it.mutableMethod.apply {
val checkMediaTypeIndex = scanResult.startIndex
val checkMediaTypeInstruction = getInstruction<TwoRegisterInstruction>(checkMediaTypeIndex)
// Treat GIFs as videos.
addInstructionsWithLabels(
checkMediaTypeIndex + 1,
"""
const/4 v${checkMediaTypeInstruction.registerB}, 0x2 # GIF
if-eq v${checkMediaTypeInstruction.registerA}, v${checkMediaTypeInstruction.registerB}, :video
""",
ExternalLabel("video", getInstruction(scanResult.endIndex)),
)
// Remove media.isDownloadable check.
removeInstruction(
getInstructions().first { insn -> insn.opcode == Opcode.IGET_BOOLEAN }.location.index + 1,
)
}
} ?: throw BuildMediaOptionsSheetFingerprint.exception
} }
} }

View file

@ -0,0 +1,14 @@
package app.revanced.patches.twitter.interaction.downloads.fingerprints
import app.revanced.patcher.fingerprint.MethodFingerprint
import com.android.tools.smali.dexlib2.Opcode
internal object BuildMediaOptionsSheetFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.IF_EQ,
Opcode.SGET_OBJECT,
Opcode.GOTO_16,
Opcode.NEW_INSTANCE,
),
strings = listOf("resources.getString(R.string.post_video)"),
)