From 0ad2464cba48b96cbb3fd72f2d92f0508f4b4596 Mon Sep 17 00:00:00 2001 From: Ulises M Date: Mon, 9 Feb 2026 21:21:49 -0800 Subject: [PATCH 1/5] no settings or remember speed patches --- .../tiktok/download/DownloadsPatch.java | 6 +- .../tiktok/feedfilter/AdsFilter.java | 21 +++++- .../tiktok/feedfilter/FeedItemsFilter.java | 74 +++++++++++++------ .../tiktok/feedfilter/ImageVideoFilter.java | 5 +- .../tiktok/feedfilter/LiveFilter.java | 7 +- .../tiktok/feedfilter/ShopFilter.java | 6 +- .../tiktok/share/ShareUrlSanitizer.java | 3 +- .../aweme/commerce/AwemeCommerceStruct.java | 16 ++++ .../android/ugc/aweme/feed/model/Aweme.java | 33 +++++++-- .../aweme/feed/model/PhotoModeImageInfo.java | 6 ++ .../aweme/feed/model/PhotoModeTextInfo.java | 6 ++ .../tiktok/feedfilter/FeedFilterPatch.kt | 62 +++++++++------- .../patches/tiktok/feedfilter/Fingerprints.kt | 19 ++--- .../cleardisplay/RememberClearDisplayPatch.kt | 4 +- .../interaction/downloads/DownloadsPatch.kt | 6 +- .../tiktok/interaction/speed/Fingerprints.kt | 8 +- .../interaction/speed/PlaybackSpeedPatch.kt | 1 + .../patches/tiktok/misc/share/Fingerprints.kt | 17 +++-- .../misc/share/SanitizeShareUrlsPatch.kt | 53 ++----------- 19 files changed, 214 insertions(+), 139 deletions(-) create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeImageInfo.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeTextInfo.java 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 c55d62878c..8a419a9774 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 @@ -5,10 +5,12 @@ import app.revanced.extension.tiktok.settings.Settings; @SuppressWarnings("unused") public class DownloadsPatch { public static String getDownloadPath() { - return Settings.DOWNLOAD_PATH.get(); + return "Pictures/Tiktok"; + //return Settings.DOWNLOAD_PATH.get(); } public static boolean shouldRemoveWatermark() { - return Settings.DOWNLOAD_WATERMARK.get(); + return true; + //return Settings.DOWNLOAD_WATERMARK.get(); } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java index 31a982c684..cd90f9d9d3 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java @@ -2,15 +2,32 @@ package app.revanced.extension.tiktok.feedfilter; import app.revanced.extension.tiktok.settings.Settings; import com.ss.android.ugc.aweme.feed.model.Aweme; +import com.ss.android.ugc.aweme.commerce.AwemeCommerceStruct; public class AdsFilter implements IFilter { @Override public boolean getEnabled() { - return Settings.REMOVE_ADS.get(); + return true; + // return Settings.REMOVE_ADS.get(); } @Override public boolean getFiltered(Aweme item) { - return item.isAd() || item.isWithPromotionalMusic(); + try { + // Standard Ads & Promotional Music + if (item.isAd() || item.isWithPromotionalMusic()) { + return true; + } + + // Paid Partnerships (Branded Content) + if (item.mCommerceVideoAuthInfo != null) { + if (item.mCommerceVideoAuthInfo.isBrandedContent()) { + return true; + } + } + } catch (Throwable t) { + return false; + } + return false; } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java index 6b361bb618..5833284a25 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java @@ -1,5 +1,7 @@ package app.revanced.extension.tiktok.feedfilter; +import app.revanced.extension.shared.Logger; +import app.revanced.extension.shared.settings.BaseSettings; import com.ss.android.ugc.aweme.feed.model.Aweme; import com.ss.android.ugc.aweme.feed.model.FeedItemList; import com.ss.android.ugc.aweme.follow.presenter.FollowFeedList; @@ -8,43 +10,73 @@ import java.util.Iterator; import java.util.List; public final class FeedItemsFilter { - private static final List FILTERS = List.of( - new AdsFilter(), - new LiveFilter(), - new StoryFilter(), - new ImageVideoFilter(), - new ViewCountFilter(), - new LikeCountFilter(), - new ShopFilter() - ); - public static void filter(FeedItemList feedItemList) { - filterFeedList(feedItemList.items, item -> item); + boolean verbose = BaseSettings.DEBUG.get(); + if (feedItemList == null || feedItemList.items == null) return; + + filterFeedList("FeedItemList", feedItemList.items, item -> item, verbose); } public static void filter(FollowFeedList followFeedList) { - filterFeedList(followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null); + boolean verbose = BaseSettings.DEBUG.get(); + if (followFeedList == null || followFeedList.mItems == null) return; + + filterFeedList("FollowFeedList", followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null, verbose); } - private static void filterFeedList(List list, AwemeExtractor extractor) { - // Could be simplified with removeIf() but requires Android 7.0+ while TikTok supports 4.0+. + private static void filterFeedList( + String source, + List list, + AwemeExtractor extractor, + boolean verbose + ) { + if (list == null) return; + + int initialSize = list.size(); + int removed = 0; Iterator iterator = list.iterator(); + while (iterator.hasNext()) { T container = iterator.next(); Aweme item = extractor.extract(container); - if (item != null && shouldFilter(item)) { + if (item == null) continue; + + String reason = getInternalizedFilterReason(item); + + if (reason != null) { + removed++; iterator.remove(); + if (verbose) { + logItem(item, reason); + } } } + + if (verbose && removed > 0) { + int finalRemoved = removed; + Logger.printInfo(() -> "[ReVanced FeedFilter] " + source + ": removed " + finalRemoved + " items."); + } } - private static boolean shouldFilter(Aweme item) { - for (IFilter filter : FILTERS) { - if (filter.getEnabled() && filter.getFiltered(item)) { - return true; - } + private static String getInternalizedFilterReason(Aweme item) { + if (item.isAd() || item.isWithPromotionalMusic()) { + return "AdsFilter"; } - return false; + + if (item.getLiveId() != 0 || item.getLiveType() != null || item.isLiveReplay()) { + return "LiveFilter"; + } + + String shareUrl = item.getShareUrl(); + if (shareUrl != null && shareUrl.contains("placeholder_product_id")) { + return "ShopFilter"; + } + + return null; + } + + private static void logItem(Aweme item, String reason) { + Logger.printInfo(() -> "[ReVanced FeedFilter] FILTERED: aid=" + item.getAid() + " Reason=" + reason); } @FunctionalInterface diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java index ed3e7cdb92..c9be3cd5e9 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java @@ -11,6 +11,9 @@ public class ImageVideoFilter implements IFilter { @Override public boolean getFiltered(Aweme item) { - return item.isImage() || item.isPhotoMode(); + var imageInfos = item.getImageInfos(); + boolean isImage = imageInfos != null && !imageInfos.isEmpty(); + boolean isPhotoMode = item.getPhotoModeImageInfo() != null || item.getPhotoModeTextInfo() != null; + return isImage || isPhotoMode; } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java index db6ab0af06..7390430c28 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java @@ -6,11 +6,12 @@ import com.ss.android.ugc.aweme.feed.model.Aweme; public class LiveFilter implements IFilter { @Override public boolean getEnabled() { - return Settings.HIDE_LIVE.get(); + // HARDCODED: Always filter live streams + return true; } @Override public boolean getFiltered(Aweme item) { - return item.isLive() || item.isLiveReplay(); + return item.getLiveId() != 0 || item.isLiveReplay() || item.getLiveType() != null; } -} +} \ No newline at end of file diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java index f134dc1bdc..627ab46c1d 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java @@ -7,11 +7,13 @@ public class ShopFilter implements IFilter { private static final String SHOP_INFO = "placeholder_product_id"; @Override public boolean getEnabled() { - return Settings.HIDE_SHOP.get(); + return true; + // return Settings.HIDE_SHOP.get(); } @Override public boolean getFiltered(Aweme item) { - return item.getShareUrl().contains(SHOP_INFO); + String shareUrl = item.getShareUrl(); + return shareUrl != null && shareUrl.contains(SHOP_INFO); } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/share/ShareUrlSanitizer.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/share/ShareUrlSanitizer.java index 5d09c10c0b..4ee81bafef 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/share/ShareUrlSanitizer.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/share/ShareUrlSanitizer.java @@ -13,7 +13,8 @@ public final class ShareUrlSanitizer { * Injection point for setting check. */ public static boolean shouldSanitize() { - return BaseSettings.SANITIZE_SHARED_LINKS.get(); + return true; + // return BaseSettings.SANITIZE_SHARED_LINKS.get(); } /** diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java new file mode 100644 index 0000000000..3d3a6891d4 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java @@ -0,0 +1,16 @@ +package com.ss.android.ugc.aweme.commerce; + +import java.io.Serializable; + +public class AwemeCommerceStruct implements Serializable { + public long brandedContentType; + public long brandOrganicType; + + public boolean isBrandedContent() { + return this.brandedContentType > 0; + } + + public boolean isBrandOrganicContent() { + return this.brandOrganicType > 0; + } +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java index a950b09057..da42ea67f9 100644 --- a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java @@ -1,16 +1,29 @@ package com.ss.android.ugc.aweme.feed.model; +import com.ss.android.ugc.aweme.commerce.AwemeCommerceStruct; + +import java.util.List; -//Dummy class public class Aweme { + + public AwemeCommerceStruct mCommerceVideoAuthInfo; + + public String getAid() { + throw new UnsupportedOperationException("Stub"); + } + public boolean isAd() { throw new UnsupportedOperationException("Stub"); } - public boolean isLive() { + public boolean isLiveReplay() { throw new UnsupportedOperationException("Stub"); } - public boolean isLiveReplay() { + public long getLiveId() { + throw new UnsupportedOperationException("Stub"); + } + + public String getLiveType() { throw new UnsupportedOperationException("Stub"); } @@ -22,11 +35,15 @@ public class Aweme { throw new UnsupportedOperationException("Stub"); } - public boolean isImage() { + public List getImageInfos() { throw new UnsupportedOperationException("Stub"); } - public boolean isPhotoMode() { + public PhotoModeImageInfo getPhotoModeImageInfo() { + throw new UnsupportedOperationException("Stub"); + } + + public PhotoModeTextInfo getPhotoModeTextInfo() { throw new UnsupportedOperationException("Stub"); } @@ -37,4 +54,8 @@ public class Aweme { public String getShareUrl() { throw new UnsupportedOperationException("Stub"); } -} + + public AwemeCommerceStruct getCommerceAndAdSettingsStruct() { + 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/PhotoModeImageInfo.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeImageInfo.java new file mode 100644 index 0000000000..67a6e999fc --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeImageInfo.java @@ -0,0 +1,6 @@ +package com.ss.android.ugc.aweme.feed.model; + +// Dummy class +public class PhotoModeImageInfo { +} + diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeTextInfo.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeTextInfo.java new file mode 100644 index 0000000000..35a0dbc69d --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/PhotoModeTextInfo.java @@ -0,0 +1,6 @@ +package com.ss.android.ugc.aweme.feed.model; + +// Dummy class +public class PhotoModeTextInfo { +} + diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt index 0f1227e4d3..1a9fa294da 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/FeedFilterPatch.kt @@ -1,11 +1,7 @@ package app.revanced.patches.tiktok.feedfilter -import app.revanced.patcher.extensions.InstructionExtensions.addInstruction -import app.revanced.patcher.extensions.InstructionExtensions.instructions +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch -import app.revanced.patches.tiktok.misc.settings.settingsPatch -import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction @@ -17,33 +13,43 @@ val feedFilterPatch = bytecodePatch( description = "Removes ads, livestreams, stories, image videos " + "and videos with a specific amount of views or likes from the feed.", ) { - dependsOn( - sharedExtensionPatch, - settingsPatch, - ) - compatibleWith( - "com.ss.android.ugc.trill"("36.5.4"), - "com.zhiliaoapp.musically"("36.5.4"), + "com.ss.android.ugc.trill"("43.8.3"), + "com.zhiliaoapp.musically"("43.8.3"), ) execute { - arrayOf( - feedApiServiceLIZFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V", - followFeedFingerprint.method to "$EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V" - ).forEach { (method, filterSignature) -> - val returnInstruction = method.instructions.first { it.opcode == Opcode.RETURN_OBJECT } - val register = (returnInstruction as OneRegisterInstruction).registerA - method.addInstruction( - returnInstruction.location.index, - "invoke-static { v$register }, $filterSignature" - ) + feedItemListGetItemsFingerprint.method.let { method -> + val returnIndices = method.implementation!!.instructions.withIndex() + .filter { it.value.opcode == Opcode.RETURN_OBJECT } + .map { it.index } + .toList() + + returnIndices.asReversed().forEach { returnIndex -> + method.addInstructions( + returnIndex, + "invoke-static {p0}, $EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V" + ) + } } - settingsStatusLoadFingerprint.method.addInstruction( - 0, - "invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableFeedFilter()V", - ) - } + followFeedFingerprint.method.let { method -> + val returnIndices = method.implementation!!.instructions.withIndex() + .filter { it.value.opcode == Opcode.RETURN_OBJECT } + .map { it.index } + .toList() -} + returnIndices.asReversed().forEach { returnIndex -> + val register = (method.implementation!!.instructions[returnIndex] as OneRegisterInstruction).registerA + method.addInstructions( + returnIndex, + """ + if-nez v$register, :skip + invoke-static/range { v$register .. v$register }, $EXTENSION_CLASS_DESCRIPTOR->filter(Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;)V + :skip + """ + ) + } + } + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt index f85dd2d072..0f17bda296 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/feedfilter/Fingerprints.kt @@ -2,21 +2,22 @@ package app.revanced.patches.tiktok.feedfilter import app.revanced.patcher.fingerprint import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -internal val feedApiServiceLIZFingerprint = fingerprint { + +internal val feedItemListGetItemsFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC) + returns("Ljava/util/List;") custom { method, classDef -> - classDef.endsWith("/FeedApiService;") && method.name == "fetchFeedList" + classDef.endsWith("/FeedItemList;") && + method.name == "getItems" && + method.parameterTypes.isEmpty() } } internal val followFeedFingerprint = fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) returns("Lcom/ss/android/ugc/aweme/follow/presenter/FollowFeedList;") - strings("getFollowFeedList") - opcodes( - Opcode.INVOKE_INTERFACE_RANGE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_INTERFACE - ) + custom { method, _ -> + method.parameterTypes.size == 2 + } } \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt index 13c829e625..da918b38b3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt @@ -16,8 +16,8 @@ val rememberClearDisplayPatch = bytecodePatch( description = "Remembers the clear display configurations in between videos.", ) { compatibleWith( - "com.ss.android.ugc.trill"("36.5.4"), - "com.zhiliaoapp.musically"("36.5.4"), + "com.ss.android.ugc.trill"("43.8.3"), + "com.zhiliaoapp.musically"("43.8.3"), ) execute { 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 e6894b521e..6b17009ab6 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 @@ -7,7 +7,6 @@ import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.extensions.InstructionExtensions.removeInstructions import app.revanced.patcher.patch.bytecodePatch import app.revanced.patches.tiktok.misc.extension.sharedExtensionPatch -import app.revanced.patches.tiktok.misc.settings.settingsPatch import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference @@ -25,12 +24,11 @@ val downloadsPatch = bytecodePatch( ) { dependsOn( sharedExtensionPatch, - settingsPatch, ) compatibleWith( - "com.ss.android.ugc.trill"("36.5.4"), - "com.zhiliaoapp.musically"("36.5.4"), + "com.ss.android.ugc.trill"("43.8.3"), + "com.zhiliaoapp.musically"("43.8.3"), ) execute { diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt index 221036bb96..1629d337fb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/Fingerprints.kt @@ -10,8 +10,8 @@ internal val getSpeedFingerprint = fingerprint { } internal val setSpeedFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) - returns("V") - parameters("Ljava/lang/String;", "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", "F") - strings("enterFrom") + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("Ljava/lang/Object;") + strings("playback_speed") + custom { method, _ -> method.name == "invoke" && method.parameterTypes.isEmpty() } } diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt index d59626ee76..1a2a865b33 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/speed/PlaybackSpeedPatch.kt @@ -16,6 +16,7 @@ val playbackSpeedPatch = bytecodePatch( name = "Playback speed", description = "Enables the playback speed option for all videos and " + "retains the speed configurations in between videos.", + use = false ) { compatibleWith( "com.ss.android.ugc.trill"("36.5.4"), diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/Fingerprints.kt index 836be89006..d45284380a 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/Fingerprints.kt @@ -5,21 +5,22 @@ import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode internal val urlShorteningFingerprint = fingerprint { - accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL) - returns("LX/") + accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) + returns("V") parameters( - "I", + "L", "Ljava/lang/String;", + "Ljava/util/List;", "Ljava/lang/String;", - "Ljava/lang/String;" + "Z", + "I" ) - opcodes(Opcode.RETURN_OBJECT) + opcodes(Opcode.RETURN_VOID) // Same Kotlin intrinsics literal on both variants. - strings("getShortShareUrlObservab\u2026ongUrl, subBizSceneValue)") + strings("share_link_id", "invitation_scene") custom { method, _ -> - // LIZLLL is obfuscated by ProGuard/R8, but stable across both TikTok and Musically. - method.name == "LIZLLL" + method.parameterTypes.size == 6 } } diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatch.kt index fd616141c7..e507705df0 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/misc/share/SanitizeShareUrlsPatch.kt @@ -26,58 +26,19 @@ val sanitizeShareUrlsPatch = bytecodePatch( dependsOn(sharedExtensionPatch) compatibleWith( - "com.ss.android.ugc.trill"("36.5.4"), - "com.zhiliaoapp.musically"("36.5.4"), + "com.ss.android.ugc.trill"("43.8.3"), + "com.zhiliaoapp.musically"("43.8.3"), ) execute { urlShorteningFingerprint.method.apply { - val invokeIndex = indexOfFirstInstructionOrThrow { - val ref = getReference() - ref?.name == "LIZ" && ref.definingClass.startsWith("LX/") - } + val longUrlRegister = implementation!!.registerCount - 6 + 3 - val moveResultIndex = indexOfFirstInstructionOrThrow(invokeIndex, Opcode.MOVE_RESULT_OBJECT) - val urlRegister = getInstruction(moveResultIndex).registerA - - // Resolve Observable wrapper classes at runtime - val observableWrapperIndex = indexOfFirstInstructionOrThrow(Opcode.NEW_INSTANCE) - val observableWrapperClass = getInstruction(observableWrapperIndex) - .reference.toString() - - val observableFactoryIndex = indexOfFirstInstructionOrThrow { - val ref = getReference() - ref?.name == "LJ" && ref.definingClass.startsWith("LX/") - } - val observableFactoryRef = getInstruction(observableFactoryIndex) - .reference as MethodReference - - val observableFactoryClass = observableFactoryRef.definingClass - val observableInterfaceType = observableFactoryRef.parameterTypes.first() - val observableReturnType = observableFactoryRef.returnType - - val wrapperRegister = findFreeRegister(moveResultIndex + 1, urlRegister) - - // Check setting and conditionally sanitize share URL. - addInstructionsWithLabels( - moveResultIndex + 1, + addInstructions( + 0, """ - invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldSanitize()Z - move-result v$wrapperRegister - if-eqz v$wrapperRegister, :skip_sanitization - - invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String; - move-result-object v$urlRegister - - # Wrap sanitized URL and return early to bypass ShareExtService - new-instance v$wrapperRegister, $observableWrapperClass - invoke-direct { v$wrapperRegister, v$urlRegister }, $observableWrapperClass->(Ljava/lang/String;)V - invoke-static { v$wrapperRegister }, $observableFactoryClass->LJ($observableInterfaceType)$observableReturnType - move-result-object v$urlRegister - return-object v$urlRegister - - :skip_sanitization - nop + invoke-static/range { v$longUrlRegister .. v$longUrlRegister }, $EXTENSION_CLASS_DESCRIPTOR->sanitizeShareUrl(Ljava/lang/String;)Ljava/lang/String; + move-result-object v$longUrlRegister """ ) } From c17c4e9050b55e2a46d2f367c6578b9a34b885a5 Mon Sep 17 00:00:00 2001 From: lbux Date: Wed, 11 Feb 2026 20:18:22 -0800 Subject: [PATCH 2/5] robust implementation of feed filter + bloat filter --- .../tiktok/feedfilter/AdsFilter.java | 35 ++++--- .../tiktok/feedfilter/BloatFilter.java | 28 ++++++ .../tiktok/feedfilter/FeedItemsFilter.java | 66 +++++-------- .../tiktok/feedfilter/ImageVideoFilter.java | 14 ++- .../tiktok/feedfilter/LikeCountFilter.java | 5 +- .../tiktok/feedfilter/LiveFilter.java | 11 ++- .../tiktok/feedfilter/ShopFilter.java | 21 ++++- .../tiktok/feedfilter/StoryFilter.java | 13 ++- .../tiktok/feedfilter/ViewCountFilter.java | 6 +- .../aweme/commerce/AwemeCommerceStruct.java | 19 ++-- .../aweme/commerce/model/ShopAdStruct.java | 4 + .../aweme/commerce/model/SimplePromotion.java | 4 + .../android/ugc/aweme/feed/model/Aweme.java | 94 +++++++++---------- .../ugc/aweme/feed/model/AwemeRawAd.java | 4 + .../ugc/aweme/feed/model/AwemeStatistics.java | 5 +- .../ugc/aweme/feed/model/RoomStruct.java | 4 + .../ugc/aweme/search/ecom/data/Product.java | 4 + 17 files changed, 209 insertions(+), 128 deletions(-) create mode 100644 extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/BloatFilter.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/ShopAdStruct.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/SimplePromotion.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeRawAd.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/RoomStruct.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/search/ecom/data/Product.java diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java index cd90f9d9d3..bb93bfb3bf 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/AdsFilter.java @@ -2,7 +2,6 @@ package app.revanced.extension.tiktok.feedfilter; import app.revanced.extension.tiktok.settings.Settings; import com.ss.android.ugc.aweme.feed.model.Aweme; -import com.ss.android.ugc.aweme.commerce.AwemeCommerceStruct; public class AdsFilter implements IFilter { @Override @@ -13,21 +12,29 @@ public class AdsFilter implements IFilter { @Override public boolean getFiltered(Aweme item) { - try { - // Standard Ads & Promotional Music - if (item.isAd() || item.isWithPromotionalMusic()) { - return true; - } + if (item == null) return false; - // Paid Partnerships (Branded Content) - if (item.mCommerceVideoAuthInfo != null) { - if (item.mCommerceVideoAuthInfo.isBrandedContent()) { - return true; - } - } - } catch (Throwable t) { - return false; + // TikTok's Internal Commercial Types + // Verified in AwemeExtKt: 1, 29, 30, 32, 33, 201 are commercial + int type = item.getAwemeType(); + if (type == 1 || type == 29 || type == 30 || type == 32 || type == 33 || type == 201) { + return true; } + + // Ad Flags (Hard and Soft/Sponsored) + if (item.isAd || item.isSoftAd || item.awemeRawAd != null) { + return true; + } + + // Music Marketing + if (item.isWithPromotionalMusic()) return true; + + if (item.mCommerceVideoAuthInfo != null) { + // PseudoAds (Spark Ads) and Branded Content + return item.mCommerceVideoAuthInfo.isBrandedContent() || + item.mCommerceVideoAuthInfo.isPseudoAd(); + } + return false; } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/BloatFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/BloatFilter.java new file mode 100644 index 0000000000..88f0487b9a --- /dev/null +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/BloatFilter.java @@ -0,0 +1,28 @@ +package app.revanced.extension.tiktok.feedfilter; + +import com.ss.android.ugc.aweme.feed.model.Aweme; + +public class BloatFilter implements IFilter { + @Override + public boolean getEnabled() { + return true; + } + + @Override + public boolean getFiltered(Aweme item) { + if (item == null) return false; + + // Full screen promos + if (item.isReferralFakeAweme || item.isRecBigCardFakeAweme) { + return true; + } + + // System cards (non video interrupts) + if (item.awemeType == 104 || item.awemeType == 105) return true; + + // Accounts to follow recs and overlays + if (item.recommendCardType != 0) return true; + + return false; + } +} \ No newline at end of file diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java index 5833284a25..5b85f6bd27 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/FeedItemsFilter.java @@ -1,7 +1,5 @@ package app.revanced.extension.tiktok.feedfilter; -import app.revanced.extension.shared.Logger; -import app.revanced.extension.shared.settings.BaseSettings; import com.ss.android.ugc.aweme.feed.model.Aweme; import com.ss.android.ugc.aweme.feed.model.FeedItemList; import com.ss.android.ugc.aweme.follow.presenter.FollowFeedList; @@ -10,73 +8,53 @@ import java.util.Iterator; import java.util.List; public final class FeedItemsFilter { - public static void filter(FeedItemList feedItemList) { - boolean verbose = BaseSettings.DEBUG.get(); - if (feedItemList == null || feedItemList.items == null) return; - filterFeedList("FeedItemList", feedItemList.items, item -> item, verbose); + private static final IFilter[] FILTERS = new IFilter[] { + new AdsFilter(), + new LiveFilter(), + new ShopFilter(), + new StoryFilter(), + new ImageVideoFilter(), + new BloatFilter() + }; + + public static void filter(FeedItemList feedItemList) { + if (feedItemList == null || feedItemList.items == null) return; + filterFeedList(feedItemList.items, item -> item); } public static void filter(FollowFeedList followFeedList) { - boolean verbose = BaseSettings.DEBUG.get(); if (followFeedList == null || followFeedList.mItems == null) return; - - filterFeedList("FollowFeedList", followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null, verbose); + filterFeedList(followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null); } private static void filterFeedList( - String source, List list, - AwemeExtractor extractor, - boolean verbose + AwemeExtractor extractor ) { if (list == null) return; - int initialSize = list.size(); - int removed = 0; Iterator iterator = list.iterator(); while (iterator.hasNext()) { T container = iterator.next(); Aweme item = extractor.extract(container); + if (item == null) continue; - String reason = getInternalizedFilterReason(item); - - if (reason != null) { - removed++; + if (shouldFilter(item)) { iterator.remove(); - if (verbose) { - logItem(item, reason); - } } } - - if (verbose && removed > 0) { - int finalRemoved = removed; - Logger.printInfo(() -> "[ReVanced FeedFilter] " + source + ": removed " + finalRemoved + " items."); - } } - private static String getInternalizedFilterReason(Aweme item) { - if (item.isAd() || item.isWithPromotionalMusic()) { - return "AdsFilter"; + private static boolean shouldFilter(Aweme item) { + for (IFilter filter : FILTERS) { + if (filter.getEnabled() && filter.getFiltered(item)) { + return true; + } } - - if (item.getLiveId() != 0 || item.getLiveType() != null || item.isLiveReplay()) { - return "LiveFilter"; - } - - String shareUrl = item.getShareUrl(); - if (shareUrl != null && shareUrl.contains("placeholder_product_id")) { - return "ShopFilter"; - } - - return null; - } - - private static void logItem(Aweme item, String reason) { - Logger.printInfo(() -> "[ReVanced FeedFilter] FILTERED: aid=" + item.getAid() + " Reason=" + reason); + return false; } @FunctionalInterface diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java index c9be3cd5e9..cefa57a882 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ImageVideoFilter.java @@ -11,9 +11,17 @@ public class ImageVideoFilter implements IFilter { @Override public boolean getFiltered(Aweme item) { + if (item == null) return false; + + int type = item.getAwemeType(); + + // 2 = Standard Image, 150 = Photo Mode, 160 = Text Mode + if (type == 2 || type == 150 || type == 160) { + return true; + } + + // Fallback checks var imageInfos = item.getImageInfos(); - boolean isImage = imageInfos != null && !imageInfos.isEmpty(); - boolean isPhotoMode = item.getPhotoModeImageInfo() != null || item.getPhotoModeTextInfo() != null; - return isImage || isPhotoMode; + return imageInfos != null && !imageInfos.isEmpty(); } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LikeCountFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LikeCountFilter.java index f5336da5b4..33534668a4 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LikeCountFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LikeCountFilter.java @@ -24,7 +24,10 @@ public final class LikeCountFilter implements IFilter { @Override public boolean getFiltered(Aweme item) { - AwemeStatistics statistics = item.getStatistics(); + AwemeStatistics statistics = item.statistics; + + if (statistics == null) statistics = item.getStatistics(); + if (statistics == null) return false; long likeCount = statistics.getDiggCount(); diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java index 7390430c28..6156f8064d 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/LiveFilter.java @@ -6,12 +6,19 @@ import com.ss.android.ugc.aweme.feed.model.Aweme; public class LiveFilter implements IFilter { @Override public boolean getEnabled() { - // HARDCODED: Always filter live streams return true; } @Override public boolean getFiltered(Aweme item) { - return item.getLiveId() != 0 || item.isLiveReplay() || item.getLiveType() != null; + if (item == null) return false; + + // awemeType 101 is the 'isLive' check in code + if (item.getAwemeType() == 101 || item.getRoom() != null) { + return true; + } + + // Fallbacks + return item.isLiveReplay() || item.getLiveId() != 0 || item.getLiveType() != null; } } \ No newline at end of file diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java index 627ab46c1d..e151906606 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ShopFilter.java @@ -4,7 +4,6 @@ import app.revanced.extension.tiktok.settings.Settings; import com.ss.android.ugc.aweme.feed.model.Aweme; public class ShopFilter implements IFilter { - private static final String SHOP_INFO = "placeholder_product_id"; @Override public boolean getEnabled() { return true; @@ -13,7 +12,25 @@ public class ShopFilter implements IFilter { @Override public boolean getFiltered(Aweme item) { + if (item == null) return false; + + // Attached Products (TikTok Shop) + if (item.productsInfo != null && !item.productsInfo.isEmpty()) { + return true; + } + + // Simple Promotions (Banner links) + if (item.simplePromotions != null && !item.simplePromotions.isEmpty()) { + return true; + } + + // Shop Ads + if (item.shopAdStruct != null) { + return true; + } + + // Fallback (URL check) String shareUrl = item.getShareUrl(); - return shareUrl != null && shareUrl.contains(SHOP_INFO); + return shareUrl != null && shareUrl.contains("placeholder_product_id"); } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/StoryFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/StoryFilter.java index 85d0a70883..fc3ce6756b 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/StoryFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/StoryFilter.java @@ -9,8 +9,17 @@ public class StoryFilter implements IFilter { return Settings.HIDE_STORY.get(); } - @Override public boolean getFiltered(Aweme item) { - return item.getIsTikTokStory(); + if (item == null) return false; + + if (item.isTikTokStory) return true; + + // Type 40 = Standard Story, 11 = Legacy/Region Story + int type = item.getAwemeType(); + if (type == 40 || type == 11 || item.isTikTokStory) { + return true; + } + + return false; } } diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ViewCountFilter.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ViewCountFilter.java index 32627ca60d..4c30500b89 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ViewCountFilter.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/feedfilter/ViewCountFilter.java @@ -23,7 +23,11 @@ public class ViewCountFilter implements IFilter { @Override public boolean getFiltered(Aweme item) { - AwemeStatistics statistics = item.getStatistics(); + AwemeStatistics statistics = item.statistics; + + // Fallback to getter if field is null + if (statistics == null) statistics = item.getStatistics(); + if (statistics == null) return false; long playCount = statistics.getPlayCount(); diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java index 3d3a6891d4..864d72ad6f 100644 --- a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/AwemeCommerceStruct.java @@ -1,16 +1,17 @@ package com.ss.android.ugc.aweme.commerce; -import java.io.Serializable; - -public class AwemeCommerceStruct implements Serializable { - public long brandedContentType; - public long brandOrganicType; - +import com.ss.android.ugc.aweme.feed.model.AwemeRawAd; +public class AwemeCommerceStruct { + public boolean isBrandedContent() { - return this.brandedContentType > 0; + throw new UnsupportedOperationException("Stub"); } - public boolean isBrandOrganicContent() { - return this.brandOrganicType > 0; + public boolean isPseudoAd() { + throw new UnsupportedOperationException("Stub"); + } + + public AwemeRawAd getPseudoAdData() { + throw new UnsupportedOperationException("Stub"); } } \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/ShopAdStruct.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/ShopAdStruct.java new file mode 100644 index 0000000000..5c237f96fe --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/ShopAdStruct.java @@ -0,0 +1,4 @@ +package com.ss.android.ugc.aweme.commerce.model; + +public class ShopAdStruct { +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/SimplePromotion.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/SimplePromotion.java new file mode 100644 index 0000000000..e2211e1877 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/commerce/model/SimplePromotion.java @@ -0,0 +1,4 @@ +package com.ss.android.ugc.aweme.commerce.model; + +public class SimplePromotion { +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java index da42ea67f9..40811c02b0 100644 --- a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Aweme.java @@ -1,61 +1,57 @@ package com.ss.android.ugc.aweme.feed.model; -import com.ss.android.ugc.aweme.commerce.AwemeCommerceStruct; +import com.ss.android.ugc.aweme.commerce.model.ShopAdStruct; +import com.ss.android.ugc.aweme.commerce.model.SimplePromotion; +import com.ss.android.ugc.aweme.search.ecom.data.Product; +import com.ss.android.ugc.aweme.commerce.AwemeCommerceStruct; import java.util.List; public class Aweme { - + + // Internal Feed Type Identifiers + public int awemeType; + public int adLinkType; + + // Live Stream Data + public RoomStruct room; + + // Monetization & Sponsored Traffic + public boolean isAd; + public boolean isSoftAd; + public AwemeRawAd awemeRawAd; public AwemeCommerceStruct mCommerceVideoAuthInfo; - public String getAid() { - throw new UnsupportedOperationException("Stub"); - } + // E-Commerce / Shop Data + public List productsInfo; + public List simplePromotions; + public ShopAdStruct shopAdStruct; + + // Non-Video Feed Injections (Fake Awemes) + public boolean isReferralFakeAweme; + public boolean isRecBigCardFakeAweme; - public boolean isAd() { - throw new UnsupportedOperationException("Stub"); - } + // Social & Follow Recommendations + public int recommendCardType; + public List familiarRecommendUser; - public boolean isLiveReplay() { - throw new UnsupportedOperationException("Stub"); - } + // Content Engagement Statistics + public AwemeStatistics statistics; - public long getLiveId() { - throw new UnsupportedOperationException("Stub"); - } + // Story Metadata + public boolean isTikTokStory; - public String getLiveType() { - throw new UnsupportedOperationException("Stub"); - } - - public boolean isWithPromotionalMusic() { - throw new UnsupportedOperationException("Stub"); - } - - public boolean getIsTikTokStory() { - throw new UnsupportedOperationException("Stub"); - } - - public List getImageInfos() { - throw new UnsupportedOperationException("Stub"); - } - - public PhotoModeImageInfo getPhotoModeImageInfo() { - throw new UnsupportedOperationException("Stub"); - } - - public PhotoModeTextInfo getPhotoModeTextInfo() { - throw new UnsupportedOperationException("Stub"); - } - - public AwemeStatistics getStatistics() { - throw new UnsupportedOperationException("Stub"); - } - - public String getShareUrl() { - throw new UnsupportedOperationException("Stub"); - } - - public AwemeCommerceStruct getCommerceAndAdSettingsStruct() { - throw new UnsupportedOperationException("Stub"); - } + public int getAwemeType() { throw new UnsupportedOperationException("Stub"); } + public RoomStruct getRoom() { throw new UnsupportedOperationException("Stub"); } + public boolean isAd() { throw new UnsupportedOperationException("Stub"); } + public boolean isSoftAd() { throw new UnsupportedOperationException("Stub"); } + public AwemeStatistics getStatistics() { throw new UnsupportedOperationException("Stub"); } + + // Stub methods for legacy compatibility + public String getAid() { throw new UnsupportedOperationException("Stub"); } + public boolean isLiveReplay() { throw new UnsupportedOperationException("Stub"); } + public long getLiveId() { throw new UnsupportedOperationException("Stub"); } + public String getLiveType() { throw new UnsupportedOperationException("Stub"); } + public boolean isWithPromotionalMusic() { throw new UnsupportedOperationException("Stub"); } + public String getShareUrl() { throw new UnsupportedOperationException("Stub"); } + public List getImageInfos() { 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/AwemeRawAd.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeRawAd.java new file mode 100644 index 0000000000..14de433032 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeRawAd.java @@ -0,0 +1,4 @@ +package com.ss.android.ugc.aweme.feed.model; + +public class AwemeRawAd { +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeStatistics.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeStatistics.java index a9123e67cf..c4af1845f9 100644 --- a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeStatistics.java +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/AwemeStatistics.java @@ -1,10 +1,13 @@ package com.ss.android.ugc.aweme.feed.model; public class AwemeStatistics { + + // Used by ViewCountFilter public long getPlayCount() { throw new UnsupportedOperationException("Stub"); } + public long getDiggCount() { 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/RoomStruct.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/RoomStruct.java new file mode 100644 index 0000000000..57e6d5cda2 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/RoomStruct.java @@ -0,0 +1,4 @@ +package com.ss.android.ugc.aweme.feed.model; + +public class RoomStruct { +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/search/ecom/data/Product.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/search/ecom/data/Product.java new file mode 100644 index 0000000000..248e24a8d5 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/search/ecom/data/Product.java @@ -0,0 +1,4 @@ +package com.ss.android.ugc.aweme.search.ecom.data; + +public class Product { +} \ No newline at end of file From e4cfa15efc2c5eae3e6a3d4e23a5deb523e0bbde Mon Sep 17 00:00:00 2001 From: lbux Date: Thu, 19 Feb 2026 14:57:44 -0800 Subject: [PATCH 3/5] fix tiktok download restrictions --- .../tiktok/download/DownloadsPatch.java | 31 +++++++++++++++++-- .../ugc/aweme/base/model/UrlModel.java | 7 +++++ .../android/ugc/aweme/feed/model/Video.java | 8 +++++ .../ugc/aweme/feed/model/VideoUrlModel.java | 5 +++ .../interaction/downloads/DownloadsPatch.kt | 17 ++++++++-- .../interaction/downloads/Fingerprints.kt | 10 ++++++ 6 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/base/model/UrlModel.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/Video.java create mode 100644 extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/feed/model/VideoUrlModel.java 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() + } +} From 6c2b836aa80584205d7cf7ecef18430c8c00ec55 Mon Sep 17 00:00:00 2001 From: lbux Date: Wed, 25 Feb 2026 13:10:27 -0800 Subject: [PATCH 4/5] download comment images w/o watermark --- .../interaction/downloads/DownloadsPatch.kt | 34 +++++++++++++++++++ .../interaction/downloads/Fingerprints.kt | 6 ++++ 2 files changed, 40 insertions(+) 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 2a35a038b3..40a57816c2 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 @@ -14,6 +14,7 @@ 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.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.reference.FieldReference private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/download/DownloadsPatch;" @@ -61,6 +62,39 @@ val downloadsPatch = bytecodePatch( ) } + commentImageWatermarkFingerprint.method.apply { + val drawBitmapIndex = findInstructionIndicesReversedOrThrow { + opcode.name == "invoke-virtual" && + this is ReferenceInstruction && + reference.toString().contains("->drawBitmap(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V") + }.first() + + val drawInstr = getInstruction(drawBitmapIndex) + val canvasReg = drawInstr.registerC + val bitmapReg = drawInstr.registerD + val xReg = drawInstr.registerE + val yReg = drawInstr.registerF + val paintReg = drawInstr.registerG + + removeInstructions(drawBitmapIndex, 1) + + addInstructionsWithLabels( + drawBitmapIndex, + """ + invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->shouldRemoveWatermark()Z + move-result v$xReg + + if-nez v$xReg, :skip_watermark + + const/4 v$xReg, 0x0 + invoke-virtual {v$canvasReg, v$bitmapReg, v$xReg, v$yReg, v$paintReg}, Landroid/graphics/Canvas;->drawBitmap(Landroid/graphics/Bitmap;FFLandroid/graphics/Paint;)V + + :skip_watermark + nop + """ + ) + } + downloadUriFingerprint.method.apply { findInstructionIndicesReversedOrThrow { getReference().let { 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 26f898ec92..80529fdb78 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 @@ -54,3 +54,9 @@ internal val awemeGetVideoFingerprint = fingerprint { method.parameterTypes.isEmpty() } } + +internal val commentImageWatermarkFingerprint = fingerprint { + strings("[tiktok_logo]", "image/jpeg", "is_pending") + parameters("Landroid/graphics/Bitmap;") + returns("V") +} From 84a73e730f74f6ebd4340e8404bb2e9006291565 Mon Sep 17 00:00:00 2001 From: lbux Date: Sun, 1 Mar 2026 15:24:11 -0800 Subject: [PATCH 5/5] experimental clear display patch --- .../RememberClearDisplayPatch.java | 16 ++++- .../interaction/cleardisplay/Fingerprints.kt | 45 +++++++++++++ .../cleardisplay/RememberClearDisplayPatch.kt | 64 ++++++++++--------- 3 files changed, 94 insertions(+), 31 deletions(-) diff --git a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch.java b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch.java index e436b5dcd0..8ce578b570 100644 --- a/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch.java +++ b/extensions/tiktok/src/main/java/app/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch.java @@ -4,10 +4,22 @@ import app.revanced.extension.tiktok.settings.Settings; @SuppressWarnings("unused") public class RememberClearDisplayPatch { + + private static Boolean cachedState = null; + public static boolean getClearDisplayState() { - return Settings.CLEAR_DISPLAY.get(); + if (cachedState == null) { + cachedState = Settings.CLEAR_DISPLAY.get(); + } + return cachedState; } + public static void rememberClearDisplayState(boolean newState) { + if (cachedState != null && cachedState == newState) { + return; + } + + cachedState = newState; Settings.CLEAR_DISPLAY.save(newState); } -} +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt index eb28683743..337eef35fc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/Fingerprints.kt @@ -1,6 +1,7 @@ package app.revanced.patches.tiktok.interaction.cleardisplay import app.revanced.patcher.fingerprint +import com.android.tools.smali.dexlib2.AccessFlags internal val onClearDisplayEventFingerprint = fingerprint { custom { method, classDef -> @@ -8,3 +9,47 @@ internal val onClearDisplayEventFingerprint = fingerprint { classDef.endsWith("/ClearModePanelComponent;") && method.name == "onClearModeEvent" } } + +internal val clearModeLogCoreFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL) + returns("V") + parameters( + "Z", + "Ljava/lang/String;", + "Ljava/lang/String;", + "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", + "Ljava/lang/String;", + "J", + "I" + ) +} + +internal val clearModeLogStateFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC, AccessFlags.FINAL) + returns("V") + parameters( + "Lcom/bytedance/common/utility/collection/WeakHandler;", + "Z", + "Ljava/lang/String;", + "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", + "J" + "I", + "I" + ) +} + +internal val clearModeLogPlaytimeFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) + returns("V") + parameters( + "F", + "I", + "J", + "J", + "Lcom/ss/android/ugc/aweme/feed/model/Aweme;", + "Ljava/lang/String;", + "Ljava/lang/String;", + "Z", + "Z" + ) +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt index da918b38b3..d8b36bdfc3 100644 --- a/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/tiktok/interaction/cleardisplay/RememberClearDisplayPatch.kt @@ -1,12 +1,11 @@ package app.revanced.patches.tiktok.interaction.cleardisplay import app.revanced.patcher.extensions.InstructionExtensions.addInstructions -import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch -import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.tiktok.shared.onRenderFirstFrameFingerprint import app.revanced.util.indexOfFirstInstructionOrThrow +import app.revanced.util.returnEarly import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction @@ -21,9 +20,14 @@ val rememberClearDisplayPatch = bytecodePatch( ) execute { - onClearDisplayEventFingerprint.method.let { - // region Hook the "Clear display" configuration save event to remember the state of clear display. + // kill loggers to prevent db from being constantly logged to + // might resolve crashing issue with this patch + clearModeLogCoreFingerprint.method.returnEarly() + clearModeLogStateFingerprint.method.returnEarly() + clearModeLogPlaytimeFingerprint.method.returnEarly() + onClearDisplayEventFingerprint.method.let { + // Hook the "Clear display" configuration save event to remember the state of clear display. val isEnabledIndex = it.indexOfFirstInstructionOrThrow(Opcode.IGET_BOOLEAN) + 1 val isEnabledRegister = it.getInstruction(isEnabledIndex - 1).registerA @@ -33,38 +37,40 @@ val rememberClearDisplayPatch = bytecodePatch( "Lapp/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch;->rememberClearDisplayState(Z)V", ) - // endregion - - // region Override the "Clear display" configuration load event to load the state of clear display. - val clearDisplayEventClass = it.parameters[0].type - onRenderFirstFrameFingerprint.method.addInstructionsWithLabels( + onRenderFirstFrameFingerprint.method.addInstructions( 0, """ - # Create a new clearDisplayEvent and post it to the EventBus (https://github.com/greenrobot/EventBus) - - # Clear display type such as 0 = LONG_PRESS, 1 = SCREEN_RECORD etc. - const/4 v1, 0x0 - - # Enter method (Such as "pinch", "swipe_exit", or an empty string (unknown, what it means)). - const-string v2, "" - - # Name of the clear display type which is equivalent to the clear display type. - const-string v3, "long_press" - - # The state of clear display. + # Get the saved state invoke-static { }, Lapp/revanced/extension/tiktok/cleardisplay/RememberClearDisplayPatch;->getClearDisplayState()Z - move-result v4 - if-eqz v4, :clear_display_disabled + move-result v1 + + # If false, jump past the event post + if-eqz v1, :clear_display_disabled + # Set up the other parameters + # Clear display type: 0 = LONG_PRESS + const/4 v2, 0x0 + + # Enter method + const-string v3, "" + + # Name of the clear display type + const-string v4, "long_press" + + # Create the event new-instance v0, $clearDisplayEventClass - invoke-direct { v0, v1, v2, v3, v4 }, $clearDisplayEventClass->(ILjava/lang/String;Ljava/lang/String;Z)V + + # Call the constructor in order + invoke-direct { v0, v1, v2, v3, v4 }, $clearDisplayEventClass->(ZILjava/lang/String;Ljava/lang/String;)V + + # Post it to the EventBus invoke-virtual { v0 }, $clearDisplayEventClass->post()Lcom/ss/android/ugc/governance/eventbus/IEvent; - """, - ExternalLabel("clear_display_disabled", onRenderFirstFrameFingerprint.method.getInstruction(0)), - ) - // endregion + :clear_display_disabled + nop + """ + ) } } -} +} \ No newline at end of file