mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-13 05:37:40 +02:00
cleanup
This commit is contained in:
@ -101,7 +101,7 @@ class EnforceShufflePatch : BytecodePatch(
|
|||||||
ImmutableField(
|
ImmutableField(
|
||||||
mutableMethod.definingClass,
|
mutableMethod.definingClass,
|
||||||
"shuffleclass",
|
"shuffleclass",
|
||||||
"$SHUFFLE_CLASS",
|
SHUFFLE_CLASS,
|
||||||
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
@ -38,6 +38,7 @@ class GeneralAdsPatch : ResourcePatch {
|
|||||||
"promotion_",
|
"promotion_",
|
||||||
"compact_premium_",
|
"compact_premium_",
|
||||||
"compact_promoted_",
|
"compact_promoted_",
|
||||||
|
"simple_text_section",
|
||||||
)
|
)
|
||||||
|
|
||||||
private val replacements = arrayOf(
|
private val replacements = arrayOf(
|
||||||
@ -46,6 +47,13 @@ class GeneralAdsPatch : ResourcePatch {
|
|||||||
"marginTop"
|
"marginTop"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val additionalReplacements = arrayOf(
|
||||||
|
"Bottom",
|
||||||
|
"End",
|
||||||
|
"Start",
|
||||||
|
"Top"
|
||||||
|
)
|
||||||
|
|
||||||
override fun execute(context: ResourceContext): PatchResult {
|
override fun execute(context: ResourceContext): PatchResult {
|
||||||
context.forEach {
|
context.forEach {
|
||||||
|
|
||||||
@ -53,11 +61,11 @@ class GeneralAdsPatch : ResourcePatch {
|
|||||||
|
|
||||||
// for each file in the "layouts" directory replace all necessary attributes content
|
// for each file in the "layouts" directory replace all necessary attributes content
|
||||||
context.xmlEditor[it.absolutePath].use { editor ->
|
context.xmlEditor[it.absolutePath].use { editor ->
|
||||||
editor.file.doRecursively { node ->
|
editor.file.doRecursively {
|
||||||
replacements.forEach replacement@{ replacement ->
|
replacements.forEach replacement@{ replacement ->
|
||||||
if (node !is Element) return@replacement
|
if (it !is Element) return@replacement
|
||||||
|
|
||||||
node.getAttributeNode("android:layout_$replacement")?.let { attribute ->
|
it.getAttributeNode("android:layout_$replacement")?.let { attribute ->
|
||||||
attribute.textContent = "0.0dip"
|
attribute.textContent = "0.0dip"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,6 +73,18 @@ class GeneralAdsPatch : ResourcePatch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.xmlEditor["res/layout/simple_text_section.xml"].use { editor ->
|
||||||
|
editor.file.doRecursively {
|
||||||
|
additionalReplacements.forEach replacement@{ replacement ->
|
||||||
|
if (it !is Element) return@replacement
|
||||||
|
|
||||||
|
it.getAttributeNode("android:padding_$replacement")?.let { attribute ->
|
||||||
|
attribute.textContent = "0.0dip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
add settings
|
add settings
|
||||||
*/
|
*/
|
||||||
|
@ -4,18 +4,18 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
import app.revanced.patcher.extensions.addInstruction
|
||||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
|
|
||||||
import app.revanced.patcher.extensions.or
|
import app.revanced.patcher.extensions.or
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patcher.util.smali.toInstructions
|
import app.revanced.patcher.util.smali.toInstructions
|
||||||
import app.revanced.patches.youtube.button.whitelist.fingerprint.*
|
import app.revanced.patches.youtube.button.whitelist.fingerprint.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
|
||||||
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
|
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
@ -23,7 +23,6 @@ import org.jf.dexlib2.iface.reference.FieldReference
|
|||||||
import org.jf.dexlib2.iface.reference.MethodReference
|
import org.jf.dexlib2.iface.reference.MethodReference
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
import org.jf.dexlib2.immutable.ImmutableMethodImplementation
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("channel-whitelist")
|
@Name("channel-whitelist")
|
||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@ -37,34 +36,67 @@ class WhitelistPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val PlayerResponseModelParentResult = PlayerResponseModelParentFingerprint.result!!
|
|
||||||
val PlayerResponseModelParentInstructions = PlayerResponseModelParentResult.mutableMethod.implementation!!.instructions
|
|
||||||
|
|
||||||
val injectIndex = PlayerResponseModelParentInstructions.indexOfFirst {
|
PlayerResponseModelParentFingerprint.result?.mutableMethod?.let { method ->
|
||||||
it.opcode == Opcode.CONST_STRING &&
|
val instructions = method.implementation!!.instructions
|
||||||
(it as BuilderInstruction21c).reference.toString() == "Person"
|
val injectIndex = instructions.indexOfFirst {
|
||||||
} + 2
|
it.opcode == Opcode.CONST_STRING &&
|
||||||
|
(it as BuilderInstruction21c).reference.toString() == "Person"
|
||||||
|
} + 2
|
||||||
|
fourthRef = (instructions.elementAt(injectIndex) as ReferenceInstruction).reference as DexBackedMethodReference
|
||||||
|
} ?: return PlayerResponseModelParentFingerprint.toErrorResult()
|
||||||
|
|
||||||
val PlayerResponseModelReference =
|
PlayerResponseModelFingerprint.result?.let { result ->
|
||||||
PlayerResponseModelParentResult.method.let { method ->
|
|
||||||
(method.implementation!!.instructions.elementAt(injectIndex) as ReferenceInstruction).reference as DexBackedMethodReference
|
with (result.method.implementation!!.instructions) {
|
||||||
|
firstRef = (elementAt(2) as ReferenceInstruction).reference as FieldReference
|
||||||
|
secondRef = (elementAt(3) as ReferenceInstruction).reference as FieldReference
|
||||||
|
thirdRef = (elementAt(4) as ReferenceInstruction).reference as MethodReference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with (result.mutableClass) {
|
||||||
|
methods.add(
|
||||||
|
ImmutableMethod(
|
||||||
|
type,
|
||||||
|
"setCurrentVideoInformation",
|
||||||
|
listOf(),
|
||||||
|
"V",
|
||||||
|
AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
ImmutableMethodImplementation(
|
||||||
|
2, """
|
||||||
|
iget-object v0, v1, ${result.classDef.type}->${firstRef.name}:${firstRef.type}
|
||||||
|
iget-object v0, v0, ${firstRef.type}->${secondRef.name}:${secondRef.type}
|
||||||
|
invoke-interface {v0}, $thirdRef
|
||||||
|
move-result-object v0
|
||||||
|
invoke-interface {v0}, $fourthRef
|
||||||
|
move-result-object v0
|
||||||
|
invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V
|
||||||
|
return-void
|
||||||
|
""".toInstructions(), null, null
|
||||||
|
)
|
||||||
|
).toMutable()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(
|
||||||
|
PrimaryInjectFingerprint,
|
||||||
|
SecondaryInjectFingerprint
|
||||||
|
).map {
|
||||||
|
it.result ?: return it.toErrorResult()
|
||||||
|
}.forEach {
|
||||||
|
val method = it.mutableMethod
|
||||||
|
val index = it.scanResult.patternScanResult!!.endIndex + 1
|
||||||
|
method.addInstruction(
|
||||||
|
index,
|
||||||
|
"invoke-direct {p0}, ${result.classDef.type}->setCurrentVideoInformation()V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return PlayerResponseModelFingerprint.toErrorResult()
|
||||||
|
|
||||||
val PlayerResponseModelResult = PlayerResponseModelFingerprint.result!!
|
val PlayerResponseModelResult = PlayerResponseModelFingerprint.result!!
|
||||||
|
|
||||||
val PrimaryReference =
|
|
||||||
PlayerResponseModelResult.method.let { method ->
|
|
||||||
(method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as FieldReference
|
|
||||||
}
|
|
||||||
val SecondaryReference =
|
|
||||||
PlayerResponseModelResult.method.let { method ->
|
|
||||||
(method.implementation!!.instructions.elementAt(3) as ReferenceInstruction).reference as FieldReference
|
|
||||||
}
|
|
||||||
val TertiaryReference =
|
|
||||||
PlayerResponseModelResult.method.let { method ->
|
|
||||||
(method.implementation!!.instructions.elementAt(4) as ReferenceInstruction).reference as MethodReference
|
|
||||||
}
|
|
||||||
|
|
||||||
val classDef = PlayerResponseModelResult.mutableClass
|
val classDef = PlayerResponseModelResult.mutableClass
|
||||||
classDef.methods.add(
|
classDef.methods.add(
|
||||||
ImmutableMethod(
|
ImmutableMethod(
|
||||||
@ -77,11 +109,11 @@ class WhitelistPatch : BytecodePatch(
|
|||||||
null,
|
null,
|
||||||
ImmutableMethodImplementation(
|
ImmutableMethodImplementation(
|
||||||
2, """
|
2, """
|
||||||
iget-object v0, v1, ${PlayerResponseModelResult.classDef.type}->${PrimaryReference.name}:${PrimaryReference.type}
|
iget-object v0, v1, ${PlayerResponseModelResult.classDef.type}->${firstRef.name}:${firstRef.type}
|
||||||
iget-object v0, v0, ${PrimaryReference.type}->${SecondaryReference.name}:${SecondaryReference.type}
|
iget-object v0, v0, ${firstRef.type}->${secondRef.name}:${secondRef.type}
|
||||||
invoke-interface {v0}, $TertiaryReference
|
invoke-interface {v0}, $thirdRef
|
||||||
move-result-object v0
|
move-result-object v0
|
||||||
invoke-interface {v0}, $PlayerResponseModelReference
|
invoke-interface {v0}, $fourthRef
|
||||||
move-result-object v0
|
move-result-object v0
|
||||||
invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V
|
invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V
|
||||||
return-void
|
return-void
|
||||||
@ -90,20 +122,13 @@ class WhitelistPatch : BytecodePatch(
|
|||||||
).toMutable()
|
).toMutable()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
listOf(
|
|
||||||
PrimaryInjectFingerprint,
|
|
||||||
SecondaryInjectFingerprint
|
|
||||||
).forEach { fingerprint ->
|
|
||||||
val result = fingerprint.result ?: return PatchResultError("${fingerprint.name} not found")
|
|
||||||
val method = result.mutableMethod
|
|
||||||
val index = result.scanResult.patternScanResult!!.endIndex + 1
|
|
||||||
method.addInstruction(
|
|
||||||
index,
|
|
||||||
"invoke-direct {p0}, ${PlayerResponseModelResult.classDef.type}->setCurrentVideoInformation()V"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private lateinit var firstRef: FieldReference
|
||||||
|
private lateinit var secondRef: FieldReference
|
||||||
|
private lateinit var thirdRef: MethodReference
|
||||||
|
private lateinit var fourthRef: DexBackedMethodReference
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object LayoutSwitchFingerprint : MethodFingerprint(
|
object LayoutSwitchFingerprint : MethodFingerprint(
|
||||||
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
returnType = "I",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
|
@ -9,6 +9,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints.LayoutSwitchFingerprint
|
import app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints.LayoutSwitchFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
|
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
|
||||||
|
|
||||||
@Name("layout-switch-bytecode-patch")
|
@Name("layout-switch-bytecode-patch")
|
||||||
@ -21,12 +22,12 @@ class LayoutSwitchBytecodePatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
|
||||||
LayoutSwitchFingerprint.result!!.mutableMethod.addInstructions(
|
LayoutSwitchFingerprint.result?.mutableMethod?.addInstructions(
|
||||||
4, """
|
4, """
|
||||||
invoke-static {p0}, $EXTENDED_PATH/LayoutOverridePatch;->getLayoutOverride(I)I
|
invoke-static {p0}, $EXTENDED_PATH/LayoutOverridePatch;->getLayoutOverride(I)I
|
||||||
move-result p0
|
move-result p0
|
||||||
"""
|
"""
|
||||||
)
|
) ?: return LayoutSwitchFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object OldLayoutFingerprint : MethodFingerprint(
|
object OldLayoutFingerprint : MethodFingerprint(
|
||||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
returnType = "L",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.GOTO,
|
Opcode.GOTO,
|
||||||
Opcode.CONST_STRING,
|
Opcode.CONST_STRING,
|
||||||
|
@ -9,6 +9,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints.OldLayoutFingerprint
|
import app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints.OldLayoutFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
|
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@ -22,17 +23,19 @@ class OldLayoutBytecodePatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
|
||||||
val result = OldLayoutFingerprint.result!!
|
OldLayoutFingerprint.result?.let {
|
||||||
val method = result.mutableMethod
|
val insertIndex = it.scanResult.patternScanResult!!.startIndex
|
||||||
val index = result.scanResult.patternScanResult!!.startIndex
|
|
||||||
val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
method.addInstructions(
|
with (it.mutableMethod) {
|
||||||
index + 1, """
|
val register = (this.implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA
|
||||||
invoke-static {v$register}, $EXTENDED_PATH/VersionOverridePatch;->getVersionOverride(Ljava/lang/String;)Ljava/lang/String;
|
addInstructions(
|
||||||
move-result-object v$register
|
insertIndex + 1, """
|
||||||
"""
|
invoke-static {v$register}, $EXTENDED_PATH/VersionOverridePatch;->getVersionOverride(Ljava/lang/String;)Ljava/lang/String;
|
||||||
)
|
move-result-object v$register
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return OldLayoutFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import org.jf.dexlib2.Opcode
|
|||||||
object QualityMenuViewInflateFingerprint : MethodFingerprint(
|
object QualityMenuViewInflateFingerprint : MethodFingerprint(
|
||||||
opcodes = listOf(Opcode.INVOKE_SUPER),
|
opcodes = listOf(Opcode.INVOKE_SUPER),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.videoqualityfragmentLabelId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.videoqualityfragmentLabelId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -3,12 +3,13 @@ package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecod
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints.QualityMenuViewInflateFingerprint
|
import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints.QualityMenuViewInflateFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.FLYOUTPANEL_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.FLYOUTPANEL_LAYOUT
|
||||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
|
|
||||||
@ -19,21 +20,18 @@ class OldQualityLayoutBytecodePatch : BytecodePatch(
|
|||||||
listOf(QualityMenuViewInflateFingerprint)
|
listOf(QualityMenuViewInflateFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!!
|
|
||||||
val method = inflateFingerprintResult.mutableMethod
|
|
||||||
val instructions = method.implementation!!.instructions
|
|
||||||
|
|
||||||
// at this index the listener is added to the list view
|
QualityMenuViewInflateFingerprint.result?.mutableMethod?.let {
|
||||||
val listenerInvokeRegister = instructions.size - 1 - 1
|
with (it.implementation!!.instructions) {
|
||||||
|
val insertIndex = this.size - 1 - 1
|
||||||
|
val register = (this[insertIndex] as FiveRegisterInstruction).registerC
|
||||||
|
|
||||||
// get the register which stores the quality menu list view
|
it.addInstructions(
|
||||||
val onItemClickViewRegister = (instructions[listenerInvokeRegister] as FiveRegisterInstruction).registerC
|
insertIndex, // insert the integrations instructions right before the listener
|
||||||
|
"invoke-static { v$register }, $FLYOUTPANEL_LAYOUT->enableOldQualityMenu(Landroid/widget/ListView;)V"
|
||||||
// insert the integrations method
|
)
|
||||||
method.addInstruction(
|
}
|
||||||
listenerInvokeRegister, // insert the integrations instructions right before the listener
|
} ?: return QualityMenuViewInflateFingerprint.toErrorResult()
|
||||||
"invoke-static { v$onItemClickViewRegister }, $FLYOUTPANEL_LAYOUT->enableOldQualityMenu(Landroid/widget/ListView;)V"
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -8,9 +8,9 @@ import org.jf.dexlib2.Opcode
|
|||||||
object ScrubbingLabelFingerprint : MethodFingerprint(
|
object ScrubbingLabelFingerprint : MethodFingerprint(
|
||||||
opcodes = listOf(Opcode.IPUT_BOOLEAN),
|
opcodes = listOf(Opcode.IPUT_BOOLEAN),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.scrubbingLabelId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.scrubbingLabelId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -7,14 +7,16 @@ import app.revanced.patcher.extensions.addInstructions
|
|||||||
import app.revanced.patcher.extensions.removeInstruction
|
import app.revanced.patcher.extensions.removeInstruction
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
|
import app.revanced.patcher.patch.PatchResultError
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints.ScrubbingLabelFingerprint
|
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints.ScrubbingLabelFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
||||||
|
import org.jf.dexlib2.Opcode
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
import org.jf.dexlib2.Opcode
|
|
||||||
|
|
||||||
@Name("hide-filmstrip-overlay-bytecode-patch")
|
@Name("hide-filmstrip-overlay-bytecode-patch")
|
||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@ -25,32 +27,33 @@ class HideFilmstripOverlayBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val scrubbingLabelResult = ScrubbingLabelFingerprint.result!!
|
ScrubbingLabelFingerprint.result?.mutableMethod?.let {
|
||||||
val scrubbingLabelMethod = scrubbingLabelResult.mutableMethod
|
with (it.implementation!!.instructions) {
|
||||||
val scrubbingLabelMethodInstructions = scrubbingLabelMethod.implementation!!.instructions
|
for ((index, instruction) in this.withIndex()) {
|
||||||
|
if (instruction.opcode != Opcode.IPUT_BOOLEAN) continue
|
||||||
|
val primaryRegister = (instruction as TwoRegisterInstruction).registerA
|
||||||
|
val secondaryRegister = (instruction as TwoRegisterInstruction).registerB
|
||||||
|
val dummyRegister = primaryRegister + 2
|
||||||
|
val fieldReference = (instruction as ReferenceInstruction).reference as FieldReference
|
||||||
|
|
||||||
for ((index, instruction) in scrubbingLabelMethodInstructions.withIndex()) {
|
it.addInstructions(
|
||||||
if (instruction.opcode != Opcode.IPUT_BOOLEAN) continue
|
index + 1, """
|
||||||
val scrubbingLabelRegisterA = (instruction as TwoRegisterInstruction).registerA
|
invoke-static {}, $FULLSCREEN_LAYOUT->hideFilmstripOverlay()Z
|
||||||
val scrubbingLabelRegisterB = scrubbingLabelRegisterA + 2
|
move-result v$dummyRegister
|
||||||
val scrubbingLabelRegisterC = (instruction as TwoRegisterInstruction).registerB
|
if-eqz v$dummyRegister, :show
|
||||||
val scrubbingLabelReference = (instruction as ReferenceInstruction).reference as FieldReference
|
const/4 v$primaryRegister, 0x0
|
||||||
|
:show
|
||||||
|
iput-boolean v$primaryRegister, v$secondaryRegister, ${fieldReference.definingClass}->${fieldReference.name}:${fieldReference.type}
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
scrubbingLabelMethod.addInstructions(
|
it.removeInstruction(index)
|
||||||
index + 1, """
|
|
||||||
invoke-static {}, $FULLSCREEN_LAYOUT->hideFilmstripOverlay()Z
|
|
||||||
move-result v$scrubbingLabelRegisterB
|
|
||||||
if-eqz v$scrubbingLabelRegisterB, :show
|
|
||||||
const/4 v$scrubbingLabelRegisterA, 0x0
|
|
||||||
:show
|
|
||||||
iput-boolean v$scrubbingLabelRegisterA, v$scrubbingLabelRegisterC, ${scrubbingLabelReference.definingClass}->${scrubbingLabelReference.name}:${scrubbingLabelReference.type}
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
scrubbingLabelMethod.removeInstruction(index)
|
return PatchResultSuccess()
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
|
} ?: return ScrubbingLabelFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultError("Could not find the method to hook.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,13 +6,14 @@ import app.revanced.patcher.data.BytecodeContext
|
|||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.extensions.instruction
|
import app.revanced.patcher.extensions.instruction
|
||||||
import app.revanced.patcher.extensions.removeInstruction
|
import app.revanced.patcher.extensions.removeInstruction
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints.*
|
import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@ -29,27 +30,36 @@ class HapticFeedBackBytecodePatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
|
||||||
SeekHapticsFingerprint.disableHaptics("disableSeekVibrate")
|
arrayOf(
|
||||||
ScrubbingHapticsFingerprint.voidHaptics("disableScrubbingVibrate")
|
SeekHapticsFingerprint to "disableSeekVibrate",
|
||||||
MarkerHapticsFingerprint.voidHaptics("disableChapterVibrate")
|
ScrubbingHapticsFingerprint to "disableScrubbingVibrate",
|
||||||
ZoomHapticsFingerprint.voidHaptics("disableZoomVibrate")
|
MarkerHapticsFingerprint to "disableChapterVibrate",
|
||||||
|
ZoomHapticsFingerprint to "disableZoomVibrate"
|
||||||
|
).map { (fingerprint, name) ->
|
||||||
|
fingerprint.result?.let {
|
||||||
|
if (fingerprint == SeekHapticsFingerprint)
|
||||||
|
it.disableHaptics(name)
|
||||||
|
else
|
||||||
|
it.voidHaptics(name)
|
||||||
|
} ?: return fingerprint.toErrorResult()
|
||||||
|
}
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
fun MethodFingerprint.disableHaptics(targetMethodName: String) {
|
fun MethodFingerprintResult.disableHaptics(targetMethodName: String) {
|
||||||
with(this.result!!) {
|
val startIndex = scanResult.patternScanResult!!.startIndex
|
||||||
val startIndex = scanResult.patternScanResult!!.startIndex
|
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
val insertIndex = endIndex + 4
|
||||||
val insertIndex = endIndex + 4
|
val targetRegister = (method.implementation!!.instructions.elementAt(insertIndex) as OneRegisterInstruction).registerA
|
||||||
val targetRegister = (method.implementation!!.instructions.elementAt(insertIndex) as OneRegisterInstruction).registerA
|
val dummyRegister = targetRegister + 1
|
||||||
val dummyRegister = targetRegister + 1
|
|
||||||
|
|
||||||
mutableMethod.removeInstruction(insertIndex)
|
with (mutableMethod) {
|
||||||
|
removeInstruction(insertIndex)
|
||||||
|
|
||||||
mutableMethod.addInstructions(
|
addInstructions(
|
||||||
insertIndex, """
|
insertIndex, """
|
||||||
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
||||||
move-result v$dummyRegister
|
move-result v$dummyRegister
|
||||||
if-eqz v$dummyRegister, :vibrate
|
if-eqz v$dummyRegister, :vibrate
|
||||||
@ -57,31 +67,30 @@ class HapticFeedBackBytecodePatch : BytecodePatch(
|
|||||||
goto :exit
|
goto :exit
|
||||||
:vibrate
|
:vibrate
|
||||||
const-wide/16 v$targetRegister, 0x19
|
const-wide/16 v$targetRegister, 0x19
|
||||||
""", listOf(ExternalLabel("exit", mutableMethod.instruction(insertIndex)))
|
""", listOf(ExternalLabel("exit", mutableMethod.instruction(insertIndex)))
|
||||||
)
|
)
|
||||||
|
|
||||||
mutableMethod.addInstructions(
|
addInstructions(
|
||||||
startIndex, """
|
startIndex, """
|
||||||
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
||||||
move-result v$dummyRegister
|
move-result v$dummyRegister
|
||||||
if-eqz v$dummyRegister, :vibrate
|
if-eqz v$dummyRegister, :vibrate
|
||||||
return-void
|
return-void
|
||||||
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(startIndex)))
|
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(startIndex)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MethodFingerprint.voidHaptics(targetMethodName: String) {
|
fun MethodFingerprintResult.voidHaptics(targetMethodName: String) {
|
||||||
with(this.result!!) {
|
mutableMethod.addInstructions(
|
||||||
mutableMethod.addInstructions(
|
0, """
|
||||||
0, """
|
|
||||||
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
|
||||||
move-result v0
|
move-result v0
|
||||||
if-eqz v0, :vibrate
|
if-eqz v0, :vibrate
|
||||||
return-void
|
return-void
|
||||||
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(0)))
|
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(0)))
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,18 +6,11 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object StartVideoInformerFingerprint : MethodFingerprint(
|
object StartVideoInformerFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L", "L", "L"), listOf(
|
returnType = "V",
|
||||||
Opcode.INVOKE_STATIC,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
Opcode.IGET_OBJECT,
|
opcodes = listOf(
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.NEW_INSTANCE,
|
|
||||||
Opcode.INVOKE_DIRECT,
|
|
||||||
Opcode.INVOKE_INTERFACE,
|
Opcode.INVOKE_INTERFACE,
|
||||||
Opcode.IF_EQZ,
|
Opcode.RETURN_VOID,
|
||||||
Opcode.CONST_STRING,
|
),
|
||||||
Opcode.INVOKE_INTERFACE,
|
strings = listOf("pc")
|
||||||
Opcode.IGET_OBJECT,
|
|
||||||
Opcode.INVOKE_VIRTUAL,
|
|
||||||
Opcode.MOVE_RESULT,
|
|
||||||
)
|
|
||||||
)
|
)
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object SubtitleTrackFingerprint : MethodFingerprint(
|
object SubtitleTrackFingerprint : MethodFingerprint(
|
||||||
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf(
|
returnType = "Z",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf(),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.CONST_STRING,
|
Opcode.CONST_STRING,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
@ -7,13 +7,12 @@ import app.revanced.patcher.extensions.addInstructions
|
|||||||
import app.revanced.patcher.extensions.instruction
|
import app.revanced.patcher.extensions.instruction
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
|
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints.*
|
import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
|
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
|
||||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||||
|
|
||||||
@ -32,8 +31,8 @@ class AutoCaptionsBytecodePatch : BytecodePatch(
|
|||||||
StartVideoInformerFingerprint.toPatch(Status.DISABLED),
|
StartVideoInformerFingerprint.toPatch(Status.DISABLED),
|
||||||
SubtitleButtonControllerFingerprint.toPatch(Status.ENABLED)
|
SubtitleButtonControllerFingerprint.toPatch(Status.ENABLED)
|
||||||
).forEach { (fingerprint, status) ->
|
).forEach { (fingerprint, status) ->
|
||||||
with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) {
|
with(fingerprint.result?.mutableMethod ?: return fingerprint.toErrorResult()) {
|
||||||
mutableMethod.addInstructions(
|
addInstructions(
|
||||||
0,
|
0,
|
||||||
"""
|
"""
|
||||||
const/4 v0, ${status.value}
|
const/4 v0, ${status.value}
|
||||||
@ -43,19 +42,19 @@ class AutoCaptionsBytecodePatch : BytecodePatch(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val subtitleTrackMethod = SubtitleTrackFingerprint.result!!.mutableMethod
|
SubtitleTrackFingerprint.result?.mutableMethod?.let {
|
||||||
|
it.addInstructions(
|
||||||
subtitleTrackMethod.addInstructions(
|
0, """
|
||||||
0, """
|
invoke-static {}, $GENERAL_LAYOUT->hideAutoCaptions()Z
|
||||||
invoke-static {}, $GENERAL_LAYOUT->hideAutoCaptions()Z
|
move-result v0
|
||||||
move-result v0
|
if-eqz v0, :auto_captions_shown
|
||||||
if-eqz v0, :auto_captions_shown
|
sget-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z
|
||||||
sget-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z
|
if-nez v0, :auto_captions_shown
|
||||||
if-nez v0, :auto_captions_shown
|
const/4 v0, 0x1
|
||||||
const/4 v0, 0x1
|
return v0
|
||||||
return v0
|
""", listOf(ExternalLabel("auto_captions_shown", it.instruction(0)))
|
||||||
""", listOf(ExternalLabel("auto_captions_shown", subtitleTrackMethod.instruction(0)))
|
)
|
||||||
)
|
} ?: return SubtitleTrackFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
|
|
||||||
object EngagementPanelControllerFingerprint : MethodFingerprint(
|
object EngagementPanelControllerFingerprint : MethodFingerprint(
|
||||||
"L",
|
returnType = "L",
|
||||||
AccessFlags.PRIVATE or AccessFlags.FINAL,
|
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
|
||||||
strings = listOf(
|
strings = listOf(
|
||||||
"EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.",
|
"EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.",
|
||||||
"[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called."
|
"[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called."
|
||||||
|
@ -11,6 +11,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
|
|||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints.EngagementPanelControllerFingerprint
|
import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints.EngagementPanelControllerFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||||
|
|
||||||
@Name("hide-auto-player-popup-panels-bytecode-patch")
|
@Name("hide-auto-player-popup-panels-bytecode-patch")
|
||||||
@ -22,18 +23,19 @@ class PlayerPopupPanelsBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val engagementPanelControllerMethod = EngagementPanelControllerFingerprint.result!!.mutableMethod
|
|
||||||
|
|
||||||
engagementPanelControllerMethod.addInstructions(
|
EngagementPanelControllerFingerprint.result?.mutableMethod?.let {
|
||||||
0, """
|
it.addInstructions(
|
||||||
invoke-static { }, $GENERAL_LAYOUT->hideAutoPlayerPopupPanels()Z
|
0, """
|
||||||
move-result v0
|
invoke-static {}, $GENERAL_LAYOUT->hideAutoPlayerPopupPanels()Z
|
||||||
if-eqz v0, :player_popup_panels_shown
|
move-result v0
|
||||||
if-eqz p4, :player_popup_panels_shown
|
if-eqz v0, :player_popup_panels_shown
|
||||||
const/4 v0, 0x0
|
if-eqz p4, :player_popup_panels_shown
|
||||||
return-object v0
|
const/4 v0, 0x0
|
||||||
""", listOf(ExternalLabel("player_popup_panels_shown", engagementPanelControllerMethod.instruction(0)))
|
return-object v0
|
||||||
)
|
""", listOf(ExternalLabel("player_popup_panels_shown", it.instruction(0)))
|
||||||
|
)
|
||||||
|
} ?: return EngagementPanelControllerFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,10 @@ import org.jf.dexlib2.Opcode
|
|||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object CreateMixPlaylistFingerprint : MethodFingerprint(
|
object CreateMixPlaylistFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L", "L"), listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
parameters = listOf("L", "L", "L", "L", "L", "L", "L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.IPUT_OBJECT,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
@ -21,9 +21,9 @@ object FourthCreateMixPlaylistFingerprint : MethodFingerprint(
|
|||||||
Opcode.CHECK_CAST
|
Opcode.CHECK_CAST
|
||||||
),
|
),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.abclistmenuitemLabelId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.abclistmenuitemLabelId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -12,7 +12,10 @@ import org.jf.dexlib2.Opcode
|
|||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object SecondCreateMixPlaylistFingerprint : MethodFingerprint(
|
object SecondCreateMixPlaylistFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L"), listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
parameters = listOf("L", "L", "L", "L", "L", "L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.IPUT_OBJECT,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
@ -21,9 +21,9 @@ object ThirdCreateMixPlaylistFingerprint : MethodFingerprint(
|
|||||||
Opcode.IPUT_OBJECT
|
Opcode.IPUT_OBJECT
|
||||||
),
|
),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottompaneloverlaytextLabelId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottompaneloverlaytextLabelId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -4,13 +4,14 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.instruction
|
import app.revanced.patcher.extensions.instruction
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.fingerprints.*
|
import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.fingerprints.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
import app.revanced.shared.extensions.injectHideCall
|
import app.revanced.shared.extensions.injectHideCall
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||||
@ -29,34 +30,41 @@ class MixPlaylistsBytecodePatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
|
||||||
arrayOf(CreateMixPlaylistFingerprint, SecondCreateMixPlaylistFingerprint).forEach(::addHook)
|
arrayOf(
|
||||||
ThirdCreateMixPlaylistFingerprint.hookMixPlaylists(true)
|
CreateMixPlaylistFingerprint,
|
||||||
FourthCreateMixPlaylistFingerprint.hookMixPlaylists(false)
|
SecondCreateMixPlaylistFingerprint
|
||||||
|
).map {
|
||||||
|
it.result ?: return it.toErrorResult()
|
||||||
|
}.forEach {
|
||||||
|
it.addHook()
|
||||||
|
}
|
||||||
|
|
||||||
|
arrayOf(
|
||||||
|
ThirdCreateMixPlaylistFingerprint to true,
|
||||||
|
FourthCreateMixPlaylistFingerprint to false
|
||||||
|
).map { (fingerprint, boolean) ->
|
||||||
|
fingerprint.result?.hookMixPlaylists(boolean) ?: return fingerprint.toErrorResult()
|
||||||
|
}
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addHook(fingerprint: MethodFingerprint) {
|
private fun MethodFingerprintResult.addHook() {
|
||||||
with (fingerprint.result!!) {
|
val insertIndex = scanResult.patternScanResult!!.endIndex - 3
|
||||||
val insertIndex = scanResult.patternScanResult!!.endIndex - 3
|
val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA
|
mutableMethod.implementation!!.injectHideCall(insertIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
|
||||||
|
|
||||||
mutableMethod.implementation!!.injectHideCall(insertIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MethodFingerprint.hookMixPlaylists(isThirdFingerprint: Boolean) {
|
private fun MethodFingerprintResult.hookMixPlaylists(isThirdFingerprint: Boolean) {
|
||||||
fun getRegister(instruction: Instruction): Int {
|
fun getRegister(instruction: Instruction): Int {
|
||||||
if (isThirdFingerprint) return (instruction as TwoRegisterInstruction).registerA
|
if (isThirdFingerprint) return (instruction as TwoRegisterInstruction).registerA
|
||||||
return (instruction as Instruction21c).registerA
|
return (instruction as Instruction21c).registerA
|
||||||
}
|
}
|
||||||
with(this.result!!) {
|
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
val instruction = method.implementation!!.instructions.elementAt(endIndex)
|
||||||
val instruction = method.implementation!!.instructions.elementAt(endIndex)
|
val register = getRegister(instruction)
|
||||||
val register = getRegister(instruction)
|
|
||||||
|
|
||||||
mutableMethod.implementation!!.injectHideCall(endIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
|
mutableMethod.implementation!!.injectHideCall(endIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,12 @@ object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint(
|
|||||||
Opcode.NEW_ARRAY,
|
Opcode.NEW_ARRAY,
|
||||||
Opcode.CONST_4,
|
Opcode.CONST_4,
|
||||||
Opcode.APUT_OBJECT,
|
Opcode.APUT_OBJECT,
|
||||||
Opcode.CONST,
|
Opcode.CONST
|
||||||
),
|
),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any { it ->
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accountSwitcherAccessibilityLabelId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accountSwitcherAccessibilityLabelId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint
|
import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@ -22,23 +23,20 @@ class HideEmailAddressBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val accountSwitcherAccessibilityLabelResult = AccountSwitcherAccessibilityLabelFingerprint.result!!
|
|
||||||
val accountSwitcherAccessibilityLabelMethod = accountSwitcherAccessibilityLabelResult.mutableMethod
|
|
||||||
|
|
||||||
val setVisibilityConstIndex =
|
AccountSwitcherAccessibilityLabelFingerprint.result?.let {
|
||||||
accountSwitcherAccessibilityLabelResult.scanResult.patternScanResult!!.endIndex
|
with (it.mutableMethod) {
|
||||||
|
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
val register = (instruction(insertIndex - 2) as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
val setVisibilityConstRegister = (
|
addInstructions(
|
||||||
accountSwitcherAccessibilityLabelMethod.instruction
|
insertIndex, """
|
||||||
(setVisibilityConstIndex - 2) as OneRegisterInstruction
|
invoke-static {v$register}, $GENERAL_LAYOUT->hideEmailAddress(I)I
|
||||||
).registerA
|
move-result v$register
|
||||||
|
"""
|
||||||
accountSwitcherAccessibilityLabelMethod.addInstructions(
|
)
|
||||||
setVisibilityConstIndex, """
|
}
|
||||||
invoke-static {v$setVisibilityConstRegister}, $GENERAL_LAYOUT->hideEmailAddress(I)I
|
} ?: return AccountSwitcherAccessibilityLabelFingerprint.toErrorResult()
|
||||||
move-result v$setVisibilityConstRegister
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ object PivotBarCreateButtonViewFingerprint : MethodFingerprint(
|
|||||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
parameters = listOf("Z"),
|
parameters = listOf("Z"),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageOnlyTabId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageOnlyTabId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -17,9 +17,9 @@ object PivotBarFingerprint : MethodFingerprint(
|
|||||||
),
|
),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.definingClass == "Lcom/google/android/apps/youtube/app/ui/pivotbar/PivotBar;" &&
|
methodDef.definingClass == "Lcom/google/android/apps/youtube/app/ui/pivotbar/PivotBar;" &&
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageWithTextTabId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageWithTextTabId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -65,14 +65,14 @@ class CreateButtonRemoverBytecodePatch : BytecodePatch(
|
|||||||
} ?: return PivotBarCreateButtonViewFingerprint.toErrorResult()
|
} ?: return PivotBarCreateButtonViewFingerprint.toErrorResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal companion object {
|
private companion object {
|
||||||
const val hook =
|
const val hook =
|
||||||
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT" +
|
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT" +
|
||||||
"->" +
|
"->" +
|
||||||
"hideCreateButton(Landroid/view/View;)V"
|
"hideCreateButton(Landroid/view/View;)V"
|
||||||
|
|
||||||
private lateinit var createRef: DexBackedMethodReference
|
lateinit var createRef: DexBackedMethodReference
|
||||||
|
|
||||||
private var isSeondary: Boolean = false
|
var isSeondary: Boolean = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,19 +3,18 @@ package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.byteco
|
|||||||
import app.revanced.patcher.annotation.Name
|
import app.revanced.patcher.annotation.Name
|
||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
|
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarEnumFingerprint
|
import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarEnumFingerprint
|
||||||
import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarShortsButtonViewFingerprint
|
import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarShortsButtonViewFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.fingerprints.PivotBarFingerprint
|
import app.revanced.shared.fingerprints.PivotBarFingerprint
|
||||||
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
|
||||||
import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook
|
|
||||||
import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
|
||||||
|
import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook
|
||||||
|
|
||||||
@Name("hide-shorts-button")
|
@Name("hide-shorts-button")
|
||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@ -29,42 +28,48 @@ class ShortsButtonRemoverBytecodePatch : BytecodePatch(
|
|||||||
* Resolve fingerprints
|
* Resolve fingerprints
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val pivotBarResult = PivotBarFingerprint.result ?: return PatchResultError("PivotBarFingerprint failed")
|
PivotBarFingerprint.result?.let { parentResult ->
|
||||||
val fingerprintResults = arrayOf(PivotBarEnumFingerprint, PivotBarShortsButtonViewFingerprint)
|
with (
|
||||||
.onEach {
|
arrayOf(
|
||||||
val resolutionSucceeded = it.resolve(
|
PivotBarEnumFingerprint,
|
||||||
context,
|
PivotBarShortsButtonViewFingerprint
|
||||||
pivotBarResult.mutableMethod,
|
).onEach {
|
||||||
pivotBarResult.mutableClass
|
it.resolve(
|
||||||
)
|
context,
|
||||||
|
parentResult.mutableMethod,
|
||||||
|
parentResult.mutableClass
|
||||||
|
)
|
||||||
|
}.map {
|
||||||
|
it.result?.scanResult?.patternScanResult ?: return it.toErrorResult()
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
val enumScanResult = this[0]
|
||||||
|
val buttonViewResult = this[1]
|
||||||
|
|
||||||
if (!resolutionSucceeded) return PatchResultError("${it.name} failed")
|
val enumHookInsertIndex = enumScanResult.startIndex + 2
|
||||||
|
val buttonHookInsertIndex = buttonViewResult.endIndex
|
||||||
|
|
||||||
|
mapOf(
|
||||||
|
buttonHook to buttonHookInsertIndex,
|
||||||
|
enumHook to enumHookInsertIndex
|
||||||
|
).forEach { (hook, insertIndex) ->
|
||||||
|
parentResult.mutableMethod.injectHook(hook, insertIndex)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.map { it.result!!.scanResult.patternScanResult!! }
|
|
||||||
|
|
||||||
val enumScanResult = fingerprintResults[0]
|
} ?: return PivotBarFingerprint.toErrorResult()
|
||||||
val buttonViewResult = fingerprintResults[1]
|
|
||||||
|
|
||||||
val enumHookInsertIndex = enumScanResult.startIndex + 2
|
|
||||||
val buttonHookInsertIndex = buttonViewResult.endIndex
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Inject hooks
|
|
||||||
*/
|
|
||||||
|
|
||||||
val enumHook =
|
|
||||||
"sput-object v$REGISTER_TEMPLATE_REPLACEMENT, $GENERAL_LAYOUT->lastPivotTab:Ljava/lang/Enum;"
|
|
||||||
val buttonHook =
|
|
||||||
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT->hideShortsButton(Landroid/view/View;)V"
|
|
||||||
|
|
||||||
// Inject bottom to top to not mess up the indices
|
|
||||||
mapOf(
|
|
||||||
buttonHook to buttonHookInsertIndex,
|
|
||||||
enumHook to enumHookInsertIndex
|
|
||||||
).forEach { (hook, insertIndex) ->
|
|
||||||
pivotBarResult.mutableMethod.injectHook(hook, insertIndex)
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
private companion object {
|
||||||
|
const val enumHook =
|
||||||
|
"sput-object v$REGISTER_TEMPLATE_REPLACEMENT, $GENERAL_LAYOUT" +
|
||||||
|
"->" +
|
||||||
|
"lastPivotTab:Ljava/lang/Enum;"
|
||||||
|
|
||||||
|
const val buttonHook =
|
||||||
|
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT" +
|
||||||
|
"->" +
|
||||||
|
"hideShortsButton(Landroid/view/View;)V"
|
||||||
|
}
|
||||||
}
|
}
|
@ -30,12 +30,15 @@ class WideSearchbarBytecodePatch : BytecodePatch(
|
|||||||
WideSearchbarOneParentFingerprint to WideSearchbarOneFingerprint,
|
WideSearchbarOneParentFingerprint to WideSearchbarOneFingerprint,
|
||||||
WideSearchbarTwoParentFingerprint to WideSearchbarTwoFingerprint
|
WideSearchbarTwoParentFingerprint to WideSearchbarTwoFingerprint
|
||||||
).map { (parentFingerprint, fingerprint) ->
|
).map { (parentFingerprint, fingerprint) ->
|
||||||
parentFingerprint.result?.let { parentResult ->
|
parentFingerprint.result?.classDef?.let { classDef ->
|
||||||
fingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
fingerprint.also { it.resolve(context, classDef) }.result?.let {
|
||||||
|
val index = if (fingerprint == WideSearchbarOneFingerprint) it.scanResult.patternScanResult!!.endIndex
|
||||||
|
else it.scanResult.patternScanResult!!.startIndex
|
||||||
|
|
||||||
val targetMethod =
|
val targetMethod =
|
||||||
context
|
context
|
||||||
.toMethodWalker(it.method)
|
.toMethodWalker(it.method)
|
||||||
.nextMethod(it.scanResult.patternScanResult!!.endIndex, true)
|
.nextMethod(index, true)
|
||||||
.getMethod() as MutableMethod
|
.getMethod() as MutableMethod
|
||||||
|
|
||||||
injectSearchBarHook(targetMethod)
|
injectSearchBarHook(targetMethod)
|
||||||
|
@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|||||||
|
|
||||||
object LayoutConstructorFingerprint : MethodFingerprint(
|
object LayoutConstructorFingerprint : MethodFingerprint(
|
||||||
strings = listOf("1.0x"),
|
strings = listOf("1.0x"),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = {
|
||||||
methodDef.definingClass.endsWith("YouTubeControlsOverlay;")
|
it.definingClass.endsWith("YouTubeControlsOverlay;")
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -11,6 +11,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
|
|||||||
import app.revanced.patcher.util.smali.ExternalLabel
|
import app.revanced.patcher.util.smali.ExternalLabel
|
||||||
import app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.fingerprints.LayoutConstructorFingerprint
|
import app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.fingerprints.LayoutConstructorFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||||
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
@ -28,31 +29,33 @@ class HideAutoplayButtonBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val layoutGenMethodResult = LayoutConstructorFingerprint.result!!
|
|
||||||
val layoutGenMethod = layoutGenMethodResult.mutableMethod
|
|
||||||
val layoutGenMethodInstructions = layoutGenMethod.implementation!!.instructions
|
|
||||||
|
|
||||||
// resolve the offsets such as ...
|
// resolve the offsets such as ...
|
||||||
val autoNavPreviewStubId = ResourceMappingPatch.resourceMappings.single {
|
val autoNavPreviewStubId = ResourceMappingPatch.resourceMappings.single {
|
||||||
it.name == "autonav_preview_stub"
|
it.name == "autonav_preview_stub"
|
||||||
}.id
|
}.id
|
||||||
// where to insert the branch instructions and ...
|
|
||||||
val insertIndex = layoutGenMethodInstructions.indexOfFirst {
|
|
||||||
(it as? WideLiteralInstruction)?.wideLiteral == autoNavPreviewStubId
|
|
||||||
}
|
|
||||||
// where to branch away
|
|
||||||
val branchIndex = layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1).indexOfFirst {
|
|
||||||
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
|
|
||||||
} + 2
|
|
||||||
|
|
||||||
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction
|
LayoutConstructorFingerprint.result?.mutableMethod?.let { method ->
|
||||||
layoutGenMethod.addInstructions(
|
with (method.implementation!!.instructions) {
|
||||||
insertIndex, """
|
// where to insert the branch instructions and ...
|
||||||
invoke-static {}, $PLAYER_LAYOUT->hideAutoPlayButton()Z
|
val insertIndex = this.indexOfFirst {
|
||||||
move-result v15
|
(it as? WideLiteralInstruction)?.wideLiteral == autoNavPreviewStubId
|
||||||
if-nez v15, :hidden
|
}
|
||||||
""", listOf(ExternalLabel("hidden", jumpInstruction))
|
// where to branch away
|
||||||
)
|
val branchIndex = this.subList(insertIndex + 1, this.size - 1).indexOfFirst {
|
||||||
|
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
|
||||||
|
} + 2
|
||||||
|
|
||||||
|
val jumpInstruction = this[insertIndex + branchIndex] as Instruction
|
||||||
|
|
||||||
|
method.addInstructions(
|
||||||
|
insertIndex, """
|
||||||
|
invoke-static {}, $PLAYER_LAYOUT->hideAutoPlayButton()Z
|
||||||
|
move-result v15
|
||||||
|
if-nez v15, :hidden
|
||||||
|
""", listOf(ExternalLabel("hidden", jumpInstruction))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return LayoutConstructorFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import app.revanced.patcher.patch.BytecodePatch
|
|||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
|
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
|
||||||
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
@ -15,24 +16,27 @@ import org.jf.dexlib2.Opcode
|
|||||||
@Name("hide-captions-button-bytecode-patch")
|
@Name("hide-captions-button-bytecode-patch")
|
||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
class HideCaptionsButtonBytecodePatch : BytecodePatch(listOf(
|
class HideCaptionsButtonBytecodePatch : BytecodePatch(
|
||||||
SubtitleButtonControllerFingerprint,
|
listOf(
|
||||||
)) {
|
SubtitleButtonControllerFingerprint
|
||||||
|
)
|
||||||
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
|
||||||
val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod
|
SubtitleButtonControllerFingerprint.result?.mutableMethod?.let {
|
||||||
val subtitleButtonControllerMethodInstructions = subtitleButtonControllerMethod.implementation!!.instructions
|
with (it.implementation!!.instructions) {
|
||||||
|
for ((index, instruction) in this.withIndex()) {
|
||||||
|
if (instruction.opcode != Opcode.IGET_BOOLEAN) continue
|
||||||
|
|
||||||
for ((index, instruction) in subtitleButtonControllerMethodInstructions.withIndex()) {
|
it.addInstruction(
|
||||||
if (instruction.opcode != Opcode.IGET_BOOLEAN) continue
|
index + 1,
|
||||||
|
"invoke-static {v0}, $PLAYER_LAYOUT->hideCaptionsButton(Landroid/widget/ImageView;)V"
|
||||||
|
)
|
||||||
|
|
||||||
subtitleButtonControllerMethod.addInstruction(
|
break
|
||||||
index + 1,
|
}
|
||||||
"invoke-static {v0}, $PLAYER_LAYOUT->hideCaptionsButton(Landroid/widget/ImageView;)V"
|
}
|
||||||
)
|
} ?: return SubtitleButtonControllerFingerprint.toErrorResult()
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object InfocardsIncognitoFingerprint : MethodFingerprint(
|
object InfocardsIncognitoFingerprint : MethodFingerprint(
|
||||||
"Ljava/lang/Boolean;",
|
returnType = "Ljava/lang/Boolean;",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
strings = listOf("vibrator")
|
strings = listOf("vibrator")
|
||||||
)
|
)
|
@ -11,7 +11,7 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
@Version("0.0.1")
|
@Version("0.0.1")
|
||||||
object InfocardsIncognitoParentFingerprint : MethodFingerprint(
|
object InfocardsIncognitoParentFingerprint : MethodFingerprint(
|
||||||
"Ljava/lang/String;",
|
returnType = "Ljava/lang/String;",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
strings = listOf("player_overlay_info_card_teaser"),
|
strings = listOf("player_overlay_info_card_teaser"),
|
||||||
)
|
)
|
@ -11,6 +11,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
|
|||||||
import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoFingerprint
|
import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoFingerprint
|
||||||
import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoParentFingerprint
|
import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoParentFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
|
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
|
||||||
|
|
||||||
@Name("hide-info-cards-bytecode-patch")
|
@Name("hide-info-cards-bytecode-patch")
|
||||||
@ -20,16 +21,17 @@ class HideInfoCardsBytecodePatch : BytecodePatch(
|
|||||||
listOf(InfocardsIncognitoParentFingerprint)
|
listOf(InfocardsIncognitoParentFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
with(InfocardsIncognitoFingerprint.also {
|
InfocardsIncognitoParentFingerprint.result?.classDef?.let { classDef ->
|
||||||
it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef)
|
InfocardsIncognitoFingerprint.also {
|
||||||
}.result!!.mutableMethod) {
|
it.resolve(context, classDef)
|
||||||
addInstructions(
|
}.result?.mutableMethod?.
|
||||||
|
addInstructions(
|
||||||
1, """
|
1, """
|
||||||
invoke-static {v0}, $PLAYER_LAYOUT->hideInfoCard(Z)Z
|
invoke-static {v0}, $PLAYER_LAYOUT->hideInfoCard(Z)Z
|
||||||
move-result v0
|
move-result v0
|
||||||
"""
|
"""
|
||||||
)
|
) ?: return InfocardsIncognitoFingerprint.toErrorResult()
|
||||||
}
|
} ?: return InfocardsIncognitoParentFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,9 @@ import org.jf.dexlib2.Opcode
|
|||||||
|
|
||||||
object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
|
object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
|
||||||
parameters = listOf("L", "L", "L"),
|
parameters = listOf("L", "L", "L"),
|
||||||
opcodes = listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL),
|
opcodes = listOf(
|
||||||
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
Opcode.INVOKE_VIRTUAL
|
||||||
|
),
|
||||||
strings = listOf("(Linux; U; Android "),
|
strings = listOf("(Linux; U; Android "),
|
||||||
)
|
)
|
@ -9,7 +9,9 @@ import app.revanced.patcher.patch.BytecodePatch
|
|||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.misc.clientspoof.bytecode.fingerprints.UserAgentHeaderBuilderFingerprint
|
import app.revanced.patches.youtube.misc.clientspoof.bytecode.fingerprints.UserAgentHeaderBuilderFingerprint
|
||||||
|
import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
|
||||||
|
|
||||||
@Name("client-spoof-bytecode-patch")
|
@Name("client-spoof-bytecode-patch")
|
||||||
@ -19,14 +21,15 @@ class ClientSpoofBytecodePatch : BytecodePatch(
|
|||||||
listOf(UserAgentHeaderBuilderFingerprint)
|
listOf(UserAgentHeaderBuilderFingerprint)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val result = UserAgentHeaderBuilderFingerprint.result!!
|
|
||||||
val method = result.mutableMethod
|
|
||||||
|
|
||||||
val insertIndex = result.scanResult.patternScanResult!!.endIndex
|
UserAgentHeaderBuilderFingerprint.result?.let {
|
||||||
val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD
|
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
|
||||||
val originalPackageName = "com.google.android.youtube"
|
with (it.mutableMethod) {
|
||||||
method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"")
|
val packageNameRegister = (instruction(insertIndex) as FiveRegisterInstruction).registerD
|
||||||
|
addInstruction(insertIndex, "const-string v$packageNameRegister, \"$PACKAGE_NAME\"")
|
||||||
|
}
|
||||||
|
} ?: return UserAgentHeaderBuilderFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -7,13 +7,20 @@ import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object MaxBufferFingerprint : MethodFingerprint(
|
object MaxBufferFingerprint : MethodFingerprint(
|
||||||
"I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(),
|
returnType = "I",
|
||||||
listOf(Opcode.SGET_OBJECT, Opcode.IGET, Opcode.IF_EQZ, Opcode.RETURN),
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
customFingerprint = { methodDef ->
|
parameters = listOf(),
|
||||||
methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
|
opcodes = listOf(
|
||||||
&& methodDef.implementation!!.instructions.any {
|
Opcode.SGET_OBJECT,
|
||||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 120000)
|
Opcode.IGET,
|
||||||
&& methodDef.name == "r"
|
Opcode.IF_EQZ,
|
||||||
|
Opcode.RETURN
|
||||||
|
),
|
||||||
|
customFingerprint = {
|
||||||
|
it.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
|
||||||
|
&& it.implementation!!.instructions.any { instruction ->
|
||||||
|
((instruction as? NarrowLiteralInstruction)?.narrowLiteral == 120000)
|
||||||
|
&& it.name == "r"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -7,12 +7,17 @@ import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object PlaybackBufferFingerprint : MethodFingerprint(
|
object PlaybackBufferFingerprint : MethodFingerprint(
|
||||||
"I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(),
|
returnType = "I",
|
||||||
listOf(Opcode.IF_LEZ, Opcode.RETURN),
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
customFingerprint = { methodDef ->
|
parameters = listOf(),
|
||||||
methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
|
opcodes = listOf(
|
||||||
&& methodDef.implementation!!.instructions.any {
|
Opcode.IF_LEZ,
|
||||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 1600)
|
Opcode.RETURN
|
||||||
|
),
|
||||||
|
customFingerprint = {
|
||||||
|
it.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
|
||||||
|
&& it.implementation!!.instructions.any { instruction ->
|
||||||
|
((instruction as? NarrowLiteralInstruction)?.narrowLiteral == 1600)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -7,12 +7,17 @@ import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object ReBufferFingerprint : MethodFingerprint(
|
object ReBufferFingerprint : MethodFingerprint(
|
||||||
"I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(),
|
returnType = "I",
|
||||||
listOf(Opcode.IF_LEZ, Opcode.RETURN),
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
customFingerprint = { methodDef ->
|
parameters = listOf(),
|
||||||
methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
|
opcodes = listOf(
|
||||||
&& methodDef.implementation!!.instructions.any {
|
Opcode.IF_LEZ,
|
||||||
((it as? NarrowLiteralInstruction)?.narrowLiteral == 5000)
|
Opcode.RETURN
|
||||||
|
),
|
||||||
|
customFingerprint = {
|
||||||
|
it.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
|
||||||
|
&& it.implementation!!.instructions.any { instruction ->
|
||||||
|
((instruction as? NarrowLiteralInstruction)?.narrowLiteral == 5000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object ExternalBrowserPrimaryFingerprint : MethodFingerprint(
|
object ExternalBrowserPrimaryFingerprint : MethodFingerprint(
|
||||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf(
|
returnType = "L",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.NEW_INSTANCE,
|
Opcode.NEW_INSTANCE,
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
|
@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object ExternalBrowserSecondaryFingerprint : MethodFingerprint(
|
object ExternalBrowserSecondaryFingerprint : MethodFingerprint(
|
||||||
"L", AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf(
|
returnType = "L",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.IPUT_OBJECT,
|
Opcode.IPUT_OBJECT,
|
||||||
Opcode.NEW_INSTANCE,
|
Opcode.NEW_INSTANCE,
|
||||||
Opcode.CONST_STRING
|
Opcode.CONST_STRING
|
||||||
|
@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object ExternalBrowserTertiaryFingerprint : MethodFingerprint(
|
object ExternalBrowserTertiaryFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, opcodes = listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.NEW_INSTANCE,
|
Opcode.NEW_INSTANCE,
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
|
@ -9,6 +9,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints.*
|
import app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.MISC_PATH
|
import app.revanced.shared.util.integrations.Constants.MISC_PATH
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
|
||||||
|
|
||||||
@ -28,19 +29,20 @@ class ExternalBrowserBytecodePatch : BytecodePatch(
|
|||||||
ExternalBrowserPrimaryFingerprint,
|
ExternalBrowserPrimaryFingerprint,
|
||||||
ExternalBrowserSecondaryFingerprint,
|
ExternalBrowserSecondaryFingerprint,
|
||||||
ExternalBrowserTertiaryFingerprint
|
ExternalBrowserTertiaryFingerprint
|
||||||
).forEach { fingerprint ->
|
).forEach {
|
||||||
val result = fingerprint.result!!
|
val result = it.result?: return it.toErrorResult()
|
||||||
val method = result.mutableMethod
|
|
||||||
val endIndex = result.scanResult.patternScanResult!!.endIndex
|
val endIndex = result.scanResult.patternScanResult!!.endIndex
|
||||||
val register = (method.implementation!!.instructions[endIndex] as Instruction21c).registerA
|
with (result.mutableMethod) {
|
||||||
|
val register = (implementation!!.instructions[endIndex] as Instruction21c).registerA
|
||||||
method.addInstructions(
|
addInstructions(
|
||||||
endIndex + 1, """
|
endIndex + 1, """
|
||||||
invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String;
|
invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String;
|
||||||
move-result-object v$register
|
move-result-object v$register
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint(
|
object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint(
|
||||||
"Ljava/lang/Object", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
returnType = "Ljava/lang/Object",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint(
|
object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint(
|
||||||
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf(
|
returnType = "L",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
Opcode.INVOKE_STATIC,
|
Opcode.INVOKE_STATIC,
|
||||||
|
@ -4,12 +4,13 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.fingerprints.*
|
import app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.fingerprints.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.MISC_PATH
|
import app.revanced.shared.util.integrations.Constants.MISC_PATH
|
||||||
import org.jf.dexlib2.iface.instruction.Instruction
|
import org.jf.dexlib2.iface.instruction.Instruction
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
import org.jf.dexlib2.iface.instruction.formats.Instruction11x
|
||||||
@ -26,29 +27,31 @@ class OpenLinksDirectlyBytecodePatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
|
||||||
OpenLinksDirectlyFingerprintPrimary.hookUriParser(true)
|
arrayOf(
|
||||||
OpenLinksDirectlyFingerprintSecondary.hookUriParser(false)
|
OpenLinksDirectlyFingerprintPrimary to true,
|
||||||
|
OpenLinksDirectlyFingerprintSecondary to false
|
||||||
|
).map { (fingerprint, boolean) ->
|
||||||
|
fingerprint.result?.hookUriParser(boolean) ?: return fingerprint.toErrorResult()
|
||||||
|
}
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MethodFingerprint.hookUriParser(isPrimaryFingerprint: Boolean) {
|
fun MethodFingerprintResult.hookUriParser(isPrimaryFingerprint: Boolean) {
|
||||||
fun getTargetRegister(instruction: Instruction): Int {
|
fun getTargetRegister(instruction: Instruction): Int {
|
||||||
if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC
|
if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC
|
||||||
return (instruction as Instruction11x).registerA
|
return (instruction as Instruction11x).registerA
|
||||||
}
|
}
|
||||||
with(this.result!!) {
|
val startIndex = scanResult.patternScanResult!!.startIndex
|
||||||
val startIndex = scanResult.patternScanResult!!.startIndex
|
val instruction = method.implementation!!.instructions.elementAt(startIndex + 1)
|
||||||
val instruction = method.implementation!!.instructions.elementAt(startIndex + 1)
|
val insertIndex = if (isPrimaryFingerprint) 1 else 2
|
||||||
val insertIndex = if (isPrimaryFingerprint) 1 else 2
|
val targetRegister = getTargetRegister(instruction)
|
||||||
val targetRegister = getTargetRegister(instruction)
|
|
||||||
|
|
||||||
mutableMethod.addInstructions(
|
mutableMethod.addInstructions(
|
||||||
startIndex + insertIndex, """
|
startIndex + insertIndex, """
|
||||||
invoke-static {v$targetRegister}, $MISC_PATH/OpenLinksDirectlyPatch;->enableBypassRedirect(Ljava/lang/String;)Ljava/lang/String;
|
invoke-static {v$targetRegister}, $MISC_PATH/OpenLinksDirectlyPatch;->enableBypassRedirect(Ljava/lang/String;)Ljava/lang/String;
|
||||||
move-result-object v$targetRegister
|
move-result-object v$targetRegister
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
}
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object PrimaryPiPFingerprint : MethodFingerprint(
|
object PrimaryPiPFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object SecondaryPiPFingerprint : MethodFingerprint(
|
object SecondaryPiPFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.IGET_OBJECT,
|
Opcode.IGET_OBJECT,
|
||||||
Opcode.CHECK_CAST,
|
Opcode.CHECK_CAST,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
|
@ -15,6 +15,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
|
|||||||
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.*
|
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.*
|
||||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Name("player-controls-bytecode-patch")
|
@Name("player-controls-bytecode-patch")
|
||||||
@ -31,24 +32,33 @@ class PlayerControlsBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
showPlayerControlsFingerprintResult = PlayerControlsVisibilityFingerprint.result!!
|
|
||||||
controlsLayoutInflateFingerprintResult = ControlsLayoutInflateFingerprint.result!!
|
|
||||||
|
|
||||||
// TODO: another solution is required, this is hacky
|
PlayerControlsVisibilityFingerprint.result?.let {
|
||||||
listOf(BottomControlsInflateFingerprint).resolve(context, context.classes)
|
showPlayerControlsResult = it
|
||||||
inflateFingerprintResult = BottomControlsInflateFingerprint.result!!
|
} ?: return PlayerControlsVisibilityFingerprint.toErrorResult()
|
||||||
|
|
||||||
VisibilityNegatedFingerprint.resolve(context, VisibilityNegatedParentFingerprint.result!!.classDef)
|
ControlsLayoutInflateFingerprint.result?.let {
|
||||||
visibilityNegatedFingerprintResult = VisibilityNegatedFingerprint.result!!
|
controlsLayoutInflateResult = it
|
||||||
|
} ?: return ControlsLayoutInflateFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
BottomControlsInflateFingerprint.result?.let {
|
||||||
|
inflateResult = it
|
||||||
|
} ?: return BottomControlsInflateFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
VisibilityNegatedParentFingerprint.result?.let { parentResult ->
|
||||||
|
VisibilityNegatedFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||||
|
visibilityNegatedResult = it
|
||||||
|
} ?: return VisibilityNegatedFingerprint.toErrorResult()
|
||||||
|
} ?: return VisibilityNegatedParentFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
internal companion object {
|
internal companion object {
|
||||||
lateinit var showPlayerControlsFingerprintResult: MethodFingerprintResult
|
lateinit var showPlayerControlsResult: MethodFingerprintResult
|
||||||
lateinit var controlsLayoutInflateFingerprintResult: MethodFingerprintResult
|
lateinit var controlsLayoutInflateResult: MethodFingerprintResult
|
||||||
lateinit var inflateFingerprintResult: MethodFingerprintResult
|
lateinit var inflateResult: MethodFingerprintResult
|
||||||
lateinit var visibilityNegatedFingerprintResult: MethodFingerprintResult
|
lateinit var visibilityNegatedResult: MethodFingerprintResult
|
||||||
|
|
||||||
fun MethodFingerprintResult.injectVisibilityCall(
|
fun MethodFingerprintResult.injectVisibilityCall(
|
||||||
descriptor: String,
|
descriptor: String,
|
||||||
@ -60,32 +70,33 @@ class PlayerControlsBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun MethodFingerprintResult.injectCalls(
|
private fun MethodFingerprintResult.injectCalls(
|
||||||
descriptor: String
|
descriptor: String
|
||||||
) {
|
) {
|
||||||
val endIndex = scanResult.patternScanResult!!.endIndex
|
val endIndex = scanResult.patternScanResult!!.endIndex
|
||||||
val viewRegister = (mutableMethod.instruction(endIndex) as OneRegisterInstruction).registerA
|
with (mutableMethod) {
|
||||||
|
val viewRegister = (instruction(endIndex) as OneRegisterInstruction).registerA
|
||||||
mutableMethod.addInstruction(
|
addInstruction(
|
||||||
endIndex + 1,
|
endIndex + 1,
|
||||||
"invoke-static {v$viewRegister}, $descriptor->initialize(Ljava/lang/Object;)V"
|
"invoke-static {v$viewRegister}, $descriptor->initialize(Ljava/lang/Object;)V"
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun injectVisibility(descriptor: String) {
|
fun injectVisibility(descriptor: String) {
|
||||||
showPlayerControlsFingerprintResult.injectVisibilityCall(descriptor, "changeVisibility")
|
showPlayerControlsResult.injectVisibilityCall(descriptor, "changeVisibility")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun injectVisibilityNegated(descriptor: String) {
|
fun injectVisibilityNegated(descriptor: String) {
|
||||||
visibilityNegatedFingerprintResult.injectVisibilityCall(descriptor, "changeVisibilityNegatedImmediate")
|
visibilityNegatedResult.injectVisibilityCall(descriptor, "changeVisibilityNegatedImmediate")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializeSB(descriptor: String) {
|
fun initializeSB(descriptor: String) {
|
||||||
controlsLayoutInflateFingerprintResult.injectCalls(descriptor)
|
controlsLayoutInflateResult.injectCalls(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initializeControl(descriptor: String) {
|
fun initializeControl(descriptor: String) {
|
||||||
inflateFingerprintResult.injectCalls(descriptor)
|
inflateResult.injectCalls(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -12,9 +12,9 @@ object BottomControlsInflateFingerprint : MethodFingerprint(
|
|||||||
Opcode.MOVE_RESULT_OBJECT
|
Opcode.MOVE_RESULT_OBJECT
|
||||||
),
|
),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottomUiContainerResourceId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottomUiContainerResourceId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -14,9 +14,9 @@ object ControlsLayoutInflateFingerprint : MethodFingerprint(
|
|||||||
Opcode.MOVE_RESULT_OBJECT
|
Opcode.MOVE_RESULT_OBJECT
|
||||||
),
|
),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.controlsLayoutStubResourceId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.controlsLayoutStubResourceId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -3,9 +3,9 @@ package app.revanced.patches.youtube.misc.playercontrols.fingerprints
|
|||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
object PlayerControlsVisibilityFingerprint : MethodFingerprint(
|
object PlayerControlsVisibilityFingerprint : MethodFingerprint(
|
||||||
"V",
|
returnType = "V",
|
||||||
parameters = listOf("Z", "Z"),
|
parameters = listOf("Z", "Z"),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = {
|
||||||
methodDef.definingClass.endsWith("YouTubeControlsOverlay;")
|
it.definingClass.endsWith("YouTubeControlsOverlay;")
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object VisibilityNegatedFingerprint : MethodFingerprint(
|
object VisibilityNegatedFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), opcodes = listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("Z"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.IF_EQZ
|
Opcode.IF_EQZ
|
||||||
)
|
)
|
||||||
)
|
)
|
@ -11,9 +11,9 @@ object VisibilityNegatedParentFingerprint : MethodFingerprint(
|
|||||||
returnType = "V",
|
returnType = "V",
|
||||||
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.educationTextViewResourceId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.educationTextViewResourceId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.playeroverlay.fingerprint
|
|||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
||||||
|
|
||||||
object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint(
|
object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint(
|
||||||
null, null, null, null, null, { methodDef ->
|
customFingerprint = {
|
||||||
methodDef.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && methodDef.name == "onFinishInflate"
|
it.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && it.name == "onFinishInflate"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint
|
import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.UTILS_PATH
|
import app.revanced.shared.util.integrations.Constants.UTILS_PATH
|
||||||
|
|
||||||
@Name("player-overlays-hook")
|
@Name("player-overlays-hook")
|
||||||
@ -23,11 +24,13 @@ class PlayerOverlaysHookPatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
// hook YouTubePlayerOverlaysLayout.onFinishInflate()
|
// hook YouTubePlayerOverlaysLayout.onFinishInflate()
|
||||||
val method = PlayerOverlaysOnFinishInflateFingerprint.result!!.mutableMethod
|
PlayerOverlaysOnFinishInflateFingerprint.result?.mutableMethod?.let {
|
||||||
method.addInstruction(
|
it.addInstruction(
|
||||||
method.implementation!!.instructions.size - 2,
|
it.implementation!!.instructions.size - 2,
|
||||||
"invoke-static { p0 }, $UTILS_PATH/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V"
|
"invoke-static { p0 }, $UTILS_PATH/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V"
|
||||||
)
|
)
|
||||||
|
} ?: return PlayerOverlaysOnFinishInflateFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint
|
import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.UTILS_PATH
|
import app.revanced.shared.util.integrations.Constants.UTILS_PATH
|
||||||
|
|
||||||
@Name("player-type-hook")
|
@Name("player-type-hook")
|
||||||
@ -23,10 +24,11 @@ class PlayerTypeHookPatch : BytecodePatch(
|
|||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
// hook YouTubePlayerOverlaysLayout.updatePlayerLayout()
|
// hook YouTubePlayerOverlaysLayout.updatePlayerLayout()
|
||||||
UpdatePlayerTypeFingerprint.result!!.mutableMethod.addInstruction(
|
UpdatePlayerTypeFingerprint.result?.mutableMethod?.addInstruction(
|
||||||
0,
|
0,
|
||||||
"invoke-static { p1 }, $UTILS_PATH/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V"
|
"invoke-static { p1 }, $UTILS_PATH/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V"
|
||||||
)
|
) ?: return UpdatePlayerTypeFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,12 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object ThemeSetterSystemFingerprint : MethodFingerprint(
|
object ThemeSetterSystemFingerprint : MethodFingerprint(
|
||||||
"L",
|
returnType = "L",
|
||||||
opcodes = listOf(Opcode.RETURN_OBJECT),
|
opcodes = listOf(Opcode.RETURN_OBJECT),
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.implementation?.instructions?.any { instruction ->
|
methodDef.implementation?.instructions?.any {
|
||||||
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
|
it.opcode.ordinal == Opcode.CONST.ordinal &&
|
||||||
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.appearanceStringId
|
(it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.appearanceStringId
|
||||||
} == true
|
} == true
|
||||||
}
|
}
|
||||||
)
|
)
|
@ -4,20 +4,21 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstruction
|
import app.revanced.patcher.extensions.addInstruction
|
||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
|
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
||||||
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint
|
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint
|
||||||
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
import app.revanced.shared.extensions.findMutableMethodOf
|
import app.revanced.shared.extensions.findMutableMethodOf
|
||||||
import app.revanced.shared.extensions.injectTheme
|
import app.revanced.shared.extensions.injectTheme
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
import app.revanced.shared.patches.mapping.ResourceMappingPatch
|
||||||
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
|
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
|
||||||
import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH
|
import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH
|
||||||
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
|
||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
|
||||||
|
|
||||||
@Name("settings-bytecode-patch")
|
@Name("settings-bytecode-patch")
|
||||||
@DependsOn(
|
@DependsOn(
|
||||||
@ -80,21 +81,24 @@ class SettingsBytecodePatch : BytecodePatch(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// apply the current theme of the settings page
|
// apply the current theme of the settings page
|
||||||
with(ThemeSetterSystemFingerprint.result!!) {
|
ThemeSetterSystemFingerprint.result?.let {
|
||||||
with(mutableMethod) {
|
with(it.mutableMethod) {
|
||||||
val call = "invoke-static {v0}, $INTEGRATIONS_PATH/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V"
|
|
||||||
|
|
||||||
addInstruction(
|
addInstruction(
|
||||||
scanResult.patternScanResult!!.startIndex,
|
it.scanResult.patternScanResult!!.startIndex,
|
||||||
call
|
SET_THEME
|
||||||
)
|
)
|
||||||
|
|
||||||
addInstruction(
|
addInstruction(
|
||||||
mutableMethod.implementation!!.instructions.size - 1,
|
this.implementation!!.instructions.size - 1,
|
||||||
call
|
SET_THEME
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
} ?: return ThemeSetterSystemFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
companion object {
|
||||||
|
const val SET_THEME =
|
||||||
|
"invoke-static {v0}, $INTEGRATIONS_PATH/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,45 +0,0 @@
|
|||||||
package app.revanced.patches.youtube.misc.settings.bytecode.patch
|
|
||||||
|
|
||||||
import app.revanced.patcher.annotation.Name
|
|
||||||
import app.revanced.patcher.annotation.Version
|
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
|
||||||
import app.revanced.patcher.extensions.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.youtube.misc.resourceid.patch.SharedResourcdIdPatch
|
|
||||||
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint
|
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
|
||||||
import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH
|
|
||||||
|
|
||||||
@Name("settings-secondary-bytecode-patch")
|
|
||||||
@DependsOn([SharedResourcdIdPatch::class])
|
|
||||||
@YouTubeCompatibility
|
|
||||||
@Version("0.0.1")
|
|
||||||
class SettingsSecondaryBytecodePatch : BytecodePatch(
|
|
||||||
listOf(ThemeSetterSystemFingerprint)
|
|
||||||
) {
|
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
|
||||||
val ThemeHelper = "$INTEGRATIONS_PATH/utils/ThemeHelper;"
|
|
||||||
|
|
||||||
// apply the current theme of the settings page
|
|
||||||
with(ThemeSetterSystemFingerprint.result!!) {
|
|
||||||
with(mutableMethod) {
|
|
||||||
val call = "invoke-static {v0}, $ThemeHelper->setTheme(Ljava/lang/Object;)V"
|
|
||||||
|
|
||||||
addInstruction(
|
|
||||||
scanResult.patternScanResult!!.startIndex,
|
|
||||||
call
|
|
||||||
)
|
|
||||||
|
|
||||||
addInstruction(
|
|
||||||
mutableMethod.implementation!!.instructions.size - 1,
|
|
||||||
call
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
@ -24,12 +24,18 @@ class SwipeRefreshPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val result = SwipeRefreshLayoutFingerprint.result ?:return SwipeRefreshLayoutFingerprint.toErrorResult()
|
|
||||||
val method = result.mutableMethod
|
|
||||||
val index = result.scanResult.patternScanResult!!.endIndex
|
|
||||||
val register = (method.instruction(index) as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
method.addInstruction(index, "const/4 v$register, 0x0")
|
SwipeRefreshLayoutFingerprint.result?.let {
|
||||||
|
with (it.mutableMethod) {
|
||||||
|
val insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
|
val register = (instruction(insertIndex) as OneRegisterInstruction).registerA
|
||||||
|
|
||||||
|
addInstruction(
|
||||||
|
insertIndex,
|
||||||
|
"const/4 v$register, 0x0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return SwipeRefreshLayoutFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object LegacyVideoIdFingerprint : MethodFingerprint(
|
object LegacyVideoIdFingerprint : MethodFingerprint(
|
||||||
"V",
|
returnType = "V",
|
||||||
AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
|
access = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
|
||||||
listOf("L"),
|
parameters = listOf("L"),
|
||||||
listOf(Opcode.INVOKE_INTERFACE),
|
opcodes = listOf(Opcode.INVOKE_INTERFACE),
|
||||||
customFingerprint = {
|
customFingerprint = {
|
||||||
it.definingClass.endsWith("PlaybackLifecycleMonitor;")
|
it.definingClass.endsWith("PlaybackLifecycleMonitor;")
|
||||||
}
|
}
|
||||||
|
@ -5,13 +5,13 @@ import app.revanced.patcher.annotation.Name
|
|||||||
import app.revanced.patcher.annotation.Version
|
import app.revanced.patcher.annotation.Version
|
||||||
import app.revanced.patcher.data.BytecodeContext
|
import app.revanced.patcher.data.BytecodeContext
|
||||||
import app.revanced.patcher.extensions.addInstructions
|
import app.revanced.patcher.extensions.addInstructions
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
|
||||||
import app.revanced.patches.youtube.misc.videoid.legacy.fingerprint.LegacyVideoIdFingerprint
|
import app.revanced.patches.youtube.misc.videoid.legacy.fingerprint.LegacyVideoIdFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
|
||||||
|
|
||||||
@Name("video-id-hook-legacy")
|
@Name("video-id-hook-legacy")
|
||||||
@ -24,13 +24,16 @@ class LegacyVideoIdPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
result = LegacyVideoIdFingerprint.result!!
|
|
||||||
|
|
||||||
insertMethod = result.mutableMethod
|
LegacyVideoIdFingerprint.result?.let {
|
||||||
videoIdRegister =
|
insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
(insertMethod.implementation!!.instructions[result.scanResult.patternScanResult!!.endIndex + 1] as OneRegisterInstruction).registerA
|
|
||||||
|
|
||||||
offset++ // offset so setCurrentVideoId is called before any injected call
|
with (it.mutableMethod) {
|
||||||
|
insertMethod = this
|
||||||
|
videoIdRegister = (implementation!!.instructions[insertIndex + 1] as OneRegisterInstruction).registerA
|
||||||
|
}
|
||||||
|
offset++ // offset so setCurrentVideoId is called before any injected call
|
||||||
|
} ?: return LegacyVideoIdFingerprint.toErrorResult()
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
@ -38,10 +41,11 @@ class LegacyVideoIdPatch : BytecodePatch(
|
|||||||
companion object {
|
companion object {
|
||||||
private var offset = 2
|
private var offset = 2
|
||||||
|
|
||||||
|
private var insertIndex: Int = 0
|
||||||
private var videoIdRegister: Int = 0
|
private var videoIdRegister: Int = 0
|
||||||
private lateinit var result: MethodFingerprintResult
|
|
||||||
private lateinit var insertMethod: MutableMethod
|
private lateinit var insertMethod: MutableMethod
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||||
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
|
||||||
@ -50,7 +54,7 @@ class LegacyVideoIdPatch : BytecodePatch(
|
|||||||
methodDescriptor: String
|
methodDescriptor: String
|
||||||
) {
|
) {
|
||||||
insertMethod.addInstructions(
|
insertMethod.addInstructions(
|
||||||
result.scanResult.patternScanResult!!.endIndex + offset, // move-result-object offset
|
insertIndex + offset, // move-result-object offset
|
||||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object MainstreamVideoIdFingerprint : MethodFingerprint(
|
object MainstreamVideoIdFingerprint : MethodFingerprint(
|
||||||
"V",
|
returnType = "V",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
listOf("L"),
|
parameters = listOf("L"),
|
||||||
listOf(
|
opcodes = listOf(
|
||||||
Opcode.IF_EQZ,
|
Opcode.IF_EQZ,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
@ -4,6 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|||||||
|
|
||||||
object PlayerControllerFingerprint : MethodFingerprint(
|
object PlayerControllerFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.definingClass == "Lapp/revanced/integrations/sponsorblock/PlayerController;" && methodDef.name == "setSponsorBarRect"
|
methodDef.definingClass == "Lapp/revanced/integrations/sponsorblock/PlayerController;"
|
||||||
|
&& methodDef.name == "setSponsorBarRect"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object VideoTimeFingerprint : MethodFingerprint (
|
object VideoTimeFingerprint : MethodFingerprint (
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("J", "J", "J", "J", "I", "L"), listOf(
|
returnType = "V",
|
||||||
|
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
|
||||||
|
parameters = listOf("J", "J", "J", "J", "I", "L"),
|
||||||
|
opcodes = listOf(
|
||||||
Opcode.INVOKE_DIRECT,
|
Opcode.INVOKE_DIRECT,
|
||||||
Opcode.IPUT_WIDE,
|
Opcode.IPUT_WIDE,
|
||||||
Opcode.IPUT_WIDE,
|
Opcode.IPUT_WIDE,
|
||||||
|
@ -7,7 +7,6 @@ import app.revanced.patcher.data.BytecodeContext
|
|||||||
import app.revanced.patcher.data.toMethodWalker
|
import app.revanced.patcher.data.toMethodWalker
|
||||||
import app.revanced.patcher.extensions.*
|
import app.revanced.patcher.extensions.*
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
|
||||||
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
|
|
||||||
import app.revanced.patcher.patch.BytecodePatch
|
import app.revanced.patcher.patch.BytecodePatch
|
||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
@ -17,6 +16,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu
|
|||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint.*
|
import app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint.*
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.patches.timebar.HookTimebarPatch
|
import app.revanced.shared.patches.timebar.HookTimebarPatch
|
||||||
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
@ -54,137 +54,146 @@ class MainstreamVideoIdPatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val VideoInformation = "$VIDEO_PATH/VideoInformation;"
|
|
||||||
|
|
||||||
val RepeatListenerResult = RepeatListenerFingerprint.result!!
|
RepeatListenerFingerprint.result?.let {
|
||||||
val RepeatListenerMethod = RepeatListenerResult.mutableMethod
|
val removeIndex = it.scanResult.patternScanResult!!.startIndex
|
||||||
val removeIndex = RepeatListenerResult.scanResult.patternScanResult!!.startIndex
|
with (it.mutableMethod) {
|
||||||
|
// removeInstruction(removeIndex)
|
||||||
|
removeInstruction(removeIndex - 1)
|
||||||
|
}
|
||||||
|
} ?: return RepeatListenerFingerprint.toErrorResult()
|
||||||
|
|
||||||
// RepeatListenerMethod.removeInstruction(removeIndex)
|
|
||||||
RepeatListenerMethod.removeInstruction(removeIndex - 1)
|
|
||||||
|
|
||||||
with(PlayerInitFingerprint.result!!) {
|
PlayerInitFingerprint.result?.let { parentResult ->
|
||||||
PlayerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
playerInitMethod = parentResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }
|
||||||
|
|
||||||
// seek method
|
SeekFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
|
||||||
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method
|
val resultMethod = it.method
|
||||||
|
|
||||||
// create helper method
|
with (it.mutableMethod) {
|
||||||
val seekHelperMethod = ImmutableMethod(
|
val seekHelperMethod = ImmutableMethod(
|
||||||
seekFingerprintResultMethod.definingClass,
|
resultMethod.definingClass,
|
||||||
"seekTo",
|
"seekTo",
|
||||||
listOf(ImmutableMethodParameter("J", null, "time")),
|
listOf(ImmutableMethodParameter("J", null, "time")),
|
||||||
"Z",
|
"Z",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
null, null,
|
null, null,
|
||||||
MutableMethodImplementation(4)
|
MutableMethodImplementation(4)
|
||||||
).toMutable()
|
).toMutable()
|
||||||
|
|
||||||
// get enum type for the seek helper method
|
val seekSourceEnumType = resultMethod.parameterTypes[1].toString()
|
||||||
val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString()
|
|
||||||
|
|
||||||
// insert helper method instructions
|
seekHelperMethod.addInstructions(
|
||||||
seekHelperMethod.addInstructions(
|
0,
|
||||||
|
"""
|
||||||
|
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
||||||
|
invoke-virtual {p0, p1, p2, v0}, ${resultMethod.definingClass}->${resultMethod.name}(J$seekSourceEnumType)Z
|
||||||
|
move-result p1
|
||||||
|
return p1
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
parentResult.mutableClass.methods.add(seekHelperMethod)
|
||||||
|
}
|
||||||
|
} ?: return SeekFingerprint.toErrorResult()
|
||||||
|
} ?: return PlayerInitFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
|
||||||
|
VideoTimeParentFingerprint.result?.let { parentResult ->
|
||||||
|
VideoTimeFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.addInstruction(
|
||||||
0,
|
0,
|
||||||
"""
|
"invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTimeHighPrecision(J)V"
|
||||||
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
|
) ?: return VideoTimeFingerprint.toErrorResult()
|
||||||
invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z
|
} ?: return VideoTimeParentFingerprint.toErrorResult()
|
||||||
move-result p1
|
|
||||||
return p1
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
// add the seekTo method to the class for the integrations to call
|
|
||||||
mutableClass.methods.add(seekHelperMethod)
|
|
||||||
}
|
|
||||||
|
|
||||||
val VideoTimeParentResult = VideoTimeParentFingerprint.result!!
|
|
||||||
VideoTimeFingerprint.resolve(context, VideoTimeParentResult.classDef)
|
|
||||||
val VideoTimeMethod = VideoTimeFingerprint.result!!.mutableMethod
|
|
||||||
VideoTimeMethod.addInstruction(
|
|
||||||
0,
|
|
||||||
"invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTimeHighPrecision(J)V"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Set current video time
|
Set current video time
|
||||||
*/
|
*/
|
||||||
val referenceResult = PlayerControllerSetTimeReferenceFingerprint.result!!
|
PlayerControllerSetTimeReferenceFingerprint.result?.let {
|
||||||
val PlayerControllerSetTimeMethod =
|
with(context
|
||||||
context.toMethodWalker(referenceResult.method)
|
.toMethodWalker(it.method)
|
||||||
.nextMethod(referenceResult.scanResult.patternScanResult!!.startIndex, true)
|
.nextMethod(it.scanResult.patternScanResult!!.startIndex, true)
|
||||||
.getMethod() as MutableMethod
|
.getMethod() as MutableMethod
|
||||||
PlayerControllerSetTimeMethod.addInstruction(
|
) {
|
||||||
2,
|
addInstruction(
|
||||||
"invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTime(J)V"
|
2,
|
||||||
)
|
"invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTime(J)V"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: return PlayerControllerSetTimeReferenceFingerprint.toErrorResult()
|
||||||
|
|
||||||
val EmptyColorMethod = HookTimebarPatch.EmptyColorFingerprintResult.mutableMethod
|
|
||||||
val EmptyColorMethodInstructions = EmptyColorMethod.implementation!!.instructions
|
|
||||||
|
|
||||||
val methodReference =
|
with (HookTimebarPatch.EmptyColorFingerprintResult.mutableMethod) {
|
||||||
HookTimebarPatch.TimbarFingerprintResult.method.let { method ->
|
val methodReference =
|
||||||
(method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as MethodReference
|
HookTimebarPatch.TimbarFingerprintResult.method.let {
|
||||||
|
(it.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as MethodReference
|
||||||
|
}
|
||||||
|
|
||||||
|
val instructions = implementation!!.instructions
|
||||||
|
|
||||||
|
reactReference =
|
||||||
|
((instructions.elementAt(instructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name
|
||||||
|
|
||||||
|
|
||||||
|
for ((index, instruction) in instructions.withIndex()) {
|
||||||
|
if (instruction.opcode != Opcode.CHECK_CAST) continue
|
||||||
|
val primaryRegister = (instruction as Instruction21c).registerA + 1
|
||||||
|
val secondaryRegister = primaryRegister + 1
|
||||||
|
addInstructions(
|
||||||
|
index, """
|
||||||
|
invoke-virtual {p0}, $methodReference
|
||||||
|
move-result-wide v$primaryRegister
|
||||||
|
invoke-static {v$primaryRegister, v$secondaryRegister}, $VideoInformation->setCurrentVideoLength(J)V
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PlayerControllerFingerprint.result?.mutableMethod?.let {
|
||||||
|
val instructions = it.implementation!!.instructions
|
||||||
|
|
||||||
|
for ((index, instruction) in instructions.withIndex()) {
|
||||||
|
if (instruction.opcode != Opcode.CONST_STRING) continue
|
||||||
|
val register = (instruction as OneRegisterInstruction).registerA
|
||||||
|
it.replaceInstruction(
|
||||||
|
index,
|
||||||
|
"const-string v$register, \"$reactReference\""
|
||||||
|
)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
for ((index, instruction) in EmptyColorMethodInstructions.withIndex()) {
|
} ?: return PlayerControllerFingerprint.toErrorResult()
|
||||||
if (instruction.opcode != Opcode.CHECK_CAST) continue
|
|
||||||
val primaryRegister = (instruction as Instruction21c).registerA + 1
|
|
||||||
val secondaryRegister = primaryRegister + 1
|
|
||||||
EmptyColorMethod.addInstructions(
|
|
||||||
index, """
|
|
||||||
invoke-virtual {p0}, $methodReference
|
|
||||||
move-result-wide v$primaryRegister
|
|
||||||
invoke-static {v$primaryRegister, v$secondaryRegister}, $VideoInformation->setCurrentVideoLength(J)V
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
val reactReference =
|
|
||||||
((EmptyColorMethodInstructions.elementAt(EmptyColorMethodInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name
|
|
||||||
|
|
||||||
val PlayerContrallerResult = PlayerControllerFingerprint.result!!
|
|
||||||
val PlayerContrallerMethod = PlayerContrallerResult.mutableMethod
|
|
||||||
val PlayerContrallerInstructions = PlayerContrallerMethod.implementation!!.instructions
|
|
||||||
|
|
||||||
/*
|
|
||||||
Get the instance of the seekbar rectangle
|
|
||||||
*/
|
|
||||||
for ((index, instruction) in PlayerContrallerInstructions.withIndex()) {
|
|
||||||
if (instruction.opcode != Opcode.CONST_STRING) continue
|
|
||||||
val register = (instruction as OneRegisterInstruction).registerA
|
|
||||||
PlayerContrallerMethod.replaceInstruction(
|
|
||||||
index,
|
|
||||||
"const-string v$register, \"$reactReference\""
|
|
||||||
)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
InsertResult = MainstreamVideoIdFingerprint.result!!
|
MainstreamVideoIdFingerprint.result?.let {
|
||||||
InsertMethod = InsertResult.mutableMethod
|
insertIndex = it.scanResult.patternScanResult!!.endIndex
|
||||||
InsertIndex = InsertResult.scanResult.patternScanResult!!.endIndex
|
|
||||||
|
|
||||||
videoIdRegister =
|
with (it.mutableMethod) {
|
||||||
(InsertMethod.implementation!!.instructions[InsertIndex] as OneRegisterInstruction).registerA
|
insertMethod = this
|
||||||
|
videoIdRegister = (implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA
|
||||||
|
}
|
||||||
|
offset++ // offset so setCurrentVideoId is called before any injected call
|
||||||
|
} ?: return MainstreamVideoIdFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
|
||||||
injectCall("$VideoInformation->setCurrentVideoId(Ljava/lang/String;)V")
|
injectCall("$VideoInformation->setCurrentVideoId(Ljava/lang/String;)V")
|
||||||
injectCallonCreate(VideoInformation, "onCreate")
|
injectCallonCreate(VideoInformation, "onCreate")
|
||||||
|
|
||||||
offset++ // offset so setCurrentVideoId is called before any injected call
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private var offset = 1
|
const val VideoInformation = "$VIDEO_PATH/VideoInformation;"
|
||||||
|
private var offset = 0
|
||||||
|
|
||||||
|
private var insertIndex: Int = 0
|
||||||
|
private var reactReference: String? = null
|
||||||
private var videoIdRegister: Int = 0
|
private var videoIdRegister: Int = 0
|
||||||
private var InsertIndex: Int = 0
|
private lateinit var insertMethod: MutableMethod
|
||||||
private lateinit var InsertResult: MethodFingerprintResult
|
private lateinit var playerInitMethod: MutableMethod
|
||||||
private lateinit var InsertMethod: MutableMethod
|
|
||||||
private lateinit var PlayerInitMethod: MutableMethod
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds an invoke-static instruction, called with the new id when the video changes
|
* Adds an invoke-static instruction, called with the new id when the video changes
|
||||||
@ -193,14 +202,14 @@ class MainstreamVideoIdPatch : BytecodePatch(
|
|||||||
fun injectCall(
|
fun injectCall(
|
||||||
methodDescriptor: String
|
methodDescriptor: String
|
||||||
) {
|
) {
|
||||||
InsertMethod.addInstructions(
|
insertMethod.addInstructions(
|
||||||
InsertIndex + offset, // move-result-object offset
|
insertIndex + offset, // move-result-object offset
|
||||||
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
"invoke-static {v$videoIdRegister}, $methodDescriptor"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun injectCallonCreate(MethodClass: String, MethodName: String) =
|
fun injectCallonCreate(MethodClass: String, MethodName: String) =
|
||||||
PlayerInitMethod.addInstruction(
|
playerInitMethod.addInstruction(
|
||||||
4,
|
4,
|
||||||
"invoke-static {v0}, $MethodClass->$MethodName(Ljava/lang/Object;)V"
|
"invoke-static {v0}, $MethodClass->$MethodName(Ljava/lang/Object;)V"
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|||||||
|
|
||||||
object SwipeControlsHostActivityFingerprint : MethodFingerprint(
|
object SwipeControlsHostActivityFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.definingClass == "Lapp/revanced/integrations/swipecontrols/SwipeControlsHostActivity;" && methodDef.name == "<init>"
|
methodDef.definingClass == "Lapp/revanced/integrations/swipecontrols/SwipeControlsHostActivity;"
|
||||||
|
&& methodDef.name == "<init>"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -4,6 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
|
|||||||
|
|
||||||
object WatchWhileActivityFingerprint : MethodFingerprint(
|
object WatchWhileActivityFingerprint : MethodFingerprint(
|
||||||
customFingerprint = { methodDef ->
|
customFingerprint = { methodDef ->
|
||||||
methodDef.definingClass.endsWith("WatchWhileActivity;") && methodDef.name == "<init>"
|
methodDef.definingClass.endsWith("WatchWhileActivity;")
|
||||||
|
&& methodDef.name == "<init>"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -9,11 +9,11 @@ import app.revanced.patcher.patch.PatchResultSuccess
|
|||||||
import app.revanced.patcher.patch.annotations.DependsOn
|
import app.revanced.patcher.patch.annotations.DependsOn
|
||||||
import app.revanced.patcher.util.TypeUtil.traverseClassHierarchy
|
import app.revanced.patcher.util.TypeUtil.traverseClassHierarchy
|
||||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||||
import app.revanced.patches.youtube.misc.hdrbrightness.bytecode.patch.HDRBrightnessBytecodePatch
|
|
||||||
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
|
||||||
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.SwipeControlsHostActivityFingerprint
|
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.SwipeControlsHostActivityFingerprint
|
||||||
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.WatchWhileActivityFingerprint
|
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.WatchWhileActivityFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.extensions.transformMethods
|
import app.revanced.shared.extensions.transformMethods
|
||||||
import org.jf.dexlib2.AccessFlags
|
import org.jf.dexlib2.AccessFlags
|
||||||
import org.jf.dexlib2.immutable.ImmutableMethod
|
import org.jf.dexlib2.immutable.ImmutableMethod
|
||||||
@ -23,7 +23,6 @@ import org.jf.dexlib2.immutable.ImmutableMethod
|
|||||||
@Version("0.0.3")
|
@Version("0.0.3")
|
||||||
@DependsOn(
|
@DependsOn(
|
||||||
[
|
[
|
||||||
HDRBrightnessBytecodePatch::class,
|
|
||||||
PlayerTypeHookPatch::class
|
PlayerTypeHookPatch::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@ -34,8 +33,8 @@ class SwipeControlsBytecodePatch : BytecodePatch(
|
|||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
val wrapperClass = SwipeControlsHostActivityFingerprint.result!!.mutableClass
|
val wrapperClass = SwipeControlsHostActivityFingerprint.result?.mutableClass ?: return SwipeControlsHostActivityFingerprint.toErrorResult()
|
||||||
val targetClass = WatchWhileActivityFingerprint.result!!.mutableClass
|
val targetClass = WatchWhileActivityFingerprint.result?.mutableClass ?: return WatchWhileActivityFingerprint.toErrorResult()
|
||||||
|
|
||||||
// inject the wrapper class from integrations into the class hierarchy of WatchWhileActivity
|
// inject the wrapper class from integrations into the class hierarchy of WatchWhileActivity
|
||||||
wrapperClass.setSuperClass(targetClass.superclass)
|
wrapperClass.setSuperClass(targetClass.superclass)
|
||||||
|
@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
|
|||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
import app.revanced.patcher.patch.ResourcePatch
|
import app.revanced.patcher.patch.ResourcePatch
|
||||||
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.patch.SwipeControlsBytecodePatch
|
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.patch.SwipeControlsBytecodePatch
|
||||||
|
import app.revanced.patches.youtube.swipe.swipebrightnessinhdr.bytecode.patch.SwipeGestureBrightnessInHDRPatch
|
||||||
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
import app.revanced.shared.util.resources.ResourceHelper
|
import app.revanced.shared.util.resources.ResourceHelper
|
||||||
@ -22,7 +23,8 @@ import app.revanced.shared.util.resources.ResourceUtils.copyResources
|
|||||||
@DependsOn(
|
@DependsOn(
|
||||||
[
|
[
|
||||||
SettingsPatch::class,
|
SettingsPatch::class,
|
||||||
SwipeControlsBytecodePatch::class
|
SwipeControlsBytecodePatch::class,
|
||||||
|
SwipeGestureBrightnessInHDRPatch::class
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
@YouTubeCompatibility
|
@YouTubeCompatibility
|
||||||
|
@ -6,7 +6,11 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object VideoQualityReferenceFingerprint : MethodFingerprint(
|
object VideoQualityReferenceFingerprint : MethodFingerprint(
|
||||||
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf(
|
returnType = "V",
|
||||||
Opcode.IPUT_OBJECT, Opcode.RETURN_VOID
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
|
parameters = listOf("L"),
|
||||||
|
opcodes = listOf(
|
||||||
|
Opcode.IPUT_OBJECT,
|
||||||
|
Opcode.RETURN_VOID
|
||||||
)
|
)
|
||||||
)
|
)
|
@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object VideoQualitySetterFingerprint : MethodFingerprint(
|
object VideoQualitySetterFingerprint : MethodFingerprint(
|
||||||
"V",
|
returnType = "V",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
listOf("[L", "I", "I", "Z", "I"),
|
parameters = listOf("[L", "I", "I", "Z", "I"),
|
||||||
listOf(
|
opcodes = listOf(
|
||||||
Opcode.IF_EQZ,
|
Opcode.IF_EQZ,
|
||||||
Opcode.INVOKE_VIRTUAL,
|
Opcode.INVOKE_VIRTUAL,
|
||||||
Opcode.MOVE_RESULT_OBJECT,
|
Opcode.MOVE_RESULT_OBJECT,
|
||||||
|
@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
|
|||||||
import org.jf.dexlib2.Opcode
|
import org.jf.dexlib2.Opcode
|
||||||
|
|
||||||
object VideoUserQualityChangeFingerprint : MethodFingerprint(
|
object VideoUserQualityChangeFingerprint : MethodFingerprint(
|
||||||
"V",
|
returnType = "V",
|
||||||
AccessFlags.PUBLIC or AccessFlags.FINAL,
|
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||||
listOf("L","L","I","J"),
|
parameters = listOf("L","L","I","J"),
|
||||||
listOf(
|
opcodes = listOf(
|
||||||
Opcode.MOVE,
|
Opcode.MOVE,
|
||||||
Opcode.MOVE_WIDE,
|
Opcode.MOVE_WIDE,
|
||||||
Opcode.INVOKE_INTERFACE_RANGE,
|
Opcode.INVOKE_INTERFACE_RANGE,
|
||||||
|
@ -15,6 +15,7 @@ import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQua
|
|||||||
import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQualitySetterFingerprint
|
import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQualitySetterFingerprint
|
||||||
import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoUserQualityChangeFingerprint
|
import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoUserQualityChangeFingerprint
|
||||||
import app.revanced.shared.annotation.YouTubeCompatibility
|
import app.revanced.shared.annotation.YouTubeCompatibility
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
|
||||||
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
|
||||||
import org.jf.dexlib2.iface.reference.FieldReference
|
import org.jf.dexlib2.iface.reference.FieldReference
|
||||||
@ -28,42 +29,39 @@ class VideoQualityBytecodePatch : BytecodePatch(
|
|||||||
VideoQualitySetterFingerprint
|
VideoQualitySetterFingerprint
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
|
override fun execute(context: BytecodeContext): PatchResult {
|
||||||
|
VideoQualitySetterFingerprint.result?.let { parentResult ->
|
||||||
|
VideoQualityReferenceFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result ->
|
||||||
|
val instructions = result.method.implementation!!.instructions
|
||||||
|
val qualityFieldReference =
|
||||||
|
(instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
|
||||||
|
|
||||||
|
val qIndexMethodName =
|
||||||
|
context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
|
||||||
|
|
||||||
|
parentResult.mutableMethod.addInstructions(
|
||||||
|
0, """
|
||||||
|
iget-object v0, p0, ${result.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
|
||||||
|
const-string v1, "$qIndexMethodName"
|
||||||
|
invoke-static {p1, p2, v0, v1}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
|
||||||
|
move-result p2
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
} ?: return VideoQualityReferenceFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
VideoUserQualityChangeFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.addInstruction(
|
||||||
|
0,
|
||||||
|
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
|
||||||
|
) ?: return VideoUserQualityChangeFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
} ?: return VideoQualitySetterFingerprint.toErrorResult()
|
||||||
|
|
||||||
|
LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
||||||
|
|
||||||
|
return PatchResultSuccess()
|
||||||
|
}
|
||||||
private companion object {
|
private companion object {
|
||||||
const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR =
|
const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR =
|
||||||
"$VIDEO_PATH/VideoQualityPatch;"
|
"$VIDEO_PATH/VideoQualityPatch;"
|
||||||
}
|
}
|
||||||
override fun execute(context: BytecodeContext): PatchResult {
|
|
||||||
val setterMethod = VideoQualitySetterFingerprint.result!!
|
|
||||||
|
|
||||||
VideoUserQualityChangeFingerprint.resolve(context, setterMethod.classDef)
|
|
||||||
val userQualityResult = VideoUserQualityChangeFingerprint.result!!
|
|
||||||
|
|
||||||
VideoQualityReferenceFingerprint.resolve(context, setterMethod.classDef)
|
|
||||||
val qualityFieldReference =
|
|
||||||
VideoQualityReferenceFingerprint.result!!.method.let { method ->
|
|
||||||
(method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
|
|
||||||
}
|
|
||||||
|
|
||||||
LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
|
|
||||||
|
|
||||||
val qIndexMethodName =
|
|
||||||
context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
|
|
||||||
|
|
||||||
setterMethod.mutableMethod.addInstructions(
|
|
||||||
0,
|
|
||||||
"""
|
|
||||||
iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
|
|
||||||
const-string v1, "$qIndexMethodName"
|
|
||||||
invoke-static {p1, p2, v0, v1}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
|
|
||||||
move-result p2
|
|
||||||
""",
|
|
||||||
)
|
|
||||||
|
|
||||||
userQualityResult.mutableMethod.addInstruction(
|
|
||||||
0,
|
|
||||||
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
|
|
||||||
)
|
|
||||||
|
|
||||||
return PatchResultSuccess()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import app.revanced.patcher.patch.BytecodePatch
|
|||||||
import app.revanced.patcher.patch.PatchResult
|
import app.revanced.patcher.patch.PatchResult
|
||||||
import app.revanced.patcher.patch.PatchResultError
|
import app.revanced.patcher.patch.PatchResultError
|
||||||
import app.revanced.patcher.patch.PatchResultSuccess
|
import app.revanced.patcher.patch.PatchResultSuccess
|
||||||
|
import app.revanced.shared.extensions.toErrorResult
|
||||||
import org.jf.dexlib2.iface.Method
|
import org.jf.dexlib2.iface.Method
|
||||||
|
|
||||||
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
|
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
|
||||||
@ -37,7 +38,7 @@ abstract class AbstractIntegrationsPatch(
|
|||||||
"sput-object v$contextRegister, " +
|
"sput-object v$contextRegister, " +
|
||||||
"$integrationsDescriptor->context:Landroid/content/Context;"
|
"$integrationsDescriptor->context:Landroid/content/Context;"
|
||||||
)
|
)
|
||||||
} ?: return PatchResultError("Could not find hook target fingerprint.")
|
} ?: return toErrorResult()
|
||||||
return PatchResultSuccess()
|
return PatchResultSuccess()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user