From aedb3eddd66190a930ea604e5a7c50b12b2fb2e7 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Wed, 13 Dec 2023 02:40:28 +0400 Subject: [PATCH] refactor(YouTube - Litho filter): Simplify filtering callbacks (#539) --- .../patches/components/AdsFilter.java | 27 ++-- .../patches/components/ButtonsFilter.java | 25 ++-- .../patches/components/CommentsFilter.java | 3 +- .../DescriptionComponentsFilter.java | 7 +- .../patches/components/DummyFilter.java | 3 - .../components/HideInfoCardsFilterPatch.java | 3 +- .../components/LayoutComponentsFilter.java | 61 ++++---- .../patches/components/LithoFilterPatch.java | 133 +++++++++++------- .../PlaybackSpeedMenuFilterPatch.java | 4 +- .../PlayerFlyoutMenuItemsFilter.java | 35 +++-- .../ReturnYouTubeDislikeFilterPatch.java | 10 +- .../patches/components/ShortsFilter.java | 26 ++-- .../VideoQualityMenuFilterPatch.java | 7 +- 13 files changed, 197 insertions(+), 147 deletions(-) delete mode 100644 app/src/main/java/app/revanced/integrations/patches/components/DummyFilter.java diff --git a/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java index 5868596dca..bcead636a8 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/AdsFilter.java @@ -1,6 +1,5 @@ package app.revanced.integrations.patches.components; - import android.view.View; import androidx.annotation.Nullable; @@ -9,7 +8,7 @@ import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.StringTrieSearch; - +@SuppressWarnings("unused") public final class AdsFilter extends Filter { private final StringTrieSearch exceptions = new StringTrieSearch(); private final StringFilterGroup shoppingLinks; @@ -23,6 +22,16 @@ public AdsFilter() { "library_recent_shelf" ); + // Identifiers. + + final var carouselAd = new StringFilterGroup( + SettingsEnum.HIDE_GENERAL_ADS, + "carousel_ad" + ); + addIdentifierCallbacks(carouselAd); + + // Paths. + final var buttonedAd = new StringFilterGroup( SettingsEnum.HIDE_BUTTONED_ADS, "_buttoned_layout", @@ -61,11 +70,6 @@ public AdsFilter() { "offer_module_root" ); - final var carouselAd = new StringFilterGroup( - SettingsEnum.HIDE_GENERAL_ADS, - "carousel_ad" - ); - final var viewProducts = new StringFilterGroup( SettingsEnum.HIDE_PRODUCTS_BANNER, "product_item", @@ -92,7 +96,7 @@ public AdsFilter() { "cta_shelf_card" ); - this.pathFilterGroupList.addAll( + addPathCallbacks( generalAds, buttonedAd, merchandise, @@ -102,20 +106,19 @@ public AdsFilter() { shoppingLinks, movieAds ); - this.identifierFilterGroupList.addAll(carouselAd); } @Override public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { if (exceptions.matches(path)) return false; // Check for the index because of likelihood of false positives. - if (matchedGroup == shoppingLinks && matchedIndex != 0) + if (matchedGroup == shoppingLinks && contentIndex != 0) return false; - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); } /** diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ButtonsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ButtonsFilter.java index 19cddf3f6e..123c58036b 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ButtonsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ButtonsFilter.java @@ -7,6 +7,7 @@ import app.revanced.integrations.settings.SettingsEnum; +@SuppressWarnings("unused") @RequiresApi(api = Build.VERSION_CODES.N) final class ButtonsFilter extends Filter { private static final String VIDEO_ACTION_BAR_PATH = "video_action_bar.eml"; @@ -20,14 +21,14 @@ public ButtonsFilter() { null, VIDEO_ACTION_BAR_PATH ); - identifierFilterGroupList.addAll(actionBarGroup); + addIdentifierCallbacks(actionBarGroup); bufferFilterPathGroup = new StringFilterGroup( null, "|CellType|CollectionType|CellType|ContainerType|button.eml|" ); - pathFilterGroupList.addAll( + addPathCallbacks( new StringFilterGroup( SettingsEnum.HIDE_LIKE_DISLIKE_BUTTON, "|segmented_like_dislike_button" @@ -48,33 +49,33 @@ public ButtonsFilter() { ); bufferButtonsGroupList.addAll( - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_LIVE_CHAT_BUTTON, "yt_outline_message_bubble_overlap" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_REPORT_BUTTON, "yt_outline_flag" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_SHARE_BUTTON, "yt_outline_share" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_REMIX_BUTTON, "yt_outline_youtube_shorts_plus" ), // Check for clip button both here and using a path filter, // as there's a chance the path is a generic action button and won't contain 'clip_button' - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_CLIP_BUTTON, "yt_outline_scissors" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_SHOP_BUTTON, "yt_outline_bag" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_THANKS_BUTTON, "yt_outline_dollar_sign_heart" ) @@ -82,7 +83,7 @@ public ButtonsFilter() { } private boolean isEveryFilterGroupEnabled() { - for (var group : pathFilterGroupList) + for (var group : pathCallbacks) if (!group.isEnabled()) return false; for (var group : bufferButtonsGroupList) @@ -93,7 +94,7 @@ private boolean isEveryFilterGroupEnabled() { @Override public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { // If the current matched group is the action bar group, // in case every filter group is enabled, hide the action bar. if (matchedGroup == actionBarGroup) { @@ -109,6 +110,6 @@ public boolean isFiltered(@Nullable String identifier, String path, byte[] proto if (!bufferButtonsGroupList.check(protobufBufferArray).isFiltered()) return false; } - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); } } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/CommentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/CommentsFilter.java index 089fb9480b..6ae67f7c4b 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/CommentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/CommentsFilter.java @@ -2,6 +2,7 @@ import app.revanced.integrations.settings.SettingsEnum; +@SuppressWarnings("unused") final class CommentsFilter extends Filter { public CommentsFilter() { @@ -18,7 +19,7 @@ public CommentsFilter() { "comments_entry_point_simplebox" ); - this.pathFilterGroupList.addAll( + addPathCallbacks( comments, previewComment ); diff --git a/app/src/main/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java index ccdd32104c..e786144ad8 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java @@ -4,6 +4,7 @@ import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.StringTrieSearch; +@SuppressWarnings("unused") final class DescriptionComponentsFilter extends Filter { private final StringTrieSearch exceptions = new StringTrieSearch(); @@ -48,7 +49,7 @@ public DescriptionComponentsFilter() { "transcript_section" ); - pathFilterGroupList.addAll( + addPathCallbacks( chapterSection, infoCardsSection, gameSection, @@ -61,9 +62,9 @@ public DescriptionComponentsFilter() { @Override boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { if (exceptions.matches(path)) return false; - return super.isFiltered(path, identifier, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(path, identifier, protobufBufferArray, matchedGroup, contentType, contentIndex); } } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/integrations/patches/components/DummyFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/DummyFilter.java deleted file mode 100644 index 3c36b51a1a..0000000000 --- a/app/src/main/java/app/revanced/integrations/patches/components/DummyFilter.java +++ /dev/null @@ -1,3 +0,0 @@ -package app.revanced.integrations.patches.components; - -final class DummyFilter extends Filter { } \ No newline at end of file diff --git a/app/src/main/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java index fc1f9a1e9f..b1637b8353 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java @@ -2,10 +2,11 @@ import app.revanced.integrations.settings.SettingsEnum; +@SuppressWarnings("unused") public final class HideInfoCardsFilterPatch extends Filter { public HideInfoCardsFilterPatch() { - identifierFilterGroupList.addAll( + addIdentifierCallbacks( new StringFilterGroup( SettingsEnum.HIDE_INFO_CARDS, "info_card_teaser_overlay.eml" diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java index a66bb133cb..28d99e051e 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -1,24 +1,26 @@ package app.revanced.integrations.patches.components; - import android.os.Build; + import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; + import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.StringTrieSearch; +@SuppressWarnings("unused") @RequiresApi(api = Build.VERSION_CODES.N) public final class LayoutComponentsFilter extends Filter { private final StringTrieSearch exceptions = new StringTrieSearch(); private static final StringTrieSearch mixPlaylistsExceptions = new StringTrieSearch(); - private static final ByteArrayAsStringFilterGroup mixPlaylistsExceptions2 = new ByteArrayAsStringFilterGroup( + private static final ByteArrayFilterGroup mixPlaylistsExceptions2 = new ByteArrayFilterGroup( null, "cell_description_body" ); private final CustomFilterGroup custom; - private static final ByteArrayAsStringFilterGroup mixPlaylists = new ByteArrayAsStringFilterGroup( + private static final ByteArrayFilterGroup mixPlaylists = new ByteArrayFilterGroup( SettingsEnum.HIDE_MIX_PLAYLISTS, "&list=" ); @@ -44,6 +46,25 @@ public LayoutComponentsFilter() { "library_recent_shelf" ); + // Identifiers. + + final var graySeparator = new StringFilterGroup( + SettingsEnum.HIDE_GRAY_SEPARATOR, + "cell_divider" // layout residue (gray line above the buttoned ad), + ); + + final var chipsShelf = new StringFilterGroup( + SettingsEnum.HIDE_CHIPS_SHELF, + "chips_shelf" + ); + + addIdentifierCallbacks( + graySeparator, + chipsShelf + ); + + // Paths. + custom = new CustomFilterGroup( SettingsEnum.CUSTOM_FILTER, SettingsEnum.CUSTOM_FILTER_STRINGS @@ -155,10 +176,6 @@ public LayoutComponentsFilter() { "image_shelf" ); - final var graySeparator = new StringFilterGroup( - SettingsEnum.HIDE_GRAY_SEPARATOR, - "cell_divider" // layout residue (gray line above the buttoned ad), - ); final var timedReactions = new StringFilterGroup( SettingsEnum.HIDE_TIMED_REACTIONS, @@ -181,11 +198,6 @@ public LayoutComponentsFilter() { "compact_sponsor_button" ); - final var chipsShelf = new StringFilterGroup( - SettingsEnum.HIDE_CHIPS_SHELF, - "chips_shelf" - ); - final var channelWatermark = new StringFilterGroup( SettingsEnum.HIDE_VIDEO_CHANNEL_WATERMARK, "featured_channel_watermark_overlay" @@ -196,7 +208,11 @@ public LayoutComponentsFilter() { "mixed_content_shelf" ); - this.pathFilterGroupList.addAll( + addPathCallbacks( + custom, + expandableMetadata, + inFeedSurvey, + notifyMe, channelBar, communityPosts, paidContent, @@ -204,13 +220,10 @@ public LayoutComponentsFilter() { channelWatermark, communityGuidelines, quickActions, - expandableMetadata, relatedVideos, compactBanner, - inFeedSurvey, joinMembership, medicalPanel, - notifyMe, videoQualityMenuFooter, infoPanel, subscribersCommunityGuidelines, @@ -220,32 +233,26 @@ public LayoutComponentsFilter() { timedReactions, imageShelf, channelMemberShelf, - forYouShelf, - custom - ); - - this.identifierFilterGroupList.addAll( - graySeparator, - chipsShelf + forYouShelf ); } @Override public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { // The groups are excluded from the filter due to the exceptions list below. // Filter them separately here. if (matchedGroup == notifyMe || matchedGroup == inFeedSurvey || matchedGroup == expandableMetadata) - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); if (matchedGroup != custom && exceptions.matches(path)) return false; // Exceptions are not filtered. // TODO: This also hides the feed Shorts shelf header - if (matchedGroup == searchResultShelfHeader && matchedIndex != 0) return false; + if (matchedGroup == searchResultShelfHeader && contentIndex != 0) return false; - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); } /** diff --git a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index 96b0976e54..26b31e64c5 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -195,6 +195,14 @@ public ByteArrayFilterGroup(SettingsEnum setting, byte[]... filters) { super(setting, filters); } + /** + * Converts the Strings into byte arrays. Used to search for text in binary data. + */ + @RequiresApi(api = Build.VERSION_CODES.N) + public ByteArrayFilterGroup(SettingsEnum setting, String... filters) { + super(setting, Arrays.stream(filters).map(String::getBytes).toArray(byte[][]::new)); + } + private synchronized void buildFailurePatterns() { if (failurePatterns != null) return; // Thread race and another thread already initialized the search. LogHelper.printDebug(() -> "Building failure array for: " + this); @@ -211,12 +219,14 @@ public FilterGroupResult check(final byte[] bytes) { int matchedLength = 0; int matchedIndex = -1; if (isEnabled()) { - if (failurePatterns == null) { + int[][] failures = failurePatterns; + if (failures == null) { buildFailurePatterns(); // Lazy load. + failures = failurePatterns; } for (int i = 0, length = filters.length; i < length; i++) { byte[] filter = filters[i]; - matchedIndex = indexOf(bytes, filter, failurePatterns[i]); + matchedIndex = indexOf(bytes, filter, failures[i]); if (matchedIndex >= 0) { matchedLength = filter.length; break; @@ -228,34 +238,16 @@ public FilterGroupResult check(final byte[] bytes) { } -final class ByteArrayAsStringFilterGroup extends ByteArrayFilterGroup { - - @RequiresApi(api = Build.VERSION_CODES.N) - public ByteArrayAsStringFilterGroup(SettingsEnum setting, String... filters) { - super(setting, Arrays.stream(filters).map(String::getBytes).toArray(byte[][]::new)); - } -} - abstract class FilterGroupList> implements Iterable { private final List filterGroups = new ArrayList<>(); - /** - * Search graph. Created only if needed. - */ - private volatile TrieSearch search; + private final TrieSearch search = createSearchGraph(); @SafeVarargs protected final void addAll(final T... groups) { filterGroups.addAll(Arrays.asList(groups)); - search = null; // Rebuild, if already created. - } - protected final synchronized void buildSearch() { - // Since litho filtering is multi-threaded, this method can be concurrently called by multiple threads. - if (search != null) return; // Thread race and another thread already initialized the search. - LogHelper.printDebug(() -> "Creating prefix search tree for: " + this); - TrieSearch search = createSearchGraph(); - for (T group : filterGroups) { + for (T group : groups) { if (!group.includeInSearch()) { continue; } @@ -270,7 +262,6 @@ protected final synchronized void buildSearch() { }); } } - this.search = search; // Must set after it's completely initialized. } @NonNull @@ -293,9 +284,6 @@ public Spliterator spliterator() { } protected FilterGroup.FilterGroupResult check(V stack) { - if (search == null) { - buildSearch(); // Lazy load. - } FilterGroup.FilterGroupResult result = new FilterGroup.FilterGroupResult(); search.matches(stack, result); return result; @@ -322,42 +310,90 @@ protected ByteTrieSearch createSearchGraph() { } } +/** + * Filters litho based components. + * + * Callbacks to filter content are added using {@link #addIdentifierCallbacks(StringFilterGroup...)} + * and {@link #addPathCallbacks(StringFilterGroup...)}. + * + * To filter {@link FilterContentType#PROTOBUFFER}, first add a callback to + * either an identifier or a path. + * Then inside {@link #isFiltered(String, String, byte[], StringFilterGroup, FilterContentType, int)} + * search for the buffer content using either a {@link ByteArrayFilterGroup} (if searching for 1 pattern) + * or a {@link ByteArrayFilterGroupList} (if searching for more than 1 pattern). + * + * All callbacks must be registered before the constructor completes. + */ abstract class Filter { + + public enum FilterContentType { + IDENTIFIER, + PATH, + PROTOBUFFER + } + /** - * All group filters must be set before the constructor call completes. - * Otherwise {@link #isFiltered(String, String, byte[], FilterGroupList, FilterGroup, int)} - * will never be called for any matches. + * Identifier callbacks. Do not add to this instance, + * and instead use {@link #addIdentifierCallbacks(StringFilterGroup...)}. */ + protected final List identifierCallbacks = new ArrayList<>(); + /** + * Path callbacks. Do not add to this instance, + * and instead use {@link #addPathCallbacks(StringFilterGroup...)}. + */ + protected final List pathCallbacks = new ArrayList<>(); - protected final StringFilterGroupList pathFilterGroupList = new StringFilterGroupList(); - protected final StringFilterGroupList identifierFilterGroupList = new StringFilterGroupList(); + /** + * Adds callbacks to {@link #isFiltered(String, String, byte[], StringFilterGroup, FilterContentType, int)} + * if any of the groups are found. + */ + protected final void addIdentifierCallbacks(StringFilterGroup... groups) { + identifierCallbacks.addAll(Arrays.asList(groups)); + } + + /** + * Adds callbacks to {@link #isFiltered(String, String, byte[], StringFilterGroup, FilterContentType, int)} + * if any of the groups are found. + */ + protected final void addPathCallbacks(StringFilterGroup... groups) { + pathCallbacks.addAll(Arrays.asList(groups)); + } /** * Called after an enabled filter has been matched. - * Default implementation is to always filter the matched item. + * Default implementation is to always filter the matched component and log the action. * Subclasses can perform additional or different checks if needed. *

+ * If the content is to be filtered, subclasses should always + * call this method (and never return a plain 'true'). + * That way the logs will always show when a component was filtered and which filter hide it. + *

* Method is called off the main thread. * - * @param matchedList The list the group filter belongs to. * @param matchedGroup The actual filter that matched. - * @param matchedIndex Matched index of string/array. - * @return True if the litho item should be filtered out. + * @param contentType The type of content matched. + * @param contentIndex Matched index of the identifier or path. + * @return True if the litho component should be filtered out. */ - @SuppressWarnings("rawtypes") boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { if (SettingsEnum.DEBUG.getBoolean()) { - if (matchedList == identifierFilterGroupList) { - LogHelper.printDebug(() -> getClass().getSimpleName() + " Filtered identifier: " + identifier); + String filterSimpleName = getClass().getSimpleName(); + if (contentType == FilterContentType.IDENTIFIER) { + LogHelper.printDebug(() -> filterSimpleName + " Filtered identifier: " + identifier); } else { - LogHelper.printDebug(() -> getClass().getSimpleName() + " Filtered path: " + path); + LogHelper.printDebug(() -> filterSimpleName + " Filtered path: " + path); } } return true; } } +/** + * Placeholder for actual filters. + */ +final class DummyFilter extends Filter { } + @RequiresApi(api = Build.VERSION_CODES.N) @SuppressWarnings("unused") public final class LithoFilterPatch { @@ -437,8 +473,10 @@ private static void findAsciiStrings(StringBuilder builder, byte[] buffer) { static { for (Filter filter : filters) { - filterGroupLists(identifierSearchTree, filter, filter.identifierFilterGroupList); - filterGroupLists(pathSearchTree, filter, filter.pathFilterGroupList); + filterUsingCallbacks(identifierSearchTree, filter, + filter.identifierCallbacks, Filter.FilterContentType.IDENTIFIER); + filterUsingCallbacks(pathSearchTree, filter, + filter.pathCallbacks, Filter.FilterContentType.PATH); } LogHelper.printDebug(() -> "Using: " @@ -448,18 +486,19 @@ private static void findAsciiStrings(StringBuilder builder, byte[] buffer) { + " (" + pathSearchTree.getEstimatedMemorySize() + " KB)"); } - private static void filterGroupLists(TrieSearch pathSearchTree, - Filter filter, FilterGroupList> list) { - for (FilterGroup group : list) { + private static void filterUsingCallbacks(StringTrieSearch pathSearchTree, + Filter filter, List groups, + Filter.FilterContentType type) { + for (StringFilterGroup group : groups) { if (!group.includeInSearch()) { continue; } - for (T pattern : group.filters) { + for (String pattern : group.filters) { pathSearchTree.addPattern(pattern, (textSearched, matchedStartIndex, matchedLength, callbackParameter) -> { if (!group.isEnabled()) return false; LithoFilterParameters parameters = (LithoFilterParameters) callbackParameter; return filter.isFiltered(parameters.identifier, parameters.path, parameters.protoBuffer, - list, group, matchedStartIndex); + group, type, matchedStartIndex); } ); } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java index 0f4b9bcfd5..f609c43e2f 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/PlaybackSpeedMenuFilterPatch.java @@ -12,7 +12,7 @@ public final class PlaybackSpeedMenuFilterPatch extends Filter { public static volatile boolean isPlaybackSpeedMenuVisible; public PlaybackSpeedMenuFilterPatch() { - pathFilterGroupList.addAll(new StringFilterGroup( + addPathCallbacks(new StringFilterGroup( null, "playback_speed_sheet_content.eml-js" )); @@ -20,7 +20,7 @@ public PlaybackSpeedMenuFilterPatch() { @Override boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { isPlaybackSpeedMenuVisible = true; return false; diff --git a/app/src/main/java/app/revanced/integrations/patches/components/PlayerFlyoutMenuItemsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/PlayerFlyoutMenuItemsFilter.java index 4e700028b3..4f994dd9f5 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/PlayerFlyoutMenuItemsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/PlayerFlyoutMenuItemsFilter.java @@ -8,65 +8,64 @@ import app.revanced.integrations.settings.SettingsEnum; import app.revanced.integrations.shared.PlayerType; +@SuppressWarnings("unused") public class PlayerFlyoutMenuItemsFilter extends Filter { - // Search the buffer only if the flyout menu path is found. - // Handle the searching in this class instead of adding to the global filter group (which searches all the time) private final ByteArrayFilterGroupList flyoutFilterGroupList = new ByteArrayFilterGroupList(); private final ByteArrayFilterGroup exception; @RequiresApi(api = Build.VERSION_CODES.N) public PlayerFlyoutMenuItemsFilter() { - exception = new ByteArrayAsStringFilterGroup( + exception = new ByteArrayFilterGroup( // Whitelist Quality menu item when "Hide Additional settings menu" is enabled SettingsEnum.HIDE_ADDITIONAL_SETTINGS_MENU, "quality_sheet" ); // Using pathFilterGroupList due to new flyout panel(A/B) - pathFilterGroupList.addAll( + addPathCallbacks( new StringFilterGroup(null, "overflow_menu_item.eml|") ); flyoutFilterGroupList.addAll( - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_CAPTIONS_MENU, "closed_caption" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_ADDITIONAL_SETTINGS_MENU, "yt_outline_gear" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_LOOP_VIDEO_MENU, "yt_outline_arrow_repeat_1_" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_AMBIENT_MODE_MENU, "yt_outline_screen_light" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_REPORT_MENU, "yt_outline_flag" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_HELP_MENU, "yt_outline_question_circle" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_MORE_INFO_MENU, "yt_outline_info_circle" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_SPEED_MENU, "yt_outline_play_arrow_half_circle" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_AUDIO_TRACK_MENU, "yt_outline_person_radar" ), - new ByteArrayAsStringFilterGroup( + new ByteArrayFilterGroup( SettingsEnum.HIDE_WATCH_IN_VR_MENU, "yt_outline_vr" ) @@ -75,15 +74,15 @@ public PlayerFlyoutMenuItemsFilter() { @Override boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { // Shorts also use this player flyout panel if (PlayerType.getCurrent().isNoneOrHidden() || exception.check(protobufBufferArray).isFiltered()) return false; - // Only 1 group is added to the parent class, so the matched group must be the overflow menu. - if (matchedIndex == 0 && flyoutFilterGroupList.check(protobufBufferArray).isFiltered()) { + // Only 1 path callback was added, so the matched group must be the overflow menu. + if (contentIndex == 0 && flyoutFilterGroupList.check(protobufBufferArray).isFiltered()) { // Super class handles logging. - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); } return false; } diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java index d6b7d151d7..b0a4b4f973 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ReturnYouTubeDislikeFilterPatch.java @@ -71,21 +71,21 @@ public static void newPlayerResponseVideoId(String videoId, boolean isShortAndOp private final ByteArrayFilterGroupList videoIdFilterGroup = new ByteArrayFilterGroupList(); public ReturnYouTubeDislikeFilterPatch() { - pathFilterGroupList.addAll( + addPathCallbacks( new StringFilterGroup(SettingsEnum.RYD_SHORTS, "|shorts_dislike_button.eml|") ); // After the dislikes icon name is some binary data and then the video id for that specific short. videoIdFilterGroup.addAll( // Video was previously disliked before video was opened. - new ByteArrayAsStringFilterGroup(null, "ic_right_dislike_on_shadowed"), + new ByteArrayFilterGroup(null, "ic_right_dislike_on_shadowed"), // Video was not already disliked. - new ByteArrayAsStringFilterGroup(null, "ic_right_dislike_off_shadowed") + new ByteArrayFilterGroup(null, "ic_right_dislike_off_shadowed") ); } @Override public boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { FilterGroup.FilterGroupResult result = videoIdFilterGroup.check(protobufBufferArray); if (result.isFiltered()) { String matchedVideoId = findVideoId(protobufBufferArray); @@ -112,7 +112,7 @@ private String findVideoId(byte[] protobufBufferArray) { } /** - * This could use {@link TrieSearch}, but since the video ids are constantly changing + * This could use {@link TrieSearch}, but since the patterns are constantly changing * the overhead of updating the Trie might negate the search performance gain. */ private static boolean byteArrayContainsString(@NonNull byte[] array, @NonNull String text) { diff --git a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java index 7ab5a54296..5e40f6e8e6 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/ShortsFilter.java @@ -10,7 +10,7 @@ import static app.revanced.integrations.utils.ReVancedUtils.hideViewBy1dpUnderCondition; import static app.revanced.integrations.utils.ReVancedUtils.hideViewUnderCondition; -/** @noinspection unused*/ +@SuppressWarnings("unused") @RequiresApi(api = Build.VERSION_CODES.N) public final class ShortsFilter extends Filter { public static PivotBar pivotBar; // Set by patch. @@ -49,7 +49,7 @@ public ShortsFilter() { "suggested_action" ); - identifierFilterGroupList.addAll(shorts, shelfHeader, thanksButton); + addIdentifierCallbacks(shorts, shelfHeader, thanksButton); // Shorts player components. var joinButton = new StringFilterGroup( @@ -87,22 +87,22 @@ public ShortsFilter() { "ContainerType|shorts_video_action_button" ); - pathFilterGroupList.addAll( + addPathCallbacks( joinButton, subscribeButton, subscribeButtonPaused, channelBar, soundButton, infoPanel, videoActionButton ); - var shortsCommentButton = new ByteArrayAsStringFilterGroup( + var shortsCommentButton = new ByteArrayFilterGroup( SettingsEnum.HIDE_SHORTS_COMMENTS_BUTTON, "reel_comment_button" ); - var shortsShareButton = new ByteArrayAsStringFilterGroup( + var shortsShareButton = new ByteArrayFilterGroup( SettingsEnum.HIDE_SHORTS_SHARE_BUTTON, "reel_share_button" ); - var shortsRemixButton = new ByteArrayAsStringFilterGroup( + var shortsRemixButton = new ByteArrayFilterGroup( SettingsEnum.HIDE_SHORTS_REMIX_BUTTON, "reel_remix_button" ); @@ -112,19 +112,19 @@ public ShortsFilter() { @Override boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { - if (matchedList == pathFilterGroupList) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { + if (contentType == FilterContentType.PATH) { // Always filter if matched. if (matchedGroup == soundButton || matchedGroup == infoPanel || matchedGroup == channelBar || matchedGroup == subscribeButtonPaused - ) return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + ) return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); // Video action buttons (comment, share, remix) have the same path. if (matchedGroup == videoActionButton) { if (videoActionButtonGroupList.check(protobufBufferArray).isFiltered()) return super.isFiltered( - identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex + identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex ); return false; } @@ -133,18 +133,18 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff // to avoid false positives. if (path.startsWith(REEL_CHANNEL_BAR_PATH)) if (matchedGroup == subscribeButton) return super.isFiltered( - identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex + identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex ); return false; } else if (matchedGroup == shelfHeader) { // Because the header is used in watch history and possibly other places, check for the index, // which is 0 when the shelf header is used for Shorts. - if (matchedIndex != 0) return false; + if (contentIndex != 0) return false; } // Super class handles logging. - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); } public static void hideShortsShelf(final View shortsShelfView) { diff --git a/app/src/main/java/app/revanced/integrations/patches/components/VideoQualityMenuFilterPatch.java b/app/src/main/java/app/revanced/integrations/patches/components/VideoQualityMenuFilterPatch.java index d09f4ddcad..2050cd3faa 100644 --- a/app/src/main/java/app/revanced/integrations/patches/components/VideoQualityMenuFilterPatch.java +++ b/app/src/main/java/app/revanced/integrations/patches/components/VideoQualityMenuFilterPatch.java @@ -9,11 +9,12 @@ * Abuse LithoFilter for {@link RestoreOldVideoQualityMenuPatch}. */ public final class VideoQualityMenuFilterPatch extends Filter { - // Must be volatile or synchronized, as litho filtering runs off main thread and this field is then access from the main thread. + // Must be volatile or synchronized, as litho filtering runs off main thread + // and this field is then access from the main thread. public static volatile boolean isVideoQualityMenuVisible; public VideoQualityMenuFilterPatch() { - pathFilterGroupList.addAll(new StringFilterGroup( + addPathCallbacks(new StringFilterGroup( SettingsEnum.RESTORE_OLD_VIDEO_QUALITY_MENU, "quick_quality_sheet_content.eml-js" )); @@ -21,7 +22,7 @@ public VideoQualityMenuFilterPatch() { @Override boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBufferArray, - FilterGroupList matchedList, FilterGroup matchedGroup, int matchedIndex) { + StringFilterGroup matchedGroup, FilterContentType contentType, int contentIndex) { isVideoQualityMenuVisible = true; return false;