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 e1e0add8e..8f4e3770f 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 @@ -2,6 +2,7 @@ package app.revanced.extension.tiktok.feedfilter; 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; import java.util.Iterator; import java.util.List; @@ -17,18 +18,36 @@ public final class FeedItemsFilter { ); public static void filter(FeedItemList feedItemList) { - Iterator feedItemListIterator = feedItemList.items.iterator(); - while (feedItemListIterator.hasNext()) { - Aweme item = feedItemListIterator.next(); - if (item == null) continue; + filterFeedList(feedItemList.items, item -> item); + } - for (IFilter filter : FILTERS) { - boolean enabled = filter.getEnabled(); - if (enabled && filter.getFiltered(item)) { - feedItemListIterator.remove(); - break; - } + public static void filter(FollowFeedList followFeedList) { + filterFeedList(followFeedList.mItems, feed -> (feed != null) ? feed.aweme : null); + } + + private static void filterFeedList(List list, AwemeExtractor extractor) { + // Could be simplified with removeIf() but requires Android 7.0+ while TikTok supports 4.0+. + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + T container = iterator.next(); + Aweme item = extractor.extract(container); + if (item != null && shouldFilter(item)) { + iterator.remove(); } } } -} + + private static boolean shouldFilter(Aweme item) { + for (IFilter filter : FILTERS) { + if (filter.getEnabled() && filter.getFiltered(item)) { + return true; + } + } + return false; + } + + @FunctionalInterface + interface AwemeExtractor { + Aweme extract(T source); + } +} \ No newline at end of file diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/follow/presenter/FollowFeed.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/follow/presenter/FollowFeed.java new file mode 100644 index 000000000..833b6d21d --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/follow/presenter/FollowFeed.java @@ -0,0 +1,8 @@ +package com.ss.android.ugc.aweme.follow.presenter; + +import com.ss.android.ugc.aweme.feed.model.Aweme; + +//Dummy class +public class FollowFeed { + public Aweme aweme; +} diff --git a/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/follow/presenter/FollowFeedList.java b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/follow/presenter/FollowFeedList.java new file mode 100644 index 000000000..d8995ca36 --- /dev/null +++ b/extensions/tiktok/stub/src/main/java/com/ss/android/ugc/aweme/follow/presenter/FollowFeedList.java @@ -0,0 +1,8 @@ +package com.ss.android.ugc.aweme.follow.presenter; + +import java.util.List; + +//Dummy class +public class FollowFeedList { + public List mItems; +} 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 9ea783f95..0f1227e4d 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 @@ -9,6 +9,8 @@ import app.revanced.patches.tiktok.misc.settings.settingsStatusLoadFingerprint import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/tiktok/feedfilter/FeedItemsFilter;" + @Suppress("unused") val feedFilterPatch = bytecodePatch( name = "Feed filter", @@ -26,14 +28,15 @@ val feedFilterPatch = bytecodePatch( ) execute { - feedApiServiceLIZFingerprint.method.apply { - val returnFeedItemInstruction = instructions.first { it.opcode == Opcode.RETURN_OBJECT } - val feedItemsRegister = (returnFeedItemInstruction as OneRegisterInstruction).registerA - - addInstruction( - returnFeedItemInstruction.location.index, - "invoke-static { v$feedItemsRegister }, " + - "Lapp/revanced/extension/tiktok/feedfilter/FeedItemsFilter;->filter(Lcom/ss/android/ugc/aweme/feed/model/FeedItemList;)V", + 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" ) } @@ -42,4 +45,5 @@ val feedFilterPatch = bytecodePatch( "invoke-static {}, Lapp/revanced/extension/tiktok/settings/SettingsStatus;->enableFeedFilter()V", ) } + } 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 4f899661e..f85dd2d07 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 @@ -1,9 +1,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 { custom { method, classDef -> classDef.endsWith("/FeedApiService;") && method.name == "fetchFeedList" } } + +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 + ) +} \ No newline at end of file