From 9238279018d452348bd7849722ae36636e7ee796 Mon Sep 17 00:00:00 2001 From: oSumAtrIX Date: Mon, 3 Oct 2022 13:39:26 +0200 Subject: [PATCH] refactor(youtube/general-ads): abstract integrations code --- .../patches/GeneralBytecodeAdsPatch.java | 156 ------------ .../patches/LithoFilterPatch.java | 227 ++++++++++++++++++ 2 files changed, 227 insertions(+), 156 deletions(-) delete mode 100644 integrations/java/app/revanced/integrations/patches/GeneralBytecodeAdsPatch.java create mode 100644 integrations/java/app/revanced/integrations/patches/LithoFilterPatch.java diff --git a/integrations/java/app/revanced/integrations/patches/GeneralBytecodeAdsPatch.java b/integrations/java/app/revanced/integrations/patches/GeneralBytecodeAdsPatch.java deleted file mode 100644 index 115616501..000000000 --- a/integrations/java/app/revanced/integrations/patches/GeneralBytecodeAdsPatch.java +++ /dev/null @@ -1,156 +0,0 @@ -package app.revanced.integrations.patches; - -import android.util.Log; - -import java.nio.ByteBuffer; -import java.util.ArrayList; - -import app.revanced.integrations.settings.SettingsEnum; -import app.revanced.integrations.utils.LogHelper; - -/** - * Helper functions. - */ -final class Extensions { - static boolean containsAny(final String value, final String... targets) { - for (String string : targets) - if (value.contains(string)) return true; - return false; - } -} - -final class ComponentRule { - private final SettingsEnum setting; - private final String[] blocks; - - /** - * Initialize a new rule for components. - * - * @param setting The setting which controls the blocking of this component. - * @param blocks The rules to block the component on. - */ - public ComponentRule(final SettingsEnum setting, final String... blocks) { - this.setting = setting; - this.blocks = blocks; - } - - public boolean isEnabled() { - return setting.getBoolean(); - } - - public boolean isBlocked(final String string) { - return Extensions.containsAny(string, blocks); - } -} - -final class LithoBlockRegister { - private final ArrayList blocks = new ArrayList<>(); - - public void addBlock(final ComponentRule block) { - blocks.add(block); - } - - public boolean isBlocked(final String value) { - for (ComponentRule block : blocks) - if (block.isEnabled() && block.isBlocked(value)) return true; - return false; - } -} - -public class GeneralBytecodeAdsPatch { - private final static LithoBlockRegister pathBlockRegister = new LithoBlockRegister(); - private final static ComponentRule identifierBlock; - - static { - var comments = new ComponentRule(SettingsEnum.ADREMOVER_COMMENTS_REMOVAL, "comments_"); - var communityPosts = new ComponentRule(SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL, "post_base_wrapper"); - var communityGuidelines = new ComponentRule(SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES_REMOVAL, "community_guidelines"); - var compactBanner = new ComponentRule(SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL, "compact_banner"); - var inFeedSurvey = new ComponentRule(SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL, "in_feed_survey"); - var medicalPanel = new ComponentRule(SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL, "medical_panel"); - var paidContent = new ComponentRule(SettingsEnum.ADREMOVER_PAID_CONTECT_REMOVAL, "paid_content_overlay"); - var merchandise = new ComponentRule(SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL, "product_carousel"); - var shorts = new ComponentRule(SettingsEnum.ADREMOVER_SHORTS_SHELF_REMOVAL, "shorts_shelf"); - var infoPanel = new ComponentRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel"); - var suggestions = new ComponentRule(SettingsEnum.ADREMOVER_SUGGESTIONS_REMOVAL, "horizontal_video_shelf"); - var latestPosts = new ComponentRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf"); - var channelGuidelines = new ComponentRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner"); - var generalAds = new ComponentRule( - SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, - // could be required - //"full_width_square_image_layout", - "video_display_full_buttoned_layout", - "_ad", - "ad_", - "ads_video_with_context", - "cell_divider", - "reels_player_overlay", - "shelf_header", - "watch_metadata_app_promo", - "video_display_full_layout" - ); - var movieAds = new ComponentRule( - SettingsEnum.ADREMOVER_MOVIE_REMOVAL, - "browsy_bar", - "compact_movie", - "horizontal_movie_shelf", - "movie_and_show_upsell_card" - ); - - // collect and add the blocks - var blocks = new ComponentRule[]{ - generalAds, - communityPosts, - paidContent, - shorts, - suggestions, - latestPosts, - movieAds, - comments, - communityGuidelines, - compactBanner, - inFeedSurvey, - medicalPanel, - merchandise, - infoPanel, - channelGuidelines - }; - for (var block : blocks) pathBlockRegister.addBlock(block); - - // Block for the ComponentContext.identifier field - identifierBlock = new ComponentRule(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, "carousel_ad"); - } - - //Used by app.revanced.patches.youtube.ad.general.bytecode.patch.GeneralBytecodeAdsPatch - public static boolean isAdComponent(StringBuilder pathBuilder, String identifier) { - var path = pathBuilder.toString(); - if (path.isEmpty()) return false; - - LogHelper.debug(GeneralBytecodeAdsPatch.class, String.format("Searching (ID: %s): %s", identifier, path)); - // Do not block on these - if (Extensions.containsAny(path, - "home_video_with_context", - "related_video_with_context", - "search_video_with_context", - "download_button", - "library_recent_shelf", - "menu", - "root", - "-count", - "-space", - "-button" - )) return false; - - if (pathBlockRegister.isBlocked(path)) { - LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocked: " + path); - return true; - } - - if (identifier != null && identifierBlock.isBlocked(identifier)){ - LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocked: " + identifier); - return true; - } - - return false; - } -} diff --git a/integrations/java/app/revanced/integrations/patches/LithoFilterPatch.java b/integrations/java/app/revanced/integrations/patches/LithoFilterPatch.java new file mode 100644 index 000000000..508b36e06 --- /dev/null +++ b/integrations/java/app/revanced/integrations/patches/LithoFilterPatch.java @@ -0,0 +1,227 @@ +package app.revanced.integrations.patches; + +import android.os.Build; + +import androidx.annotation.NonNull; +import androidx.annotation.RequiresApi; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.Spliterator; +import java.util.function.Consumer; + +import app.revanced.integrations.settings.SettingsEnum; +import app.revanced.integrations.utils.LogHelper; + +/** + * Helper functions. + */ +final class Extensions { + static boolean containsAny(final String value, final String... targets) { + for (String string : targets) + if (value.contains(string)) return true; + return false; + } + + static boolean any(LithoBlockRegister register, String path) { + for (var rule : register) { + if (!rule.isEnabled()) continue; + + var result = rule.check(path); + if (result.isBlocked()) { + return true; + } + } + + return false; + } +} + +final class BlockRule { + final static class BlockResult { + private final boolean blocked; + private final SettingsEnum setting; + + public BlockResult(final SettingsEnum setting, final boolean blocked) { + this.setting = setting; + this.blocked = blocked; + } + + public SettingsEnum getSetting() { + return setting; + } + + public boolean isBlocked() { + return blocked; + } + } + + private final SettingsEnum setting; + private final String[] blocks; + + /** + * Initialize a new rule for components. + * + * @param setting The setting which controls the blocking of this component. + * @param blocks The rules to block the component on. + */ + public BlockRule(final SettingsEnum setting, final String... blocks) { + this.setting = setting; + this.blocks = blocks; + } + + public boolean isEnabled() { + return setting.getBoolean(); + } + + public BlockResult check(final String string) { + return new BlockResult(setting, string != null && Extensions.containsAny(string, blocks)); + } +} + +abstract class Filter { + final LithoBlockRegister register = new LithoBlockRegister(); + + abstract boolean filter(final String path, final String identifier); +} + +final class LithoBlockRegister implements Iterable { + private final ArrayList blocks = new ArrayList<>(); + + public void registerAll(BlockRule... blocks) { + this.blocks.addAll(Arrays.asList(blocks)); + } + + @NonNull + @Override + public Iterator iterator() { + return blocks.iterator(); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @Override + public void forEach(@NonNull Consumer action) { + blocks.forEach(action); + } + + @RequiresApi(api = Build.VERSION_CODES.N) + @NonNull + @Override + public Spliterator spliterator() { + return blocks.spliterator(); + } +} + +public final class LithoFilterPatch { + private static final Filter[] filters = new Filter[]{ + new GeneralBytecodeAdsPatch() + }; + + public static boolean filter(final StringBuilder pathBuilder, final String identifier) { + var path = pathBuilder.toString(); + if (path.isEmpty()) return false; + + LogHelper.debug(LithoFilterPatch.class, String.format("Searching (ID: %s): %s", identifier, path)); + + for (var filter : filters) { + if (filter.filter(path, identifier)) return true; + } + + return false; + } +} + +class GeneralBytecodeAdsPatch extends Filter { + private final BlockRule identifierBlock; + + public GeneralBytecodeAdsPatch() { + var comments = new BlockRule(SettingsEnum.ADREMOVER_COMMENTS_REMOVAL, "comments_"); + var communityPosts = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_POSTS_REMOVAL, "post_base_wrapper"); + var communityGuidelines = new BlockRule(SettingsEnum.ADREMOVER_COMMUNITY_GUIDELINES_REMOVAL, "community_guidelines"); + var compactBanner = new BlockRule(SettingsEnum.ADREMOVER_COMPACT_BANNER_REMOVAL, "compact_banner"); + var inFeedSurvey = new BlockRule(SettingsEnum.ADREMOVER_FEED_SURVEY_REMOVAL, "in_feed_survey"); + var medicalPanel = new BlockRule(SettingsEnum.ADREMOVER_MEDICAL_PANEL_REMOVAL, "medical_panel"); + var paidContent = new BlockRule(SettingsEnum.ADREMOVER_PAID_CONTECT_REMOVAL, "paid_content_overlay"); + var merchandise = new BlockRule(SettingsEnum.ADREMOVER_MERCHANDISE_REMOVAL, "product_carousel"); + var shorts = new BlockRule(SettingsEnum.ADREMOVER_SHORTS_SHELF_REMOVAL, "shorts_shelf"); + var infoPanel = new BlockRule(SettingsEnum.ADREMOVER_INFO_PANEL_REMOVAL, "publisher_transparency_panel", "single_item_information_panel"); + var suggestions = new BlockRule(SettingsEnum.ADREMOVER_SUGGESTIONS_REMOVAL, "horizontal_video_shelf"); + var latestPosts = new BlockRule(SettingsEnum.ADREMOVER_HIDE_LATEST_POSTS, "post_shelf"); + var channelGuidelines = new BlockRule(SettingsEnum.ADREMOVER_HIDE_CHANNEL_GUIDELINES, "channel_guidelines_entry_banner"); + var generalAds = new BlockRule( + SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, + // could be required + //"full_width_square_image_layout", + "video_display_full_buttoned_layout", + "_ad", + "ad_", + "ads_video_with_context", + "cell_divider", + "reels_player_overlay", + "shelf_header", + "watch_metadata_app_promo", + "video_display_full_layout" + ); + var movieAds = new BlockRule( + SettingsEnum.ADREMOVER_MOVIE_REMOVAL, + "browsy_bar", + "compact_movie", + "horizontal_movie_shelf", + "movie_and_show_upsell_card" + ); + + this.register.registerAll( + generalAds, + communityPosts, + paidContent, + shorts, + suggestions, + latestPosts, + movieAds, + comments, + communityGuidelines, + compactBanner, + inFeedSurvey, + medicalPanel, + merchandise, + infoPanel, + channelGuidelines + ); + + // Block for the ComponentContext.identifier field + identifierBlock = new BlockRule(SettingsEnum.ADREMOVER_GENERAL_ADS_REMOVAL, "carousel_ad"); + } + + public boolean filter(final String path, final String identifier) { + // Do not block on these + if (Extensions.containsAny(path, + "home_video_with_context", + "related_video_with_context", + "search_video_with_context", + "download_button", + "library_recent_shelf", + "menu", + "root", + "-count", + "-space", + "-button" + )) return false; + + for (var rule : register) { + if (!rule.isEnabled()) continue; + + var result = rule.check(path); + if (result.isBlocked()) { + LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocked: " + path); + return true; + } + } + + if (identifierBlock.check(identifier).isBlocked()) { + LogHelper.debug(GeneralBytecodeAdsPatch.class, "Blocked: " + identifier); + return true; + } + return false; + } +}