feat(litho-filter): change to abstract patch

This commit is contained in:
inotia00 2023-06-20 14:39:35 +09:00
parent e83fa54c87
commit 5b476eca33
32 changed files with 329 additions and 552 deletions

View File

@ -9,7 +9,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.litho.patch.MusicLithoFilterPatch
import app.revanced.patches.music.utils.litho.patch.MusicLithoFilterPatch
import app.revanced.patches.music.utils.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType

View File

@ -9,7 +9,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.litho.patch.MusicLithoFilterPatch
import app.revanced.patches.music.utils.litho.patch.MusicLithoFilterPatch
import app.revanced.patches.music.utils.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType

View File

@ -14,7 +14,8 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.music.layout.floatingbutton.fingerprints.*
import app.revanced.patches.music.layout.floatingbutton.fingerprints.FloatingButtonFingerprint
import app.revanced.patches.music.layout.floatingbutton.fingerprints.FloatingButtonParentFingerprint
import app.revanced.patches.music.utils.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.music.utils.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility

View File

@ -9,7 +9,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.music.misc.litho.patch.MusicLithoFilterPatch
import app.revanced.patches.music.utils.litho.patch.MusicLithoFilterPatch
import app.revanced.patches.music.utils.settings.resource.patch.MusicSettingsPatch
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.util.enum.CategoryType

View File

@ -1,71 +0,0 @@
package app.revanced.patches.music.misc.litho.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.fingerprints.LithoFingerprint
import app.revanced.util.bytecode.getNarrowLiteralIndex
import app.revanced.util.integrations.Constants.MUSIC_ADS_PATH
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference
@YouTubeMusicCompatibility
@Version("0.0.1")
class MusicLithoFilterPatch : BytecodePatch(
listOf(LithoFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
LithoFingerprint.result?.let {
it.mutableMethod.apply {
val targetInstruction = implementation!!.instructions
val endIndex = it.scanResult.patternScanResult!!.endIndex
val bufferIndex = getNarrowLiteralIndex(168777401)
val bufferRegister = getInstruction<OneRegisterInstruction>(bufferIndex).registerA
val targetIndex = targetInstruction.indexOfFirst { instruction ->
instruction.opcode == Opcode.CONST_STRING &&
(instruction as BuilderInstruction21c).reference.toString() == "Element missing type extension"
} + 2
val builderMethodDescriptor = (getInstruction(targetIndex) as ReferenceInstruction).reference as MethodReference
val emptyComponentFieldDescriptor = (getInstruction(targetIndex + 2) as ReferenceInstruction).reference as FieldReference
val identifierRegister = getInstruction<OneRegisterInstruction>(endIndex).registerA
targetInstruction.filter { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference
fieldReference?.let { reference -> reference.type == "Ljava/lang/StringBuilder;" } == true
}.forEach { instruction ->
val insertIndex = targetInstruction.indexOf(instruction)
val stringBuilderRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
addInstructionsWithLabels(
insertIndex, """
invoke-static {v$stringBuilderRegister, v$identifierRegister}, $MUSIC_ADS_PATH/MusicLithoFilterPatch;->filter(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
move-result v$bufferRegister
if-eqz v$bufferRegister, :not_an_ad
move-object/from16 v$identifierRegister, p1
invoke-static {v$identifierRegister}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
""", ExternalLabel("not_an_ad", getInstruction(insertIndex))
)
}
}
} ?: return LithoFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,26 @@
package app.revanced.patches.music.utils.litho.patch
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.shared.annotation.YouTubeMusicCompatibility
import app.revanced.patches.shared.fingerprints.IdentifierFingerprint
import app.revanced.patches.shared.patch.litho.ComponentParserPatch
import app.revanced.patches.shared.patch.litho.ComponentParserPatch.Companion.identifierHook
import app.revanced.util.integrations.Constants.MUSIC_ADS_PATH
@DependsOn([ComponentParserPatch::class])
@YouTubeMusicCompatibility
@Version("0.0.1")
class MusicLithoFilterPatch : BytecodePatch(
listOf(IdentifierFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
identifierHook("$MUSIC_ADS_PATH/MusicLithoFilterPatch;->filter")
return PatchResultSuccess()
}
}

View File

@ -0,0 +1,13 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object ByteBufferHookFingerprint : MethodFingerprint(
returnType = "L",
opcodes = listOf(
Opcode.ADD_INT_2ADDR,
Opcode.INVOKE_VIRTUAL
),
strings = listOf("Unssuported TextDecorator adjustment. Extension: %s")
)

View File

@ -5,12 +5,13 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object LithoFingerprint : MethodFingerprint(
object IdentifierFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.IF_EQZ
Opcode.IF_EQZ,
Opcode.IPUT_OBJECT
),
strings = listOf("Element missing type extension")
)

View File

@ -1,18 +0,0 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object LithoBufferFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.GOTO
),
strings = listOf("Element missing type extension")
)

