From 12d2bdaafd111eee81f22bdafa306c3493754c80 Mon Sep 17 00:00:00 2001 From: swakwork Date: Sun, 22 Dec 2024 11:57:11 +0530 Subject: [PATCH 1/2] refactor(Twitter): Added 'Native features' section --- .../twitter/settings/values/strings.xml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/main/resources/twitter/settings/values/strings.xml b/src/main/resources/twitter/settings/values/strings.xml index 6110a531..7331785b 100644 --- a/src/main/resources/twitter/settings/values/strings.xml +++ b/src/main/resources/twitter/settings/values/strings.xml @@ -26,12 +26,22 @@ Copy media link Share media link - + + Native features Native downloader + Enable native downloader Download media Download all No media found + Native post translation + Enable native post translation + Translation providers + Translate to + No text found to translate + Google translator + Google translator V2 + Ads Promoted posts @@ -152,13 +162,6 @@ Single settings page View settings in a single page - Enable native post translation - Translation providers - Translate to - No text found to translate - Google translator - Google translator V2 - Users Events Ordered section From 99a10b1615ffa3fb72df0ad283255e9c837a012f Mon Sep 17 00:00:00 2001 From: swakwork Date: Sun, 22 Dec 2024 17:53:15 +0530 Subject: [PATCH 2/2] refactor(Twitter): Added Native download filename customization --- .../NativeDownloaderHooksPatch.kt | 127 +++++++++++------- .../twitter/settings/values-v21/arrays.xml | 16 +++ .../twitter/settings/values/strings.xml | 1 + 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt b/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt index 8f3c9717..1f9686de 100644 --- a/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt +++ b/src/main/kotlin/crimera/patches/twitter/misc/shareMenu/nativeDownloader/NativeDownloaderHooksPatch.kt @@ -1,9 +1,11 @@ package crimera.patches.twitter.misc.shareMenu.nativeDownloader import app.revanced.patcher.data.BytecodeContext +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.getInstructions import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.patcher.fingerprint.MethodFingerprintResult import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.PatchException import app.revanced.patcher.patch.annotation.CompatiblePackage @@ -11,14 +13,14 @@ import app.revanced.patcher.patch.annotation.Patch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.builder.instruction.BuilderInstruction21c -import com.android.tools.smali.dexlib2.dexbacked.instruction.DexBackedInstruction35c -import com.android.tools.smali.dexlib2.iface.reference.Reference +import com.android.tools.smali.dexlib2.dexbacked.reference.DexBackedMethodReference +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction internal abstract class NativeDownloaderMethodFingerprint( private val methodName: String, ) : MethodFingerprint(customFingerprint = { methodDef, classDef -> - methodDef.name == methodName && classDef.toString() == "Lapp/revanced/integrations/twitter/patches/NativeDownloader;" -}) + methodDef.name == methodName && classDef.toString() == "Lapp/revanced/integrations/twitter/patches/NativeDownloader;" + }) internal object TweetObjectFingerprint : MethodFingerprint(strings = listOf("https://x.com/%1\$s/status/%2\$d")) @@ -28,33 +30,38 @@ internal object GetTweetIdFingerprint : NativeDownloaderMethodFingerprint("getTw internal object GetTweetUsernameFingerprint : NativeDownloaderMethodFingerprint("getTweetUsername") +internal object GetTweetProfileNameFingerprint : NativeDownloaderMethodFingerprint("getTweetProfileName") + +internal object GetTweetUserIdFingerprint : NativeDownloaderMethodFingerprint("getTweetUserId") + internal object GetTweetMediaFingerprint : NativeDownloaderMethodFingerprint("getTweetMedia") internal object GetUserNameMethodCaller : MethodFingerprint( - returnType = "Z", opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT, - Opcode.RETURN - ) + returnType = "V", + strings = + listOf( + "Ref_ID (Tweet ID)", + "Name", + "User Name", + ), ) @Patch( compatiblePackages = [CompatiblePackage("com.twitter.android")], ) -class NativeDownloaderHooksPatch : BytecodePatch( - setOf( - GetTweetClassFingerprint, - GetTweetIdFingerprint, - GetTweetUsernameFingerprint, - GetTweetMediaFingerprint, - GetUserNameMethodCaller, - TweetObjectFingerprint, - ), -) { +class NativeDownloaderHooksPatch : + BytecodePatch( + setOf( + GetTweetClassFingerprint, + GetTweetIdFingerprint, + GetTweetUsernameFingerprint, + GetTweetMediaFingerprint, + GetUserNameMethodCaller, + TweetObjectFingerprint, + GetTweetProfileNameFingerprint, + GetTweetUserIdFingerprint, + ), + ) { private fun MutableMethod.changeFirstString(value: String) { this.getInstructions().firstOrNull { it.opcode == Opcode.CONST_STRING }?.let { instruction -> val register = (instruction as BuilderInstruction21c).registerA @@ -62,43 +69,55 @@ class NativeDownloaderHooksPatch : BytecodePatch( } ?: throw PatchException("const-string not found for method: ${this.name}") } - private fun Reference.getMethodFromReference(): Char { - val ref = this.toString() - val index = ref.indexOf("->") - return ref[index + 2] - } + private fun MethodFingerprintResult.getMethodName(index: Int): String = + (this.mutableMethod.getInstruction(index).reference as DexBackedMethodReference).name override fun execute(context: BytecodeContext) { - val getTweetObjectFingerprint = TweetObjectFingerprint.result ?: throw PatchException("bruh") + val getTweetObjectResult = TweetObjectFingerprint.result ?: throw PatchException("bruh") - val tweetObjectClass = getTweetObjectFingerprint.classDef + val tweetObjectClass = getTweetObjectResult.classDef val tweetObjectClassName = tweetObjectClass.toString().removePrefix("L").removeSuffix(";") - val getIdMethod = tweetObjectClass.methods.firstOrNull { mutableMethod -> - mutableMethod.name == "getId" - } ?: throw PatchException("getIdMethod not found") + val getIdMethod = + tweetObjectClass.methods.firstOrNull { mutableMethod -> + mutableMethod.name == "getId" + } ?: throw PatchException("getIdMethod not found") val getUserNameMethodCaller = GetUserNameMethodCaller.result ?: throw PatchException("Could not find UserNameMethodCaller fingerprint") - val getUserNameMethodName = getUserNameMethodCaller.method.implementation?.instructions?.firstOrNull { t -> - t.opcode == Opcode.INVOKE_STATIC - }.let { - (it as DexBackedInstruction35c).reference.getMethodFromReference() - } - val getUsernameMethod = tweetObjectClass.methods.firstOrNull { mutableMethod -> - mutableMethod.name.contains(getUserNameMethodName) && mutableMethod.returnType == "Ljava/lang/String;" - } ?: throw PatchException("getUsernameMethod not found") + var getUsernameMethod = "" + var getProfileNameMethod = "" + getUserNameMethodCaller.scanResult.stringsScanResult!!.matches.forEach { match -> + val str = match.string + if (str == "Name") { + getProfileNameMethod = getUserNameMethodCaller.getMethodName(match.index + 1) + } + if (str == "User Name") { + getUsernameMethod = getUserNameMethodCaller.getMethodName(match.index + 1) + } + } - val getMediaObjectMethod = tweetObjectClass.methods.firstOrNull { methodDef -> - methodDef.implementation?.instructions?.map { it.opcode }?.toList() == listOf( - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.IGET_OBJECT, - Opcode.RETURN_OBJECT, - ) - } ?: throw PatchException("getMediaObject not found") + val getTweetUserIdMethod = + getTweetObjectResult.classDef.methods + .last { + it.returnType.equals("J") + }.name + + val getMediaObjectMethod = + tweetObjectClass.methods.firstOrNull { methodDef -> + methodDef.implementation + ?.instructions + ?.map { it.opcode } + ?.toList() == + listOf( + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.IGET_OBJECT, + Opcode.RETURN_OBJECT, + ) + } ?: throw PatchException("getMediaObject not found") GetTweetClassFingerprint.result?.mutableMethod?.changeFirstString(tweetObjectClassName) ?: throw GetTweetClassFingerprint.exception @@ -106,9 +125,15 @@ class NativeDownloaderHooksPatch : BytecodePatch( GetTweetIdFingerprint.result?.mutableMethod?.changeFirstString(getIdMethod.name) ?: throw GetTweetIdFingerprint.exception - GetTweetUsernameFingerprint.result?.mutableMethod?.changeFirstString(getUsernameMethod.name) + GetTweetUsernameFingerprint.result?.mutableMethod?.changeFirstString(getUsernameMethod) ?: throw GetTweetUsernameFingerprint.exception + GetTweetProfileNameFingerprint.result?.mutableMethod?.changeFirstString(getProfileNameMethod) + ?: throw GetTweetProfileNameFingerprint.exception + + GetTweetUserIdFingerprint.result?.mutableMethod?.changeFirstString(getTweetUserIdMethod) + ?: throw GetTweetUserIdFingerprint.exception + GetTweetMediaFingerprint.result?.mutableMethod?.changeFirstString(getMediaObjectMethod.name) ?: throw GetTweetMediaFingerprint.exception } diff --git a/src/main/resources/twitter/settings/values-v21/arrays.xml b/src/main/resources/twitter/settings/values-v21/arrays.xml index e06eea39..71cb67d8 100644 --- a/src/main/resources/twitter/settings/values-v21/arrays.xml +++ b/src/main/resources/twitter/settings/values-v21/arrays.xml @@ -67,4 +67,20 @@ 7 13 + + + username_tweetid + name_tweetid + userid_tweetid + tweetid + Current timestamp + + + + 1 + 2 + 3 + 4 + 5 + \ No newline at end of file diff --git a/src/main/resources/twitter/settings/values/strings.xml b/src/main/resources/twitter/settings/values/strings.xml index 7331785b..c21e6a6e 100644 --- a/src/main/resources/twitter/settings/values/strings.xml +++ b/src/main/resources/twitter/settings/values/strings.xml @@ -33,6 +33,7 @@ Download media Download all No media found + Save filename pattern Native post translation Enable native post translation