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(
mutableMethod.definingClass,
"shuffleclass",
"$SHUFFLE_CLASS",
SHUFFLE_CLASS,
AccessFlags.PUBLIC or AccessFlags.STATIC,
null,
null,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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