View File

@ -1,16 +0,0 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object LithoObjectFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.CONST_STRING,
Opcode.INVOKE_VIRTUAL
),
strings = listOf("Element missing type extension")
)

View File

@ -0,0 +1,172 @@
package app.revanced.patches.shared.patch.litho
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.proxy.mutableTypes.MutableField.Companion.toMutable
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.RVXCompatibility
import app.revanced.patches.shared.fingerprints.ByteBufferHookFingerprint
import app.revanced.patches.shared.fingerprints.EmptyComponentBuilderFingerprint
import app.revanced.patches.shared.fingerprints.IdentifierFingerprint
import app.revanced.util.bytecode.getStringIndex
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.immutable.ImmutableField
import kotlin.properties.Delegates
@Name("component-parser-patch")
@RVXCompatibility
@Version("0.0.1")
class ComponentParserPatch : BytecodePatch(
listOf(
ByteBufferHookFingerprint,
EmptyComponentBuilderFingerprint,
IdentifierFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
EmptyComponentBuilderFingerprint.result?.let {
it.mutableMethod.apply {
val targetIndex = getStringIndex("Failed to convert Element to Flatbuffers: %s") + 2
val builderMethodDescriptor = getInstruction<ReferenceInstruction>(targetIndex).reference
val emptyComponentFieldDescriptor = getInstruction<ReferenceInstruction>(targetIndex + 2).reference
emptyComponentLabel = """
move-object/from16 v0, p1
invoke-static {v0}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
"""
it.mutableClass.staticFields.add(
ImmutableField(
definingClass,
"buffer",
"Ljava/nio/ByteBuffer;",
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
null,
null
).toMutable()
)
}
} ?: return EmptyComponentBuilderFingerprint.toErrorResult()
ByteBufferHookFingerprint.result?.let {
(context
.toMethodWalker(it.method)
.nextMethod(it.scanResult.patternScanResult!!.endIndex, true)
.getMethod() as MutableMethod
).apply {
val methodName = EmptyComponentBuilderFingerprint.result!!.mutableMethod.definingClass
addInstruction(
0,
"sput-object p2, $methodName->buffer:Ljava/nio/ByteBuffer;"
)
}
} ?: return ByteBufferHookFingerprint.toErrorResult()
IdentifierFingerprint.result?.let {
it.mutableMethod.apply {
insertMethod = this
val stringBuilderIndex =
implementation!!.instructions.indexOfFirst { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference
fieldReference?.let { reference -> reference.type == "Ljava/lang/StringBuilder;" } == true
}
val identifierIndex = it.scanResult.patternScanResult!!.endIndex
val objectIndex = getStringIndex("") + 1
val freeIndex = implementation!!.instructions.indexOfFirst { instruction ->
instruction.opcode == Opcode.CONST
}
stringBuilderRegister = getInstruction<TwoRegisterInstruction>(stringBuilderIndex).registerA
identifierRegister = getInstruction<OneRegisterInstruction>(identifierIndex).registerA
objectRegister = getInstruction<BuilderInstruction35c>(objectIndex).registerC
freeRegister = getInstruction<OneRegisterInstruction>(freeIndex).registerA
insertIndex = stringBuilderIndex + 1
}
} ?: return IdentifierFingerprint.toErrorResult()
return PatchResultSuccess()
}
internal companion object {
lateinit var emptyComponentLabel: String
lateinit var insertMethod: MutableMethod
var insertIndex by Delegates.notNull<Int>()
var freeRegister by Delegates.notNull<Int>()
var identifierRegister by Delegates.notNull<Int>()
var objectRegister by Delegates.notNull<Int>()
var stringBuilderRegister by Delegates.notNull<Int>()
fun generalHook(
descriptor: String
) {
insertMethod.apply {
addInstructionsWithLabels(
insertIndex, """
sget-object v$freeRegister, $definingClass->buffer:Ljava/nio/ByteBuffer;
invoke-static {v$stringBuilderRegister, v$identifierRegister, v$objectRegister, v$freeRegister}, $descriptor(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/Object;Ljava/nio/ByteBuffer;)Z
move-result v$freeRegister
if-eqz v$freeRegister, :not_an_ad
""" + emptyComponentLabel, ExternalLabel("not_an_ad", getInstruction(insertIndex))
)
}
}
fun identifierHook(
descriptor: String
) {
insertMethod.apply {
addInstructionsWithLabels(
insertIndex, """
invoke-static {v$stringBuilderRegister, v$identifierRegister}, $descriptor(Ljava/lang/StringBuilder;Ljava/lang/String;)Z
move-result v$freeRegister
if-eqz v$freeRegister, :not_an_ad
""" + emptyComponentLabel, ExternalLabel("not_an_ad", getInstruction(insertIndex))
)
}
}
fun objectHook(
descriptor: String
) {
insertMethod.apply {
addInstructionsWithLabels(
0, """
move-object/from16 v0, p2
sget-object v1, $definingClass->buffer:Ljava/nio/ByteBuffer;
invoke-static {v0, v1}, $descriptor(Ljava/lang/Object;Ljava/nio/ByteBuffer;)Z
move-result v0
if-eqz v0, :not_an_ad
""" + emptyComponentLabel, ExternalLabel("not_an_ad", getInstruction(0))
)
}
}
}
}

