diff --git a/integrations/java/app/revanced/integrations/patches/RemoveViewerDiscretionDialogPatch.java b/integrations/java/app/revanced/integrations/patches/RemoveViewerDiscretionDialogPatch.java new file mode 100644 index 000000000..c0d013e54 --- /dev/null +++ b/integrations/java/app/revanced/integrations/patches/RemoveViewerDiscretionDialogPatch.java @@ -0,0 +1,18 @@ +package app.revanced.integrations.patches; + +import android.app.AlertDialog; +import app.revanced.integrations.settings.SettingsEnum; + +public class RemoveViewerDiscretionDialogPatch { + public static void confirmDialog(AlertDialog dialog) { + if (!SettingsEnum.REMOVE_VIEWER_DISCRETION_DIALOG.getBoolean()) { + // Since the patch replaces the AlertDialog#show() method, we need to call the original method here. + dialog.show(); + return; + } + + final var button = dialog.getButton(AlertDialog.BUTTON_POSITIVE); + button.setSoundEffectsEnabled(false); + button.performClick(); + } +} diff --git a/integrations/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java b/integrations/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java index 9a14366ea..9c8caa455 100644 --- a/integrations/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java +++ b/integrations/java/app/revanced/integrations/patches/ReturnYouTubeDislikePatch.java @@ -570,7 +570,7 @@ public class ReturnYouTubeDislikePatch { return; } - final boolean videoIdIsShort = VideoInformation.lastVideoIdIsShort(); + final boolean videoIdIsShort = VideoInformation.lastPlayerResponseIsShort(); // Shorts shelf in home and subscription feed causes player response hook to be called, // and the 'is opening/playing' parameter will be false. // This hook will be called again when the Short is actually opened. diff --git a/integrations/java/app/revanced/integrations/patches/VideoInformation.java b/integrations/java/app/revanced/integrations/patches/VideoInformation.java index a6ba5649c..15c97fb5e 100644 --- a/integrations/java/app/revanced/integrations/patches/VideoInformation.java +++ b/integrations/java/app/revanced/integrations/patches/VideoInformation.java @@ -32,6 +32,7 @@ public final class VideoInformation { @NonNull private static volatile String playerResponseVideoId = ""; + private static volatile boolean playerResponseVideoIdIsShort; private static volatile boolean videoIdIsShort; /** @@ -82,6 +83,7 @@ public final class VideoInformation { */ public static String newPlayerResponseSignature(@NonNull String signature, boolean isShortAndOpeningOrPlaying) { final boolean isShort = playerParametersAreShort(signature); + playerResponseVideoIdIsShort = isShort; if (!isShort || isShortAndOpeningOrPlaying) { if (videoIdIsShort != isShort) { videoIdIsShort = isShort; @@ -155,20 +157,29 @@ public final class VideoInformation { * Caution: If called from a videoTimeHook() callback, * this will cause a recursive call into the same videoTimeHook() callback. * - * @param millisecond The millisecond to seek the video to. + * @param seekTime The seekTime to seek the video to. * @return true if the seek was successful. */ - public static boolean seekTo(final long millisecond) { - final long videoLength = getVideoLength(); - - // Prevent issues such as play/ pause button or autoplay not working. - final long seekToMilliseconds = Math.min(millisecond, VideoInformation.getVideoLength() - 250); - + public static boolean seekTo(final long seekTime) { ReVancedUtils.verifyOnMainThread(); try { - LogHelper.printDebug(() -> "Seeking to " + seekToMilliseconds); + final long videoTime = getVideoTime(); + final long videoLength = getVideoLength(); + + // Prevent issues such as play/ pause button or autoplay not working. + final long adjustedSeekTime = Math.min(seekTime, videoLength - 250); + if (videoTime <= seekTime && videoTime >= adjustedSeekTime) { + // Both the current video time and the seekTo are in the last 250ms of the video. + // Ignore this seek call, otherwise if a video ends with multiple closely timed segments + // then seeking here can create an infinite loop of skip attempts. + LogHelper.printDebug(() -> "Ignoring seekTo call as video playback is almost finished. " + + " videoTime: " + videoTime + " videoLength: " + videoLength + " seekTo: " + seekTime); + return false; + } + + LogHelper.printDebug(() -> "Seeking to " + adjustedSeekTime); //noinspection DataFlowIssue - return (Boolean) seekMethod.invoke(playerControllerRef.get(), seekToMilliseconds); + return (Boolean) seekMethod.invoke(playerControllerRef.get(), adjustedSeekTime); } catch (Exception ex) { LogHelper.printException(() -> "Failed to seek", ex); return false; @@ -206,11 +217,17 @@ public final class VideoInformation { return playerResponseVideoId; } + /** + * @return If the last player response video id was a Short. + * Includes Shorts shelf items appearing in the feed that are not opened. + * @see #lastVideoIdIsShort() + */ + public static boolean lastPlayerResponseIsShort() { + return playerResponseVideoIdIsShort; + } + /** * @return If the last player response video id _that was opened_ was a Short. - *
- * Note: This value returned may not match the status of {@link #getPlayerResponseVideoId()} - * since that includes player responses for videos not opened. */ public static boolean lastVideoIdIsShort() { return videoIdIsShort; diff --git a/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java b/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java index 5868596dc..3b0cb0ec5 100644 --- a/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java +++ b/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java @@ -1,16 +1,25 @@ package app.revanced.integrations.patches.components; - +import android.app.Instrumentation; +import android.view.KeyEvent; import android.view.View; import androidx.annotation.Nullable; import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; import app.revanced.integrations.utils.StringTrieSearch; - +@SuppressWarnings("unused") public final class AdsFilter extends Filter { + // region Fullscreen ad + private static long lastTimeClosedFullscreenAd = 0; + private static final Instrumentation instrumentation = new Instrumentation(); + private final StringFilterGroup fullscreenAd; + + // endregion + private final StringTrieSearch exceptions = new StringTrieSearch(); private final StringFilterGroup shoppingLinks; @@ -23,6 +32,22 @@ public final class AdsFilter extends Filter { "library_recent_shelf" ); + // Identifiers. + + + final var carouselAd = new StringFilterGroup( + SettingsEnum.HIDE_GENERAL_ADS, + "carousel_ad" + ); + addIdentifierCallbacks(carouselAd); + + // Paths. + + fullscreenAd = new StringFilterGroup( + SettingsEnum.HIDE_FULLSCREEN_ADS, + "_interstitial" + ); + final var buttonedAd = new StringFilterGroup( SettingsEnum.HIDE_BUTTONED_ADS, "_buttoned_layout", @@ -30,7 +55,8 @@ public final class AdsFilter extends Filter { "_ad_with", "text_image_button_group_layout", "video_display_button_group_layout", - "landscape_image_wide_button_layout" + "landscape_image_wide_button_layout", + "video_display_carousel_button_group_layout" ); final var generalAds = new StringFilterGroup( @@ -61,11 +87,6 @@ public final class AdsFilter extends Filter { "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,30 +113,34 @@ public final class AdsFilter extends Filter { "cta_shelf_card" ); - this.pathFilterGroupList.addAll( + addPathCallbacks( generalAds, buttonedAd, merchandise, viewProducts, selfSponsor, + fullscreenAd, webLinkPanel, 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) return false; - return super.isFiltered(identifier, path, protobufBufferArray, matchedList, matchedGroup, matchedIndex); + if (matchedGroup == fullscreenAd && path.contains("|ImageType|")) { + closeFullscreenAd(); + } + + // Check for the index because of likelihood of false positives. + if (matchedGroup == shoppingLinks && contentIndex != 0) + return false; + + return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); } /** @@ -126,4 +151,21 @@ public final class AdsFilter extends Filter { public static void hideAdAttributionView(View view) { ReVancedUtils.hideViewBy1dpUnderCondition(SettingsEnum.HIDE_GENERAL_ADS, view); } + + /** + * Close the fullscreen ad. + *
+ * The strategy is to send a back button event to the app to close the fullscreen ad using the back button event.
+ */
+ private static void closeFullscreenAd() {
+ final var currentTime = System.currentTimeMillis();
+
+ // Prevent spamming the back button.
+ if (currentTime - lastTimeClosedFullscreenAd < 10000) return;
+ lastTimeClosedFullscreenAd = currentTime;
+
+ LogHelper.printDebug(() -> "Closing fullscreen ad");
+
+ ReVancedUtils.runOnMainThreadDelayed(() -> instrumentation.sendKeyDownUpSync(KeyEvent.KEYCODE_BACK), 1000);
+ }
}
diff --git a/integrations/java/app/revanced/integrations/patches/components/ButtonsFilter.java b/integrations/java/app/revanced/integrations/patches/components/ButtonsFilter.java
index 19cddf3f6..123c58036 100644
--- a/integrations/java/app/revanced/integrations/patches/components/ButtonsFilter.java
+++ b/integrations/java/app/revanced/integrations/patches/components/ButtonsFilter.java
@@ -7,6 +7,7 @@ import androidx.annotation.RequiresApi;
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 @@ final class ButtonsFilter extends Filter {
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 @@ final class ButtonsFilter extends Filter {
);
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 @@ final class ButtonsFilter extends Filter {
}
private boolean isEveryFilterGroupEnabled() {
- for (var group : pathFilterGroupList)
+ for (var group : pathCallbacks)
if (!group.isEnabled()) return false;
for (var group : bufferButtonsGroupList)
@@ -93,7 +94,7 @@ final class ButtonsFilter extends Filter {
@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 @@ final class ButtonsFilter extends Filter {
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/integrations/java/app/revanced/integrations/patches/components/CommentsFilter.java b/integrations/java/app/revanced/integrations/patches/components/CommentsFilter.java
index 089fb9480..6ae67f7c4 100644
--- a/integrations/java/app/revanced/integrations/patches/components/CommentsFilter.java
+++ b/integrations/java/app/revanced/integrations/patches/components/CommentsFilter.java
@@ -2,6 +2,7 @@ package app.revanced.integrations.patches.components;
import app.revanced.integrations.settings.SettingsEnum;
+@SuppressWarnings("unused")
final class CommentsFilter extends Filter {
public CommentsFilter() {
@@ -18,7 +19,7 @@ final class CommentsFilter extends Filter {
"comments_entry_point_simplebox"
);
- this.pathFilterGroupList.addAll(
+ addPathCallbacks(
comments,
previewComment
);
diff --git a/integrations/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java b/integrations/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java
index ccdd32104..e786144ad 100644
--- a/integrations/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java
+++ b/integrations/java/app/revanced/integrations/patches/components/DescriptionComponentsFilter.java
@@ -4,6 +4,7 @@ import androidx.annotation.Nullable;
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 @@ final class DescriptionComponentsFilter extends Filter {
"transcript_section"
);
- pathFilterGroupList.addAll(
+ addPathCallbacks(
chapterSection,
infoCardsSection,
gameSection,
@@ -61,9 +62,9 @@ final class DescriptionComponentsFilter extends Filter {
@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/integrations/java/app/revanced/integrations/patches/components/DummyFilter.java b/integrations/java/app/revanced/integrations/patches/components/DummyFilter.java
deleted file mode 100644
index 3c36b51a1..000000000
--- a/integrations/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/integrations/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java b/integrations/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java
index fc1f9a1e9..b1637b835 100644
--- a/integrations/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java
+++ b/integrations/java/app/revanced/integrations/patches/components/HideInfoCardsFilterPatch.java
@@ -2,10 +2,11 @@ package app.revanced.integrations.patches.components;
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/integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java
index a66bb133c..afc9b8457 100644
--- a/integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java
+++ b/integrations/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="
);
@@ -26,6 +28,8 @@ public final class LayoutComponentsFilter extends Filter {
private final StringFilterGroup inFeedSurvey;
private final StringFilterGroup notifyMe;
private final StringFilterGroup expandableMetadata;
+ private final ByteArrayFilterGroup searchResultRecommendations;
+ private final StringFilterGroup searchResultVideo;
static {
mixPlaylistsExceptions.addPatterns(
@@ -39,11 +43,31 @@ public final class LayoutComponentsFilter extends Filter {
exceptions.addPatterns(
"home_video_with_context",
"related_video_with_context",
+ "search_video_with_context",
"comment_thread", // Whitelist comments
"|comment.", // Whitelist comment replies
"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
@@ -64,7 +88,6 @@ public final class LayoutComponentsFilter extends Filter {
"sponsorships_comments_upsell"
);
-
final var channelMemberShelf = new StringFilterGroup(
SettingsEnum.HIDE_CHANNEL_MEMBER_SHELF,
"member_recognition_shelf"
@@ -107,6 +130,11 @@ public final class LayoutComponentsFilter extends Filter {
"channel_guidelines_entry_banner"
);
+ final var emergencyBox = new StringFilterGroup(
+ SettingsEnum.HIDE_EMERGENCY_BOX,
+ "emergency_onebox"
+ );
+
// The player audio track button does the exact same function as the audio track flyout menu option.
// But if the copy url button is shown, these button clashes and the the audio button does not work.
// Previously this was a setting to show/hide the player button.
@@ -155,10 +183,6 @@ public final class LayoutComponentsFilter extends Filter {
"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 +205,6 @@ public final class LayoutComponentsFilter extends Filter {
"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,23 +215,36 @@ public final class LayoutComponentsFilter extends Filter {
"mixed_content_shelf"
);
- this.pathFilterGroupList.addAll(
+ searchResultVideo = new StringFilterGroup(
+ SettingsEnum.HIDE_SEARCH_RESULT_RECOMMENDATIONS,
+ "search_video_with_context.eml"
+ );
+
+ searchResultRecommendations = new ByteArrayFilterGroup(
+ SettingsEnum.HIDE_SEARCH_RESULT_RECOMMENDATIONS,
+ "endorsement_header_footer"
+ );
+
+ addPathCallbacks(
+ custom,
+ expandableMetadata,
+ inFeedSurvey,
+ notifyMe,
channelBar,
communityPosts,
paidContent,
+ searchResultVideo,
latestPosts,
channelWatermark,
communityGuidelines,
quickActions,
- expandableMetadata,
relatedVideos,
compactBanner,
- inFeedSurvey,
joinMembership,
medicalPanel,
- notifyMe,
videoQualityMenuFooter,
infoPanel,
+ emergencyBox,
subscribersCommunityGuidelines,
channelGuidelines,
audioTrackButton,
@@ -220,32 +252,31 @@ public final class LayoutComponentsFilter extends Filter {
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) {
+ if (matchedGroup == searchResultVideo) {
+ if (searchResultRecommendations.check(protobufBufferArray).isFiltered()) {
+ return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, 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);
+ if (matchedGroup == notifyMe || matchedGroup == inFeedSurvey || matchedGroup == expandableMetadata)
+ 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/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java
index 96b0976e5..26b31e64c 100644
--- a/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java
+++ b/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java
@@ -195,6 +195,14 @@ class ByteArrayFilterGroup extends FilterGroup
+ * 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 @@ public final class LithoFilterPatch {
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 @@ public final class LithoFilterPatch {
+ " (" + pathSearchTree.getEstimatedMemorySize() + " KB)");
}
- private static