From 37e5a48665a12ca2768a45ede0ed5cbacbfb9899 Mon Sep 17 00:00:00 2001 From: inotia00 <108592928+inotia00@users.noreply.github.com> Date: Mon, 10 Feb 2025 17:16:40 +0900 Subject: [PATCH] feat(YouTube - Description components): Remove `Title in video description panel` setting (No more necessary) --- .../patches/feed/RelatedVideoPatch.java | 18 +-- .../youtube/patches/player/PlayerPatch.java | 62 +++------- .../extension/youtube/settings/Settings.java | 3 +- .../youtube/shared/EngagementPanel.java | 46 ++++++++ .../feed/components/FeedComponentsPatch.kt | 3 - .../youtube/player/components/Fingerprints.kt | 26 ----- .../components/PlayerComponentsPatch.kt | 71 ++++-------- .../DescriptionComponentsPatch.kt | 15 +-- .../player/descriptions/Fingerprints.kt | 20 ---- .../engagement/EngagementPanelHookPatch.kt | 107 +++++++++++------- .../youtube/utils/engagement/Fingerprints .kt | 22 ---- .../youtube/utils/engagement/Fingerprints.kt | 46 ++++++++ .../utils/resourceid/SharedResourceIdPatch.kt | 12 -- .../youtube/settings/host/values/strings.xml | 4 - .../youtube/settings/xml/revanced_prefs.xml | 1 - 15 files changed, 200 insertions(+), 256 deletions(-) create mode 100644 extensions/shared/src/main/java/app/revanced/extension/youtube/shared/EngagementPanel.java delete mode 100644 patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints .kt create mode 100644 patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints.kt diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/feed/RelatedVideoPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/feed/RelatedVideoPatch.java index ccc20a631..cc1c9d59a 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/feed/RelatedVideoPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/feed/RelatedVideoPatch.java @@ -1,32 +1,18 @@ package app.revanced.extension.youtube.patches.feed; -import androidx.annotation.Nullable; - -import java.util.concurrent.atomic.AtomicBoolean; - import app.revanced.extension.youtube.settings.Settings; import app.revanced.extension.youtube.shared.BottomSheetState; +import app.revanced.extension.youtube.shared.EngagementPanel; import app.revanced.extension.youtube.shared.RootView; @SuppressWarnings("unused") public final class RelatedVideoPatch { private static final boolean HIDE_RELATED_VIDEOS = Settings.HIDE_RELATED_VIDEOS.get(); - private static final int OFFSET = Settings.RELATED_VIDEOS_OFFSET.get(); // video title,channel bar, video action bar, comment private static final int MAX_ITEM_COUNT = 4 + OFFSET; - private static final AtomicBoolean engagementPanelOpen = new AtomicBoolean(false); - - public static void showEngagementPanel(@Nullable Object object) { - engagementPanelOpen.set(object != null); - } - - public static void hideEngagementPanel() { - engagementPanelOpen.compareAndSet(true, false); - } - public static int overrideItemCounts(int itemCounts) { if (!HIDE_RELATED_VIDEOS) { return itemCounts; @@ -40,7 +26,7 @@ public final class RelatedVideoPatch { if (BottomSheetState.getCurrent().isOpen()) { return itemCounts; } - if (engagementPanelOpen.get()) { + if (EngagementPanel.isOpen()) { return itemCounts; } return MAX_ITEM_COUNT; diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java index 3e0f0747c..f87708b9a 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/patches/player/PlayerPatch.java @@ -19,6 +19,7 @@ import androidx.annotation.Nullable; import androidx.coordinatorlayout.widget.CoordinatorLayout; import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; import app.revanced.extension.shared.settings.BaseSettings; import app.revanced.extension.shared.settings.BooleanSetting; @@ -30,6 +31,7 @@ import app.revanced.extension.shared.utils.Utils; import app.revanced.extension.youtube.patches.utils.InitializationPatch; import app.revanced.extension.youtube.patches.utils.PatchStatus; import app.revanced.extension.youtube.settings.Settings; +import app.revanced.extension.youtube.shared.EngagementPanel; import app.revanced.extension.youtube.shared.PlayerType; import app.revanced.extension.youtube.shared.RootView; import app.revanced.extension.youtube.shared.ShortsPlayerState; @@ -118,37 +120,6 @@ public class PlayerPatch { */ private static final int contentId = ResourceUtils.getIdIdentifier("content"); private static final boolean EXPAND_VIDEO_DESCRIPTION = Settings.EXPAND_VIDEO_DESCRIPTION.get(); - private static final StringSetting EXPAND_VIDEO_DESCRIPTION_STRINGS = Settings.EXPAND_VIDEO_DESCRIPTION_STRINGS; - private static final String EXPAND_VIDEO_DESCRIPTION_STRINGS_DEFAULT_VALUE = "revanced_expand_video_description_strings_default_value"; - - static { - final String descriptionString = EXPAND_VIDEO_DESCRIPTION_STRINGS.get(); - if (descriptionString.equals(EXPAND_VIDEO_DESCRIPTION_STRINGS_DEFAULT_VALUE) && - Utils.getContext() != null) { - String defaultValue = ResourceUtils.getString(EXPAND_VIDEO_DESCRIPTION_STRINGS_DEFAULT_VALUE); - if (!descriptionString.equals(defaultValue)) { - EXPAND_VIDEO_DESCRIPTION_STRINGS.save(defaultValue); - } - } - } - - private static boolean isDescriptionPanel = false; - - public static void setContentDescription(String contentDescription) { - if (!EXPAND_VIDEO_DESCRIPTION) { - return; - } - if (contentDescription == null || contentDescription.isEmpty()) { - isDescriptionPanel = false; - return; - } - final String descriptionString = EXPAND_VIDEO_DESCRIPTION_STRINGS.get(); - if (descriptionString.isEmpty()) { - isDescriptionPanel = false; - return; - } - isDescriptionPanel = descriptionString.equals(contentDescription); - } /** * The last time the clickDescriptionView method was called. @@ -172,9 +143,8 @@ public class PlayerPatch { if (contentView.getId() != contentId) { return; } - // This method is invoked whenever the Engagement panel is opened. (Description, Chapters, Comments, etc.) - // Check the title of the Engagement panel to prevent unnecessary clicking. - if (!isDescriptionPanel) { + // Check description panel opened. + if (!EngagementPanel.isDescription()) { return; } // The first view group contains information such as the video's title, like count, and number of views. @@ -456,20 +426,22 @@ public class PlayerPatch { imageView.setImageAlpha(PLAYER_OVERLAY_OPACITY_LEVEL); } - private static boolean isAutoPopupPanel; + @NonNull + private static final AtomicBoolean newVideoStarted = new AtomicBoolean(false); - public static boolean disableAutoPlayerPopupPanels(boolean isLiveChatOrPlaylistPanel) { - if (!Settings.DISABLE_AUTO_PLAYER_POPUP_PANELS.get()) { - return false; + public static boolean disableAutoPlayerPopupPanels(boolean isLiveChatOrPlaylistPanel, String panelId) { + if (Settings.DISABLE_AUTO_PLAYER_POPUP_PANELS.get()) { + return isLiveChatOrPlaylistPanel || (panelId.equals("PAproduct_list") && newVideoStarted.get()); } - if (isLiveChatOrPlaylistPanel) { - return true; - } - return isAutoPopupPanel && ShortsPlayerState.getCurrent().isClosed(); + return false; } - public static void setInitVideoPanel(boolean initVideoPanel) { - isAutoPopupPanel = initVideoPanel; + public static void disableAutoPlayerPopupPanels(@NonNull String newlyLoadedChannelId, @NonNull String newlyLoadedChannelName, + @NonNull String newlyLoadedVideoId, @NonNull String newlyLoadedVideoTitle, + final long newlyLoadedVideoLength, boolean newlyLoadedLiveStreamValue) { + if (Settings.DISABLE_AUTO_PLAYER_POPUP_PANELS.get() && newVideoStarted.compareAndSet(false, true)) { + Utils.runOnMainThreadDelayed(() -> newVideoStarted.compareAndSet(true, false), 1500L); + } } @NonNull @@ -493,7 +465,7 @@ public class PlayerPatch { return; } VideoUtils.pauseMedia(); - VideoUtils.openVideo(videoId); + VideoUtils.openVideo(newlyLoadedVideoId); } public static boolean disableSpeedOverlay() { diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java index 7c99324c0..6a254f03b 100644 --- a/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/settings/Settings.java @@ -345,7 +345,7 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_PLAYER_FLYOUT_MENU_YT_MUSIC = new BooleanSetting("revanced_hide_player_flyout_menu_listen_with_youtube_music", TRUE); // PreferenceScreen: Player - Fullscreen - public static final BooleanSetting DISABLE_ENGAGEMENT_PANEL = new BooleanSetting("revanced_disable_engagement_panel", FALSE, true); + public static final BooleanSetting DISABLE_ENGAGEMENT_PANEL = new BooleanSetting("revanced_disable_engagement_panel", FALSE); public static final BooleanSetting ENTER_FULLSCREEN = new BooleanSetting("revanced_enter_fullscreen", FALSE); public static final EnumSetting EXIT_FULLSCREEN = new EnumSetting<>("revanced_exit_fullscreen", FullscreenMode.DISABLED); public static final BooleanSetting SHOW_VIDEO_TITLE_SECTION = new BooleanSetting("revanced_show_video_title_section", TRUE, true, parent(DISABLE_ENGAGEMENT_PANEL)); @@ -428,7 +428,6 @@ public class Settings extends BaseSettings { public static final BooleanSetting HIDE_TRANSCRIPT_SECTION = new BooleanSetting("revanced_hide_transcript_section", FALSE); public static final BooleanSetting DISABLE_VIDEO_DESCRIPTION_INTERACTION = new BooleanSetting("revanced_disable_video_description_interaction", FALSE, true); public static final BooleanSetting EXPAND_VIDEO_DESCRIPTION = new BooleanSetting("revanced_expand_video_description", FALSE, true); - public static final StringSetting EXPAND_VIDEO_DESCRIPTION_STRINGS = new StringSetting("revanced_expand_video_description_strings", str("revanced_expand_video_description_strings_default_value"), true, parent(EXPAND_VIDEO_DESCRIPTION)); // PreferenceScreen: Shorts diff --git a/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/EngagementPanel.java b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/EngagementPanel.java new file mode 100644 index 000000000..11c4b3c8b --- /dev/null +++ b/extensions/shared/src/main/java/app/revanced/extension/youtube/shared/EngagementPanel.java @@ -0,0 +1,46 @@ +package app.revanced.extension.youtube.shared; + +import androidx.annotation.Nullable; + +import java.util.concurrent.atomic.AtomicReference; + +import app.revanced.extension.shared.utils.Logger; + +@SuppressWarnings("unused") +public final class EngagementPanel { + private static final AtomicReference engagementPanelId = new AtomicReference<>(""); + + /** + * Injection point. + */ + public static void setId(@Nullable String panelId) { + if (panelId != null) { + Logger.printDebug(() -> "engagementPanel open\npanelId: " + panelId); + engagementPanelId.set(panelId); + } + } + + /** + * Injection point. + */ + public static void hide() { + String panelId = getId(); + if (!panelId.isEmpty()) { + Logger.printDebug(() -> "engagementPanel closed\npanelId: " + panelId); + engagementPanelId.set(""); + } + } + + public static boolean isOpen() { + return !getId().isEmpty(); + } + + public static boolean isDescription() { + return getId().equals("video-description-ep-identifier"); + } + + public static String getId() { + return engagementPanelId.get(); + } + +} diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/feed/components/FeedComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/feed/components/FeedComponentsPatch.kt index d4054ad43..ff76bc9f7 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/feed/components/FeedComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/feed/components/FeedComponentsPatch.kt @@ -14,7 +14,6 @@ import app.revanced.patches.shared.mainactivity.onCreateMethod import app.revanced.patches.youtube.utils.bottomsheet.bottomSheetHookPatch import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch -import app.revanced.patches.youtube.utils.engagement.hookEngagementPanelState import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.extension.Constants.FEED_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.FEED_PATH @@ -190,8 +189,6 @@ val feedComponentsPatch = bytecodePatch( } } - hookEngagementPanelState(RELATED_VIDEO_CLASS_DESCRIPTOR) - // endregion // region patch for hide subscriptions channel section for tablet diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt index a36f776ab..b489f3dd6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt @@ -2,14 +2,12 @@ package app.revanced.patches.youtube.player.components -import app.revanced.patches.youtube.utils.resourceid.componentLongClickListener import app.revanced.patches.youtube.utils.resourceid.darkBackground import app.revanced.patches.youtube.utils.resourceid.donationCompanion import app.revanced.patches.youtube.utils.resourceid.easySeekEduContainer import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutCircle import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutVideo -import app.revanced.patches.youtube.utils.resourceid.offlineActionsVideoDeletedUndoSnackbarText import app.revanced.patches.youtube.utils.resourceid.scrubbing import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing import app.revanced.patches.youtube.utils.resourceid.suggestedAction @@ -209,30 +207,6 @@ internal val layoutVideoFingerprint = legacyFingerprint( literals = listOf(endScreenElementLayoutVideo), ) -internal val lithoComponentOnClickListenerFingerprint = legacyFingerprint( - name = "lithoComponentOnClickListenerFingerprint", - returnType = "V", - accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC, - parameters = listOf("L"), - literals = listOf(componentLongClickListener), -) - -internal val engagementPanelPlaylistSyntheticFingerprint = legacyFingerprint( - name = "engagementPanelPlaylistSyntheticFingerprint", - strings = listOf("engagement-panel-playlist"), - customFingerprint = { _, classDef -> - classDef.interfaces.contains("Landroid/view/View${'$'}OnClickListener;") - } -) - -internal val offlineActionsOnClickListenerFingerprint = legacyFingerprint( - name = "offlineActionsOnClickListenerFingerprint", - returnType = "V", - accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("Ljava/lang/String;"), - literals = listOf(offlineActionsVideoDeletedUndoSnackbarText), -) - internal val quickSeekOverlayFingerprint = legacyFingerprint( name = "quickSeekOverlayFingerprint", returnType = "V", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt index 9c2796c68..326b1e5c6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt @@ -13,10 +13,13 @@ import app.revanced.patches.shared.litho.addLithoFilter import app.revanced.patches.shared.litho.lithoFilterPatch import app.revanced.patches.shared.spans.addSpanFilter import app.revanced.patches.shared.spans.inclusiveSpanPatch -import app.revanced.patches.shared.startVideoInformerFingerprint import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.controlsoverlay.controlsOverlayConfigPatch -import app.revanced.patches.youtube.utils.engagementPanelBuilderFingerprint +import app.revanced.patches.youtube.utils.engagement.engagementPanelBuilderMethod +import app.revanced.patches.youtube.utils.engagement.engagementPanelFreeRegister +import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch +import app.revanced.patches.youtube.utils.engagement.engagementPanelIdIndex +import app.revanced.patches.youtube.utils.engagement.engagementPanelIdRegister import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.SPANS_PATH @@ -39,7 +42,6 @@ import app.revanced.patches.youtube.utils.youtubeControlsOverlayFingerprint import app.revanced.patches.youtube.video.information.hookVideoInformation import app.revanced.patches.youtube.video.information.videoInformationPatch import app.revanced.util.REGISTER_TEMPLATE_REPLACEMENT -import app.revanced.util.Utils.printWarn import app.revanced.util.findMethodOrThrow import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.injectLiteralInstructionViewCall @@ -49,7 +51,6 @@ import app.revanced.util.fingerprint.mutableClassOrThrow import app.revanced.util.fingerprint.resolvable import app.revanced.util.getReference import app.revanced.util.getWalkerMethod -import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstLiteralInstructionOrThrow @@ -286,6 +287,7 @@ val playerComponentsPatch = bytecodePatch( suggestedVideoEndScreenPatch, videoInformationPatch, versionCheckPatch, + engagementPanelHookPatch, ) execute { @@ -373,54 +375,19 @@ val playerComponentsPatch = bytecodePatch( // region patch for disable auto player popup panels - fun MutableMethod.hookInitVideoPanel(initVideoPanel: Int) = - addInstructions( - 0, """ - const/4 v0, $initVideoPanel - invoke-static {v0}, $PLAYER_CLASS_DESCRIPTOR->setInitVideoPanel(Z)V - """ - ) - - arrayOf( - lithoComponentOnClickListenerFingerprint, - offlineActionsOnClickListenerFingerprint, - ).forEach { fingerprint -> - fingerprint.methodOrThrow().apply { - val syntheticIndex = - indexOfFirstInstruction(Opcode.NEW_INSTANCE) - if (syntheticIndex >= 0) { - val syntheticReference = - getInstruction(syntheticIndex).reference.toString() - - findMethodOrThrow(syntheticReference) { - name == "onClick" - }.hookInitVideoPanel(0) - } else { - printWarn("target Opcode not found in ${fingerprint.first}") - } - } - } - - findMethodOrThrow( - engagementPanelPlaylistSyntheticFingerprint.methodOrThrow().definingClass - ) { - name == "onClick" - }.hookInitVideoPanel(0) - - startVideoInformerFingerprint.methodOrThrow().hookInitVideoPanel(1) - - engagementPanelBuilderFingerprint.methodOrThrow().apply { - addInstructionsWithLabels( - 0, """ - move/from16 v0, p4 - invoke-static {v0}, $PLAYER_CLASS_DESCRIPTOR->disableAutoPlayerPopupPanels(Z)Z - move-result v0 - if-eqz v0, :shown - const/4 v0, 0x0 - return-object v0 - """, ExternalLabel("shown", getInstruction(0)) - ) - } + engagementPanelBuilderMethod.addInstructionsWithLabels( + engagementPanelIdIndex, """ + move/from16 v$engagementPanelFreeRegister, p4 + invoke-static {v$engagementPanelFreeRegister, v$engagementPanelIdRegister}, $PLAYER_CLASS_DESCRIPTOR->disableAutoPlayerPopupPanels(ZLjava/lang/String;)Z + move-result v$engagementPanelFreeRegister + if-eqz v$engagementPanelFreeRegister, :shown + const/4 v$engagementPanelFreeRegister, 0x0 + return-object v$engagementPanelFreeRegister + :shown + nop + """ + ) + hookVideoInformation("$PLAYER_CLASS_DESCRIPTOR->disableAutoPlayerPopupPanels(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;JZ)V") // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt index 7cfda01cf..12be08c50 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/DescriptionComponentsPatch.kt @@ -9,6 +9,7 @@ import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patches.shared.litho.addLithoFilter import app.revanced.patches.shared.litho.lithoFilterPatch import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE +import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.patch.PatchList.DESCRIPTION_COMPONENTS @@ -46,6 +47,7 @@ val descriptionComponentsPatch = bytecodePatch( lithoFilterPatch, playerTypeHookPatch, recyclerViewTreeObserverPatch, + engagementPanelHookPatch, sharedResourceIdPatch, versionCheckPatch, ) @@ -104,19 +106,6 @@ val descriptionComponentsPatch = bytecodePatch( ) } - engagementPanelTitleFingerprint.methodOrThrow(engagementPanelTitleParentFingerprint) - .apply { - val contentDescriptionIndex = indexOfContentDescriptionInstruction(this) - val contentDescriptionRegister = - getInstruction(contentDescriptionIndex).registerD - - addInstruction( - contentDescriptionIndex, - "invoke-static {v$contentDescriptionRegister}," + - "$PLAYER_CLASS_DESCRIPTOR->setContentDescription(Ljava/lang/String;)V" - ) - } - recyclerViewTreeObserverHook("$PLAYER_CLASS_DESCRIPTOR->onVideoDescriptionCreate(Landroid/support/v7/widget/RecyclerView;)V") settingArray += "SETTINGS: DESCRIPTION_INTERACTION" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/Fingerprints.kt index 135a3a021..0fccda3a4 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/descriptions/Fingerprints.kt @@ -3,30 +3,10 @@ package app.revanced.patches.youtube.player.descriptions import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.indexOfFirstInstructionReversed import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method import com.android.tools.smali.dexlib2.iface.reference.MethodReference -internal val engagementPanelTitleFingerprint = legacyFingerprint( - name = "engagementPanelTitleFingerprint", - strings = listOf(". "), - customFingerprint = { method, _ -> - indexOfContentDescriptionInstruction(method) >= 0 - } -) - -internal val engagementPanelTitleParentFingerprint = legacyFingerprint( - name = "engagementPanelTitleParentFingerprint", - strings = listOf("[EngagementPanelTitleHeader] Cannot remove action buttons from header as the child count is out of sync. Buttons to remove exceed current header child count.") -) - -internal fun indexOfContentDescriptionInstruction(method: Method) = - method.indexOfFirstInstructionReversed { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "setContentDescription" - } - /** * This fingerprint is compatible with YouTube v18.35.xx~ * Nonetheless, the patch works in YouTube v19.02.xx~ diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/EngagementPanelHookPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/EngagementPanelHookPatch.kt index dd1bc5793..6af2931bc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/EngagementPanelHookPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/EngagementPanelHookPatch.kt @@ -1,24 +1,30 @@ package app.revanced.patches.youtube.utils.engagement import app.revanced.patcher.extensions.InstructionExtensions.addInstruction +import app.revanced.patcher.extensions.InstructionExtensions.addInstructions import app.revanced.patcher.extensions.InstructionExtensions.getInstruction import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod -import app.revanced.patches.youtube.utils.engagementPanelBuilderFingerprint +import app.revanced.patches.youtube.utils.extension.Constants.SHARED_PATH import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch -import app.revanced.util.fingerprint.matchOrThrow +import app.revanced.util.findMethodOrThrow import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionReversed +import app.revanced.util.indexOfFirstInstruction +import app.revanced.util.indexOfFirstInstructionOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.Method -import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction -import com.android.tools.smali.dexlib2.iface.reference.MethodReference -import com.android.tools.smali.dexlib2.util.MethodUtil +import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction +import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction +import com.android.tools.smali.dexlib2.iface.reference.FieldReference -private lateinit var engagementPanelBuilderMethod: MutableMethod -private lateinit var hideEngagementPanelMethod: MutableMethod -private var showEngagementPanelMethods = mutableListOf() +private const val EXTENSION_CLASS_DESCRIPTOR = + "$SHARED_PATH/EngagementPanel;" + +internal lateinit var engagementPanelBuilderMethod: MutableMethod +internal var engagementPanelFreeRegister = 0 +internal var engagementPanelIdIndex = 0 +internal var engagementPanelIdRegister = 0 val engagementPanelHookPatch = bytecodePatch( description = "engagementPanelHookPatch" @@ -26,45 +32,66 @@ val engagementPanelHookPatch = bytecodePatch( dependsOn(sharedResourceIdPatch) execute { - engagementPanelBuilderFingerprint.matchOrThrow().let { - engagementPanelBuilderMethod = it.method + fun Method.setFreeIndex(startIndex: Int) { + val startRegister = engagementPanelIdRegister + var index = startIndex + var register = startRegister - it.classDef.methods.filter { method -> - method.indexOfEngagementPanelBuilderInstruction() >= 0 - }.forEach { method -> - showEngagementPanelMethods.add(method) + while (register == startRegister) { + index = indexOfFirstInstruction(index + 1, Opcode.IGET_OBJECT) + register = getInstruction(index).registerA } + + engagementPanelFreeRegister = register } - hideEngagementPanelMethod = - engagementPanelUpdateFingerprint.methodOrThrow(engagementPanelBuilderFingerprint) - } -} + val engagementPanelInfoClass = engagementPanelLayoutFingerprint + .methodOrThrow() + .parameters[0] + .toString() -private fun Method.indexOfEngagementPanelBuilderInstruction() = - indexOfFirstInstructionReversed { - opcode == Opcode.INVOKE_DIRECT && - MethodUtil.methodSignaturesMatch( - engagementPanelBuilderMethod, - getReference()!! + val (engagementPanelIdReference, engagementPanelObjectReference) = + with(findMethodOrThrow(engagementPanelInfoClass)) { + val engagementPanelIdIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.IPUT_OBJECT && + getReference()?.type == "Ljava/lang/String;" + } + val engagementPanelObjectIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.IPUT_OBJECT && + getReference()?.type != "Ljava/lang/String;" + } + Pair( + getInstruction(engagementPanelIdIndex).reference.toString(), + getInstruction(engagementPanelObjectIndex).reference.toString(), ) - } + } -internal fun hookEngagementPanelState(classDescriptor: String) { - showEngagementPanelMethods.forEach { method -> - method.apply { - val index = indexOfEngagementPanelBuilderInstruction() - val register = getInstruction(index + 1).registerA + engagementPanelBuilderFingerprint.methodOrThrow().apply { + val insertIndex = indexOfFirstInstructionOrThrow { + opcode == Opcode.IGET_OBJECT && + getReference()?.toString() == engagementPanelObjectReference + } + val insertInstruction = getInstruction(insertIndex) + val classRegister = insertInstruction.registerB + engagementPanelIdRegister = insertInstruction.registerA - addInstruction( - index + 2, - "invoke-static {v$register}, $classDescriptor->showEngagementPanel(Ljava/lang/Object;)V" + setFreeIndex(insertIndex) + + addInstructions( + insertIndex, """ + iget-object v$engagementPanelIdRegister, v$classRegister, $engagementPanelIdReference + invoke-static {v$engagementPanelIdRegister}, $EXTENSION_CLASS_DESCRIPTOR->setId(Ljava/lang/String;)V + """ ) + engagementPanelIdIndex = insertIndex + 1 + engagementPanelBuilderMethod = this } - } - hideEngagementPanelMethod.addInstruction( - 0, - "invoke-static {}, $classDescriptor->hideEngagementPanel()V" - ) -} + engagementPanelUpdateFingerprint + .methodOrThrow(engagementPanelBuilderFingerprint) + .addInstruction( + 0, + "invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->hide()V" + ) + } +} \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints .kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints .kt deleted file mode 100644 index 855f89fd8..000000000 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints .kt +++ /dev/null @@ -1,22 +0,0 @@ -package app.revanced.patches.youtube.utils.engagement - -import app.revanced.util.fingerprint.legacyFingerprint -import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstruction -import app.revanced.util.or -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode -import com.android.tools.smali.dexlib2.iface.reference.MethodReference - -internal val engagementPanelUpdateFingerprint = legacyFingerprint( - name = "engagementPanelUpdateFingerprint", - returnType = "V", - accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, - parameters = listOf("L", "Z"), - customFingerprint = { method, _ -> - method.indexOfFirstInstruction { - opcode == Opcode.INVOKE_VIRTUAL && - getReference().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;" - } >= 0 - } -) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints.kt new file mode 100644 index 000000000..2e6866839 --- /dev/null +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/engagement/Fingerprints.kt @@ -0,0 +1,46 @@ +package app.revanced.patches.youtube.utils.engagement + +import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction +import app.revanced.util.or +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.reference.MethodReference + +internal val engagementPanelBuilderFingerprint = legacyFingerprint( + name = "engagementPanelBuilderFingerprint", + returnType = "L", + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + parameters = listOf("L", "L", "Z", "Z"), + strings = listOf( + "EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.", + "[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called." + ) +) + +internal val engagementPanelLayoutFingerprint = legacyFingerprint( + name = "engagementPanelLayoutFingerprint", + returnType = "V", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf("L", "L", "I"), + customFingerprint = { method, _ -> + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference().toString() == "Landroid/widget/FrameLayout;->indexOfChild(Landroid/view/View;)I" + } >= 0 + } +) + +internal val engagementPanelUpdateFingerprint = legacyFingerprint( + name = "engagementPanelUpdateFingerprint", + returnType = "V", + accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, + parameters = listOf("L", "Z"), + customFingerprint = { method, _ -> + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;" + } >= 0 + } +) diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt index 654130e91..cfb48d045 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt @@ -61,8 +61,6 @@ var compactLink = -1L private set var compactListItem = -1L private set -var componentLongClickListener = -1L - private set var contentPill = -1L private set var controlsLayoutStub = -1L @@ -145,8 +143,6 @@ var musicAppDeeplinkButtonView = -1L private set var notificationBigPictureIconWidth = -1L private set -var offlineActionsVideoDeletedUndoSnackbarText = -1L - private set var playerCollapseButton = -1L private set var playerControlPreviousButtonTouchArea = -1L @@ -352,10 +348,6 @@ internal val sharedResourceIdPatch = resourcePatch( LAYOUT, "compact_list_item" ] - componentLongClickListener = resourceMappings[ - ID, - "component_long_click_listener" - ] contentPill = resourceMappings[ LAYOUT, "content_pill" @@ -520,10 +512,6 @@ internal val sharedResourceIdPatch = resourcePatch( DIMEN, "notification_big_picture_icon_width" ] - offlineActionsVideoDeletedUndoSnackbarText = resourceMappings[ - STRING, - "offline_actions_video_deleted_undo_snackbar_text" - ] playerCollapseButton = resourceMappings[ ID, "player_collapse_button" diff --git a/patches/src/main/resources/youtube/settings/host/values/strings.xml b/patches/src/main/resources/youtube/settings/host/values/strings.xml index 6627eaf54..78055881d 100644 --- a/patches/src/main/resources/youtube/settings/host/values/strings.xml +++ b/patches/src/main/resources/youtube/settings/host/values/strings.xml @@ -1323,10 +1323,6 @@ This feature works best with a very fast internet connection." Expand video descriptions Video descriptions are expanded automatically. Video descriptions are not expanded automatically. - Title in video description panel - "Enter the title of the video description panel in your language. -The Expand video description option may not work if the entered string does not match the video description panel title." - Description diff --git a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml index 79744f686..eb402adbb 100644 --- a/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml +++ b/patches/src/main/resources/youtube/settings/xml/revanced_prefs.xml @@ -535,7 +535,6 @@ - SETTINGS: DESCRIPTION_INTERACTION -->