View File

@ -1,9 +0,0 @@
package app.revanced.patches.youtube.ads.doublebacktoclose.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.Opcode
object OnBackPressedFingerprint : MethodFingerprint(
opcodes = listOf(Opcode.RETURN_VOID),
customFingerprint = { it, _ -> it.definingClass.endsWith("WatchWhileActivity;") && it.name == "onBackPressed" }
)

View File

@ -1,19 +0,0 @@
package app.revanced.patches.youtube.ads.doublebacktoclose.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object ScrollPositionFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IF_NEZ,
Opcode.INVOKE_DIRECT,
Opcode.RETURN_VOID
),
strings = listOf("scroll_position")
)

View File

@ -1,21 +0,0 @@
package app.revanced.patches.youtube.ads.doublebacktoclose.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object ScrollTopFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.CHECK_CAST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.GOTO,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE
)
)

View File

@ -1,25 +0,0 @@
package app.revanced.patches.youtube.ads.doublebacktoclose.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object ScrollTopParentFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
opcodes = listOf(
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.IPUT_OBJECT,
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID
),
customFingerprint = { it, _ -> it.name == "<init>"}
)

View File

@ -1,92 +0,0 @@
package app.revanced.patches.youtube.ads.doublebacktoclose.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.ads.gestures.PredictiveBackGesturePatch
import app.revanced.patches.youtube.ads.doublebacktoclose.fingerprint.*
import app.revanced.util.integrations.Constants.UTILS_PATH
@Name("double-back-to-close")
@DependsOn([PredictiveBackGesturePatch::class])
@YouTubeCompatibility
@Version("0.0.1")
class DoubleBackToClosePatch : BytecodePatch(
listOf(
OnBackPressedFingerprint,
ScrollPositionFingerprint,
ScrollTopParentFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
/**
* Hook onBackPressed method inside WatchWhileActivity
*/
OnBackPressedFingerprint.result?.let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
addInstruction(
insertIndex,
"invoke-static {p0}, $INTEGRATIONS_CLASS_DESCRIPTOR" +
"->" +
"closeActivityOnBackPressed(Landroid/app/Activity;)V"
)
}
} ?: return OnBackPressedFingerprint.toErrorResult()
/**
* Inject the methods which start of ScrollView
*/
ScrollPositionFingerprint.result?.let {
val insertMethod = context.toMethodWalker(it.method)
.nextMethod(it.scanResult.patternScanResult!!.startIndex + 1, true)
.getMethod() as MutableMethod
val insertIndex = insertMethod.implementation!!.instructions.size - 1 - 1
insertMethod.injectScrollView(insertIndex, "onStartScrollView")
} ?: return ScrollPositionFingerprint.toErrorResult()
/**Inject the methods which stop of ScrollView
*/
ScrollTopParentFingerprint.result?.let { parentResult ->
ScrollTopFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val insertMethod = it.mutableMethod
val insertIndex = it.scanResult.patternScanResult!!.endIndex
insertMethod.injectScrollView(insertIndex, "onStopScrollView")
} ?: return ScrollTopFingerprint.toErrorResult()
} ?: return ScrollTopParentFingerprint.toErrorResult()
return PatchResultSuccess()
}
private companion object {
const val INTEGRATIONS_CLASS_DESCRIPTOR =
"$UTILS_PATH/DoubleBackToClosePatch;"
fun MutableMethod.injectScrollView(
index: Int,
descriptor: String
) {
addInstruction(
index,
"invoke-static {}, $INTEGRATIONS_CLASS_DESCRIPTOR->$descriptor()V"
)
}
}
}

