This commit is contained in:
inotia00
2023-01-10 04:30:54 +09:00
parent 1b83a30a56
commit 7db88c2dc8
77 changed files with 807 additions and 663 deletions

View File

@ -101,7 +101,7 @@ class EnforceShufflePatch : BytecodePatch(
ImmutableField( ImmutableField(
mutableMethod.definingClass, mutableMethod.definingClass,
"shuffleclass", "shuffleclass",
"$SHUFFLE_CLASS", SHUFFLE_CLASS,
AccessFlags.PUBLIC or AccessFlags.STATIC, AccessFlags.PUBLIC or AccessFlags.STATIC,
null, null,
null, null,

View File

@ -38,6 +38,7 @@ class GeneralAdsPatch : ResourcePatch {
"promotion_", "promotion_",
"compact_premium_", "compact_premium_",
"compact_promoted_", "compact_promoted_",
"simple_text_section",
) )
private val replacements = arrayOf( private val replacements = arrayOf(
@ -46,6 +47,13 @@ class GeneralAdsPatch : ResourcePatch {
"marginTop" "marginTop"
) )
private val additionalReplacements = arrayOf(
"Bottom",
"End",
"Start",
"Top"
)
override fun execute(context: ResourceContext): PatchResult { override fun execute(context: ResourceContext): PatchResult {
context.forEach { context.forEach {
@ -53,11 +61,11 @@ class GeneralAdsPatch : ResourcePatch {
// for each file in the "layouts" directory replace all necessary attributes content // for each file in the "layouts" directory replace all necessary attributes content
context.xmlEditor[it.absolutePath].use { editor -> context.xmlEditor[it.absolutePath].use { editor ->
editor.file.doRecursively { node -> editor.file.doRecursively {
replacements.forEach replacement@{ replacement -> replacements.forEach replacement@{ replacement ->
if (node !is Element) return@replacement if (it !is Element) return@replacement
node.getAttributeNode("android:layout_$replacement")?.let { attribute -> it.getAttributeNode("android:layout_$replacement")?.let { attribute ->
attribute.textContent = "0.0dip" attribute.textContent = "0.0dip"
} }
} }
@ -65,6 +73,18 @@ class GeneralAdsPatch : ResourcePatch {
} }
} }
context.xmlEditor["res/layout/simple_text_section.xml"].use { editor ->
editor.file.doRecursively {
additionalReplacements.forEach replacement@{ replacement ->
if (it !is Element) return@replacement
it.getAttributeNode("android:padding_$replacement")?.let { attribute ->
attribute.textContent = "0.0dip"
}
}
}
}
/* /*
add settings add settings
*/ */

View File

@ -4,18 +4,18 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patcher.util.smali.toInstructions import app.revanced.patcher.util.smali.toInstructions
import app.revanced.patches.youtube.button.whitelist.fingerprint.* import app.revanced.patches.youtube.button.whitelist.fingerprint.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21c import org.jf.dexlib2.builder.instruction.BuilderInstruction21c
import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference import org.jf.dexlib2.dexbacked.reference.DexBackedMethodReference
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@ -23,7 +23,6 @@ import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.iface.reference.MethodReference import org.jf.dexlib2.iface.reference.MethodReference
import org.jf.dexlib2.immutable.ImmutableMethod import org.jf.dexlib2.immutable.ImmutableMethod
import org.jf.dexlib2.immutable.ImmutableMethodImplementation import org.jf.dexlib2.immutable.ImmutableMethodImplementation
import org.jf.dexlib2.Opcode
@Name("channel-whitelist") @Name("channel-whitelist")
@YouTubeCompatibility @YouTubeCompatibility
@ -37,34 +36,67 @@ class WhitelistPatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val PlayerResponseModelParentResult = PlayerResponseModelParentFingerprint.result!!
val PlayerResponseModelParentInstructions = PlayerResponseModelParentResult.mutableMethod.implementation!!.instructions
val injectIndex = PlayerResponseModelParentInstructions.indexOfFirst { PlayerResponseModelParentFingerprint.result?.mutableMethod?.let { method ->
it.opcode == Opcode.CONST_STRING && val instructions = method.implementation!!.instructions
(it as BuilderInstruction21c).reference.toString() == "Person" val injectIndex = instructions.indexOfFirst {
} + 2 it.opcode == Opcode.CONST_STRING &&
(it as BuilderInstruction21c).reference.toString() == "Person"
} + 2
fourthRef = (instructions.elementAt(injectIndex) as ReferenceInstruction).reference as DexBackedMethodReference
} ?: return PlayerResponseModelParentFingerprint.toErrorResult()
val PlayerResponseModelReference = PlayerResponseModelFingerprint.result?.let { result ->
PlayerResponseModelParentResult.method.let { method ->
(method.implementation!!.instructions.elementAt(injectIndex) as ReferenceInstruction).reference as DexBackedMethodReference with (result.method.implementation!!.instructions) {
firstRef = (elementAt(2) as ReferenceInstruction).reference as FieldReference
secondRef = (elementAt(3) as ReferenceInstruction).reference as FieldReference
thirdRef = (elementAt(4) as ReferenceInstruction).reference as MethodReference
} }
with (result.mutableClass) {
methods.add(
ImmutableMethod(
type,
"setCurrentVideoInformation",
listOf(),
"V",
AccessFlags.PRIVATE or AccessFlags.FINAL,
null,
null,
ImmutableMethodImplementation(
2, """
iget-object v0, v1, ${result.classDef.type}->${firstRef.name}:${firstRef.type}
iget-object v0, v0, ${firstRef.type}->${secondRef.name}:${secondRef.type}
invoke-interface {v0}, $thirdRef
move-result-object v0
invoke-interface {v0}, $fourthRef
move-result-object v0
invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V
return-void
""".toInstructions(), null, null
)
).toMutable()
)
}
listOf(
PrimaryInjectFingerprint,
SecondaryInjectFingerprint
).map {
it.result ?: return it.toErrorResult()
}.forEach {
val method = it.mutableMethod
val index = it.scanResult.patternScanResult!!.endIndex + 1
method.addInstruction(
index,
"invoke-direct {p0}, ${result.classDef.type}->setCurrentVideoInformation()V"
)
}
} ?: return PlayerResponseModelFingerprint.toErrorResult()
val PlayerResponseModelResult = PlayerResponseModelFingerprint.result!! val PlayerResponseModelResult = PlayerResponseModelFingerprint.result!!
val PrimaryReference =
PlayerResponseModelResult.method.let { method ->
(method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as FieldReference
}
val SecondaryReference =
PlayerResponseModelResult.method.let { method ->
(method.implementation!!.instructions.elementAt(3) as ReferenceInstruction).reference as FieldReference
}
val TertiaryReference =
PlayerResponseModelResult.method.let { method ->
(method.implementation!!.instructions.elementAt(4) as ReferenceInstruction).reference as MethodReference
}
val classDef = PlayerResponseModelResult.mutableClass val classDef = PlayerResponseModelResult.mutableClass
classDef.methods.add( classDef.methods.add(
ImmutableMethod( ImmutableMethod(
@ -77,11 +109,11 @@ class WhitelistPatch : BytecodePatch(
null, null,
ImmutableMethodImplementation( ImmutableMethodImplementation(
2, """ 2, """
iget-object v0, v1, ${PlayerResponseModelResult.classDef.type}->${PrimaryReference.name}:${PrimaryReference.type} iget-object v0, v1, ${PlayerResponseModelResult.classDef.type}->${firstRef.name}:${firstRef.type}
iget-object v0, v0, ${PrimaryReference.type}->${SecondaryReference.name}:${SecondaryReference.type} iget-object v0, v0, ${firstRef.type}->${secondRef.name}:${secondRef.type}
invoke-interface {v0}, $TertiaryReference invoke-interface {v0}, $thirdRef
move-result-object v0 move-result-object v0
invoke-interface {v0}, $PlayerResponseModelReference invoke-interface {v0}, $fourthRef
move-result-object v0 move-result-object v0
invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V invoke-static {v0}, $VIDEO_PATH/VideoInformation;->setChannelName(Ljava/lang/String;)V
return-void return-void
@ -90,20 +122,13 @@ class WhitelistPatch : BytecodePatch(
).toMutable() ).toMutable()
) )
listOf(
PrimaryInjectFingerprint,
SecondaryInjectFingerprint
).forEach { fingerprint ->
val result = fingerprint.result ?: return PatchResultError("${fingerprint.name} not found")
val method = result.mutableMethod
val index = result.scanResult.patternScanResult!!.endIndex + 1
method.addInstruction(
index,
"invoke-direct {p0}, ${PlayerResponseModelResult.classDef.type}->setCurrentVideoInformation()V"
)
}
return PatchResultSuccess() return PatchResultSuccess()
} }
companion object {
private lateinit var firstRef: FieldReference
private lateinit var secondRef: FieldReference
private lateinit var thirdRef: MethodReference
private lateinit var fourthRef: DexBackedMethodReference
}
} }

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object LayoutSwitchFingerprint : MethodFingerprint( object LayoutSwitchFingerprint : MethodFingerprint(
"I", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( returnType = "I",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,

View File

@ -9,6 +9,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints.LayoutSwitchFingerprint import app.revanced.patches.youtube.extended.layoutswitch.bytecode.fingerprints.LayoutSwitchFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
@Name("layout-switch-bytecode-patch") @Name("layout-switch-bytecode-patch")
@ -21,12 +22,12 @@ class LayoutSwitchBytecodePatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
LayoutSwitchFingerprint.result!!.mutableMethod.addInstructions( LayoutSwitchFingerprint.result?.mutableMethod?.addInstructions(
4, """ 4, """
invoke-static {p0}, $EXTENDED_PATH/LayoutOverridePatch;->getLayoutOverride(I)I invoke-static {p0}, $EXTENDED_PATH/LayoutOverridePatch;->getLayoutOverride(I)I
move-result p0 move-result p0
""" """
) ) ?: return LayoutSwitchFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object OldLayoutFingerprint : MethodFingerprint( object OldLayoutFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,
Opcode.GOTO, Opcode.GOTO,
Opcode.CONST_STRING, Opcode.CONST_STRING,

View File

@ -9,6 +9,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints.OldLayoutFingerprint import app.revanced.patches.youtube.extended.oldlayout.bytecode.fingerprints.OldLayoutFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH import app.revanced.shared.util.integrations.Constants.EXTENDED_PATH
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@ -22,17 +23,19 @@ class OldLayoutBytecodePatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = OldLayoutFingerprint.result!! OldLayoutFingerprint.result?.let {
val method = result.mutableMethod val insertIndex = it.scanResult.patternScanResult!!.startIndex
val index = result.scanResult.patternScanResult!!.startIndex
val register = (method.implementation!!.instructions[index] as OneRegisterInstruction).registerA
method.addInstructions( with (it.mutableMethod) {
index + 1, """ val register = (this.implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA
invoke-static {v$register}, $EXTENDED_PATH/VersionOverridePatch;->getVersionOverride(Ljava/lang/String;)Ljava/lang/String; addInstructions(
move-result-object v$register insertIndex + 1, """
""" invoke-static {v$register}, $EXTENDED_PATH/VersionOverridePatch;->getVersionOverride(Ljava/lang/String;)Ljava/lang/String;
) move-result-object v$register
"""
)
}
} ?: return OldLayoutFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -8,9 +8,9 @@ import org.jf.dexlib2.Opcode
object QualityMenuViewInflateFingerprint : MethodFingerprint( object QualityMenuViewInflateFingerprint : MethodFingerprint(
opcodes = listOf(Opcode.INVOKE_SUPER), opcodes = listOf(Opcode.INVOKE_SUPER),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.videoqualityfragmentLabelId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.videoqualityfragmentLabelId
} == true } == true
} }
) )

View File

@ -3,12 +3,13 @@ package app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecod
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints.QualityMenuViewInflateFingerprint import app.revanced.patches.youtube.layout.flyoutpanel.oldqualitylayout.bytecode.fingerprints.QualityMenuViewInflateFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.FLYOUTPANEL_LAYOUT import app.revanced.shared.util.integrations.Constants.FLYOUTPANEL_LAYOUT
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
@ -19,21 +20,18 @@ class OldQualityLayoutBytecodePatch : BytecodePatch(
listOf(QualityMenuViewInflateFingerprint) listOf(QualityMenuViewInflateFingerprint)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val inflateFingerprintResult = QualityMenuViewInflateFingerprint.result!!
val method = inflateFingerprintResult.mutableMethod
val instructions = method.implementation!!.instructions
// at this index the listener is added to the list view QualityMenuViewInflateFingerprint.result?.mutableMethod?.let {
val listenerInvokeRegister = instructions.size - 1 - 1 with (it.implementation!!.instructions) {
val insertIndex = this.size - 1 - 1
val register = (this[insertIndex] as FiveRegisterInstruction).registerC
// get the register which stores the quality menu list view it.addInstructions(
val onItemClickViewRegister = (instructions[listenerInvokeRegister] as FiveRegisterInstruction).registerC insertIndex, // insert the integrations instructions right before the listener
"invoke-static { v$register }, $FLYOUTPANEL_LAYOUT->enableOldQualityMenu(Landroid/widget/ListView;)V"
// insert the integrations method )
method.addInstruction( }
listenerInvokeRegister, // insert the integrations instructions right before the listener } ?: return QualityMenuViewInflateFingerprint.toErrorResult()
"invoke-static { v$onItemClickViewRegister }, $FLYOUTPANEL_LAYOUT->enableOldQualityMenu(Landroid/widget/ListView;)V"
)
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -8,9 +8,9 @@ import org.jf.dexlib2.Opcode
object ScrubbingLabelFingerprint : MethodFingerprint( object ScrubbingLabelFingerprint : MethodFingerprint(
opcodes = listOf(Opcode.IPUT_BOOLEAN), opcodes = listOf(Opcode.IPUT_BOOLEAN),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.scrubbingLabelId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.scrubbingLabelId
} == true } == true
} }
) )

View File

@ -7,14 +7,16 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.removeInstruction import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints.ScrubbingLabelFingerprint import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.bytecode.fingerprints.ScrubbingLabelFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
import org.jf.dexlib2.iface.reference.FieldReference import org.jf.dexlib2.iface.reference.FieldReference
import org.jf.dexlib2.Opcode
@Name("hide-filmstrip-overlay-bytecode-patch") @Name("hide-filmstrip-overlay-bytecode-patch")
@YouTubeCompatibility @YouTubeCompatibility
@ -25,32 +27,33 @@ class HideFilmstripOverlayBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val scrubbingLabelResult = ScrubbingLabelFingerprint.result!! ScrubbingLabelFingerprint.result?.mutableMethod?.let {
val scrubbingLabelMethod = scrubbingLabelResult.mutableMethod with (it.implementation!!.instructions) {
val scrubbingLabelMethodInstructions = scrubbingLabelMethod.implementation!!.instructions for ((index, instruction) in this.withIndex()) {
if (instruction.opcode != Opcode.IPUT_BOOLEAN) continue
val primaryRegister = (instruction as TwoRegisterInstruction).registerA
val secondaryRegister = (instruction as TwoRegisterInstruction).registerB
val dummyRegister = primaryRegister + 2
val fieldReference = (instruction as ReferenceInstruction).reference as FieldReference
for ((index, instruction) in scrubbingLabelMethodInstructions.withIndex()) { it.addInstructions(
if (instruction.opcode != Opcode.IPUT_BOOLEAN) continue index + 1, """
val scrubbingLabelRegisterA = (instruction as TwoRegisterInstruction).registerA invoke-static {}, $FULLSCREEN_LAYOUT->hideFilmstripOverlay()Z
val scrubbingLabelRegisterB = scrubbingLabelRegisterA + 2 move-result v$dummyRegister
val scrubbingLabelRegisterC = (instruction as TwoRegisterInstruction).registerB if-eqz v$dummyRegister, :show
val scrubbingLabelReference = (instruction as ReferenceInstruction).reference as FieldReference const/4 v$primaryRegister, 0x0
:show
iput-boolean v$primaryRegister, v$secondaryRegister, ${fieldReference.definingClass}->${fieldReference.name}:${fieldReference.type}
"""
)
scrubbingLabelMethod.addInstructions( it.removeInstruction(index)
index + 1, """
invoke-static {}, $FULLSCREEN_LAYOUT->hideFilmstripOverlay()Z
move-result v$scrubbingLabelRegisterB
if-eqz v$scrubbingLabelRegisterB, :show
const/4 v$scrubbingLabelRegisterA, 0x0
:show
iput-boolean v$scrubbingLabelRegisterA, v$scrubbingLabelRegisterC, ${scrubbingLabelReference.definingClass}->${scrubbingLabelReference.name}:${scrubbingLabelReference.type}
"""
)
scrubbingLabelMethod.removeInstruction(index) return PatchResultSuccess()
break }
} }
} ?: return ScrubbingLabelFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultError("Could not find the method to hook.")
} }
} }

View File

@ -6,13 +6,14 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.removeInstruction import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints.* import app.revanced.patches.youtube.layout.fullscreen.hapticfeedback.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT import app.revanced.shared.util.integrations.Constants.FULLSCREEN_LAYOUT
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@ -29,27 +30,36 @@ class HapticFeedBackBytecodePatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
SeekHapticsFingerprint.disableHaptics("disableSeekVibrate") arrayOf(
ScrubbingHapticsFingerprint.voidHaptics("disableScrubbingVibrate") SeekHapticsFingerprint to "disableSeekVibrate",
MarkerHapticsFingerprint.voidHaptics("disableChapterVibrate") ScrubbingHapticsFingerprint to "disableScrubbingVibrate",
ZoomHapticsFingerprint.voidHaptics("disableZoomVibrate") MarkerHapticsFingerprint to "disableChapterVibrate",
ZoomHapticsFingerprint to "disableZoomVibrate"
).map { (fingerprint, name) ->
fingerprint.result?.let {
if (fingerprint == SeekHapticsFingerprint)
it.disableHaptics(name)
else
it.voidHaptics(name)
} ?: return fingerprint.toErrorResult()
}
return PatchResultSuccess() return PatchResultSuccess()
} }
private companion object { private companion object {
fun MethodFingerprint.disableHaptics(targetMethodName: String) { fun MethodFingerprintResult.disableHaptics(targetMethodName: String) {
with(this.result!!) { val startIndex = scanResult.patternScanResult!!.startIndex
val startIndex = scanResult.patternScanResult!!.startIndex val endIndex = scanResult.patternScanResult!!.endIndex
val endIndex = scanResult.patternScanResult!!.endIndex val insertIndex = endIndex + 4
val insertIndex = endIndex + 4 val targetRegister = (method.implementation!!.instructions.elementAt(insertIndex) as OneRegisterInstruction).registerA
val targetRegister = (method.implementation!!.instructions.elementAt(insertIndex) as OneRegisterInstruction).registerA val dummyRegister = targetRegister + 1
val dummyRegister = targetRegister + 1
mutableMethod.removeInstruction(insertIndex) with (mutableMethod) {
removeInstruction(insertIndex)
mutableMethod.addInstructions( addInstructions(
insertIndex, """ insertIndex, """
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
move-result v$dummyRegister move-result v$dummyRegister
if-eqz v$dummyRegister, :vibrate if-eqz v$dummyRegister, :vibrate
@ -57,31 +67,30 @@ class HapticFeedBackBytecodePatch : BytecodePatch(
goto :exit goto :exit
:vibrate :vibrate
const-wide/16 v$targetRegister, 0x19 const-wide/16 v$targetRegister, 0x19
""", listOf(ExternalLabel("exit", mutableMethod.instruction(insertIndex))) """, listOf(ExternalLabel("exit", mutableMethod.instruction(insertIndex)))
) )
mutableMethod.addInstructions( addInstructions(
startIndex, """ startIndex, """
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
move-result v$dummyRegister move-result v$dummyRegister
if-eqz v$dummyRegister, :vibrate if-eqz v$dummyRegister, :vibrate
return-void return-void
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(startIndex))) """, listOf(ExternalLabel("vibrate", mutableMethod.instruction(startIndex)))
) )
} }
} }
fun MethodFingerprint.voidHaptics(targetMethodName: String) { fun MethodFingerprintResult.voidHaptics(targetMethodName: String) {
with(this.result!!) { mutableMethod.addInstructions(
mutableMethod.addInstructions( 0, """
0, """
invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z invoke-static {}, $FULLSCREEN_LAYOUT->$targetMethodName()Z
move-result v0 move-result v0
if-eqz v0, :vibrate if-eqz v0, :vibrate
return-void return-void
""", listOf(ExternalLabel("vibrate", mutableMethod.instruction(0))) """, listOf(ExternalLabel("vibrate", mutableMethod.instruction(0)))
) )
}
} }
} }
} }

View File

@ -6,18 +6,11 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object StartVideoInformerFingerprint : MethodFingerprint( object StartVideoInformerFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L", "L", "L"), listOf( returnType = "V",
Opcode.INVOKE_STATIC, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
Opcode.IGET_OBJECT, opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.IF_EQZ, Opcode.RETURN_VOID,
Opcode.CONST_STRING, ),
Opcode.INVOKE_INTERFACE, strings = listOf("pc")
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
)
) )

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object SubtitleTrackFingerprint : MethodFingerprint( object SubtitleTrackFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( returnType = "Z",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
opcodes = listOf(
Opcode.CONST_STRING, Opcode.CONST_STRING,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,

View File

@ -7,13 +7,12 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints.* import app.revanced.patches.youtube.layout.general.autocaptions.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
@ -32,8 +31,8 @@ class AutoCaptionsBytecodePatch : BytecodePatch(
StartVideoInformerFingerprint.toPatch(Status.DISABLED), StartVideoInformerFingerprint.toPatch(Status.DISABLED),
SubtitleButtonControllerFingerprint.toPatch(Status.ENABLED) SubtitleButtonControllerFingerprint.toPatch(Status.ENABLED)
).forEach { (fingerprint, status) -> ).forEach { (fingerprint, status) ->
with(fingerprint.result ?: return PatchResultError("Failed to find ${fingerprint.name} method.")) { with(fingerprint.result?.mutableMethod ?: return fingerprint.toErrorResult()) {
mutableMethod.addInstructions( addInstructions(
0, 0,
""" """
const/4 v0, ${status.value} const/4 v0, ${status.value}
@ -43,19 +42,19 @@ class AutoCaptionsBytecodePatch : BytecodePatch(
} }
} }
val subtitleTrackMethod = SubtitleTrackFingerprint.result!!.mutableMethod SubtitleTrackFingerprint.result?.mutableMethod?.let {
it.addInstructions(
subtitleTrackMethod.addInstructions( 0, """
0, """ invoke-static {}, $GENERAL_LAYOUT->hideAutoCaptions()Z
invoke-static {}, $GENERAL_LAYOUT->hideAutoCaptions()Z move-result v0
move-result v0 if-eqz v0, :auto_captions_shown
if-eqz v0, :auto_captions_shown sget-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z
sget-boolean v0, $GENERAL_LAYOUT->captionsButtonStatus:Z if-nez v0, :auto_captions_shown
if-nez v0, :auto_captions_shown const/4 v0, 0x1
const/4 v0, 0x1 return v0
return v0 """, listOf(ExternalLabel("auto_captions_shown", it.instruction(0)))
""", listOf(ExternalLabel("auto_captions_shown", subtitleTrackMethod.instruction(0))) )
) } ?: return SubtitleTrackFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -5,8 +5,8 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
object EngagementPanelControllerFingerprint : MethodFingerprint( object EngagementPanelControllerFingerprint : MethodFingerprint(
"L", returnType = "L",
AccessFlags.PRIVATE or AccessFlags.FINAL, access = AccessFlags.PRIVATE or AccessFlags.FINAL,
strings = listOf( strings = listOf(
"EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.", "EngagementPanelController: cannot show EngagementPanel before EngagementPanelController.init() has been called.",
"[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called." "[EngagementPanel] Cannot show EngagementPanel before EngagementPanelController.init() has been called."

View File

@ -11,6 +11,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints.EngagementPanelControllerFingerprint import app.revanced.patches.youtube.layout.general.autopopuppanels.bytecode.fingerprints.EngagementPanelControllerFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
@Name("hide-auto-player-popup-panels-bytecode-patch") @Name("hide-auto-player-popup-panels-bytecode-patch")
@ -22,18 +23,19 @@ class PlayerPopupPanelsBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val engagementPanelControllerMethod = EngagementPanelControllerFingerprint.result!!.mutableMethod
engagementPanelControllerMethod.addInstructions( EngagementPanelControllerFingerprint.result?.mutableMethod?.let {
0, """ it.addInstructions(
invoke-static { }, $GENERAL_LAYOUT->hideAutoPlayerPopupPanels()Z 0, """
move-result v0 invoke-static {}, $GENERAL_LAYOUT->hideAutoPlayerPopupPanels()Z
if-eqz v0, :player_popup_panels_shown move-result v0
if-eqz p4, :player_popup_panels_shown if-eqz v0, :player_popup_panels_shown
const/4 v0, 0x0 if-eqz p4, :player_popup_panels_shown
return-object v0 const/4 v0, 0x0
""", listOf(ExternalLabel("player_popup_panels_shown", engagementPanelControllerMethod.instruction(0))) return-object v0
) """, listOf(ExternalLabel("player_popup_panels_shown", it.instruction(0)))
)
} ?: return EngagementPanelControllerFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -12,7 +12,10 @@ import org.jf.dexlib2.Opcode
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
object CreateMixPlaylistFingerprint : MethodFingerprint( object CreateMixPlaylistFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L", "L"), listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "L", "L", "L", "L", "L", "L"),
opcodes = listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,

View File

@ -21,9 +21,9 @@ object FourthCreateMixPlaylistFingerprint : MethodFingerprint(
Opcode.CHECK_CAST Opcode.CHECK_CAST
), ),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.abclistmenuitemLabelId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.abclistmenuitemLabelId
} == true } == true
} }
) )

View File

@ -12,7 +12,10 @@ import org.jf.dexlib2.Opcode
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
object SecondCreateMixPlaylistFingerprint : MethodFingerprint( object SecondCreateMixPlaylistFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("L", "L", "L", "L", "L", "L"), listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L", "L", "L", "L", "L", "L"),
opcodes = listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,

View File

@ -21,9 +21,9 @@ object ThirdCreateMixPlaylistFingerprint : MethodFingerprint(
Opcode.IPUT_OBJECT Opcode.IPUT_OBJECT
), ),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottompaneloverlaytextLabelId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottompaneloverlaytextLabelId
} == true } == true
} }
) )

View File

@ -4,13 +4,14 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.fingerprints.* import app.revanced.patches.youtube.layout.general.mixplaylists.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.injectHideCall import app.revanced.shared.extensions.injectHideCall
import app.revanced.shared.extensions.toErrorResult
import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@ -29,34 +30,41 @@ class MixPlaylistsBytecodePatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
arrayOf(CreateMixPlaylistFingerprint, SecondCreateMixPlaylistFingerprint).forEach(::addHook) arrayOf(
ThirdCreateMixPlaylistFingerprint.hookMixPlaylists(true) CreateMixPlaylistFingerprint,
FourthCreateMixPlaylistFingerprint.hookMixPlaylists(false) SecondCreateMixPlaylistFingerprint
).map {
it.result ?: return it.toErrorResult()
}.forEach {
it.addHook()
}
arrayOf(
ThirdCreateMixPlaylistFingerprint to true,
FourthCreateMixPlaylistFingerprint to false
).map { (fingerprint, boolean) ->
fingerprint.result?.hookMixPlaylists(boolean) ?: return fingerprint.toErrorResult()
}
return PatchResultSuccess() return PatchResultSuccess()
} }
private fun addHook(fingerprint: MethodFingerprint) { private fun MethodFingerprintResult.addHook() {
with (fingerprint.result!!) { val insertIndex = scanResult.patternScanResult!!.endIndex - 3
val insertIndex = scanResult.patternScanResult!!.endIndex - 3 val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA
val register = (mutableMethod.instruction(insertIndex - 2) as OneRegisterInstruction).registerA mutableMethod.implementation!!.injectHideCall(insertIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
mutableMethod.implementation!!.injectHideCall(insertIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
}
} }
fun MethodFingerprint.hookMixPlaylists(isThirdFingerprint: Boolean) { private fun MethodFingerprintResult.hookMixPlaylists(isThirdFingerprint: Boolean) {
fun getRegister(instruction: Instruction): Int { fun getRegister(instruction: Instruction): Int {
if (isThirdFingerprint) return (instruction as TwoRegisterInstruction).registerA if (isThirdFingerprint) return (instruction as TwoRegisterInstruction).registerA
return (instruction as Instruction21c).registerA return (instruction as Instruction21c).registerA
} }
with(this.result!!) { val endIndex = scanResult.patternScanResult!!.endIndex
val endIndex = scanResult.patternScanResult!!.endIndex val instruction = method.implementation!!.instructions.elementAt(endIndex)
val instruction = method.implementation!!.instructions.elementAt(endIndex) val register = getRegister(instruction)
val register = getRegister(instruction)
mutableMethod.implementation!!.injectHideCall(endIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists") mutableMethod.implementation!!.injectHideCall(endIndex, register, "layout/GeneralLayoutPatch", "hideMixPlaylists")
}
} }
} }

View File

@ -19,12 +19,12 @@ object AccountSwitcherAccessibilityLabelFingerprint : MethodFingerprint(
Opcode.NEW_ARRAY, Opcode.NEW_ARRAY,
Opcode.CONST_4, Opcode.CONST_4,
Opcode.APUT_OBJECT, Opcode.APUT_OBJECT,
Opcode.CONST, Opcode.CONST
), ),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any { it ->
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accountSwitcherAccessibilityLabelId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accountSwitcherAccessibilityLabelId
} == true } == true
} }
) )

View File

@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint import app.revanced.patches.youtube.layout.general.personalinformation.bytecode.fingerprints.AccountSwitcherAccessibilityLabelFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@ -22,23 +23,20 @@ class HideEmailAddressBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val accountSwitcherAccessibilityLabelResult = AccountSwitcherAccessibilityLabelFingerprint.result!!
val accountSwitcherAccessibilityLabelMethod = accountSwitcherAccessibilityLabelResult.mutableMethod
val setVisibilityConstIndex = AccountSwitcherAccessibilityLabelFingerprint.result?.let {
accountSwitcherAccessibilityLabelResult.scanResult.patternScanResult!!.endIndex with (it.mutableMethod) {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
val register = (instruction(insertIndex - 2) as OneRegisterInstruction).registerA
val setVisibilityConstRegister = ( addInstructions(
accountSwitcherAccessibilityLabelMethod.instruction insertIndex, """
(setVisibilityConstIndex - 2) as OneRegisterInstruction invoke-static {v$register}, $GENERAL_LAYOUT->hideEmailAddress(I)I
).registerA move-result v$register
"""
accountSwitcherAccessibilityLabelMethod.addInstructions( )
setVisibilityConstIndex, """ }
invoke-static {v$setVisibilityConstRegister}, $GENERAL_LAYOUT->hideEmailAddress(I)I } ?: return AccountSwitcherAccessibilityLabelFingerprint.toErrorResult()
move-result v$setVisibilityConstRegister
"""
)
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -12,9 +12,9 @@ object PivotBarCreateButtonViewFingerprint : MethodFingerprint(
access = AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Z"), parameters = listOf("Z"),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageOnlyTabId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageOnlyTabId
} == true } == true
} }
) )

View File

@ -17,9 +17,9 @@ object PivotBarFingerprint : MethodFingerprint(
), ),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.definingClass == "Lcom/google/android/apps/youtube/app/ui/pivotbar/PivotBar;" && methodDef.definingClass == "Lcom/google/android/apps/youtube/app/ui/pivotbar/PivotBar;" &&
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageWithTextTabId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.imageWithTextTabId
} == true } == true
} }
) )

View File

@ -65,14 +65,14 @@ class CreateButtonRemoverBytecodePatch : BytecodePatch(
} ?: return PivotBarCreateButtonViewFingerprint.toErrorResult() } ?: return PivotBarCreateButtonViewFingerprint.toErrorResult()
} }
internal companion object { private companion object {
const val hook = const val hook =
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT" + "invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT" +
"->" + "->" +
"hideCreateButton(Landroid/view/View;)V" "hideCreateButton(Landroid/view/View;)V"
private lateinit var createRef: DexBackedMethodReference lateinit var createRef: DexBackedMethodReference
private var isSeondary: Boolean = false var isSeondary: Boolean = false
} }
} }

View File

@ -3,19 +3,18 @@ package app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.byteco
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.MethodFingerprintExtensions.name
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarEnumFingerprint import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarEnumFingerprint
import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarShortsButtonViewFingerprint import app.revanced.patches.youtube.layout.general.pivotbar.shortsbutton.bytecode.fingerprints.PivotBarShortsButtonViewFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.fingerprints.PivotBarFingerprint import app.revanced.shared.fingerprints.PivotBarFingerprint
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook
import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT import app.revanced.shared.util.pivotbar.InjectionUtils.REGISTER_TEMPLATE_REPLACEMENT
import app.revanced.shared.util.pivotbar.InjectionUtils.injectHook
@Name("hide-shorts-button") @Name("hide-shorts-button")
@YouTubeCompatibility @YouTubeCompatibility
@ -29,42 +28,48 @@ class ShortsButtonRemoverBytecodePatch : BytecodePatch(
* Resolve fingerprints * Resolve fingerprints
*/ */
val pivotBarResult = PivotBarFingerprint.result ?: return PatchResultError("PivotBarFingerprint failed") PivotBarFingerprint.result?.let { parentResult ->
val fingerprintResults = arrayOf(PivotBarEnumFingerprint, PivotBarShortsButtonViewFingerprint) with (
.onEach { arrayOf(
val resolutionSucceeded = it.resolve( PivotBarEnumFingerprint,
context, PivotBarShortsButtonViewFingerprint
pivotBarResult.mutableMethod, ).onEach {
pivotBarResult.mutableClass it.resolve(
) context,
parentResult.mutableMethod,
parentResult.mutableClass
)
}.map {
it.result?.scanResult?.patternScanResult ?: return it.toErrorResult()
}
) {
val enumScanResult = this[0]
val buttonViewResult = this[1]
if (!resolutionSucceeded) return PatchResultError("${it.name} failed") val enumHookInsertIndex = enumScanResult.startIndex + 2
val buttonHookInsertIndex = buttonViewResult.endIndex
mapOf(
buttonHook to buttonHookInsertIndex,
enumHook to enumHookInsertIndex
).forEach { (hook, insertIndex) ->
parentResult.mutableMethod.injectHook(hook, insertIndex)
}
} }
.map { it.result!!.scanResult.patternScanResult!! }
val enumScanResult = fingerprintResults[0] } ?: return PivotBarFingerprint.toErrorResult()
val buttonViewResult = fingerprintResults[1]
val enumHookInsertIndex = enumScanResult.startIndex + 2
val buttonHookInsertIndex = buttonViewResult.endIndex
/*
* Inject hooks
*/
val enumHook =
"sput-object v$REGISTER_TEMPLATE_REPLACEMENT, $GENERAL_LAYOUT->lastPivotTab:Ljava/lang/Enum;"
val buttonHook =
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT->hideShortsButton(Landroid/view/View;)V"
// Inject bottom to top to not mess up the indices
mapOf(
buttonHook to buttonHookInsertIndex,
enumHook to enumHookInsertIndex
).forEach { (hook, insertIndex) ->
pivotBarResult.mutableMethod.injectHook(hook, insertIndex)
}
return PatchResultSuccess() return PatchResultSuccess()
} }
private companion object {
const val enumHook =
"sput-object v$REGISTER_TEMPLATE_REPLACEMENT, $GENERAL_LAYOUT" +
"->" +
"lastPivotTab:Ljava/lang/Enum;"
const val buttonHook =
"invoke-static { v$REGISTER_TEMPLATE_REPLACEMENT }, $GENERAL_LAYOUT" +
"->" +
"hideShortsButton(Landroid/view/View;)V"
}
} }

View File

@ -30,12 +30,15 @@ class WideSearchbarBytecodePatch : BytecodePatch(
WideSearchbarOneParentFingerprint to WideSearchbarOneFingerprint, WideSearchbarOneParentFingerprint to WideSearchbarOneFingerprint,
WideSearchbarTwoParentFingerprint to WideSearchbarTwoFingerprint WideSearchbarTwoParentFingerprint to WideSearchbarTwoFingerprint
).map { (parentFingerprint, fingerprint) -> ).map { (parentFingerprint, fingerprint) ->
parentFingerprint.result?.let { parentResult -> parentFingerprint.result?.classDef?.let { classDef ->
fingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { fingerprint.also { it.resolve(context, classDef) }.result?.let {
val index = if (fingerprint == WideSearchbarOneFingerprint) it.scanResult.patternScanResult!!.endIndex
else it.scanResult.patternScanResult!!.startIndex
val targetMethod = val targetMethod =
context context
.toMethodWalker(it.method) .toMethodWalker(it.method)
.nextMethod(it.scanResult.patternScanResult!!.endIndex, true) .nextMethod(index, true)
.getMethod() as MutableMethod .getMethod() as MutableMethod
injectSearchBarHook(targetMethod) injectSearchBarHook(targetMethod)

View File

@ -4,7 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object LayoutConstructorFingerprint : MethodFingerprint( object LayoutConstructorFingerprint : MethodFingerprint(
strings = listOf("1.0x"), strings = listOf("1.0x"),
customFingerprint = { methodDef -> customFingerprint = {
methodDef.definingClass.endsWith("YouTubeControlsOverlay;") it.definingClass.endsWith("YouTubeControlsOverlay;")
} }
) )

View File

@ -11,6 +11,7 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.fingerprints.LayoutConstructorFingerprint import app.revanced.patches.youtube.layout.player.autoplaybutton.bytecode.fingerprints.LayoutConstructorFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.patches.mapping.ResourceMappingPatch import app.revanced.shared.patches.mapping.ResourceMappingPatch
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.Instruction
@ -28,31 +29,33 @@ class HideAutoplayButtonBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val layoutGenMethodResult = LayoutConstructorFingerprint.result!!
val layoutGenMethod = layoutGenMethodResult.mutableMethod
val layoutGenMethodInstructions = layoutGenMethod.implementation!!.instructions
// resolve the offsets such as ... // resolve the offsets such as ...
val autoNavPreviewStubId = ResourceMappingPatch.resourceMappings.single { val autoNavPreviewStubId = ResourceMappingPatch.resourceMappings.single {
it.name == "autonav_preview_stub" it.name == "autonav_preview_stub"
}.id }.id
// where to insert the branch instructions and ...
val insertIndex = layoutGenMethodInstructions.indexOfFirst {
(it as? WideLiteralInstruction)?.wideLiteral == autoNavPreviewStubId
}
// where to branch away
val branchIndex = layoutGenMethodInstructions.subList(insertIndex + 1, layoutGenMethodInstructions.size - 1).indexOfFirst {
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
} + 2
val jumpInstruction = layoutGenMethodInstructions[insertIndex + branchIndex] as Instruction LayoutConstructorFingerprint.result?.mutableMethod?.let { method ->
layoutGenMethod.addInstructions( with (method.implementation!!.instructions) {
insertIndex, """ // where to insert the branch instructions and ...
invoke-static {}, $PLAYER_LAYOUT->hideAutoPlayButton()Z val insertIndex = this.indexOfFirst {
move-result v15 (it as? WideLiteralInstruction)?.wideLiteral == autoNavPreviewStubId
if-nez v15, :hidden }
""", listOf(ExternalLabel("hidden", jumpInstruction)) // where to branch away
) val branchIndex = this.subList(insertIndex + 1, this.size - 1).indexOfFirst {
((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "addOnLayoutChangeListener"
} + 2
val jumpInstruction = this[insertIndex + branchIndex] as Instruction
method.addInstructions(
insertIndex, """
invoke-static {}, $PLAYER_LAYOUT->hideAutoPlayButton()Z
move-result v15
if-nez v15, :hidden
""", listOf(ExternalLabel("hidden", jumpInstruction))
)
}
} ?: return LayoutConstructorFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -8,6 +8,7 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint import app.revanced.shared.fingerprints.SubtitleButtonControllerFingerprint
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@ -15,24 +16,27 @@ import org.jf.dexlib2.Opcode
@Name("hide-captions-button-bytecode-patch") @Name("hide-captions-button-bytecode-patch")
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideCaptionsButtonBytecodePatch : BytecodePatch(listOf( class HideCaptionsButtonBytecodePatch : BytecodePatch(
SubtitleButtonControllerFingerprint, listOf(
)) { SubtitleButtonControllerFingerprint
)
) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val subtitleButtonControllerMethod = SubtitleButtonControllerFingerprint.result!!.mutableMethod SubtitleButtonControllerFingerprint.result?.mutableMethod?.let {
val subtitleButtonControllerMethodInstructions = subtitleButtonControllerMethod.implementation!!.instructions with (it.implementation!!.instructions) {
for ((index, instruction) in this.withIndex()) {
if (instruction.opcode != Opcode.IGET_BOOLEAN) continue
for ((index, instruction) in subtitleButtonControllerMethodInstructions.withIndex()) { it.addInstruction(
if (instruction.opcode != Opcode.IGET_BOOLEAN) continue index + 1,
"invoke-static {v0}, $PLAYER_LAYOUT->hideCaptionsButton(Landroid/widget/ImageView;)V"
)
subtitleButtonControllerMethod.addInstruction( break
index + 1, }
"invoke-static {v0}, $PLAYER_LAYOUT->hideCaptionsButton(Landroid/widget/ImageView;)V" }
) } ?: return SubtitleButtonControllerFingerprint.toErrorResult()
break
}
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -11,7 +11,7 @@ import org.jf.dexlib2.AccessFlags
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
object InfocardsIncognitoFingerprint : MethodFingerprint( object InfocardsIncognitoFingerprint : MethodFingerprint(
"Ljava/lang/Boolean;", returnType = "Ljava/lang/Boolean;",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("vibrator") strings = listOf("vibrator")
) )

View File

@ -11,7 +11,7 @@ import org.jf.dexlib2.AccessFlags
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
object InfocardsIncognitoParentFingerprint : MethodFingerprint( object InfocardsIncognitoParentFingerprint : MethodFingerprint(
"Ljava/lang/String;", returnType = "Ljava/lang/String;",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("player_overlay_info_card_teaser"), strings = listOf("player_overlay_info_card_teaser"),
) )

View File

@ -11,6 +11,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoFingerprint import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoFingerprint
import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoParentFingerprint import app.revanced.patches.youtube.layout.player.infocards.bytecode.fingerprints.InfocardsIncognitoParentFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
@Name("hide-info-cards-bytecode-patch") @Name("hide-info-cards-bytecode-patch")
@ -20,16 +21,17 @@ class HideInfoCardsBytecodePatch : BytecodePatch(
listOf(InfocardsIncognitoParentFingerprint) listOf(InfocardsIncognitoParentFingerprint)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
with(InfocardsIncognitoFingerprint.also { InfocardsIncognitoParentFingerprint.result?.classDef?.let { classDef ->
it.resolve(context, InfocardsIncognitoParentFingerprint.result!!.classDef) InfocardsIncognitoFingerprint.also {
}.result!!.mutableMethod) { it.resolve(context, classDef)
addInstructions( }.result?.mutableMethod?.
addInstructions(
1, """ 1, """
invoke-static {v0}, $PLAYER_LAYOUT->hideInfoCard(Z)Z invoke-static {v0}, $PLAYER_LAYOUT->hideInfoCard(Z)Z
move-result v0 move-result v0
""" """
) ) ?: return InfocardsIncognitoFingerprint.toErrorResult()
} } ?: return InfocardsIncognitoParentFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -5,6 +5,9 @@ import org.jf.dexlib2.Opcode
object UserAgentHeaderBuilderFingerprint : MethodFingerprint( object UserAgentHeaderBuilderFingerprint : MethodFingerprint(
parameters = listOf("L", "L", "L"), parameters = listOf("L", "L", "L"),
opcodes = listOf(Opcode.MOVE_RESULT_OBJECT, Opcode.INVOKE_VIRTUAL), opcodes = listOf(
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL
),
strings = listOf("(Linux; U; Android "), strings = listOf("(Linux; U; Android "),
) )

View File

@ -9,7 +9,9 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.misc.clientspoof.bytecode.fingerprints.UserAgentHeaderBuilderFingerprint import app.revanced.patches.youtube.misc.clientspoof.bytecode.fingerprints.UserAgentHeaderBuilderFingerprint
import app.revanced.patches.youtube.misc.microg.shared.Constants.PACKAGE_NAME
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction import org.jf.dexlib2.iface.instruction.FiveRegisterInstruction
@Name("client-spoof-bytecode-patch") @Name("client-spoof-bytecode-patch")
@ -19,14 +21,15 @@ class ClientSpoofBytecodePatch : BytecodePatch(
listOf(UserAgentHeaderBuilderFingerprint) listOf(UserAgentHeaderBuilderFingerprint)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = UserAgentHeaderBuilderFingerprint.result!!
val method = result.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex UserAgentHeaderBuilderFingerprint.result?.let {
val packageNameRegister = (method.instruction(insertIndex) as FiveRegisterInstruction).registerD val insertIndex = it.scanResult.patternScanResult!!.endIndex
val originalPackageName = "com.google.android.youtube" with (it.mutableMethod) {
method.addInstruction(insertIndex, "const-string v$packageNameRegister, \"$originalPackageName\"") val packageNameRegister = (instruction(insertIndex) as FiveRegisterInstruction).registerD
addInstruction(insertIndex, "const-string v$packageNameRegister, \"$PACKAGE_NAME\"")
}
} ?: return UserAgentHeaderBuilderFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -7,13 +7,20 @@ import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MaxBufferFingerprint : MethodFingerprint( object MaxBufferFingerprint : MethodFingerprint(
"I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), returnType = "I",
listOf(Opcode.SGET_OBJECT, Opcode.IGET, Opcode.IF_EQZ, Opcode.RETURN), access = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef -> parameters = listOf(),
methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" opcodes = listOf(
&& methodDef.implementation!!.instructions.any { Opcode.SGET_OBJECT,
((it as? NarrowLiteralInstruction)?.narrowLiteral == 120000) Opcode.IGET,
&& methodDef.name == "r" Opcode.IF_EQZ,
Opcode.RETURN
),
customFingerprint = {
it.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
&& it.implementation!!.instructions.any { instruction ->
((instruction as? NarrowLiteralInstruction)?.narrowLiteral == 120000)
&& it.name == "r"
} }
} }
) )

View File

@ -7,12 +7,17 @@ import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object PlaybackBufferFingerprint : MethodFingerprint( object PlaybackBufferFingerprint : MethodFingerprint(
"I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), returnType = "I",
listOf(Opcode.IF_LEZ, Opcode.RETURN), access = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef -> parameters = listOf(),
methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" opcodes = listOf(
&& methodDef.implementation!!.instructions.any { Opcode.IF_LEZ,
((it as? NarrowLiteralInstruction)?.narrowLiteral == 1600) Opcode.RETURN
),
customFingerprint = {
it.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
&& it.implementation!!.instructions.any { instruction ->
((instruction as? NarrowLiteralInstruction)?.narrowLiteral == 1600)
} }
} }
) )

View File

@ -7,12 +7,17 @@ import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object ReBufferFingerprint : MethodFingerprint( object ReBufferFingerprint : MethodFingerprint(
"I", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), returnType = "I",
listOf(Opcode.IF_LEZ, Opcode.RETURN), access = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef -> parameters = listOf(),
methodDef.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" opcodes = listOf(
&& methodDef.implementation!!.instructions.any { Opcode.IF_LEZ,
((it as? NarrowLiteralInstruction)?.narrowLiteral == 5000) Opcode.RETURN
),
customFingerprint = {
it.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;"
&& it.implementation!!.instructions.any { instruction ->
((instruction as? NarrowLiteralInstruction)?.narrowLiteral == 5000)
} }
} }
) )

View File

@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object ExternalBrowserPrimaryFingerprint : MethodFingerprint( object ExternalBrowserPrimaryFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
opcodes = listOf(
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.NEW_INSTANCE, Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,

View File

@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object ExternalBrowserSecondaryFingerprint : MethodFingerprint( object ExternalBrowserSecondaryFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.FINAL, opcodes = listOf( returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf(
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.NEW_INSTANCE, Opcode.NEW_INSTANCE,
Opcode.CONST_STRING Opcode.CONST_STRING

View File

@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object ExternalBrowserTertiaryFingerprint : MethodFingerprint( object ExternalBrowserTertiaryFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, opcodes = listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
opcodes = listOf(
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.NEW_INSTANCE, Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,

View File

@ -9,6 +9,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints.* import app.revanced.patches.youtube.misc.externalbrowser.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.MISC_PATH import app.revanced.shared.util.integrations.Constants.MISC_PATH
import org.jf.dexlib2.iface.instruction.formats.Instruction21c import org.jf.dexlib2.iface.instruction.formats.Instruction21c
@ -28,19 +29,20 @@ class ExternalBrowserBytecodePatch : BytecodePatch(
ExternalBrowserPrimaryFingerprint, ExternalBrowserPrimaryFingerprint,
ExternalBrowserSecondaryFingerprint, ExternalBrowserSecondaryFingerprint,
ExternalBrowserTertiaryFingerprint ExternalBrowserTertiaryFingerprint
).forEach { fingerprint -> ).forEach {
val result = fingerprint.result!! val result = it.result?: return it.toErrorResult()
val method = result.mutableMethod
val endIndex = result.scanResult.patternScanResult!!.endIndex val endIndex = result.scanResult.patternScanResult!!.endIndex
val register = (method.implementation!!.instructions[endIndex] as Instruction21c).registerA with (result.mutableMethod) {
val register = (implementation!!.instructions[endIndex] as Instruction21c).registerA
method.addInstructions( addInstructions(
endIndex + 1, """ endIndex + 1, """
invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String; invoke-static {v$register}, $MISC_PATH/ExternalBrowserPatch;->enableExternalBrowser(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$register move-result-object v$register
""" """
) )
}
} }
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint( object OpenLinksDirectlyFingerprintPrimary : MethodFingerprint(
"Ljava/lang/Object", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( returnType = "Ljava/lang/Object",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint( object OpenLinksDirectlyFingerprintSecondary : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), listOf( returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,

View File

@ -4,12 +4,13 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.fingerprints.* import app.revanced.patches.youtube.misc.openlinksdirectly.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.MISC_PATH import app.revanced.shared.util.integrations.Constants.MISC_PATH
import org.jf.dexlib2.iface.instruction.Instruction import org.jf.dexlib2.iface.instruction.Instruction
import org.jf.dexlib2.iface.instruction.formats.Instruction11x import org.jf.dexlib2.iface.instruction.formats.Instruction11x
@ -26,29 +27,31 @@ class OpenLinksDirectlyBytecodePatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
OpenLinksDirectlyFingerprintPrimary.hookUriParser(true) arrayOf(
OpenLinksDirectlyFingerprintSecondary.hookUriParser(false) OpenLinksDirectlyFingerprintPrimary to true,
OpenLinksDirectlyFingerprintSecondary to false
).map { (fingerprint, boolean) ->
fingerprint.result?.hookUriParser(boolean) ?: return fingerprint.toErrorResult()
}
return PatchResultSuccess() return PatchResultSuccess()
} }
} }
fun MethodFingerprint.hookUriParser(isPrimaryFingerprint: Boolean) { fun MethodFingerprintResult.hookUriParser(isPrimaryFingerprint: Boolean) {
fun getTargetRegister(instruction: Instruction): Int { fun getTargetRegister(instruction: Instruction): Int {
if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC if (isPrimaryFingerprint) return (instruction as Instruction35c).registerC
return (instruction as Instruction11x).registerA return (instruction as Instruction11x).registerA
} }
with(this.result!!) { val startIndex = scanResult.patternScanResult!!.startIndex
val startIndex = scanResult.patternScanResult!!.startIndex val instruction = method.implementation!!.instructions.elementAt(startIndex + 1)
val instruction = method.implementation!!.instructions.elementAt(startIndex + 1) val insertIndex = if (isPrimaryFingerprint) 1 else 2
val insertIndex = if (isPrimaryFingerprint) 1 else 2 val targetRegister = getTargetRegister(instruction)
val targetRegister = getTargetRegister(instruction)
mutableMethod.addInstructions( mutableMethod.addInstructions(
startIndex + insertIndex, """ startIndex + insertIndex, """
invoke-static {v$targetRegister}, $MISC_PATH/OpenLinksDirectlyPatch;->enableBypassRedirect(Ljava/lang/String;)Ljava/lang/String; invoke-static {v$targetRegister}, $MISC_PATH/OpenLinksDirectlyPatch;->enableBypassRedirect(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister move-result-object v$targetRegister
""" """
) )
}
} }

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object PrimaryPiPFingerprint : MethodFingerprint( object PrimaryPiPFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object SecondaryPiPFingerprint : MethodFingerprint( object SecondaryPiPFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,

View File

@ -15,6 +15,7 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.misc.playercontrols.fingerprints.* import app.revanced.patches.youtube.misc.playercontrols.fingerprints.*
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("player-controls-bytecode-patch") @Name("player-controls-bytecode-patch")
@ -31,24 +32,33 @@ class PlayerControlsBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
showPlayerControlsFingerprintResult = PlayerControlsVisibilityFingerprint.result!!
controlsLayoutInflateFingerprintResult = ControlsLayoutInflateFingerprint.result!!
// TODO: another solution is required, this is hacky PlayerControlsVisibilityFingerprint.result?.let {
listOf(BottomControlsInflateFingerprint).resolve(context, context.classes) showPlayerControlsResult = it
inflateFingerprintResult = BottomControlsInflateFingerprint.result!! } ?: return PlayerControlsVisibilityFingerprint.toErrorResult()
VisibilityNegatedFingerprint.resolve(context, VisibilityNegatedParentFingerprint.result!!.classDef) ControlsLayoutInflateFingerprint.result?.let {
visibilityNegatedFingerprintResult = VisibilityNegatedFingerprint.result!! controlsLayoutInflateResult = it
} ?: return ControlsLayoutInflateFingerprint.toErrorResult()
BottomControlsInflateFingerprint.result?.let {
inflateResult = it
} ?: return BottomControlsInflateFingerprint.toErrorResult()
VisibilityNegatedParentFingerprint.result?.let { parentResult ->
VisibilityNegatedFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
visibilityNegatedResult = it
} ?: return VisibilityNegatedFingerprint.toErrorResult()
} ?: return VisibilityNegatedParentFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
internal companion object { internal companion object {
lateinit var showPlayerControlsFingerprintResult: MethodFingerprintResult lateinit var showPlayerControlsResult: MethodFingerprintResult
lateinit var controlsLayoutInflateFingerprintResult: MethodFingerprintResult lateinit var controlsLayoutInflateResult: MethodFingerprintResult
lateinit var inflateFingerprintResult: MethodFingerprintResult lateinit var inflateResult: MethodFingerprintResult
lateinit var visibilityNegatedFingerprintResult: MethodFingerprintResult lateinit var visibilityNegatedResult: MethodFingerprintResult
fun MethodFingerprintResult.injectVisibilityCall( fun MethodFingerprintResult.injectVisibilityCall(
descriptor: String, descriptor: String,
@ -60,32 +70,33 @@ class PlayerControlsBytecodePatch : BytecodePatch(
) )
} }
fun MethodFingerprintResult.injectCalls( private fun MethodFingerprintResult.injectCalls(
descriptor: String descriptor: String
) { ) {
val endIndex = scanResult.patternScanResult!!.endIndex val endIndex = scanResult.patternScanResult!!.endIndex
val viewRegister = (mutableMethod.instruction(endIndex) as OneRegisterInstruction).registerA with (mutableMethod) {
val viewRegister = (instruction(endIndex) as OneRegisterInstruction).registerA
mutableMethod.addInstruction( addInstruction(
endIndex + 1, endIndex + 1,
"invoke-static {v$viewRegister}, $descriptor->initialize(Ljava/lang/Object;)V" "invoke-static {v$viewRegister}, $descriptor->initialize(Ljava/lang/Object;)V"
) )
}
} }
fun injectVisibility(descriptor: String) { fun injectVisibility(descriptor: String) {
showPlayerControlsFingerprintResult.injectVisibilityCall(descriptor, "changeVisibility") showPlayerControlsResult.injectVisibilityCall(descriptor, "changeVisibility")
} }
fun injectVisibilityNegated(descriptor: String) { fun injectVisibilityNegated(descriptor: String) {
visibilityNegatedFingerprintResult.injectVisibilityCall(descriptor, "changeVisibilityNegatedImmediate") visibilityNegatedResult.injectVisibilityCall(descriptor, "changeVisibilityNegatedImmediate")
} }
fun initializeSB(descriptor: String) { fun initializeSB(descriptor: String) {
controlsLayoutInflateFingerprintResult.injectCalls(descriptor) controlsLayoutInflateResult.injectCalls(descriptor)
} }
fun initializeControl(descriptor: String) { fun initializeControl(descriptor: String) {
inflateFingerprintResult.injectCalls(descriptor) inflateResult.injectCalls(descriptor)
} }
} }
} }

View File

@ -12,9 +12,9 @@ object BottomControlsInflateFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT_OBJECT Opcode.MOVE_RESULT_OBJECT
), ),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottomUiContainerResourceId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.bottomUiContainerResourceId
} == true } == true
} }
) )

View File

@ -14,9 +14,9 @@ object ControlsLayoutInflateFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT_OBJECT Opcode.MOVE_RESULT_OBJECT
), ),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.controlsLayoutStubResourceId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.controlsLayoutStubResourceId
} == true } == true
} }
) )

View File

@ -3,9 +3,9 @@ package app.revanced.patches.youtube.misc.playercontrols.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PlayerControlsVisibilityFingerprint : MethodFingerprint( object PlayerControlsVisibilityFingerprint : MethodFingerprint(
"V", returnType = "V",
parameters = listOf("Z", "Z"), parameters = listOf("Z", "Z"),
customFingerprint = { methodDef -> customFingerprint = {
methodDef.definingClass.endsWith("YouTubeControlsOverlay;") it.definingClass.endsWith("YouTubeControlsOverlay;")
} }
) )

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object VisibilityNegatedFingerprint : MethodFingerprint( object VisibilityNegatedFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("Z"), opcodes = listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Z"),
opcodes = listOf(
Opcode.IF_EQZ Opcode.IF_EQZ
) )
) )

View File

@ -11,9 +11,9 @@ object VisibilityNegatedParentFingerprint : MethodFingerprint(
returnType = "V", returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.educationTextViewResourceId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.educationTextViewResourceId
} == true } == true
} }
) )

View File

@ -3,7 +3,7 @@ package app.revanced.patches.youtube.misc.playeroverlay.fingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint( object PlayerOverlaysOnFinishInflateFingerprint : MethodFingerprint(
null, null, null, null, null, { methodDef -> customFingerprint = {
methodDef.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && methodDef.name == "onFinishInflate" it.definingClass.endsWith("YouTubePlayerOverlaysLayout;") && it.name == "onFinishInflate"
} }
) )

View File

@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint import app.revanced.patches.youtube.misc.playeroverlay.fingerprint.PlayerOverlaysOnFinishInflateFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.UTILS_PATH import app.revanced.shared.util.integrations.Constants.UTILS_PATH
@Name("player-overlays-hook") @Name("player-overlays-hook")
@ -23,11 +24,13 @@ class PlayerOverlaysHookPatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// hook YouTubePlayerOverlaysLayout.onFinishInflate() // hook YouTubePlayerOverlaysLayout.onFinishInflate()
val method = PlayerOverlaysOnFinishInflateFingerprint.result!!.mutableMethod PlayerOverlaysOnFinishInflateFingerprint.result?.mutableMethod?.let {
method.addInstruction( it.addInstruction(
method.implementation!!.instructions.size - 2, it.implementation!!.instructions.size - 2,
"invoke-static { p0 }, $UTILS_PATH/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V" "invoke-static { p0 }, $UTILS_PATH/PlayerOverlaysHookPatch;->YouTubePlayerOverlaysLayout_onFinishInflateHook(Ljava/lang/Object;)V"
) )
} ?: return PlayerOverlaysOnFinishInflateFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint import app.revanced.patches.youtube.misc.playertype.fingerprint.UpdatePlayerTypeFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.UTILS_PATH import app.revanced.shared.util.integrations.Constants.UTILS_PATH
@Name("player-type-hook") @Name("player-type-hook")
@ -23,10 +24,11 @@ class PlayerTypeHookPatch : BytecodePatch(
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// hook YouTubePlayerOverlaysLayout.updatePlayerLayout() // hook YouTubePlayerOverlaysLayout.updatePlayerLayout()
UpdatePlayerTypeFingerprint.result!!.mutableMethod.addInstruction( UpdatePlayerTypeFingerprint.result?.mutableMethod?.addInstruction(
0, 0,
"invoke-static { p1 }, $UTILS_PATH/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V" "invoke-static { p1 }, $UTILS_PATH/PlayerTypeHookPatch;->YouTubePlayerOverlaysLayout_updatePlayerTypeHookEX(Ljava/lang/Object;)V"
) ) ?: return UpdatePlayerTypeFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -6,12 +6,12 @@ import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object ThemeSetterSystemFingerprint : MethodFingerprint( object ThemeSetterSystemFingerprint : MethodFingerprint(
"L", returnType = "L",
opcodes = listOf(Opcode.RETURN_OBJECT), opcodes = listOf(Opcode.RETURN_OBJECT),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction -> methodDef.implementation?.instructions?.any {
instruction.opcode.ordinal == Opcode.CONST.ordinal && it.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.appearanceStringId (it as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.appearanceStringId
} == true } == true
} }
) )

View File

@ -4,20 +4,21 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint import app.revanced.patches.youtube.misc.settings.bytecode.fingerprints.ThemeSetterSystemFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.findMutableMethodOf import app.revanced.shared.extensions.findMutableMethodOf
import app.revanced.shared.extensions.injectTheme import app.revanced.shared.extensions.injectTheme
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.patches.mapping.ResourceMappingPatch import app.revanced.shared.patches.mapping.ResourceMappingPatch
import app.revanced.patches.youtube.misc.integrations.patch.IntegrationsPatch
import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH import app.revanced.shared.util.integrations.Constants.INTEGRATIONS_PATH
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Name("settings-bytecode-patch") @Name("settings-bytecode-patch")
@DependsOn( @DependsOn(
@ -80,21 +81,24 @@ class SettingsBytecodePatch : BytecodePatch(
} }
// apply the current theme of the settings page // apply the current theme of the settings page
with(ThemeSetterSystemFingerprint.result!!) { ThemeSetterSystemFingerprint.result?.let {
with(mutableMethod) { with(it.mutableMethod) {
val call = "invoke-static {v0}, $INTEGRATIONS_PATH/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V"
addInstruction( addInstruction(
scanResult.patternScanResult!!.startIndex, it.scanResult.patternScanResult!!.startIndex,
call SET_THEME
) )
addInstruction( addInstruction(
mutableMethod.implementation!!.instructions.size - 1, this.implementation!!.instructions.size - 1,
call SET_THEME
) )
} }
} } ?: return ThemeSetterSystemFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
companion object {
const val SET_THEME =
"invoke-static {v0}, $INTEGRATIONS_PATH/utils/ThemeHelper;->setTheme(Ljava/lang/Object;)V"
}
} }

View File

@ -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()
}
}

View File

@ -24,12 +24,18 @@ class SwipeRefreshPatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = SwipeRefreshLayoutFingerprint.result ?:return SwipeRefreshLayoutFingerprint.toErrorResult()
val method = result.mutableMethod
val index = result.scanResult.patternScanResult!!.endIndex
val register = (method.instruction(index) as OneRegisterInstruction).registerA
method.addInstruction(index, "const/4 v$register, 0x0") SwipeRefreshLayoutFingerprint.result?.let {
with (it.mutableMethod) {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
val register = (instruction(insertIndex) as OneRegisterInstruction).registerA
addInstruction(
insertIndex,
"const/4 v$register, 0x0"
)
}
} ?: return SwipeRefreshLayoutFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object LegacyVideoIdFingerprint : MethodFingerprint( object LegacyVideoIdFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC, access = AccessFlags.DECLARED_SYNCHRONIZED or AccessFlags.FINAL or AccessFlags.PUBLIC,
listOf("L"), parameters = listOf("L"),
listOf(Opcode.INVOKE_INTERFACE), opcodes = listOf(Opcode.INVOKE_INTERFACE),
customFingerprint = { customFingerprint = {
it.definingClass.endsWith("PlaybackLifecycleMonitor;") it.definingClass.endsWith("PlaybackLifecycleMonitor;")
} }

View File

@ -5,13 +5,13 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.misc.videoid.legacy.fingerprint.LegacyVideoIdFingerprint import app.revanced.patches.youtube.misc.videoid.legacy.fingerprint.LegacyVideoIdFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("video-id-hook-legacy") @Name("video-id-hook-legacy")
@ -24,13 +24,16 @@ class LegacyVideoIdPatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
result = LegacyVideoIdFingerprint.result!!
insertMethod = result.mutableMethod LegacyVideoIdFingerprint.result?.let {
videoIdRegister = insertIndex = it.scanResult.patternScanResult!!.endIndex
(insertMethod.implementation!!.instructions[result.scanResult.patternScanResult!!.endIndex + 1] as OneRegisterInstruction).registerA
offset++ // offset so setCurrentVideoId is called before any injected call with (it.mutableMethod) {
insertMethod = this
videoIdRegister = (implementation!!.instructions[insertIndex + 1] as OneRegisterInstruction).registerA
}
offset++ // offset so setCurrentVideoId is called before any injected call
} ?: return LegacyVideoIdFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
@ -38,10 +41,11 @@ class LegacyVideoIdPatch : BytecodePatch(
companion object { companion object {
private var offset = 2 private var offset = 2
private var insertIndex: Int = 0
private var videoIdRegister: Int = 0 private var videoIdRegister: Int = 0
private lateinit var result: MethodFingerprintResult
private lateinit var insertMethod: MutableMethod private lateinit var insertMethod: MutableMethod
/** /**
* Adds an invoke-static instruction, called with the new id when the video changes * Adds an invoke-static instruction, called with the new id when the video changes
* @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;` * @param methodDescriptor which method to call. Params have to be `Ljava/lang/String;`
@ -50,7 +54,7 @@ class LegacyVideoIdPatch : BytecodePatch(
methodDescriptor: String methodDescriptor: String
) { ) {
insertMethod.addInstructions( insertMethod.addInstructions(
result.scanResult.patternScanResult!!.endIndex + offset, // move-result-object offset insertIndex + offset, // move-result-object offset
"invoke-static {v$videoIdRegister}, $methodDescriptor" "invoke-static {v$videoIdRegister}, $methodDescriptor"
) )
} }

View File

@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MainstreamVideoIdFingerprint : MethodFingerprint( object MainstreamVideoIdFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L"), parameters = listOf("L"),
listOf( opcodes = listOf(
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,

View File

@ -4,6 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object PlayerControllerFingerprint : MethodFingerprint( object PlayerControllerFingerprint : MethodFingerprint(
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.definingClass == "Lapp/revanced/integrations/sponsorblock/PlayerController;" && methodDef.name == "setSponsorBarRect" methodDef.definingClass == "Lapp/revanced/integrations/sponsorblock/PlayerController;"
&& methodDef.name == "setSponsorBarRect"
} }
) )

View File

@ -6,7 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object VideoTimeFingerprint : MethodFingerprint ( object VideoTimeFingerprint : MethodFingerprint (
"V", AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, listOf("J", "J", "J", "J", "I", "L"), listOf( returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("J", "J", "J", "J", "I", "L"),
opcodes = listOf(
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,
Opcode.IPUT_WIDE, Opcode.IPUT_WIDE,
Opcode.IPUT_WIDE, Opcode.IPUT_WIDE,

View File

@ -7,7 +7,6 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.data.toMethodWalker import app.revanced.patcher.data.toMethodWalker
import app.revanced.patcher.extensions.* import app.revanced.patcher.extensions.*
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
@ -17,6 +16,7 @@ import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMu
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
import app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint.* import app.revanced.patches.youtube.misc.videoid.mainstream.fingerprint.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.patches.timebar.HookTimebarPatch import app.revanced.shared.patches.timebar.HookTimebarPatch
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
@ -54,137 +54,146 @@ class MainstreamVideoIdPatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val VideoInformation = "$VIDEO_PATH/VideoInformation;"
val RepeatListenerResult = RepeatListenerFingerprint.result!! RepeatListenerFingerprint.result?.let {
val RepeatListenerMethod = RepeatListenerResult.mutableMethod val removeIndex = it.scanResult.patternScanResult!!.startIndex
val removeIndex = RepeatListenerResult.scanResult.patternScanResult!!.startIndex with (it.mutableMethod) {
// removeInstruction(removeIndex)
removeInstruction(removeIndex - 1)
}
} ?: return RepeatListenerFingerprint.toErrorResult()
// RepeatListenerMethod.removeInstruction(removeIndex)
RepeatListenerMethod.removeInstruction(removeIndex - 1)
with(PlayerInitFingerprint.result!!) { PlayerInitFingerprint.result?.let { parentResult ->
PlayerInitMethod = mutableClass.methods.first { MethodUtil.isConstructor(it) } playerInitMethod = parentResult.mutableClass.methods.first { MethodUtil.isConstructor(it) }
// seek method SeekFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val seekFingerprintResultMethod = SeekFingerprint.also { it.resolve(context, classDef) }.result!!.method val resultMethod = it.method
// create helper method with (it.mutableMethod) {
val seekHelperMethod = ImmutableMethod( val seekHelperMethod = ImmutableMethod(
seekFingerprintResultMethod.definingClass, resultMethod.definingClass,
"seekTo", "seekTo",
listOf(ImmutableMethodParameter("J", null, "time")), listOf(ImmutableMethodParameter("J", null, "time")),
"Z", "Z",
AccessFlags.PUBLIC or AccessFlags.FINAL, AccessFlags.PUBLIC or AccessFlags.FINAL,
null, null, null, null,
MutableMethodImplementation(4) MutableMethodImplementation(4)
).toMutable() ).toMutable()
// get enum type for the seek helper method val seekSourceEnumType = resultMethod.parameterTypes[1].toString()
val seekSourceEnumType = seekFingerprintResultMethod.parameterTypes[1].toString()
// insert helper method instructions seekHelperMethod.addInstructions(
seekHelperMethod.addInstructions( 0,
"""
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType
invoke-virtual {p0, p1, p2, v0}, ${resultMethod.definingClass}->${resultMethod.name}(J$seekSourceEnumType)Z
move-result p1
return p1
"""
)
parentResult.mutableClass.methods.add(seekHelperMethod)
}
} ?: return SeekFingerprint.toErrorResult()
} ?: return PlayerInitFingerprint.toErrorResult()
VideoTimeParentFingerprint.result?.let { parentResult ->
VideoTimeFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.addInstruction(
0, 0,
""" "invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTimeHighPrecision(J)V"
sget-object v0, $seekSourceEnumType->a:$seekSourceEnumType ) ?: return VideoTimeFingerprint.toErrorResult()
invoke-virtual {p0, p1, p2, v0}, ${seekFingerprintResultMethod.definingClass}->${seekFingerprintResultMethod.name}(J$seekSourceEnumType)Z } ?: return VideoTimeParentFingerprint.toErrorResult()
move-result p1
return p1
"""
)
// add the seekTo method to the class for the integrations to call
mutableClass.methods.add(seekHelperMethod)
}
val VideoTimeParentResult = VideoTimeParentFingerprint.result!!
VideoTimeFingerprint.resolve(context, VideoTimeParentResult.classDef)
val VideoTimeMethod = VideoTimeFingerprint.result!!.mutableMethod
VideoTimeMethod.addInstruction(
0,
"invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTimeHighPrecision(J)V"
)
/* /*
Set current video time Set current video time
*/ */
val referenceResult = PlayerControllerSetTimeReferenceFingerprint.result!! PlayerControllerSetTimeReferenceFingerprint.result?.let {
val PlayerControllerSetTimeMethod = with(context
context.toMethodWalker(referenceResult.method) .toMethodWalker(it.method)
.nextMethod(referenceResult.scanResult.patternScanResult!!.startIndex, true) .nextMethod(it.scanResult.patternScanResult!!.startIndex, true)
.getMethod() as MutableMethod .getMethod() as MutableMethod
PlayerControllerSetTimeMethod.addInstruction( ) {
2, addInstruction(
"invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTime(J)V" 2,
) "invoke-static {p1, p2}, $VideoInformation->setCurrentVideoTime(J)V"
)
}
} ?: return PlayerControllerSetTimeReferenceFingerprint.toErrorResult()
val EmptyColorMethod = HookTimebarPatch.EmptyColorFingerprintResult.mutableMethod
val EmptyColorMethodInstructions = EmptyColorMethod.implementation!!.instructions
val methodReference = with (HookTimebarPatch.EmptyColorFingerprintResult.mutableMethod) {
HookTimebarPatch.TimbarFingerprintResult.method.let { method -> val methodReference =
(method.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as MethodReference HookTimebarPatch.TimbarFingerprintResult.method.let {
(it.implementation!!.instructions.elementAt(2) as ReferenceInstruction).reference as MethodReference
}
val instructions = implementation!!.instructions
reactReference =
((instructions.elementAt(instructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name
for ((index, instruction) in instructions.withIndex()) {
if (instruction.opcode != Opcode.CHECK_CAST) continue
val primaryRegister = (instruction as Instruction21c).registerA + 1
val secondaryRegister = primaryRegister + 1
addInstructions(
index, """
invoke-virtual {p0}, $methodReference
move-result-wide v$primaryRegister
invoke-static {v$primaryRegister, v$secondaryRegister}, $VideoInformation->setCurrentVideoLength(J)V
"""
)
break
}
}
PlayerControllerFingerprint.result?.mutableMethod?.let {
val instructions = it.implementation!!.instructions
for ((index, instruction) in instructions.withIndex()) {
if (instruction.opcode != Opcode.CONST_STRING) continue
val register = (instruction as OneRegisterInstruction).registerA
it.replaceInstruction(
index,
"const-string v$register, \"$reactReference\""
)
break
} }
for ((index, instruction) in EmptyColorMethodInstructions.withIndex()) { } ?: return PlayerControllerFingerprint.toErrorResult()
if (instruction.opcode != Opcode.CHECK_CAST) continue
val primaryRegister = (instruction as Instruction21c).registerA + 1
val secondaryRegister = primaryRegister + 1
EmptyColorMethod.addInstructions(
index, """
invoke-virtual {p0}, $methodReference
move-result-wide v$primaryRegister
invoke-static {v$primaryRegister, v$secondaryRegister}, $VideoInformation->setCurrentVideoLength(J)V
"""
)
break
}
val reactReference =
((EmptyColorMethodInstructions.elementAt(EmptyColorMethodInstructions.count() - 3) as ReferenceInstruction).reference as FieldReference).name
val PlayerContrallerResult = PlayerControllerFingerprint.result!!
val PlayerContrallerMethod = PlayerContrallerResult.mutableMethod
val PlayerContrallerInstructions = PlayerContrallerMethod.implementation!!.instructions
/*
Get the instance of the seekbar rectangle
*/
for ((index, instruction) in PlayerContrallerInstructions.withIndex()) {
if (instruction.opcode != Opcode.CONST_STRING) continue
val register = (instruction as OneRegisterInstruction).registerA
PlayerContrallerMethod.replaceInstruction(
index,
"const-string v$register, \"$reactReference\""
)
break
}
InsertResult = MainstreamVideoIdFingerprint.result!! MainstreamVideoIdFingerprint.result?.let {
InsertMethod = InsertResult.mutableMethod insertIndex = it.scanResult.patternScanResult!!.endIndex
InsertIndex = InsertResult.scanResult.patternScanResult!!.endIndex
videoIdRegister = with (it.mutableMethod) {
(InsertMethod.implementation!!.instructions[InsertIndex] as OneRegisterInstruction).registerA insertMethod = this
videoIdRegister = (implementation!!.instructions[insertIndex] as OneRegisterInstruction).registerA
}
offset++ // offset so setCurrentVideoId is called before any injected call
} ?: return MainstreamVideoIdFingerprint.toErrorResult()
injectCall("$VideoInformation->setCurrentVideoId(Ljava/lang/String;)V") injectCall("$VideoInformation->setCurrentVideoId(Ljava/lang/String;)V")
injectCallonCreate(VideoInformation, "onCreate") injectCallonCreate(VideoInformation, "onCreate")
offset++ // offset so setCurrentVideoId is called before any injected call
return PatchResultSuccess() return PatchResultSuccess()
} }
companion object { companion object {
private var offset = 1 const val VideoInformation = "$VIDEO_PATH/VideoInformation;"
private var offset = 0
private var insertIndex: Int = 0
private var reactReference: String? = null
private var videoIdRegister: Int = 0 private var videoIdRegister: Int = 0
private var InsertIndex: Int = 0 private lateinit var insertMethod: MutableMethod
private lateinit var InsertResult: MethodFingerprintResult private lateinit var playerInitMethod: MutableMethod
private lateinit var InsertMethod: MutableMethod
private lateinit var PlayerInitMethod: MutableMethod
/** /**
* Adds an invoke-static instruction, called with the new id when the video changes * Adds an invoke-static instruction, called with the new id when the video changes
@ -193,14 +202,14 @@ class MainstreamVideoIdPatch : BytecodePatch(
fun injectCall( fun injectCall(
methodDescriptor: String methodDescriptor: String
) { ) {
InsertMethod.addInstructions( insertMethod.addInstructions(
InsertIndex + offset, // move-result-object offset insertIndex + offset, // move-result-object offset
"invoke-static {v$videoIdRegister}, $methodDescriptor" "invoke-static {v$videoIdRegister}, $methodDescriptor"
) )
} }
fun injectCallonCreate(MethodClass: String, MethodName: String) = fun injectCallonCreate(MethodClass: String, MethodName: String) =
PlayerInitMethod.addInstruction( playerInitMethod.addInstruction(
4, 4,
"invoke-static {v0}, $MethodClass->$MethodName(Ljava/lang/Object;)V" "invoke-static {v0}, $MethodClass->$MethodName(Ljava/lang/Object;)V"
) )

View File

@ -4,6 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object SwipeControlsHostActivityFingerprint : MethodFingerprint( object SwipeControlsHostActivityFingerprint : MethodFingerprint(
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.definingClass == "Lapp/revanced/integrations/swipecontrols/SwipeControlsHostActivity;" && methodDef.name == "<init>" methodDef.definingClass == "Lapp/revanced/integrations/swipecontrols/SwipeControlsHostActivity;"
&& methodDef.name == "<init>"
} }
) )

View File

@ -4,6 +4,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
object WatchWhileActivityFingerprint : MethodFingerprint( object WatchWhileActivityFingerprint : MethodFingerprint(
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.definingClass.endsWith("WatchWhileActivity;") && methodDef.name == "<init>" methodDef.definingClass.endsWith("WatchWhileActivity;")
&& methodDef.name == "<init>"
} }
) )

View File

@ -9,11 +9,11 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.TypeUtil.traverseClassHierarchy import app.revanced.patcher.util.TypeUtil.traverseClassHierarchy
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
import app.revanced.patches.youtube.misc.hdrbrightness.bytecode.patch.HDRBrightnessBytecodePatch
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.SwipeControlsHostActivityFingerprint import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.SwipeControlsHostActivityFingerprint
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.WatchWhileActivityFingerprint import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.fingerprints.WatchWhileActivityFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.extensions.transformMethods import app.revanced.shared.extensions.transformMethods
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.immutable.ImmutableMethod import org.jf.dexlib2.immutable.ImmutableMethod
@ -23,7 +23,6 @@ import org.jf.dexlib2.immutable.ImmutableMethod
@Version("0.0.3") @Version("0.0.3")
@DependsOn( @DependsOn(
[ [
HDRBrightnessBytecodePatch::class,
PlayerTypeHookPatch::class PlayerTypeHookPatch::class
] ]
) )
@ -34,8 +33,8 @@ class SwipeControlsBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val wrapperClass = SwipeControlsHostActivityFingerprint.result!!.mutableClass val wrapperClass = SwipeControlsHostActivityFingerprint.result?.mutableClass ?: return SwipeControlsHostActivityFingerprint.toErrorResult()
val targetClass = WatchWhileActivityFingerprint.result!!.mutableClass val targetClass = WatchWhileActivityFingerprint.result?.mutableClass ?: return WatchWhileActivityFingerprint.toErrorResult()
// inject the wrapper class from integrations into the class hierarchy of WatchWhileActivity // inject the wrapper class from integrations into the class hierarchy of WatchWhileActivity
wrapperClass.setSuperClass(targetClass.superclass) wrapperClass.setSuperClass(targetClass.superclass)

View File

@ -10,6 +10,7 @@ import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.ResourcePatch import app.revanced.patcher.patch.ResourcePatch
import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.patch.SwipeControlsBytecodePatch import app.revanced.patches.youtube.swipe.swipecontrols.bytecode.patch.SwipeControlsBytecodePatch
import app.revanced.patches.youtube.swipe.swipebrightnessinhdr.bytecode.patch.SwipeGestureBrightnessInHDRPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.util.resources.ResourceHelper import app.revanced.shared.util.resources.ResourceHelper
@ -22,7 +23,8 @@ import app.revanced.shared.util.resources.ResourceUtils.copyResources
@DependsOn( @DependsOn(
[ [
SettingsPatch::class, SettingsPatch::class,
SwipeControlsBytecodePatch::class SwipeControlsBytecodePatch::class,
SwipeGestureBrightnessInHDRPatch::class
] ]
) )
@YouTubeCompatibility @YouTubeCompatibility

View File

@ -6,7 +6,11 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object VideoQualityReferenceFingerprint : MethodFingerprint( object VideoQualityReferenceFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( returnType = "V",
Opcode.IPUT_OBJECT, Opcode.RETURN_VOID access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf(
Opcode.IPUT_OBJECT,
Opcode.RETURN_VOID
) )
) )

View File

@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object VideoQualitySetterFingerprint : MethodFingerprint( object VideoQualitySetterFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("[L", "I", "I", "Z", "I"), parameters = listOf("[L", "I", "I", "Z", "I"),
listOf( opcodes = listOf(
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,

View File

@ -6,10 +6,10 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object VideoUserQualityChangeFingerprint : MethodFingerprint( object VideoUserQualityChangeFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L","L","I","J"), parameters = listOf("L","L","I","J"),
listOf( opcodes = listOf(
Opcode.MOVE, Opcode.MOVE,
Opcode.MOVE_WIDE, Opcode.MOVE_WIDE,
Opcode.INVOKE_INTERFACE_RANGE, Opcode.INVOKE_INTERFACE_RANGE,

View File

@ -15,6 +15,7 @@ import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQua
import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQualitySetterFingerprint import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoQualitySetterFingerprint
import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoUserQualityChangeFingerprint import app.revanced.patches.youtube.video.quality.bytecode.fingerprints.VideoUserQualityChangeFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.FieldReference import org.jf.dexlib2.iface.reference.FieldReference
@ -28,42 +29,39 @@ class VideoQualityBytecodePatch : BytecodePatch(
VideoQualitySetterFingerprint VideoQualitySetterFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult {
VideoQualitySetterFingerprint.result?.let { parentResult ->
VideoQualityReferenceFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result ->
val instructions = result.method.implementation!!.instructions
val qualityFieldReference =
(instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
val qIndexMethodName =
context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
parentResult.mutableMethod.addInstructions(
0, """
iget-object v0, p0, ${result.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
const-string v1, "$qIndexMethodName"
invoke-static {p1, p2, v0, v1}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
move-result p2
""",
)
} ?: return VideoQualityReferenceFingerprint.toErrorResult()
VideoUserQualityChangeFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.mutableMethod?.addInstruction(
0,
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
) ?: return VideoUserQualityChangeFingerprint.toErrorResult()
} ?: return VideoQualitySetterFingerprint.toErrorResult()
LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
return PatchResultSuccess()
}
private companion object { private companion object {
const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR = const val INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoQualityPatch;" "$VIDEO_PATH/VideoQualityPatch;"
} }
override fun execute(context: BytecodeContext): PatchResult {
val setterMethod = VideoQualitySetterFingerprint.result!!
VideoUserQualityChangeFingerprint.resolve(context, setterMethod.classDef)
val userQualityResult = VideoUserQualityChangeFingerprint.result!!
VideoQualityReferenceFingerprint.resolve(context, setterMethod.classDef)
val qualityFieldReference =
VideoQualityReferenceFingerprint.result!!.method.let { method ->
(method.implementation!!.instructions.elementAt(0) as ReferenceInstruction).reference as FieldReference
}
LegacyVideoIdPatch.injectCall("$INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->newVideoStarted(Ljava/lang/String;)V")
val qIndexMethodName =
context.classes.single { it.type == qualityFieldReference.type }.methods.single { it.parameterTypes.first() == "I" }.name
setterMethod.mutableMethod.addInstructions(
0,
"""
iget-object v0, p0, ${setterMethod.classDef.type}->${qualityFieldReference.name}:${qualityFieldReference.type}
const-string v1, "$qIndexMethodName"
invoke-static {p1, p2, v0, v1}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->setVideoQuality([Ljava/lang/Object;ILjava/lang/Object;Ljava/lang/String;)I
move-result p2
""",
)
userQualityResult.mutableMethod.addInstruction(
0,
"invoke-static {p3}, $INTEGRATIONS_VIDEO_QUALITY_CLASS_DESCRIPTOR->userChangedQuality(I)V"
)
return PatchResultSuccess()
}
} }

View File

@ -9,6 +9,7 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.shared.extensions.toErrorResult
import org.jf.dexlib2.iface.Method import org.jf.dexlib2.iface.Method
@Description("Applies mandatory patches to implement the ReVanced integrations into the application.") @Description("Applies mandatory patches to implement the ReVanced integrations into the application.")
@ -37,7 +38,7 @@ abstract class AbstractIntegrationsPatch(
"sput-object v$contextRegister, " + "sput-object v$contextRegister, " +
"$integrationsDescriptor->context:Landroid/content/Context;" "$integrationsDescriptor->context:Landroid/content/Context;"
) )
} ?: return PatchResultError("Could not find hook target fingerprint.") } ?: return toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }