mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-16 14:27:18 +02:00
fix(YouTube - Change live ring click action): Clicking on the timestamp in the comments opens the channel
This commit is contained in:
parent
78f1d962cd
commit
da770b32bf
@ -1,5 +1,9 @@
|
||||
package app.revanced.extension.youtube.patches.general;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
import app.revanced.extension.youtube.patches.general.requests.VideoDetailsRequest;
|
||||
import app.revanced.extension.youtube.settings.Settings;
|
||||
@ -10,16 +14,16 @@ public final class OpenChannelOfLiveAvatarPatch {
|
||||
private static final boolean CHANGE_LIVE_RING_CLICK_ACTION =
|
||||
Settings.CHANGE_LIVE_RING_CLICK_ACTION.get();
|
||||
|
||||
private static volatile String videoId = "";
|
||||
private static volatile boolean isCommentsPanelOpen = false;
|
||||
private static final AtomicBoolean engagementPanelOpen = new AtomicBoolean(false);
|
||||
private static volatile boolean liveChannelAvatarClicked = false;
|
||||
private static volatile String videoId = "";
|
||||
|
||||
public static void commentsPanelClosed() {
|
||||
isCommentsPanelOpen = false;
|
||||
public static void showEngagementPanel(@Nullable Object object) {
|
||||
engagementPanelOpen.set(object != null);
|
||||
}
|
||||
|
||||
public static void commentsPanelOpen() {
|
||||
isCommentsPanelOpen = true;
|
||||
public static void hideEngagementPanel() {
|
||||
engagementPanelOpen.compareAndSet(true, false);
|
||||
}
|
||||
|
||||
public static void liveChannelAvatarClicked() {
|
||||
@ -34,13 +38,14 @@ public final class OpenChannelOfLiveAvatarPatch {
|
||||
if (!liveChannelAvatarClicked) {
|
||||
return false;
|
||||
}
|
||||
if (isCommentsPanelOpen) {
|
||||
if (engagementPanelOpen.get()) {
|
||||
return false;
|
||||
}
|
||||
VideoDetailsRequest request = VideoDetailsRequest.getRequestForVideoId(videoId);
|
||||
if (request != null) {
|
||||
String channelId = request.getInfo();
|
||||
if (channelId != null) {
|
||||
videoId = "";
|
||||
liveChannelAvatarClicked = false;
|
||||
VideoUtils.openChannel(channelId);
|
||||
return true;
|
||||
@ -60,7 +65,7 @@ public final class OpenChannelOfLiveAvatarPatch {
|
||||
if (!liveChannelAvatarClicked) {
|
||||
return;
|
||||
}
|
||||
if (isCommentsPanelOpen) {
|
||||
if (engagementPanelOpen.get()) {
|
||||
return;
|
||||
}
|
||||
if (newlyLoadedVideoId.isEmpty()) {
|
||||
|
@ -7,14 +7,14 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||
import app.revanced.patcher.util.smali.ExternalLabel
|
||||
import app.revanced.patches.shared.litho.addLithoFilter
|
||||
import app.revanced.patches.shared.litho.emptyComponentLabel
|
||||
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.engagementPanelBuilderFingerprint
|
||||
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
|
||||
@ -41,19 +41,16 @@ import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.fingerprint.mutableClassOrThrow
|
||||
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
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
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.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.StringReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
private const val CAROUSEL_SHELF_FILTER_CLASS_DESCRIPTOR =
|
||||
"$COMPONENTS_PATH/CarouselShelfFilter;"
|
||||
@ -82,6 +79,7 @@ val feedComponentsPatch = bytecodePatch(
|
||||
sharedResourceIdPatch,
|
||||
settingsPatch,
|
||||
bottomSheetHookPatch,
|
||||
engagementPanelHookPatch,
|
||||
versionCheckPatch,
|
||||
)
|
||||
execute {
|
||||
@ -176,38 +174,6 @@ val feedComponentsPatch = bytecodePatch(
|
||||
|
||||
// region patch for hide relative video
|
||||
|
||||
fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: MutableMethod) =
|
||||
indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
MethodUtil.methodSignaturesMatch(
|
||||
targetMethod,
|
||||
getReference<MethodReference>()!!
|
||||
)
|
||||
}
|
||||
|
||||
engagementPanelBuilderFingerprint.matchOrThrow().let {
|
||||
it.classDef.methods.filter { method ->
|
||||
method.indexOfEngagementPanelBuilderInstruction(it.method) >= 0
|
||||
}.forEach { method ->
|
||||
method.apply {
|
||||
val index = indexOfEngagementPanelBuilderInstruction(it.method)
|
||||
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
|
||||
|
||||
addInstruction(
|
||||
index + 2,
|
||||
"invoke-static {v$register}, " +
|
||||
"$RELATED_VIDEO_CLASS_DESCRIPTOR->showEngagementPanel(Ljava/lang/Object;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
engagementPanelUpdateFingerprint.methodOrThrow(engagementPanelBuilderFingerprint)
|
||||
.addInstruction(
|
||||
0,
|
||||
"invoke-static {}, $RELATED_VIDEO_CLASS_DESCRIPTOR->hideEngagementPanel()V"
|
||||
)
|
||||
|
||||
linearLayoutManagerItemCountsFingerprint.matchOrThrow().let {
|
||||
val methodWalker =
|
||||
it.getWalkerMethod(it.patternMatch!!.endIndex)
|
||||
@ -224,6 +190,8 @@ val feedComponentsPatch = bytecodePatch(
|
||||
}
|
||||
}
|
||||
|
||||
hookEngagementPanelState(RELATED_VIDEO_CLASS_DESCRIPTOR)
|
||||
|
||||
// endregion
|
||||
|
||||
// region patch for hide subscriptions channel section for tablet
|
||||
|
@ -11,12 +11,9 @@ import app.revanced.patches.youtube.utils.resourceid.filterBarHeight
|
||||
import app.revanced.patches.youtube.utils.resourceid.horizontalCardList
|
||||
import app.revanced.patches.youtube.utils.resourceid.relatedChipCloudMargin
|
||||
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 breakingNewsFingerprint = legacyFingerprint(
|
||||
name = "breakingNewsFingerprint",
|
||||
@ -103,19 +100,6 @@ internal val elementParserParentFingerprint = legacyFingerprint(
|
||||
strings = listOf("Element tree missing id in debug mode.")
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
)
|
||||
|
||||
internal val filterBarHeightFingerprint = legacyFingerprint(
|
||||
name = "filterBarHeightFingerprint",
|
||||
returnType = "V",
|
||||
|
@ -40,39 +40,3 @@ internal fun indexOfPlaybackStartDescriptorInstruction(method: Method) =
|
||||
reference?.returnType == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" &&
|
||||
reference.parameterTypes.isEmpty()
|
||||
}
|
||||
|
||||
internal val engagementPanelCommentsClosedFingerprint = legacyFingerprint(
|
||||
name = "engagementPanelCommentsClosedFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_STATIC,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.INVOKE_DIRECT,
|
||||
),
|
||||
customFingerprint = { method, _ ->
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>()?.name == "hasNext"
|
||||
} >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal val engagementPanelCommentsOpenFingerprint = legacyFingerprint(
|
||||
name = "engagementPanelCommentsOpenFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.IF_NE,
|
||||
Opcode.RETURN_VOID,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.RETURN_VOID,
|
||||
),
|
||||
customFingerprint = { method, _ ->
|
||||
method.implementation!!.instructions.count() == 5
|
||||
}
|
||||
)
|
||||
|
@ -6,7 +6,8 @@ import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWith
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.engagementPanelTitleParentFingerprint
|
||||
import app.revanced.patches.youtube.utils.engagement.engagementPanelHookPatch
|
||||
import app.revanced.patches.youtube.utils.engagement.hookEngagementPanelState
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.CHANGE_LIVE_RING_CLICK_ACTION
|
||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
@ -31,30 +32,21 @@ val openChannelOfLiveAvatarPatch = bytecodePatch(
|
||||
compatibleWith(COMPATIBLE_PACKAGE)
|
||||
|
||||
dependsOn(
|
||||
playbackStartDescriptorPatch,
|
||||
sharedResourceIdPatch,
|
||||
settingsPatch,
|
||||
sharedResourceIdPatch,
|
||||
playbackStartDescriptorPatch,
|
||||
engagementPanelHookPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
|
||||
mapOf(
|
||||
engagementPanelCommentsClosedFingerprint to "commentsPanelClosed",
|
||||
engagementPanelCommentsOpenFingerprint to "commentsPanelOpen",
|
||||
).forEach { (fingerprint, methodName) ->
|
||||
fingerprint
|
||||
.methodOrThrow(engagementPanelTitleParentFingerprint)
|
||||
.addInstruction(
|
||||
0,
|
||||
"invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->$methodName()V"
|
||||
)
|
||||
}
|
||||
|
||||
elementsImageFingerprint.methodOrThrow().addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->liveChannelAvatarClicked()V"
|
||||
)
|
||||
|
||||
hookEngagementPanelState(EXTENSION_CLASS_DESCRIPTOR)
|
||||
|
||||
clientSettingEndpointFingerprint.methodOrThrow().apply {
|
||||
val eqzIndex = indexOfFirstInstructionReversedOrThrow(Opcode.IF_EQZ)
|
||||
var freeIndex = indexOfFirstInstructionReversedOrThrow(eqzIndex, Opcode.NEW_INSTANCE)
|
||||
|
@ -9,7 +9,6 @@ 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.engagementPanelTitleParentFingerprint
|
||||
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
|
||||
|
@ -16,6 +16,11 @@ internal val engagementPanelTitleFingerprint = legacyFingerprint(
|
||||
}
|
||||
)
|
||||
|
||||
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 &&
|
||||
|
@ -59,11 +59,6 @@ internal val engagementPanelBuilderFingerprint = legacyFingerprint(
|
||||
)
|
||||
)
|
||||
|
||||
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 val layoutConstructorFingerprint = legacyFingerprint(
|
||||
name = "layoutConstructorFingerprint",
|
||||
returnType = "V",
|
||||
|
@ -0,0 +1,67 @@
|
||||
package app.revanced.patches.youtube.utils.engagement
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
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.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.util.fingerprint.matchOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
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.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.util.MethodUtil
|
||||
|
||||
private lateinit var hideEngagementPanelMethod: MutableMethod
|
||||
private var showEngagementPanelMethods = mutableListOf<MutableMethod>()
|
||||
|
||||
val engagementPanelHookPatch = bytecodePatch(
|
||||
description = "engagementPanelHookPatch"
|
||||
) {
|
||||
dependsOn(sharedResourceIdPatch)
|
||||
|
||||
execute {
|
||||
engagementPanelBuilderFingerprint.matchOrThrow().let {
|
||||
it.classDef.methods.filter { method ->
|
||||
method.indexOfEngagementPanelBuilderInstruction(it.method) >= 0
|
||||
}.forEach { method ->
|
||||
showEngagementPanelMethods.add(method)
|
||||
}
|
||||
}
|
||||
|
||||
hideEngagementPanelMethod =
|
||||
engagementPanelUpdateFingerprint.methodOrThrow(engagementPanelBuilderFingerprint)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: MutableMethod) =
|
||||
indexOfFirstInstructionReversed {
|
||||
opcode == Opcode.INVOKE_DIRECT &&
|
||||
MethodUtil.methodSignaturesMatch(
|
||||
targetMethod,
|
||||
getReference<MethodReference>()!!
|
||||
)
|
||||
}
|
||||
|
||||
internal fun hookEngagementPanelState(classDescriptor: String) {
|
||||
showEngagementPanelMethods.forEach { method ->
|
||||
method.apply {
|
||||
val index = indexOfEngagementPanelBuilderInstruction(this)
|
||||
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
|
||||
|
||||
addInstruction(
|
||||
index + 2,
|
||||
"invoke-static {v$register}, $classDescriptor->showEngagementPanel(Ljava/lang/Object;)V"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
hideEngagementPanelMethod.addInstruction(
|
||||
0,
|
||||
"invoke-static {}, $classDescriptor->hideEngagementPanel()V"
|
||||
)
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
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
|
||||
}
|
||||
)
|
Loading…
x
Reference in New Issue
Block a user