mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-04-29 22:24:31 +02:00
feat(YouTube - Description components): Remove Title in video description panel
setting (No more necessary)
This commit is contained in:
parent
d1154db77e
commit
37e5a48665
@ -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;
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
@ -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",
|
||||
|
@ -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
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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~
|
||||
|
@ -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"
|
||||
)
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
)
|
@ -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
|
||||
}
|
||||
)
|
@ -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"
|
||||
|
@ -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 -->
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user