View File

@ -32,7 +32,7 @@ class GeneralAdsBytecodePatch : BytecodePatch() {
.mutableClass
.findMutableMethodOf(method)
.apply {
val insertIndex = method.getWideLiteralIndex(AdAttribution) + 1
val insertIndex = getWideLiteralIndex(AdAttribution) + 1
if (getInstruction(insertIndex).opcode != org.jf.dexlib2.Opcode.INVOKE_VIRTUAL)
return@forEach

View File

@ -14,8 +14,9 @@ import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.ads.general.bytecode.patch.GeneralAdsBytecodePatch
import app.revanced.patches.youtube.ads.getpremium.patch.HideGetPremiumPatch
import app.revanced.patches.youtube.misc.litho.patch.ByteBufferFilterPatch
import app.revanced.patches.youtube.utils.litho.patch.LithoFilterPatch
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
import app.revanced.util.resources.ResourceUtils.copyXmlNode
import org.w3c.dom.Element
@Patch
@ -23,9 +24,9 @@ import org.w3c.dom.Element
@Description("Removes general ads.")
@DependsOn(
[
ByteBufferFilterPatch::class,
GeneralAdsBytecodePatch::class,
HideGetPremiumPatch::class,
LithoFilterPatch::class,
SettingsPatch::class
]
)
@ -84,6 +85,11 @@ class GeneralAdsPatch : ResourcePatch {
}
}
/**
* Copy arrays
*/
context.copyXmlNode("youtube/doubleback/host", "values/arrays.xml", "resources")
/*
* Add settings
*/

View File

@ -1,35 +0,0 @@
package app.revanced.patches.youtube.ads.gestures
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
@Name("predictive-back-gesture")
@Description("Enables the predictive back gesture introduced on Android 13.")
@Version("0.0.1")
class PredictiveBackGesturePatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
context.xmlEditor["AndroidManifest.xml"].use { editor ->
val document = editor.file
with(document.getElementsByTagName("application").item(0)) {
if (attributes.getNamedItem(FLAG) != null) return@with
document.createAttribute(FLAG)
.apply { value = "false" }
.let(attributes::setNamedItem)
}
}
return PatchResultSuccess()
}
private companion object {
const val FLAG = "android:enableOnBackInvokedCallback"
}
}

View File

@ -1,19 +0,0 @@
package app.revanced.patches.youtube.ads.swiperefresh.fingerprint
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object SwipeRefreshLayoutFingerprint : MethodFingerprint(
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.RETURN,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.RETURN
),
customFingerprint = { it, _ -> it.definingClass.endsWith("SwipeRefreshLayout;") }
)

