From 7e683906418434dd4e2104337d73a2292415c615 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Wed, 29 Jan 2025 09:40:59 +0200 Subject: [PATCH] fix(YouTube - Hide Ads): Hide end screen store banner without leaving empty space (#4367) --- .../youtube/patches/VideoAdsPatch.java | 9 ++- .../youtube/patches/components/AdsFilter.java | 57 ++++++++++--------- .../extension/youtube/settings/Settings.java | 2 +- .../youtube/ad/general/Fingerprints.kt | 25 ++++++++ .../youtube/ad/general/HideAdsPatch.kt | 27 ++++++++- 5 files changed, 88 insertions(+), 32 deletions(-) create mode 100644 patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VideoAdsPatch.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VideoAdsPatch.java index 9950de5e0b..ce07d8d16d 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VideoAdsPatch.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/VideoAdsPatch.java @@ -5,10 +5,13 @@ @SuppressWarnings("unused") public class VideoAdsPatch { - // Used by app.revanced.patches.youtube.ad.general.video.patch.VideoAdsPatch - // depends on Whitelist patch (still needs to be written) + private static final boolean SHOW_VIDEO_ADS = !Settings.HIDE_VIDEO_ADS.get(); + + /** + * Injection point. + */ public static boolean shouldShowAds() { - return !Settings.HIDE_VIDEO_ADS.get(); // TODO && Whitelist.shouldShowAds(); + return SHOW_VIDEO_ADS; } } diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java index 372fcebcab..12aa73c516 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/components/AdsFilter.java @@ -8,10 +8,12 @@ import androidx.annotation.Nullable; -import app.revanced.extension.youtube.settings.Settings; +import java.util.List; + import app.revanced.extension.shared.Logger; import app.revanced.extension.shared.Utils; import app.revanced.extension.youtube.StringTrieSearch; +import app.revanced.extension.youtube.settings.Settings; @SuppressWarnings("unused") public final class AdsFilter extends Filter { @@ -22,14 +24,16 @@ public final class AdsFilter extends Filter { // endregion + // https://encrypted-tbn0.gstatic.com/shopping?q=abc + private static final String STORE_BANNER_DOMAIN = "gstatic.com/shopping"; + private static final boolean HIDE_END_SCREEN_STORE_BANNER = + Settings.HIDE_END_SCREEN_STORE_BANNER.get(); + private final StringTrieSearch exceptions = new StringTrieSearch(); private final StringFilterGroup playerShoppingShelf; private final ByteArrayFilterGroup playerShoppingShelfBuffer; - private final StringFilterGroup fullscreenOverlay; - private final ByteArrayFilterGroup endScreenStoreBannerBuffer; - private final StringFilterGroup channelProfile; private final ByteArrayFilterGroup visitStoreButton; @@ -116,32 +120,22 @@ public AdsFilter() { ); playerShoppingShelf = new StringFilterGroup( - null, + Settings.HIDE_PLAYER_STORE_SHELF, "horizontal_shelf.eml" ); playerShoppingShelfBuffer = new ByteArrayFilterGroup( - Settings.HIDE_PLAYER_STORE_SHELF, - "shopping_item_card_list.eml" - ); - - fullscreenOverlay = new StringFilterGroup( - Settings.HIDE_END_SCREEN_STORE_BANNER, - "fullscreen_overlay.eml" - ); - - endScreenStoreBannerBuffer = new ByteArrayFilterGroup( null, - "gstatic.com/shopping" + "shopping_item_card_list.eml" ); channelProfile = new StringFilterGroup( - null, + Settings.HIDE_VISIT_STORE_BUTTON, "channel_profile.eml" ); visitStoreButton = new ByteArrayFilterGroup( - Settings.HIDE_VISIT_STORE_BUTTON, + null, "header_store_button" ); @@ -167,7 +161,6 @@ public AdsFilter() { viewProducts, selfSponsor, fullscreenAd, - fullscreenOverlay, channelProfile, webLinkPanel, shoppingLinks, @@ -186,10 +179,8 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff return false; } - if (matchedGroup == fullscreenOverlay) { - if (contentIndex == 0 && endScreenStoreBannerBuffer.check(protobufBufferArray).isFiltered()) { - return super.isFiltered(identifier, path, protobufBufferArray, matchedGroup, contentType, contentIndex); - } + // Check for the index because of likelihood of false positives. + if (matchedGroup == shoppingLinks && contentIndex != 0) { return false; } @@ -209,13 +200,25 @@ boolean isFiltered(@Nullable String identifier, String path, byte[] protobufBuff return false; } - // 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); } + /** + * Injection point. + * + * @param elementsList List of components of the end screen container. + * @param protobufList Component (ProtobufList). + */ + public static void hideEndScreenStoreBanner(List elementsList, Object protobufList) { + if (HIDE_END_SCREEN_STORE_BANNER && protobufList.toString().contains(STORE_BANNER_DOMAIN)) { + Logger.printDebug(() -> "Hiding store banner"); + return; + } + + elementsList.add(protobufList); + } + + /** * Hide the view, which shows ads in the homepage. * diff --git a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 35d4e49bc8..cea0c0a692 100644 --- a/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -64,7 +64,7 @@ public class Settings extends BaseSettings { // Ads public static final BooleanSetting HIDE_BUTTONED_ADS = new BooleanSetting("revanced_hide_buttoned_ads", TRUE); - public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", FALSE); + public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true); public static final BooleanSetting HIDE_FULLSCREEN_ADS = new BooleanSetting("revanced_hide_fullscreen_ads", TRUE); public static final BooleanSetting HIDE_GENERAL_ADS = new BooleanSetting("revanced_hide_general_ads", TRUE); public static final BooleanSetting HIDE_GET_PREMIUM = new BooleanSetting("revanced_hide_get_premium", TRUE); diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt new file mode 100644 index 0000000000..254b440f39 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/Fingerprints.kt @@ -0,0 +1,25 @@ +package app.revanced.patches.youtube.ad.general + +import app.revanced.patcher.fingerprint +import app.revanced.util.containsLiteralInstruction +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversed +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.iface.Method +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +internal val fullScreenEngagementAdContainerFingerprint = fingerprint { + accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) + returns("V") + parameters() + custom { method, _ -> + method.containsLiteralInstruction(fullScreenEngagementAdContainer) + && indexOfAddListInstruction(method) >= 0 + } +} + +internal fun indexOfAddListInstruction(method: Method) = + method.indexOfFirstInstructionReversed { + getReference()?.name == "add" + } + diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt index 3047d6fe42..098e840efc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ad/general/HideAdsPatch.kt @@ -1,5 +1,7 @@ package app.revanced.patches.youtube.ad.general +import app.revanced.patcher.extensions.InstructionExtensions.getInstruction +import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.patch.resourcePatch import app.revanced.patches.all.misc.resources.addResources @@ -18,11 +20,16 @@ import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.util.findMutableMethodOf import app.revanced.util.injectHideViewCall import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction31i import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c internal var adAttributionId = -1L private set +internal var fullScreenEngagementAdContainer = -1L + private set + +private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/components/AdsFilter;" private val hideAdsResourcePatch = resourcePatch { dependsOn( @@ -53,6 +60,7 @@ private val hideAdsResourcePatch = resourcePatch { addLithoFilter("Lapp/revanced/extension/youtube/patches/components/AdsFilter;") adAttributionId = resourceMappings["id", "ad_attribution"] + fullScreenEngagementAdContainer = resourceMappings["id", "fullscreen_engagement_ad_container"] } } @@ -83,6 +91,23 @@ val hideAdsPatch = bytecodePatch( ) execute { + // Hide end screen store banner + + fullScreenEngagementAdContainerFingerprint.method.apply { + val addListIndex = indexOfAddListInstruction(this) + val addListInstruction = getInstruction(addListIndex) + val listRegister = addListInstruction.registerC + val objectRegister = addListInstruction.registerD + + replaceInstruction( + addListIndex, + "invoke-static { v$listRegister, v$objectRegister }, $EXTENSION_CLASS_DESCRIPTOR" + + "->hideEndScreenStoreBanner(Ljava/util/List;Ljava/lang/Object;)V" + ) + } + + // Hide ad views + classes.forEach { classDef -> classDef.methods.forEach { method -> with(method.implementation) { @@ -111,7 +136,7 @@ val hideAdsPatch = bytecodePatch( .injectHideViewCall( insertIndex, viewRegister, - "Lapp/revanced/extension/youtube/patches/components/AdsFilter;", + EXTENSION_CLASS_DESCRIPTOR, "hideAdAttributionView", ) }