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