View File

@ -1,40 +0,0 @@
package app.revanced.patches.youtube.ads.swiperefresh.patch
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.ads.swiperefresh.fingerprint.SwipeRefreshLayoutFingerprint
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.extensions.toErrorResult
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("enable-swipe-refresh")
@Description("Enable swipe refresh.")
@YouTubeCompatibility
@Version("0.0.1")
class SwipeRefreshPatch : BytecodePatch(
listOf(SwipeRefreshLayoutFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
SwipeRefreshLayoutFingerprint.result?.let {
it.mutableMethod.apply {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
addInstruction(
insertIndex,
"const/4 v$register, 0x0"
)
}
} ?: return SwipeRefreshLayoutFingerprint.toErrorResult()
return PatchResultSuccess()
}
}

View File

@ -10,7 +10,8 @@ import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.misc.litho.patch.ByteBufferFilterPatch
import app.revanced.patches.shared.patch.litho.ComponentParserPatch.Companion.objectHook
import app.revanced.patches.youtube.utils.litho.patch.LithoFilterPatch
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
import app.revanced.util.integrations.Constants.BOTTOM_PLAYER
@ -19,7 +20,7 @@ import app.revanced.util.integrations.Constants.BOTTOM_PLAYER
@Description("Adds the options to hide action buttons under a video.")
@DependsOn(
[
ByteBufferFilterPatch::class,
LithoFilterPatch::class,
SettingsPatch::class
]
)
@ -28,7 +29,7 @@ import app.revanced.util.integrations.Constants.BOTTOM_PLAYER
class ButtonContainerPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
ByteBufferFilterPatch.inject("$BOTTOM_PLAYER->hideActionButtons")
objectHook("$BOTTOM_PLAYER->hideActionButton")
/**
* Add settings

View File

@ -7,7 +7,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.youtube.misc.litho.patch.LithoThemePatch
import app.revanced.patches.youtube.utils.litho.patch.LithoThemePatch
import app.revanced.util.integrations.Constants.UTILS_PATH
import org.w3c.dom.Element

View File

@ -1,50 +0,0 @@
package app.revanced.patches.youtube.misc.litho.patch
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.ResourceContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.utils.playertype.patch.PlayerTypeHookPatch
@DependsOn(
[
LithoFilterPatch::class,
PlayerTypeHookPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class ByteBufferFilterPatch : ResourcePatch {
override fun execute(context: ResourceContext): PatchResult {
return PatchResultSuccess()
}
companion object{
fun inject(descriptor: String){
LithoFilterPatch.lithoMethod.addInstructionsWithLabels(
0, """
move-object/from16 v10, p3
iget-object v10, v10, ${LithoFilterPatch.objectReference}
if-eqz v10, :do_not_block
check-cast v10, ${LithoFilterPatch.bufferReference}
iget-object v10, v10, ${LithoFilterPatch.bufferReference}->b:Ljava/nio/ByteBuffer;
move-object/from16 v3, p2
invoke-static {v3, v10}, $descriptor(Ljava/lang/Object;Ljava/nio/ByteBuffer;)Z
move-result v10
if-eqz v10, :do_not_block
move-object/from16 v15, p1
invoke-static {v15}, ${LithoFilterPatch.builderMethodDescriptor}
move-result-object v0
iget-object v0, v0, ${LithoFilterPatch.emptyComponentFieldDescriptor}
return-object v0
""", ExternalLabel("do_not_block", LithoFilterPatch.lithoMethod.getInstruction(0))
)
}
}
}

View File

@ -1,116 +0,0 @@
package app.revanced.patches.youtube.misc.litho.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.fingerprints.LithoBufferFingerprint
import app.revanced.patches.shared.fingerprints.LithoFingerprint
import app.revanced.patches.shared.fingerprints.LithoObjectFingerprint
import app.revanced.patches.youtube.ads.doublebacktoclose.patch.DoubleBackToClosePatch
import app.revanced.patches.youtube.ads.swiperefresh.patch.SwipeRefreshPatch
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus
import app.revanced.util.bytecode.getNarrowLiteralIndex
import app.revanced.util.bytecode.getStringIndex
import app.revanced.util.integrations.Constants.ADS_PATH
import org.jf.dexlib2.builder.instruction.BuilderInstruction35c
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.Reference
import kotlin.properties.Delegates
@DependsOn(
[
DoubleBackToClosePatch::class,
SwipeRefreshPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class LithoFilterPatch : BytecodePatch(
listOf(
LithoFingerprint,
LithoBufferFingerprint,
LithoObjectFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult {
LithoBufferFingerprint.result?.let {
val startIndex = it.scanResult.patternScanResult!!.startIndex
bufferReference = it.mutableMethod.getInstruction<ReferenceInstruction>(startIndex).reference
} ?: return LithoBufferFingerprint.toErrorResult()
LithoObjectFingerprint.result?.let {
val endIndex = it.scanResult.patternScanResult!!.endIndex
objectRegister = it.mutableMethod.getInstruction<BuilderInstruction35c>(endIndex).registerC
} ?: return LithoObjectFingerprint.toErrorResult()
LithoFingerprint.result?.let { result ->
val endIndex = result.scanResult.patternScanResult!!.endIndex
lithoMethod = result.mutableMethod
lithoMethod.apply {
val bufferIndex = getNarrowLiteralIndex(168777401)
val bufferRegister = getInstruction<OneRegisterInstruction>(bufferIndex).registerA
val targetIndex = getStringIndex("Element missing type extension") + 2
val identifierRegister = getInstruction<OneRegisterInstruction>(endIndex).registerA
builderMethodDescriptor = getInstruction<ReferenceInstruction>(targetIndex).reference
emptyComponentFieldDescriptor = getInstruction<ReferenceInstruction>(targetIndex + 2).reference
implementation!!.instructions.apply {
filter { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? FieldReference
fieldReference?.let { it.type == "Ljava/lang/StringBuilder;" } == true
}.forEach { instruction ->
val insertIndex = indexOf(instruction)
val stringBuilderRegister = lithoMethod.getInstruction<TwoRegisterInstruction>(insertIndex).registerA
val objectIndex = lithoMethod.getStringIndex("") - 2
objectReference = lithoMethod.getInstruction<ReferenceInstruction>(objectIndex).reference
lithoMethod.addInstructionsWithLabels(
insertIndex + 1, """
move-object/from16 v$bufferRegister, p3
iget-object v$bufferRegister, v$bufferRegister, $objectReference
if-eqz v$bufferRegister, :not_an_ad
check-cast v$bufferRegister, $bufferReference
iget-object v$bufferRegister, v$bufferRegister, $bufferReference->b:Ljava/nio/ByteBuffer;
invoke-static {v$stringBuilderRegister, v$identifierRegister, v$objectRegister, v$bufferRegister}, $ADS_PATH/LithoFilterPatch;->filters(Ljava/lang/StringBuilder;Ljava/lang/String;Ljava/lang/Object;Ljava/nio/ByteBuffer;)Z
move-result v$bufferRegister
if-eqz v$bufferRegister, :not_an_ad
move-object/from16 v$identifierRegister, p1
invoke-static {v$identifierRegister}, $builderMethodDescriptor
move-result-object v0
iget-object v0, v0, $emptyComponentFieldDescriptor
return-object v0
""", ExternalLabel("not_an_ad", lithoMethod.getInstruction(insertIndex + 1))
)
}
}
}
} ?: return LithoFingerprint.toErrorResult()
context.updatePatchStatus("ByteBuffer")
return PatchResultSuccess()
}
internal companion object {
var objectRegister by Delegates.notNull<Int>()
lateinit var lithoMethod: MutableMethod
lateinit var bufferReference: Reference
lateinit var builderMethodDescriptor: Reference
lateinit var emptyComponentFieldDescriptor: Reference
lateinit var objectReference: Reference
}
}

View File

@ -14,7 +14,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.player.suggestactions.fingerprints.SuggestedActionsFingerprint
import app.revanced.patches.youtube.misc.litho.patch.LithoFilterPatch
import app.revanced.patches.youtube.utils.litho.patch.LithoFilterPatch
import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.settings.resource.patch.SettingsPatch
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction

View File

@ -19,7 +19,7 @@ import app.revanced.patches.shared.fingerprints.ControlsOverlayStyleFingerprint
import app.revanced.patches.youtube.seekbar.seekbarcolor.bytecode.fingerprints.ProgressColorFingerprint
import app.revanced.patches.youtube.seekbar.seekbarcolor.bytecode.fingerprints.SeekbarColorFingerprint
import app.revanced.patches.youtube.seekbar.seekbarcolor.resource.patch.SeekbarColorResourcePatch
import app.revanced.patches.youtube.misc.litho.patch.LithoThemePatch
import app.revanced.patches.youtube.utils.litho.patch.LithoThemePatch
import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch.Companion.InlineTimeBarColorizedBarPlayedColorDark
import app.revanced.patches.youtube.utils.resourceid.patch.SharedResourceIdPatch.Companion.InlineTimeBarPlayedNotHighlightedColor
@ -48,9 +48,11 @@ class SeekbarColorPatch : BytecodePatch(
)
) {
override fun execute(context: BytecodeContext): PatchResult {
SeekbarColorFingerprint.result?.mutableMethod?.let {
it.hook(it.getWideLiteralIndex(InlineTimeBarColorizedBarPlayedColorDark) + 2)
it.hook(it.getWideLiteralIndex(InlineTimeBarPlayedNotHighlightedColor) + 2)
SeekbarColorFingerprint.result?.let {
it.mutableMethod.apply {
hook(getWideLiteralIndex(InlineTimeBarColorizedBarPlayedColorDark) + 2)
hook(getWideLiteralIndex(InlineTimeBarPlayedNotHighlightedColor) + 2)
}
} ?: return SeekbarColorFingerprint.toErrorResult()
ControlsOverlayStyleFingerprint.result?.let { parentResult ->

View File

@ -0,0 +1,25 @@
package app.revanced.patches.youtube.utils.litho.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
object ByteBufferFingerprint : MethodFingerprint(
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L","L"),
opcodes = listOf(
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.ADD_INT_2ADDR,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID
)
)

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.misc.litho.fingerprints
package app.revanced.patches.youtube.utils.litho.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint

View File

@ -0,0 +1,46 @@
package app.revanced.patches.youtube.utils.litho.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.litho.ComponentParserPatch
import app.revanced.patches.shared.patch.litho.ComponentParserPatch.Companion.generalHook
import app.revanced.patches.youtube.utils.fix.doublebacktoclose.patch.DoubleBackToClosePatch
import app.revanced.patches.youtube.utils.fix.swiperefresh.patch.SwipeRefreshPatch
import app.revanced.patches.youtube.utils.litho.fingerprints.ByteBufferFingerprint
import app.revanced.patches.youtube.utils.playertype.patch.PlayerTypeHookPatch
import app.revanced.util.integrations.Constants.ADS_PATH
@DependsOn(
[
ComponentParserPatch::class,
DoubleBackToClosePatch::class,
PlayerTypeHookPatch::class,
SwipeRefreshPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class LithoFilterPatch : BytecodePatch(
listOf(ByteBufferFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
ByteBufferFingerprint.result?.mutableMethod?.addInstruction(
0,
"sput-object p0, $ADS_PATH/ByteBufferFilterPatch;->bytebuffer:Ljava/nio/ByteBuffer;"
) ?: return ByteBufferFingerprint.toErrorResult()
generalHook("$ADS_PATH/LithoFilterPatch;->filters")
return PatchResultSuccess()
}
}

View File

@ -1,4 +1,4 @@
package app.revanced.patches.youtube.misc.litho.patch
package app.revanced.patches.youtube.utils.litho.patch
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Name
@ -10,7 +10,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.misc.litho.fingerprints.LithoThemeFingerprint
import app.revanced.patches.youtube.utils.litho.fingerprints.LithoThemeFingerprint
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
import org.jf.dexlib2.iface.reference.MethodReference

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="revanced_double_back_timeout_entry">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
<string-array name="revanced_double_back_timeout_value">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>