From 944aa485cec513faa30a21b91887dcacf9d70b45 Mon Sep 17 00:00:00 2001 From: d4rkk3y <43563783+d4rkk3y@users.noreply.github.com> Date: Thu, 15 Sep 2022 21:04:20 +0700 Subject: [PATCH] feat(tiktok-download): custom download path (#479) --- .../DownloadPathParentFingerprint.kt | 23 +++++ .../downloads/patch/DownloadsPatch.kt | 89 +++++++++++++++++-- 2 files changed, 107 insertions(+), 5 deletions(-) create mode 100644 src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt new file mode 100644 index 000000000..dda746765 --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/fingerprints/DownloadPathParentFingerprint.kt @@ -0,0 +1,23 @@ +package app.revanced.patches.tiktok.interaction.downloads.fingerprints + +import app.revanced.patcher.annotation.Name +import app.revanced.patcher.annotation.Version +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.method.annotation.MatchingMethod +import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint +import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility +import org.jf.dexlib2.AccessFlags + +@Name("download-path-parent-fingerprint") +@MatchingMethod("LX/4bF;", "LIZ") +@DownloadsCompatibility +@Version("0.0.1") +object DownloadPathParentFingerprint : MethodFingerprint( + "V", + AccessFlags.PUBLIC or AccessFlags.FINAL, + strings = listOf( + "code", + "reason", + "params insufficient" + ) +) \ No newline at end of file diff --git a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt index 0360d2dbe..3e2cb34a4 100644 --- a/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt +++ b/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/patch/DownloadsPatch.kt @@ -4,24 +4,34 @@ import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Version import app.revanced.patcher.data.impl.BytecodeData +import app.revanced.patcher.data.impl.toMethodWalker +import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstructions -import app.revanced.patcher.patch.PatchResult -import app.revanced.patcher.patch.PatchResultSuccess +import app.revanced.patcher.patch.* import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.impl.BytecodePatch +import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patches.tiktok.interaction.downloads.annotations.DownloadsCompatibility -import app.revanced.patches.tiktok.interaction.downloads.fingerprints.* +import app.revanced.patches.tiktok.interaction.downloads.fingerprints.ACLCommonShareFingerprint +import app.revanced.patches.tiktok.interaction.downloads.fingerprints.ACLCommonShareFingerprint2 +import app.revanced.patches.tiktok.interaction.downloads.fingerprints.ACLCommonShareFingerprint3 +import app.revanced.patches.tiktok.interaction.downloads.fingerprints.DownloadPathParentFingerprint +import org.jf.dexlib2.Opcode +import org.jf.dexlib2.iface.instruction.OneRegisterInstruction +import org.jf.dexlib2.iface.instruction.ReferenceInstruction +import org.jf.dexlib2.iface.reference.StringReference @Patch @Name("tiktok-download") -@Description("Remove restrictions on downloads video.") +@Description("Removes download restrictions and changes the default path to download to.") @DownloadsCompatibility @Version("0.0.1") class DownloadsPatch : BytecodePatch( listOf( ACLCommonShareFingerprint, ACLCommonShareFingerprint2, - ACLCommonShareFingerprint3 + ACLCommonShareFingerprint3, + DownloadPathParentFingerprint ) ) { override fun execute(data: BytecodeData): PatchResult { @@ -50,7 +60,76 @@ class DownloadsPatch : BytecodePatch( return v0 """ ) + //Change the download path patch + val method4 = DownloadPathParentFingerprint.result!!.mutableMethod + val implementation4 = method4.implementation + val instructions = implementation4!!.instructions + var targetOffset = -1 + //Search for the target method called instruction offset. + for ((index, instruction) in instructions.withIndex()) { + if (instruction.opcode != Opcode.CONST_STRING) continue + val reference = (instruction as ReferenceInstruction).reference as StringReference + if (reference.string != "video/mp4") continue + val targetInstruction = instructions[index + 1] + if (targetInstruction.opcode != Opcode.INVOKE_STATIC) continue + targetOffset = index + 1 + break + } + if (targetOffset == -1) return PatchResultError("Can not find download path uri method.") + //Change videos' download path. + val downloadPath = "$downloadPathParent/$downloadPathChild" + val downloadUriMethod = data + .toMethodWalker(DownloadPathParentFingerprint.result!!.method) + .nextMethod(targetOffset, true) + .getMethod() as MutableMethod + downloadUriMethod.implementation!!.instructions.forEachIndexed { index, instruction -> + if (instruction.opcode == Opcode.SGET_OBJECT) { + val overrideRegister = (instruction as OneRegisterInstruction).registerA + downloadUriMethod.replaceInstruction( + index, + """ + const-string v$overrideRegister, "$downloadPath" + """ + ) + } + if (instruction.opcode == Opcode.CONST_STRING) { + val string = ((instruction as ReferenceInstruction).reference as StringReference).string + if (string.contains("/Camera")) { + val overrideRegister = (instruction as OneRegisterInstruction).registerA + val overrideString = string.replace("/Camera", "") + downloadUriMethod.replaceInstruction( + index, + """ + const-string v$overrideRegister, "$overrideString" + """ + ) + } + } + } return PatchResultSuccess() } + companion object : OptionsContainer() { + private var downloadPathParent: String? by option( + PatchOption.StringListOption( + key = "mediaFolder", + default = "DCIM", + options = listOf( + "DCIM", "Movies", "Pictures" + ), + title = "Media folder", + description = "The media root folder to download to.", + required = true + ) + ) + private var downloadPathChild: String? by option( + PatchOption.StringOption( + key = "downloadPath", + default = "TikTok", + title = "Download path", + description = "Download path relative to the media folder.", + required = true + ) + ) + } } \ No newline at end of file