mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-12 13:17:46 +02:00
feat(YouTube): Add Open channel of live avatar
patch
This commit is contained in:
@ -0,0 +1,42 @@
|
||||
package app.revanced.patches.youtube.general.channel
|
||||
|
||||
import app.revanced.patches.youtube.utils.resourceid.elementsImage
|
||||
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.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
internal val elementsImageFingerprint = legacyFingerprint(
|
||||
name = "elementsImageFingerprint",
|
||||
returnType = "Landroid/view/View;",
|
||||
accessFlags = AccessFlags.PRIVATE or AccessFlags.STATIC,
|
||||
parameters = listOf("Landroid/view/View;"),
|
||||
literals = listOf(elementsImage),
|
||||
)
|
||||
|
||||
internal val clientSettingEndpointFingerprint = legacyFingerprint(
|
||||
name = "clientSettingEndpointFingerprint",
|
||||
returnType = "V",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = listOf("L", "Ljava/util/Map;"),
|
||||
strings = listOf(
|
||||
"force_fullscreen",
|
||||
"PLAYBACK_START_DESCRIPTOR_MUTATOR",
|
||||
"VideoPresenterConstants.VIDEO_THUMBNAIL_BITMAP_KEY"
|
||||
),
|
||||
customFingerprint = { method, _ ->
|
||||
indexOfPlaybackStartDescriptorInstruction(method) >= 0
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfPlaybackStartDescriptorInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
val reference = getReference<MethodReference>()
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
reference?.returnType == "Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;" &&
|
||||
reference.parameterTypes.isEmpty()
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
package app.revanced.patches.youtube.general.channel
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
|
||||
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.extension.Constants.GENERAL_PATH
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.OPEN_CHANNEL_OF_LIVE_AVATAR
|
||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.video.playbackstart.playbackStartDescriptorPatch
|
||||
import app.revanced.patches.youtube.video.playbackstart.playbackStartVideoIdReference
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import app.revanced.util.indexOfFirstInstructionReversedOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"$GENERAL_PATH/OpenChannelOfLiveAvatarPatch;"
|
||||
|
||||
@Suppress("unused")
|
||||
val layoutSwitchPatch = bytecodePatch(
|
||||
OPEN_CHANNEL_OF_LIVE_AVATAR.title,
|
||||
OPEN_CHANNEL_OF_LIVE_AVATAR.summary,
|
||||
) {
|
||||
compatibleWith(COMPATIBLE_PACKAGE)
|
||||
|
||||
dependsOn(
|
||||
playbackStartDescriptorPatch,
|
||||
sharedResourceIdPatch,
|
||||
settingsPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
|
||||
elementsImageFingerprint.methodOrThrow().addInstruction(
|
||||
0,
|
||||
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->liveChannelAvatarClicked()V"
|
||||
)
|
||||
|
||||
clientSettingEndpointFingerprint.methodOrThrow().apply {
|
||||
val eqzIndex = indexOfFirstInstructionReversedOrThrow(Opcode.IF_EQZ)
|
||||
var freeIndex = indexOfFirstInstructionReversedOrThrow(eqzIndex, Opcode.NEW_INSTANCE)
|
||||
var freeRegister = getInstruction<OneRegisterInstruction>(freeIndex).registerA
|
||||
|
||||
addInstructionsWithLabels(
|
||||
eqzIndex, """
|
||||
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->openChannelOfLiveAvatar()Z
|
||||
move-result v$freeRegister
|
||||
if-eqz v$freeRegister, :ignore
|
||||
return-void
|
||||
:ignore
|
||||
nop
|
||||
"""
|
||||
)
|
||||
|
||||
val playbackStartIndex = indexOfPlaybackStartDescriptorInstruction(this) + 1
|
||||
val playbackStartRegister = getInstruction<OneRegisterInstruction>(playbackStartIndex).registerA
|
||||
|
||||
freeIndex = indexOfFirstInstructionOrThrow(playbackStartIndex, Opcode.CONST_STRING)
|
||||
freeRegister = getInstruction<OneRegisterInstruction>(freeIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
playbackStartIndex + 1, """
|
||||
invoke-virtual { v$playbackStartRegister }, $playbackStartVideoIdReference
|
||||
move-result-object v$freeRegister
|
||||
invoke-static { v$freeRegister }, $EXTENSION_CLASS_DESCRIPTOR->openChannelOfLiveAvatar(Ljava/lang/String;)V
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
// region add settings
|
||||
|
||||
addPreference(
|
||||
arrayOf(
|
||||
"PREFERENCE_SCREEN: GENERAL",
|
||||
"PREFERENCE_CATEGORY: GENERAL_EXPERIMENTAL_FLAGS",
|
||||
"SETTINGS: OPEN_CHANNEL_OF_LIVE_AVATAR"
|
||||
),
|
||||
OPEN_CHANNEL_OF_LIVE_AVATAR
|
||||
)
|
||||
|
||||
// endregion
|
||||
|
||||
}
|
||||
}
|
@ -169,6 +169,10 @@ internal enum class PatchList(
|
||||
"Navigation bar components",
|
||||
"Adds options to hide or change components related to the navigation bar."
|
||||
),
|
||||
OPEN_CHANNEL_OF_LIVE_AVATAR(
|
||||
"Open channel of live avatar",
|
||||
"Adds an option to open channel instead of video when clicking on live avatar."
|
||||
),
|
||||
OPEN_LINKS_EXTERNALLY(
|
||||
"Open links externally",
|
||||
"Adds an option to always open links in your browser instead of in the in-app-browser."
|
||||
|
@ -83,6 +83,8 @@ var easySeekEduContainer = -1L
|
||||
private set
|
||||
var editSettingsAction = -1L
|
||||
private set
|
||||
var elementsImage = -1L
|
||||
private set
|
||||
var endScreenElementLayoutCircle = -1L
|
||||
private set
|
||||
var endScreenElementLayoutIcon = -1L
|
||||
@ -383,6 +385,10 @@ internal val sharedResourceIdPatch = resourcePatch(
|
||||
STRING,
|
||||
"edit_settings_action"
|
||||
]
|
||||
elementsImage = resourceMappings[
|
||||
ID,
|
||||
"elements_image"
|
||||
]
|
||||
endScreenElementLayoutCircle = resourceMappings[
|
||||
LAYOUT,
|
||||
"endscreen_element_layout_circle"
|
||||
|
@ -0,0 +1,19 @@
|
||||
package app.revanced.patches.youtube.video.playbackstart
|
||||
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
|
||||
const val PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR =
|
||||
"Lcom/google/android/libraries/youtube/player/model/PlaybackStartDescriptor;"
|
||||
|
||||
/**
|
||||
* Purpose of this method is not clear, and it's only used to identify
|
||||
* the obfuscated name of the videoId() method in PlaybackStartDescriptor.
|
||||
*/
|
||||
internal val playbackStartFeatureFlagFingerprint = legacyFingerprint(
|
||||
name = "playbackStartFeatureFlagFingerprint",
|
||||
returnType = "Z",
|
||||
parameters = listOf(PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR),
|
||||
literals = listOf(45380134L)
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,33 @@
|
||||
package app.revanced.patches.youtube.video.playbackstart
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
import com.android.tools.smali.dexlib2.iface.reference.Reference
|
||||
|
||||
internal lateinit var playbackStartVideoIdReference: Reference
|
||||
|
||||
val playbackStartDescriptorPatch = bytecodePatch(
|
||||
description = "playbackStartDescriptorPatch"
|
||||
) {
|
||||
dependsOn(sharedResourceIdPatch)
|
||||
|
||||
execute {
|
||||
// Find the obfuscated method name for PlaybackStartDescriptor.videoId()
|
||||
playbackStartFeatureFlagFingerprint.methodOrThrow().apply {
|
||||
val stringMethodIndex = indexOfFirstInstructionOrThrow {
|
||||
val reference = getReference<MethodReference>()
|
||||
reference?.definingClass == PLAYBACK_START_DESCRIPTOR_CLASS_DESCRIPTOR
|
||||
&& reference.returnType == "Ljava/lang/String;"
|
||||
}
|
||||
|
||||
playbackStartVideoIdReference = getInstruction<ReferenceInstruction>(stringMethodIndex).reference
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user