diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/download/DownloadsPatch.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/download/DownloadsPatch.java index 8a419a9774..bd2444d38d 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/download/DownloadsPatch.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/download/DownloadsPatch.java @@ -1,9 +1,10 @@ package app.revanced.extension.tiktok.download; -import app.revanced.extension.tiktok.settings.Settings; +import com.ss.android.ugc.aweme.feed.model.Video; @SuppressWarnings("unused") public class DownloadsPatch { + public static String getDownloadPath() { return "Pictures/Tiktok"; //return Settings.DOWNLOAD_PATH.get(); @@ -13,4 +14,30 @@ public class DownloadsPatch { return true; //return Settings.DOWNLOAD_WATERMARK.get(); } -} + + public static void patchVideoObject(Video video) { + if (video == null) return; + + try { + boolean isMissingCleanUrl = false; + + // non-watermark url is removed by tiktok for some videos (licensing/user restrictions) + if (video.downloadNoWatermarkAddr == null) { + isMissingCleanUrl = true; + } else if (video.downloadNoWatermarkAddr.getUrlList() == null || video.downloadNoWatermarkAddr.getUrlList().isEmpty()) { + isMissingCleanUrl = true; + } + + // overwrite field with the play address if empty + if (isMissingCleanUrl) { + if (video.h264PlayAddr != null && video.h264PlayAddr.getUrlList() != null && !video.h264PlayAddr.getUrlList().isEmpty()) { + video.downloadNoWatermarkAddr = video.h264PlayAddr; + } else if (video.playAddr != null) { + // fallback + video.downloadNoWatermarkAddr = video.playAddr; + } + } + } catch (Throwable t) { + } + } +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/base/model/UrlModel.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/base/model/UrlModel.java new file mode 100644 index 0000000000..392be76b1c --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/base/model/UrlModel.java @@ -0,0 +1,7 @@ +package com.ss.android.ugc.aweme.base.model; +import java.util.List; + +public class UrlModel { + public List getUrlList() { throw new UnsupportedOperationException("Stub"); } + public String getUri() { throw new UnsupportedOperationException("Stub"); } +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Video.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Video.java new file mode 100644 index 0000000000..619e5d6f01 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Video.java @@ -0,0 +1,8 @@ +package com.ss.android.ugc.aweme.feed.model; +import com.ss.android.ugc.aweme.base.model.UrlModel; + +public class Video { + public VideoUrlModel playAddr; + public VideoUrlModel h264PlayAddr; + public UrlModel downloadNoWatermarkAddr; +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/VideoUrlModel.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/VideoUrlModel.java new file mode 100644 index 0000000000..42877cf4c2 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/VideoUrlModel.java @@ -0,0 +1,5 @@ +package com.ss.android.ugc.aweme.feed.model; +import com.ss.android.ugc.aweme.base.model.UrlModel; + +public class VideoUrlModel extends UrlModel { +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt index 6b17009ab6..2a35a038b3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/DownloadsPatch.kt @@ -11,6 +11,7 @@ import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference import app.revanced.util.returnEarly +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 import com.android.tools.smali.dexlib2.iface.reference.FieldReference @@ -35,7 +36,6 @@ val downloadsPatch = bytecodePatch( aclCommonShareFingerprint.method.returnEarly(0) aclCommonShare2Fingerprint.method.returnEarly(2) - // Download videos without watermark. aclCommonShare3Fingerprint.method.addInstructionsWithLabels( 0, """ @@ -49,7 +49,18 @@ val downloadsPatch = bytecodePatch( """, ) - // Change the download path patch. + awemeGetVideoFingerprint.method.apply { + val returnIndex = findInstructionIndicesReversedOrThrow { opcode == Opcode.RETURN_OBJECT }.first() + val register = getInstruction(returnIndex).registerA + + addInstructions( + returnIndex, + """ + invoke-static {v$register}, $EXTENSION_CLASS_DESCRIPTOR->patchVideoObject(Lcom/ss/android/ugc/aweme/feed/model/Video;)V + """ + ) + } + downloadUriFingerprint.method.apply { findInstructionIndicesReversedOrThrow { getReference().let { @@ -78,4 +89,4 @@ val downloadsPatch = bytecodePatch( "invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableDownload()V", ) } -} +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt index 160b49c158..26f898ec92 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/downloads/Fingerprints.kt @@ -44,3 +44,13 @@ internal val downloadUriFingerprint = fingerprint { "video/mp4" ) } + +internal val awemeGetVideoFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC) + returns("Lcom/ss/android/ugc/aweme/feed/model/Video;") + custom { method, classDef -> + classDef.endsWith("/Aweme;") && + method.name == "getVideo" && + method.parameterTypes.isEmpty() + } +}