mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-12 13:17:46 +02:00
feat(YouTube - Hide action buttons): Add setting Hide action button by index
, Remove patch option Hide action buttons by index
This commit is contained in:
@ -1,7 +1,6 @@
|
||||
package app.revanced.patches.youtube.player.action
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.booleanOption
|
||||
import app.revanced.patcher.patch.bytecodePatch
|
||||
import app.revanced.patches.shared.litho.addLithoFilter
|
||||
import app.revanced.patches.shared.litho.emptyComponentsFingerprint
|
||||
@ -10,10 +9,11 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
|
||||
import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_PATH
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_ACTION_BUTTONS
|
||||
import app.revanced.patches.youtube.utils.request.buildRequestPatch
|
||||
import app.revanced.patches.youtube.utils.request.hookBuildRequest
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||
import app.revanced.patches.youtube.video.information.videoInformationPatch
|
||||
import app.revanced.util.Utils.trimIndentMultiline
|
||||
import app.revanced.util.addInstructionsAtControlFlowLabel
|
||||
import app.revanced.util.findMethodOrThrow
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
@ -44,72 +44,61 @@ val actionButtonsPatch = bytecodePatch(
|
||||
settingsPatch,
|
||||
lithoFilterPatch,
|
||||
videoInformationPatch,
|
||||
)
|
||||
|
||||
val hideActionButtonByIndex by booleanOption(
|
||||
key = "hideActionButtonByIndex",
|
||||
default = false,
|
||||
title = "Hide action buttons by index",
|
||||
description = """
|
||||
Add an option to hide action buttons by index.
|
||||
|
||||
This setting is still experimental, so use it only for debugging purposes.
|
||||
""".trimIndentMultiline(),
|
||||
required = true
|
||||
buildRequestPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
addLithoFilter(FILTER_CLASS_DESCRIPTOR)
|
||||
|
||||
var settingArray = arrayOf(
|
||||
"PREFERENCE_SCREEN: PLAYER",
|
||||
"SETTINGS: HIDE_ACTION_BUTTONS"
|
||||
)
|
||||
// region patch for hide action buttons by index
|
||||
|
||||
if (hideActionButtonByIndex == true) {
|
||||
componentListFingerprint.methodOrThrow(emptyComponentsFingerprint).apply {
|
||||
val conversionContextToStringMethod =
|
||||
findMethodOrThrow(parameters[1].type) {
|
||||
name == "toString"
|
||||
}
|
||||
val identifierReference = with (conversionContextToStringMethod) {
|
||||
val identifierStringIndex =
|
||||
indexOfFirstStringInstructionOrThrow(", identifierProperty=")
|
||||
val identifierStringAppendIndex =
|
||||
indexOfFirstInstructionOrThrow(identifierStringIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val identifierStringAppendIndexRegister = getInstruction<FiveRegisterInstruction>(identifierStringAppendIndex).registerD
|
||||
val identifierAppendIndex =
|
||||
indexOfFirstInstructionOrThrow(identifierStringAppendIndex + 1, Opcode.INVOKE_VIRTUAL)
|
||||
val identifierRegister = getInstruction<FiveRegisterInstruction>(identifierAppendIndex).registerD
|
||||
val identifierIndex = indexOfFirstInstructionReversedOrThrow(identifierAppendIndex) {
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
getReference<FieldReference>()?.type == "Ljava/lang/String;" &&
|
||||
(this as? TwoRegisterInstruction)?.registerA == identifierRegister
|
||||
}
|
||||
getInstruction<ReferenceInstruction>(identifierIndex).reference
|
||||
componentListFingerprint.methodOrThrow(emptyComponentsFingerprint).apply {
|
||||
val conversionContextToStringMethod =
|
||||
findMethodOrThrow(parameters[1].type) {
|
||||
name == "toString"
|
||||
}
|
||||
|
||||
val listIndex = implementation!!.instructions.lastIndex
|
||||
val listRegister = getInstruction<OneRegisterInstruction>(listIndex).registerA
|
||||
val identifierRegister = listRegister + 1
|
||||
|
||||
addInstructionsAtControlFlowLabel(
|
||||
listIndex, """
|
||||
move-object/from16 v$identifierRegister, p2
|
||||
iget-object v$identifierRegister, v$identifierRegister, $identifierReference
|
||||
invoke-static {v$listRegister, v$identifierRegister}, $ACTION_BUTTONS_CLASS_DESCRIPTOR->hideActionButtonByIndex(Ljava/util/List;Ljava/lang/String;)Ljava/util/List;
|
||||
move-result-object v$listRegister
|
||||
"""
|
||||
)
|
||||
|
||||
settingArray += "SETTINGS: HIDE_BUTTONS_BY_INDEX"
|
||||
val identifierReference = with (conversionContextToStringMethod) {
|
||||
val identifierStringIndex =
|
||||
indexOfFirstStringInstructionOrThrow(", identifierProperty=")
|
||||
val identifierStringAppendIndex =
|
||||
indexOfFirstInstructionOrThrow(identifierStringIndex, Opcode.INVOKE_VIRTUAL)
|
||||
val identifierStringAppendIndexRegister = getInstruction<FiveRegisterInstruction>(identifierStringAppendIndex).registerD
|
||||
val identifierAppendIndex =
|
||||
indexOfFirstInstructionOrThrow(identifierStringAppendIndex + 1, Opcode.INVOKE_VIRTUAL)
|
||||
val identifierRegister = getInstruction<FiveRegisterInstruction>(identifierAppendIndex).registerD
|
||||
val identifierIndex = indexOfFirstInstructionReversedOrThrow(identifierAppendIndex) {
|
||||
opcode == Opcode.IGET_OBJECT &&
|
||||
getReference<FieldReference>()?.type == "Ljava/lang/String;" &&
|
||||
(this as? TwoRegisterInstruction)?.registerA == identifierRegister
|
||||
}
|
||||
getInstruction<ReferenceInstruction>(identifierIndex).reference
|
||||
}
|
||||
|
||||
val listIndex = implementation!!.instructions.lastIndex
|
||||
val listRegister = getInstruction<OneRegisterInstruction>(listIndex).registerA
|
||||
val identifierRegister = listRegister + 1
|
||||
|
||||
addInstructionsAtControlFlowLabel(
|
||||
listIndex, """
|
||||
move-object/from16 v$identifierRegister, p2
|
||||
iget-object v$identifierRegister, v$identifierRegister, $identifierReference
|
||||
invoke-static {v$listRegister, v$identifierRegister}, $ACTION_BUTTONS_CLASS_DESCRIPTOR->hideActionButtonByIndex(Ljava/util/List;Ljava/lang/String;)Ljava/util/List;
|
||||
move-result-object v$listRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
hookBuildRequest("$ACTION_BUTTONS_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V")
|
||||
|
||||
// endregion
|
||||
|
||||
// region add settings
|
||||
|
||||
addPreference(
|
||||
settingArray,
|
||||
arrayOf(
|
||||
"PREFERENCE_SCREEN: PLAYER",
|
||||
"SETTINGS: HIDE_ACTION_BUTTONS"
|
||||
),
|
||||
HIDE_ACTION_BUTTONS
|
||||
)
|
||||
|
||||
|
@ -33,38 +33,6 @@ internal val buildMediaDataSourceFingerprint = legacyFingerprint(
|
||||
)
|
||||
)
|
||||
|
||||
internal val buildRequestFingerprint = legacyFingerprint(
|
||||
name = "buildRequestFingerprint",
|
||||
customFingerprint = { method, _ ->
|
||||
method.implementation != null &&
|
||||
indexOfRequestFinishedListenerInstruction(method) >= 0 &&
|
||||
!method.definingClass.startsWith("Lorg/") &&
|
||||
indexOfNewUrlRequestBuilderInstruction(method) >= 0 &&
|
||||
// Earlier targets
|
||||
(indexOfEntrySetInstruction(method) >= 0 ||
|
||||
// Later targets
|
||||
method.parameters[1].type == "Ljava/util/Map;")
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfRequestFinishedListenerInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setRequestFinishedListener"
|
||||
}
|
||||
|
||||
internal fun indexOfNewUrlRequestBuilderInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>().toString() == "Lorg/chromium/net/CronetEngine;->newUrlRequestBuilder(Ljava/lang/String;Lorg/chromium/net/UrlRequest${'$'}Callback;Ljava/util/concurrent/Executor;)Lorg/chromium/net/UrlRequest${'$'}Builder;"
|
||||
}
|
||||
|
||||
internal fun indexOfEntrySetInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>().toString() == "Ljava/util/Map;->entrySet()Ljava/util/Set;"
|
||||
}
|
||||
|
||||
internal val createStreamingDataFingerprint = legacyFingerprint(
|
||||
name = "createStreamingDataFingerprint",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||
|
@ -18,6 +18,8 @@ import app.revanced.patches.shared.spoof.useragent.baseSpoofUserAgentPatch
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.YOUTUBE_PACKAGE_NAME
|
||||
import app.revanced.patches.youtube.utils.patch.PatchList.SPOOF_STREAMING_DATA
|
||||
import app.revanced.patches.youtube.utils.request.buildRequestPatch
|
||||
import app.revanced.patches.youtube.utils.request.hookBuildRequest
|
||||
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
|
||||
import app.revanced.patches.youtube.utils.settings.settingsPatch
|
||||
import app.revanced.util.findInstructionIndicesReversedOrThrow
|
||||
@ -31,7 +33,6 @@ import app.revanced.util.indexOfFirstInstructionOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
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
|
||||
@ -39,7 +40,7 @@ import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
|
||||
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
|
||||
|
||||
const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
private const val EXTENSION_CLASS_DESCRIPTOR =
|
||||
"$SPOOF_PATH/SpoofStreamingDataPatch;"
|
||||
|
||||
val spoofStreamingDataPatch = bytecodePatch(
|
||||
@ -52,36 +53,14 @@ val spoofStreamingDataPatch = bytecodePatch(
|
||||
settingsPatch,
|
||||
baseSpoofUserAgentPatch(YOUTUBE_PACKAGE_NAME),
|
||||
blockRequestPatch,
|
||||
buildRequestPatch,
|
||||
)
|
||||
|
||||
execute {
|
||||
|
||||
// region Get replacement streams at player requests.
|
||||
|
||||
buildRequestFingerprint.methodOrThrow().apply {
|
||||
val newRequestBuilderIndex = indexOfNewUrlRequestBuilderInstruction(this)
|
||||
val urlRegister =
|
||||
getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
|
||||
|
||||
val entrySetIndex = indexOfEntrySetInstruction(this)
|
||||
val mapRegister = if (entrySetIndex < 0)
|
||||
urlRegister + 1
|
||||
else
|
||||
getInstruction<FiveRegisterInstruction>(entrySetIndex).registerC
|
||||
|
||||
var smaliInstructions =
|
||||
"invoke-static { v$urlRegister, v$mapRegister }, " +
|
||||
"$EXTENSION_CLASS_DESCRIPTOR->" +
|
||||
"fetchStreams(Ljava/lang/String;Ljava/util/Map;)V"
|
||||
|
||||
if (entrySetIndex < 0) smaliInstructions = """
|
||||
move-object/from16 v$mapRegister, p1
|
||||
|
||||
""" + smaliInstructions
|
||||
|
||||
// Copy request headers for streaming data fetch.
|
||||
addInstructions(newRequestBuilderIndex + 2, smaliInstructions)
|
||||
}
|
||||
hookBuildRequest("$EXTENSION_CLASS_DESCRIPTOR->fetchStreams(Ljava/lang/String;Ljava/util/Map;)V")
|
||||
|
||||
// endregion
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
package app.revanced.patches.youtube.utils.request
|
||||
|
||||
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.extension.sharedExtensionPatch
|
||||
import app.revanced.util.fingerprint.methodOrThrow
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||
|
||||
private lateinit var buildRequestMethod: MutableMethod
|
||||
private var urlRegister = 0
|
||||
private var mapRegister = 0
|
||||
private var offSet = 0
|
||||
|
||||
val buildRequestPatch = bytecodePatch(
|
||||
description = "buildRequestPatch",
|
||||
) {
|
||||
dependsOn(sharedExtensionPatch)
|
||||
|
||||
execute {
|
||||
buildRequestFingerprint.methodOrThrow().apply {
|
||||
buildRequestMethod = this
|
||||
|
||||
val newRequestBuilderIndex = indexOfNewUrlRequestBuilderInstruction(this)
|
||||
urlRegister =
|
||||
getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD
|
||||
|
||||
val entrySetIndex = indexOfEntrySetInstruction(this)
|
||||
val isLegacyTarget = entrySetIndex < 0
|
||||
mapRegister = if (isLegacyTarget)
|
||||
urlRegister + 1
|
||||
else
|
||||
getInstruction<FiveRegisterInstruction>(entrySetIndex).registerC
|
||||
|
||||
if (isLegacyTarget) {
|
||||
addInstructions(
|
||||
newRequestBuilderIndex + 2,
|
||||
"move-object/from16 v$mapRegister, p1"
|
||||
)
|
||||
offSet++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun hookBuildRequest(descriptor: String) {
|
||||
buildRequestMethod.apply {
|
||||
val insertIndex = indexOfNewUrlRequestBuilderInstruction(this) + 2 + offSet
|
||||
|
||||
addInstructions(
|
||||
insertIndex,
|
||||
"invoke-static { v$urlRegister, v$mapRegister }, $descriptor"
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package app.revanced.patches.youtube.utils.request
|
||||
|
||||
import app.revanced.util.fingerprint.legacyFingerprint
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
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 buildRequestFingerprint = legacyFingerprint(
|
||||
name = "buildRequestFingerprint",
|
||||
customFingerprint = { method, _ ->
|
||||
method.implementation != null &&
|
||||
indexOfRequestFinishedListenerInstruction(method) >= 0 &&
|
||||
!method.definingClass.startsWith("Lorg/") &&
|
||||
indexOfNewUrlRequestBuilderInstruction(method) >= 0 &&
|
||||
// Earlier targets
|
||||
(indexOfEntrySetInstruction(method) >= 0 ||
|
||||
// Later targets
|
||||
method.parameters[1].type == "Ljava/util/Map;")
|
||||
}
|
||||
)
|
||||
|
||||
internal fun indexOfRequestFinishedListenerInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>()?.name == "setRequestFinishedListener"
|
||||
}
|
||||
|
||||
internal fun indexOfNewUrlRequestBuilderInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_VIRTUAL &&
|
||||
getReference<MethodReference>().toString() == "Lorg/chromium/net/CronetEngine;->newUrlRequestBuilder(Ljava/lang/String;Lorg/chromium/net/UrlRequest${'$'}Callback;Ljava/util/concurrent/Executor;)Lorg/chromium/net/UrlRequest${'$'}Builder;"
|
||||
}
|
||||
|
||||
internal fun indexOfEntrySetInstruction(method: Method) =
|
||||
method.indexOfFirstInstruction {
|
||||
opcode == Opcode.INVOKE_INTERFACE &&
|
||||
getReference<MethodReference>().toString() == "Ljava/util/Map;->entrySet()Ljava/util/Set;"
|
||||
}
|
Reference in New Issue
Block a user