From 8cce916abb3ac90238c43676eadff3ce2eb8e201 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Wed, 14 Jun 2023 03:30:14 +0200 Subject: [PATCH] fix(youtube): separate `hide-ads` to `hide-layout-components` patch --- .../patches/components/AdsFilter.java | 260 +++--------------- .../components/LayoutComponentsFilter.java | 217 +++++++++++++++ .../patches/components/LithoFilterPatch.java | 17 +- 3 files changed, 263 insertions(+), 231 deletions(-) create mode 100644 integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java diff --git a/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java b/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java index 0d860631c..a16ea57f8 100644 --- a/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java +++ b/integrations/java/app/revanced/integrations/patches/components/AdsFilter.java @@ -1,160 +1,23 @@ package app.revanced.integrations.patches.components; -import android.os.Build; import android.view.View; -import androidx.annotation.RequiresApi; import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.utils.LogHelper; import app.revanced.integrations.utils.ReVancedUtils; public final class AdsFilter extends Filter { private final String[] exceptions; - private final CustomFilterGroup custom; - - // region Mix playlists - private final ByteArrayAsStringFilterGroup mixPlaylists; - private final ByteArrayAsStringFilterGroup imageHosting; - - // endregion - - @RequiresApi(api = Build.VERSION_CODES.N) public AdsFilter() { exceptions = new String[]{ - "home_video_with_context", - "related_video_with_context", - "comment_thread", // skip filtering anything in the comments - "|comment.", // skip filtering anything in the comments replies + "home_video_with_context", // Don't filter anything in the home page video component. + "related_video_with_context", // Don't filter anything in the related video component. + "comment_thread", // Don't filter anything in the comments. + "|comment.", // Don't filter anything in the comments replies. "library_recent_shelf", }; - custom = new CustomFilterGroup( - SettingsEnum.CUSTOM_FILTER, - SettingsEnum.CUSTOM_FILTER_STRINGS - ); - - final var communityPosts = new StringFilterGroup( - SettingsEnum.HIDE_COMMUNITY_POSTS, - "post_base_wrapper" - ); - - final var communityGuidelines = new StringFilterGroup( - SettingsEnum.HIDE_COMMUNITY_GUIDELINES, - "community_guidelines" - ); - - final var subscribersCommunityGuidelines = new StringFilterGroup( - SettingsEnum.HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES, - "sponsorships_comments_upsell" - ); - - - final var channelMemberShelf = new StringFilterGroup( - SettingsEnum.HIDE_CHANNEL_MEMBER_SHELF, - "member_recognition_shelf" - ); - - final var compactBanner = new StringFilterGroup( - SettingsEnum.HIDE_COMPACT_BANNER, - "compact_banner" - ); - - final var inFeedSurvey = new StringFilterGroup( - SettingsEnum.HIDE_FEED_SURVEY, - "in_feed_survey", - "slimline_survey" - ); - - final var medicalPanel = new StringFilterGroup( - SettingsEnum.HIDE_MEDICAL_PANELS, - "medical_panel" - ); - - final var paidContent = new StringFilterGroup( - SettingsEnum.HIDE_PAID_CONTENT, - "paid_content_overlay" - ); - - final var merchandise = new StringFilterGroup( - SettingsEnum.HIDE_MERCHANDISE_BANNERS, - "product_carousel" - ); - - final var infoPanel = new StringFilterGroup( - SettingsEnum.HIDE_HIDE_INFO_PANELS, - "publisher_transparency_panel", - "single_item_information_panel" - ); - - final var latestPosts = new StringFilterGroup( - SettingsEnum.HIDE_HIDE_LATEST_POSTS, - "post_shelf" - ); - - final var channelGuidelines = new StringFilterGroup( - SettingsEnum.HIDE_HIDE_CHANNEL_GUIDELINES, - "channel_guidelines_entry_banner" - ); - - final var audioTrackButton = new StringFilterGroup( - SettingsEnum.HIDE_AUDIO_TRACK_BUTTON, - "multi_feed_icon_button" - ); - - final var artistCard = new StringFilterGroup( - SettingsEnum.HIDE_ARTIST_CARDS, - "official_card" - ); - - final var selfSponsor = new StringFilterGroup( - SettingsEnum.HIDE_SELF_SPONSOR, - "cta_shelf_card" - ); - - final var chapterTeaser = new StringFilterGroup( - SettingsEnum.HIDE_CHAPTER_TEASER, - "expandable_metadata", - "macro_markers_carousel" - ); - - final var viewProducts = new StringFilterGroup( - SettingsEnum.HIDE_PRODUCTS_BANNER, - "product_item", - "products_in_video" - ); - - final var webLinkPanel = new StringFilterGroup( - SettingsEnum.HIDE_WEB_SEARCH_RESULTS, - "web_link_panel" - ); - - final var channelBar = new StringFilterGroup( - SettingsEnum.HIDE_CHANNEL_BAR, - "channel_bar" - ); - - final var relatedVideos = new StringFilterGroup( - SettingsEnum.HIDE_RELATED_VIDEOS, - "fullscreen_related_videos" - ); - - final var quickActions = new StringFilterGroup( - SettingsEnum.HIDE_QUICK_ACTIONS, - "quick_actions" - ); - - final var imageShelf = new StringFilterGroup( - SettingsEnum.HIDE_IMAGE_SHELF, - "image_shelf" - ); - - final var graySeparator = new StringFilterGroup( - SettingsEnum.HIDE_GRAY_SEPARATOR, - "cell_divider" // layout residue (gray line above the buttoned ad), - ); - final var buttonedAd = new StringFilterGroup( SettingsEnum.HIDE_BUTTONED_ADS, "_buttoned_layout", @@ -192,107 +55,50 @@ public final class AdsFilter extends Filter { "offer_module_root" ); - // region Mix playlists - - mixPlaylists = new ByteArrayAsStringFilterGroup( - SettingsEnum.HIDE_MIX_PLAYLISTS, - "&list=", - "YouTube Music" - ); - - imageHosting = new ByteArrayAsStringFilterGroup( - SettingsEnum.HIDE_MIX_PLAYLISTS, // Unused - "ggpht.com" - ); - - // endregion - - this.pathFilterGroups.addAll( - generalAds, - buttonedAd, - channelBar, - communityPosts, - paidContent, - latestPosts, - movieAds, - chapterTeaser, - communityGuidelines, - quickActions, - relatedVideos, - compactBanner, - inFeedSurvey, - viewProducts, - medicalPanel, - merchandise, - infoPanel, - channelGuidelines, - audioTrackButton, - artistCard, - selfSponsor, - webLinkPanel, - imageShelf, - subscribersCommunityGuidelines, - channelMemberShelf - ); - final var carouselAd = new StringFilterGroup( SettingsEnum.HIDE_GENERAL_ADS, "carousel_ad" ); - this.identifierFilterGroups.addAll( - graySeparator, - carouselAd + final var viewProducts = new StringFilterGroup( + SettingsEnum.HIDE_PRODUCTS_BANNER, + "product_item", + "products_in_video" ); - } - private boolean isMixPlaylistFiltered(final byte[] _protobufBufferArray) { - if (!mixPlaylists.isEnabled()) return false; + final var webLinkPanel = new StringFilterGroup( + SettingsEnum.HIDE_WEB_SEARCH_RESULTS, + "web_link_panel" + ); - // Two checks are required to prevent false positives. + final var merchandise = new StringFilterGroup( + SettingsEnum.HIDE_MERCHANDISE_BANNERS, + "product_carousel" + ); - // First check if the current buffer potentially contains a mix playlist. - if (!mixPlaylists.check(_protobufBufferArray).isFiltered()) return false; + final var selfSponsor = new StringFilterGroup( + SettingsEnum.HIDE_SELF_SPONSOR, + "cta_shelf_card" + ); - // Ensure that the buffer actually contains a mix playlist. - return imageHosting.check(_protobufBufferArray).isFiltered(); + this.pathFilterGroups.addAll( + generalAds, + buttonedAd, + merchandise, + viewProducts, + selfSponsor, + webLinkPanel, + movieAds + ); + this.identifierFilterGroups.addAll(carouselAd); } @Override public boolean isFiltered(final String path, final String identifier, final byte[] _protobufBufferArray) { - FilterResult result; + if (ReVancedUtils.containsAny(path, exceptions)) + return false; - if (custom.isEnabled() && custom.check(path).isFiltered()) - result = FilterResult.CUSTOM; - else if (ReVancedUtils.containsAny(path, exceptions)) - result = FilterResult.EXCEPTION; - else { - var filtered = - pathFilterGroups.contains(path) || // Check if the path is filtered. - identifierFilterGroups.contains(identifier) || // Check if the identifier is filtered. - isMixPlaylistFiltered(_protobufBufferArray); // Check if the buffer contains a mix playlist. - - result = filtered ? FilterResult.FILTERED : FilterResult.UNFILTERED; - } - - LogHelper.printDebug(() -> String.format("%s (ID: %s): %s", result.message, identifier, path)); - - return result.filter; - } - - private enum FilterResult { - UNFILTERED(false, "Unfiltered"), - EXCEPTION(false, "Exception"), - FILTERED(true, "Filtered"), - CUSTOM(true, "Custom"); - - final Boolean filter; - final String message; - - FilterResult(boolean filter, String message) { - this.filter = filter; - this.message = message; - } + return super.isFiltered(path, identifier, _protobufBufferArray); } /** diff --git a/integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java b/integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java new file mode 100644 index 000000000..75203d523 --- /dev/null +++ b/integrations/java/app/revanced/integrations/patches/components/LayoutComponentsFilter.java @@ -0,0 +1,217 @@ +package app.revanced.integrations.patches.components; + + +import android.os.Build; +import android.view.View; +import androidx.annotation.RequiresApi; +import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.utils.ReVancedUtils; + + +public final class LayoutComponentsFilter extends Filter { + private final String[] exceptions; + + private final CustomFilterGroup custom; + + // region Mix playlists + private final ByteArrayAsStringFilterGroup mixPlaylists; + private final ByteArrayAsStringFilterGroup imageHosting; + + // endregion + + @RequiresApi(api = Build.VERSION_CODES.N) + public LayoutComponentsFilter() { + exceptions = new String[]{ + "home_video_with_context", + "related_video_with_context", + "comment_thread", // skip filtering anything in the comments + "|comment.", // skip filtering anything in the comments replies + "library_recent_shelf", + }; + + custom = new CustomFilterGroup( + SettingsEnum.CUSTOM_FILTER, + SettingsEnum.CUSTOM_FILTER_STRINGS + ); + + final var communityPosts = new StringFilterGroup( + SettingsEnum.HIDE_COMMUNITY_POSTS, + "post_base_wrapper" + ); + + final var communityGuidelines = new StringFilterGroup( + SettingsEnum.HIDE_COMMUNITY_GUIDELINES, + "community_guidelines" + ); + + final var subscribersCommunityGuidelines = new StringFilterGroup( + SettingsEnum.HIDE_SUBSCRIBERS_COMMUNITY_GUIDELINES, + "sponsorships_comments_upsell" + ); + + + final var channelMemberShelf = new StringFilterGroup( + SettingsEnum.HIDE_CHANNEL_MEMBER_SHELF, + "member_recognition_shelf" + ); + + final var compactBanner = new StringFilterGroup( + SettingsEnum.HIDE_COMPACT_BANNER, + "compact_banner" + ); + + final var inFeedSurvey = new StringFilterGroup( + SettingsEnum.HIDE_FEED_SURVEY, + "in_feed_survey", + "slimline_survey" + ); + + final var medicalPanel = new StringFilterGroup( + SettingsEnum.HIDE_MEDICAL_PANELS, + "medical_panel" + ); + + final var paidContent = new StringFilterGroup( + SettingsEnum.HIDE_PAID_CONTENT, + "paid_content_overlay" + ); + + final var infoPanel = new StringFilterGroup( + SettingsEnum.HIDE_HIDE_INFO_PANELS, + "publisher_transparency_panel", + "single_item_information_panel" + ); + + final var latestPosts = new StringFilterGroup( + SettingsEnum.HIDE_HIDE_LATEST_POSTS, + "post_shelf" + ); + + final var channelGuidelines = new StringFilterGroup( + SettingsEnum.HIDE_HIDE_CHANNEL_GUIDELINES, + "channel_guidelines_entry_banner" + ); + + final var audioTrackButton = new StringFilterGroup( + SettingsEnum.HIDE_AUDIO_TRACK_BUTTON, + "multi_feed_icon_button" + ); + + final var artistCard = new StringFilterGroup( + SettingsEnum.HIDE_ARTIST_CARDS, + "official_card" + ); + + final var chapterTeaser = new StringFilterGroup( + SettingsEnum.HIDE_CHAPTER_TEASER, + "expandable_metadata", + "macro_markers_carousel" + ); + + final var channelBar = new StringFilterGroup( + SettingsEnum.HIDE_CHANNEL_BAR, + "channel_bar" + ); + + final var relatedVideos = new StringFilterGroup( + SettingsEnum.HIDE_RELATED_VIDEOS, + "fullscreen_related_videos" + ); + + final var quickActions = new StringFilterGroup( + SettingsEnum.HIDE_QUICK_ACTIONS, + "quick_actions" + ); + + final var imageShelf = new StringFilterGroup( + SettingsEnum.HIDE_IMAGE_SHELF, + "image_shelf" + ); + + final var graySeparator = new StringFilterGroup( + SettingsEnum.HIDE_GRAY_SEPARATOR, + "cell_divider" // layout residue (gray line above the buttoned ad), + ); + + // region Mix playlists + + mixPlaylists = new ByteArrayAsStringFilterGroup( + SettingsEnum.HIDE_MIX_PLAYLISTS, + "&list=", + "YouTube Music" + ); + + imageHosting = new ByteArrayAsStringFilterGroup( + SettingsEnum.HIDE_MIX_PLAYLISTS, // Unused + "ggpht.com" + ); + + // endregion + + this.pathFilterGroups.addAll( + channelBar, + communityPosts, + paidContent, + latestPosts, + chapterTeaser, + communityGuidelines, + quickActions, + relatedVideos, + compactBanner, + inFeedSurvey, + medicalPanel, + infoPanel, + channelGuidelines, + audioTrackButton, + artistCard, + imageShelf, + subscribersCommunityGuidelines, + channelMemberShelf + ); + + final var carouselAd = new StringFilterGroup( + SettingsEnum.HIDE_GENERAL_ADS, + "carousel_ad" + ); + + this.identifierFilterGroups.addAll( + graySeparator, + carouselAd + ); + } + + private boolean isMixPlaylistFiltered(final byte[] _protobufBufferArray) { + if (!mixPlaylists.isEnabled()) return false; + + // Two checks are required to prevent false positives. + + // First check if the current buffer potentially contains a mix playlist. + if (!mixPlaylists.check(_protobufBufferArray).isFiltered()) return false; + + // Ensure that the buffer actually contains a mix playlist. + return imageHosting.check(_protobufBufferArray).isFiltered(); + } + + @Override + public boolean isFiltered(final String path, final String identifier, final byte[] _protobufBufferArray) { + if (custom.isEnabled() && custom.check(path).isFiltered()) + return true; + + if (ReVancedUtils.containsAny(path, exceptions)) + return false; // Exceptions are not filtered. + + if (super.isFiltered(path, identifier, _protobufBufferArray)) + return true; + + return isMixPlaylistFiltered(_protobufBufferArray); + } + + /** + * Hide the view, which shows ads in the homepage. + * + * @param view The view, which shows ads. + */ + public static void hideAdAttributionView(View view) { + ReVancedUtils.hideViewBy1dpUnderCondition(SettingsEnum.HIDE_GENERAL_ADS, view); + } +} diff --git a/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java b/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java index e1a0126d4..314dabcb9 100644 --- a/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java +++ b/integrations/java/app/revanced/integrations/patches/components/LithoFilterPatch.java @@ -238,7 +238,10 @@ public final class LithoFilterPatch { @SuppressWarnings("unused") public static boolean filter(final StringBuilder pathBuilder, final String identifier, final ByteBuffer protobufBuffer) { + // TODO: Maybe this can be moved to the Filter class, to prevent unnecessary string creation + // because some filters might not need the path. var path = pathBuilder.toString(); + // It is assumed that protobufBuffer is empty as well in this case. if (path.isEmpty()) return false; @@ -249,10 +252,16 @@ public final class LithoFilterPatch { var protobufBufferArray = protobufBuffer.array(); - // check if any filter-group - for (var filter : filters) - if (filter.isFiltered(path, identifier, protobufBufferArray)) return true; + for (var filter : filters) { + var filtered = filter.isFiltered(path, identifier, protobufBufferArray); + + LogHelper.printDebug(() -> + String.format("%s (ID: %s): %s", filtered ? "Filtered" : "Unfiltered", identifier, path) + ); + + if (filtered) return true; + } return false; } -} +} \ No newline at end of file