feat(YouTube - Description components): Remove Title in video description panel setting (No more necessary)

This commit is contained in:
inotia00 2025-02-10 17:16:40 +09:00
parent d1154db77e
commit 37e5a48665
15 changed files with 200 additions and 256 deletions

View File

@ -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;

View File

@ -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() {

View File

@ -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<FullscreenMode> 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

View File

@ -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<String> 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();
}
}

View File

@ -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

View File

@ -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",

View File

@ -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<ReferenceInstruction>(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

View File

@ -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<FiveRegisterInstruction>(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"

View File

@ -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<MethodReference>()?.name == "setContentDescription"
}
/**
* This fingerprint is compatible with YouTube v18.35.xx~
* Nonetheless, the patch works in YouTube v19.02.xx~

View File

@ -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<MutableMethod>()
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<TwoRegisterInstruction>(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<MethodReference>()!!
val (engagementPanelIdReference, engagementPanelObjectReference) =
with(findMethodOrThrow(engagementPanelInfoClass)) {
val engagementPanelIdIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type == "Ljava/lang/String;"
}
val engagementPanelObjectIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IPUT_OBJECT &&
getReference<FieldReference>()?.type != "Ljava/lang/String;"
}
Pair(
getInstruction<ReferenceInstruction>(engagementPanelIdIndex).reference.toString(),
getInstruction<ReferenceInstruction>(engagementPanelObjectIndex).reference.toString(),
)
}
}
internal fun hookEngagementPanelState(classDescriptor: String) {
showEngagementPanelMethods.forEach { method ->
method.apply {
val index = indexOfEngagementPanelBuilderInstruction()
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
engagementPanelBuilderFingerprint.methodOrThrow().apply {
val insertIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.IGET_OBJECT &&
getReference<FieldReference>()?.toString() == engagementPanelObjectReference
}
val insertInstruction = getInstruction<TwoRegisterInstruction>(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"
)
}
}

View File

@ -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<MethodReference>().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;"
} >= 0
}
)

View File

@ -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<MethodReference>().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<MethodReference>().toString() == "Ljava/util/ArrayDeque;->pop()Ljava/lang/Object;"
} >= 0
}
)

View File

@ -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"

View File

@ -1323,10 +1323,6 @@ This feature works best with a very fast internet connection."</string>
<string name="revanced_expand_video_description_title">Expand video descriptions</string>
<string name="revanced_expand_video_description_summary_on">Video descriptions are expanded automatically.</string>
<string name="revanced_expand_video_description_summary_off">Video descriptions are not expanded automatically.</string>
<string name="revanced_expand_video_description_strings_title">Title in video description panel</string>
<string name="revanced_expand_video_description_strings_summary">"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."</string>
<string name="revanced_expand_video_description_strings_default_value">Description</string>
<!-- PreferenceScreen: Shorts -->

View File

@ -535,7 +535,6 @@
<PreferenceCategory android:title="@string/revanced_preference_category_experimental_flag" android:layout="@layout/revanced_settings_preferences_category">
<SwitchPreference android:title="@string/revanced_disable_video_description_interaction_title" android:key="revanced_disable_video_description_interaction" android:summary="@string/revanced_disable_video_description_interaction_summary" />
<SwitchPreference android:title="@string/revanced_expand_video_description_title" android:key="revanced_expand_video_description" android:summaryOn="@string/revanced_expand_video_description_summary_on" android:summaryOff="@string/revanced_expand_video_description_summary_off" />
<app.revanced.extension.shared.settings.preference.ResettableEditTextPreference android:title="@string/revanced_expand_video_description_strings_title" android:key="revanced_expand_video_description_strings" android:summary="@string/revanced_expand_video_description_strings_summary" android:inputType="text" />
</PreferenceCategory>SETTINGS: DESCRIPTION_INTERACTION -->
<!-- SETTINGS: DESCRIPTION_COMPONENTS