This commit is contained in:
inotia00 2023-01-09 04:10:53 +09:00
parent 74a46d644d
commit 1b83a30a56
37 changed files with 412 additions and 426 deletions

View File

@ -34,14 +34,14 @@ class CreateButtonRemoverBytecodePatch : BytecodePatch(
* Resolve fingerprints * Resolve fingerprints
*/ */
PivotBarFingerprint.result?.let { result -> PivotBarFingerprint.result?.let {
val startIndex = result.scanResult.patternScanResult!!.startIndex val startIndex = it.scanResult.patternScanResult!!.startIndex
val pivotBarInstructions = result.mutableMethod.implementation!!.instructions val pivotBarInstructions = it.mutableMethod.implementation!!.instructions
createRef = (pivotBarInstructions.elementAt(startIndex) as ReferenceInstruction).reference as DexBackedMethodReference createRef = (pivotBarInstructions.elementAt(startIndex) as ReferenceInstruction).reference as DexBackedMethodReference
} ?: return PivotBarFingerprint.toErrorResult() } ?: return PivotBarFingerprint.toErrorResult()
PivotBarCreateButtonViewFingerprint.result?.let { result -> PivotBarCreateButtonViewFingerprint.result?.let {
with (result.mutableMethod){ with (it.mutableMethod){
val createButtonInstructions = implementation!!.instructions val createButtonInstructions = implementation!!.instructions
createButtonInstructions.filter { instruction -> createButtonInstructions.filter { instruction ->
val fieldReference = (instruction as? ReferenceInstruction)?.reference as? DexBackedMethodReference val fieldReference = (instruction as? ReferenceInstruction)?.reference as? DexBackedMethodReference

View File

@ -1,23 +1,20 @@
package app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.fingerprints package app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(3)
object UserWasInShortsFingerprint : MethodFingerprint( object UserWasInShortsFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"),
opcodes = listOf( opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT
), ),
strings = listOf("Failed to read user_was_in_shorts proto after successful warmup"), strings = listOf("Failed to read user_was_in_shorts proto after successful warmup"),
) )

View File

@ -11,7 +11,9 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.fingerprints.UserWasInShortsFingerprint import app.revanced.patches.youtube.layout.general.startupshortsreset.bytecode.fingerprints.UserWasInShortsFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("hide-startup-shorts-player-bytecode-patch") @Name("hide-startup-shorts-player-bytecode-patch")
@YouTubeCompatibility @YouTubeCompatibility
@ -22,18 +24,22 @@ class HideShortsOnStartupBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val userWasInShortsResult = UserWasInShortsFingerprint.result!!
val userWasInShortsMethod = userWasInShortsResult.mutableMethod
val moveResultIndex = userWasInShortsResult.scanResult.patternScanResult!!.endIndex
userWasInShortsMethod.addInstructions( UserWasInShortsFingerprint.result?.let {
moveResultIndex + 1, """ val insertIndex = it.scanResult.patternScanResult!!.endIndex + 1
invoke-static { }, $GENERAL_LAYOUT->hideStartupShortsPlayer()Z
move-result v5 with (it.mutableMethod) {
if-eqz v5, :show_startup_shorts_player val register = (instruction(insertIndex - 1) as OneRegisterInstruction).registerA + 2
return-void addInstructions(
""", listOf(ExternalLabel("show_startup_shorts_player", userWasInShortsMethod.instruction(moveResultIndex + 1))) insertIndex, """
) invoke-static { }, $GENERAL_LAYOUT->hideStartupShortsPlayer()Z
move-result v$register
if-eqz v$register, :show_startup_shorts_player
return-void
""", listOf(ExternalLabel("show_startup_shorts_player", instruction(insertIndex)))
)
}
} ?: return UserWasInShortsFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -1,22 +1,19 @@
package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints package app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@FuzzyPatternScanMethod(2) // TODO: Find a good threshold value
object MiniPlayerDimensionsCalculatorFingerprint : MethodFingerprint( object MiniPlayerDimensionsCalculatorFingerprint : MethodFingerprint(
"V", "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L"), customFingerprint = { methodDef ->
listOf( methodDef.implementation?.instructions?.any { instruction ->
Opcode.INVOKE_DIRECT, instruction.opcode.ordinal == Opcode.CONST.ordinal &&
Opcode.MOVE_RESULT, (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.floatybarQueueLabelId
Opcode.IF_NEZ, } == true
Opcode.FLOAT_TO_DOUBLE, }
Opcode.CONST_WIDE_HIGH16,
Opcode.CMPL_DOUBLE,
)
) )

View File

@ -6,6 +6,8 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MiniPlayerOverrideFingerprint : MethodFingerprint( object MiniPlayerOverrideFingerprint : MethodFingerprint(
"Z", AccessFlags.STATIC or AccessFlags.PUBLIC, returnType = "Z",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction
) )

View File

@ -6,6 +6,7 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MiniPlayerOverrideNoContextFingerprint : MethodFingerprint( object MiniPlayerOverrideNoContextFingerprint : MethodFingerprint(
"Z", AccessFlags.FINAL or AccessFlags.PRIVATE, returnType = "Z",
access = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction opcodes = listOf(Opcode.RETURN), // anchor to insert the instruction
) )

View File

@ -6,15 +6,15 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object MiniPlayerResponseModelSizeCheckFingerprint : MethodFingerprint( object MiniPlayerResponseModelSizeCheckFingerprint : MethodFingerprint(
"L", returnType = "L",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
listOf("L", "L"), parameters = listOf("L", "L"),
listOf( opcodes = listOf(
Opcode.RETURN_OBJECT, Opcode.RETURN_OBJECT,
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.CHECK_CAST, Opcode.CHECK_CAST,
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_NEZ, Opcode.IF_NEZ
) )
) )

View File

@ -4,21 +4,22 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprintResult
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerDimensionsCalculatorFingerprint import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.*
import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerOverrideFingerprint import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerOverrideNoContextFingerprint
import app.revanced.patches.youtube.layout.general.tabletminiplayer.bytecode.fingerprints.MiniPlayerResponseModelSizeCheckFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Name("enable-tablet-miniplayer-bytecode-patch") @Name("enable-tablet-miniplayer-bytecode-patch")
@DependsOn([SharedResourcdIdPatch::class])
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class TabletMiniPlayerBytecodePatch : BytecodePatch( class TabletMiniPlayerBytecodePatch : BytecodePatch(
@ -28,35 +29,33 @@ class TabletMiniPlayerBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
// first resolve the fingerprints via the parent fingerprint
val miniPlayerClass = MiniPlayerDimensionsCalculatorFingerprint.result!!.classDef
/* MiniPlayerDimensionsCalculatorFingerprint.result?.let { parentResult ->
* no context parameter method // first resolve the fingerprints via the parent fingerprint
*/ val miniPlayerClass = parentResult.classDef
MiniPlayerOverrideNoContextFingerprint.resolve(context, miniPlayerClass)
val (method, _, parameterRegister) = MiniPlayerOverrideNoContextFingerprint.addProxyCall()
// - 1 means to insert before the return instruction
val secondInsertIndex = method.implementation!!.instructions.size - 1
method.insertOverride(secondInsertIndex, parameterRegister /** same register used to return **/)
/* arrayOf(
* method with context parameter MiniPlayerOverrideNoContextFingerprint,
*/ MiniPlayerOverrideFingerprint,
MiniPlayerOverrideFingerprint.resolve(context, miniPlayerClass) MiniPlayerResponseModelSizeCheckFingerprint
val (_, _, _) = MiniPlayerOverrideFingerprint.addProxyCall() ).map {
it to (it.also { it.resolve(context, miniPlayerClass) }.result ?: return it.toErrorResult())
/* }.forEach { (fingerprint, result) ->
* size check return value override if (fingerprint == MiniPlayerOverrideNoContextFingerprint) {
*/ val (method, _, parameterRegister) = result.addProxyCall()
val (_, _, _) = MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall() method.insertOverride(method.implementation!!.instructions.size - 1, parameterRegister)
} else {
val (_, _, _) = result.addProxyCall()
}
}
} ?: return MiniPlayerDimensionsCalculatorFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }
// helper methods // helper methods
private companion object { private companion object {
fun MethodFingerprint.addProxyCall(): Triple<MutableMethod, Int, Int> { fun MethodFingerprintResult.addProxyCall(): Triple<MutableMethod, Int, Int> {
val (method, scanIndex, parameterRegister) = this.unwrap() val (method, scanIndex, parameterRegister) = this.unwrap()
method.insertOverride(scanIndex, parameterRegister) method.insertOverride(scanIndex, parameterRegister)
@ -73,10 +72,9 @@ class TabletMiniPlayerBytecodePatch : BytecodePatch(
) )
} }
fun MethodFingerprint.unwrap(): Triple<MutableMethod, Int, Int> { fun MethodFingerprintResult.unwrap(): Triple<MutableMethod, Int, Int> {
val result = this.result!! val scanIndex = this.scanResult.patternScanResult!!.endIndex
val scanIndex = result.scanResult.patternScanResult!!.endIndex val method = this.mutableMethod
val method = result.mutableMethod
val instructions = method.implementation!!.instructions val instructions = method.implementation!!.instructions
val parameterRegister = (instructions[scanIndex] as OneRegisterInstruction).registerA val parameterRegister = (instructions[scanIndex] as OneRegisterInstruction).registerA

View File

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

View File

@ -5,6 +5,11 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
object WideSearchbarOneParentFingerprint : MethodFingerprint( object WideSearchbarOneParentFingerprint : MethodFingerprint(
"V", AccessFlags.PRIVATE or AccessFlags.FINAL, listOf("L"), returnType = "V", access = AccessFlags.PRIVATE or AccessFlags.FINAL,
strings = listOf("FEhistory", "FEmy_videos", "FEpurchases") parameters = listOf("L"),
strings = listOf(
"FEhistory",
"FEmy_videos",
"FEpurchases"
)
) )

View File

@ -6,7 +6,9 @@ import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
object WideSearchbarTwoFingerprint : MethodFingerprint( object WideSearchbarTwoFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.STATIC, opcodes = listOf( returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.STATIC,
opcodes = listOf(
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_EQZ, Opcode.IF_EQZ,

View File

@ -5,8 +5,8 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
object WideSearchbarTwoParentFingerprint : MethodFingerprint( object WideSearchbarTwoParentFingerprint : MethodFingerprint(
"L", returnType = "L",
AccessFlags.PUBLIC or AccessFlags.STATIC, access = AccessFlags.PUBLIC or AccessFlags.STATIC,
strings = listOf( strings = listOf(
"Callback already registered.", "Callback already registered.",
"Failed to create SpotlightModeController." "Failed to create SpotlightModeController."

View File

@ -10,11 +10,9 @@ import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarOneFingerprint import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.*
import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarOneParentFingerprint
import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarTwoFingerprint
import app.revanced.patches.youtube.layout.general.widesearchbar.bytecode.fingerprints.WideSearchbarTwoParentFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
@Name("enable-wide-searchbar-bytecode-patch") @Name("enable-wide-searchbar-bytecode-patch")
@ -22,29 +20,28 @@ import app.revanced.shared.util.integrations.Constants.GENERAL_LAYOUT
@Version("0.0.1") @Version("0.0.1")
class WideSearchbarBytecodePatch : BytecodePatch( class WideSearchbarBytecodePatch : BytecodePatch(
listOf( listOf(
WideSearchbarOneParentFingerprint, WideSearchbarTwoParentFingerprint WideSearchbarOneParentFingerprint,
WideSearchbarTwoParentFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
WideSearchbarOneFingerprint.resolve(context, WideSearchbarOneParentFingerprint.result!!.classDef)
WideSearchbarTwoFingerprint.resolve(context, WideSearchbarTwoParentFingerprint.result!!.classDef)
val resultOne = WideSearchbarOneFingerprint.result arrayOf(
val targetMethodOne = WideSearchbarOneParentFingerprint to WideSearchbarOneFingerprint,
context WideSearchbarTwoParentFingerprint to WideSearchbarTwoFingerprint
.toMethodWalker(resultOne!!.method) ).map { (parentFingerprint, fingerprint) ->
.nextMethod(resultOne.scanResult.patternScanResult!!.endIndex, true) parentFingerprint.result?.let { parentResult ->
.getMethod() as MutableMethod fingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val targetMethod =
context
.toMethodWalker(it.method)
.nextMethod(it.scanResult.patternScanResult!!.endIndex, true)
.getMethod() as MutableMethod
injectSearchBarHook(targetMethod)
val resultTwo = WideSearchbarTwoFingerprint.result } ?: return fingerprint.toErrorResult()
val targetMethodTwo = } ?: return parentFingerprint.toErrorResult()
context.toMethodWalker(resultTwo!!.method) }
.nextMethod(resultTwo.scanResult.patternScanResult!!.startIndex, true)
.getMethod() as MutableMethod
injectSearchBarHook(targetMethodOne)
injectSearchBarHook(targetMethodTwo)
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -1,11 +1,17 @@
package app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints package app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(3)
object HideWatermarkFingerprint : MethodFingerprint ( object HideWatermarkFingerprint : MethodFingerprint (
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L", "L"), null ,null, null returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L"),
opcodes = listOf(
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.IGET_BOOLEAN
)
) )

View File

@ -1,11 +1,11 @@
package app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints package app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
@FuzzyPatternScanMethod(3)
object HideWatermarkParentFingerprint : MethodFingerprint ( object HideWatermarkParentFingerprint : MethodFingerprint (
"L", AccessFlags.PUBLIC or AccessFlags.FINAL, null, null, listOf("player_overlay_in_video_programming"), null returnType = "L",
access = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("player_overlay_in_video_programming")
) )

View File

@ -4,16 +4,18 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.removeInstruction import app.revanced.patcher.extensions.removeInstruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints.HideWatermarkFingerprint import app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints.HideWatermarkFingerprint
import app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints.HideWatermarkParentFingerprint import app.revanced.patches.youtube.layout.player.watermark.bytecode.fingerprints.HideWatermarkParentFingerprint
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT import app.revanced.shared.util.integrations.Constants.PLAYER_LAYOUT
import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@Name("hide-channel-watermark-bytecode-patch") @Name("hide-channel-watermark-bytecode-patch")
@YouTubeCompatibility @YouTubeCompatibility
@ -24,20 +26,23 @@ class HideChannelWatermarkBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
HideWatermarkFingerprint.resolve(context, HideWatermarkParentFingerprint.result!!.classDef)
val result = HideWatermarkFingerprint.result
?: return PatchResultError("Required parent method could not be found.")
val method = result.mutableMethod HideWatermarkParentFingerprint.result?.let { parentResult ->
val line = method.implementation!!.instructions.size - 5 HideWatermarkFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val insertIndex = it.scanResult.patternScanResult!!.endIndex
method.removeInstruction(line) with (it.mutableMethod) {
method.addInstructions( val register = (instruction(insertIndex) as TwoRegisterInstruction).registerA
line, """ removeInstruction(insertIndex)
invoke-static {}, $PLAYER_LAYOUT->hideChannelWatermark()Z addInstructions(
move-result p2 insertIndex, """
""" invoke-static {}, $PLAYER_LAYOUT->hideChannelWatermark()Z
) move-result v$register
"""
)
}
} ?: return HideWatermarkFingerprint.toErrorResult()
} ?: return HideWatermarkParentFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -1,33 +1,26 @@
package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object SeekbarTappingFingerprint : MethodFingerprint( object SeekbarTappingFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf("L"), listOf( returnType = "Z",
Opcode.INVOKE_VIRTUAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
Opcode.MOVE_RESULT_WIDE, parameters = listOf("L"),
Opcode.IGET, opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IGET,
Opcode.DIV_INT_2ADDR,
Opcode.ADD_INT,
Opcode.SUB_INT_2ADDR,
Opcode.INT_TO_FLOAT,
Opcode.CMPG_FLOAT,
Opcode.IF_GTZ,
Opcode.INT_TO_FLOAT,
Opcode.CMPG_FLOAT,
Opcode.IF_GTZ,
Opcode.CONST_4,
Opcode.INVOKE_INTERFACE,
Opcode.NEW_INSTANCE, Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT, Opcode.INVOKE_DIRECT,
Opcode.IPUT_OBJECT, Opcode.IPUT_OBJECT,
Opcode.INVOKE_VIRTUAL Opcode.INVOKE_VIRTUAL,
) Opcode.RETURN
),
customFingerprint = { methodDef ->
methodDef.name == "onTouchEvent"
&& methodDef.implementation!!.instructions.any {
((it as? NarrowLiteralInstruction)?.narrowLiteral == 2147483647)
}
}
) )

View File

@ -1,43 +1,19 @@
package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints package app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
@FuzzyPatternScanMethod(2) // FIXME: Test this threshold and find the best value.
object SeekbarTappingParentFingerprint : MethodFingerprint( object SeekbarTappingParentFingerprint : MethodFingerprint(
"L", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( returnType = "L",
Opcode.INVOKE_VIRTUAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
Opcode.MOVE_RESULT_OBJECT, customFingerprint = { methodDef ->
Opcode.INVOKE_VIRTUAL, methodDef.implementation?.instructions?.any { instruction ->
Opcode.MOVE_RESULT_OBJECT, instruction.opcode.ordinal == Opcode.CONST.ordinal &&
Opcode.CONST_4, (instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.accessibilityProgressTimeLabelId
Opcode.NEW_ARRAY, } == true
Opcode.INVOKE_VIRTUAL, }
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_WIDE,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_4,
Opcode.APUT_OBJECT,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.RETURN_OBJECT
)
) )

View File

@ -4,21 +4,25 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints.SeekbarTappingFingerprint import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints.SeekbarTappingFingerprint
import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints.SeekbarTappingParentFingerprint import app.revanced.patches.youtube.layout.seekbar.seekbartapping.bytecode.fingerprints.SeekbarTappingParentFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.util.integrations.Constants.SEEKBAR_LAYOUT import app.revanced.shared.util.integrations.Constants.SEEKBAR_LAYOUT
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.instruction.BuilderInstruction21t
import org.jf.dexlib2.iface.Method import org.jf.dexlib2.iface.Method
import org.jf.dexlib2.iface.instruction.formats.Instruction11n import org.jf.dexlib2.iface.instruction.formats.Instruction11n
import org.jf.dexlib2.iface.instruction.formats.Instruction35c import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Name("enable-seekbar-tapping-bytecode-patch") @Name("enable-seekbar-tapping-bytecode-patch")
@DependsOn([SharedResourcdIdPatch::class])
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class SeekbarTappingBytecodePatch : BytecodePatch( class SeekbarTappingBytecodePatch : BytecodePatch(
@ -27,65 +31,51 @@ class SeekbarTappingBytecodePatch : BytecodePatch(
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
var result = SeekbarTappingParentFingerprint.result!!
val tapSeekMethods = mutableMapOf<String, Method>() val tapSeekMethods = mutableMapOf<String, Method>()
// find the methods which tap the seekbar SeekbarTappingParentFingerprint.result?.let { parentResult ->
for (it in result.classDef.methods) { for (it in parentResult.classDef.methods) {
if (it.implementation == null) continue if (it.implementation == null) continue
val instructions = it.implementation!!.instructions val instructions = it.implementation!!.instructions
// here we make sure we actually find the method because it has more than 7 instructions // here we make sure we actually find the method because it has more than 7 instructions
if (instructions.count() < 7) continue if (instructions.count() < 7) continue
// we know that the 7th instruction has the opcode CONST_4 // we know that the 7th instruction has the opcode CONST_4
val instruction = instructions.elementAt(6) val instruction = instructions.elementAt(6)
if (instruction.opcode != Opcode.CONST_4) continue if (instruction.opcode != Opcode.CONST_4) continue
// the literal for this instruction has to be either 1 or 2 // the literal for this instruction has to be either 1 or 2
val literal = (instruction as Instruction11n).narrowLiteral val literal = (instruction as Instruction11n).narrowLiteral
// method founds // method founds
if (literal == 1) tapSeekMethods["P"] = it if (literal == 1) tapSeekMethods["P"] = it
if (literal == 2) tapSeekMethods["O"] = it if (literal == 2) tapSeekMethods["O"] = it
} }
} ?: return SeekbarTappingParentFingerprint.toErrorResult()
// replace map because we don't need the upper one anymore SeekbarTappingFingerprint.result?.let {
result = SeekbarTappingFingerprint.result!! val insertIndex = it.scanResult.patternScanResult!!.endIndex
val implementation = result.mutableMethod.implementation!! with (it.mutableMethod) {
val instructions = implementation!!.instructions
val register = (instructions[insertIndex - 1] as Instruction35c).registerC
// if tap-seeking is enabled, do not invoke the two methods below val pMethod = tapSeekMethods["P"]!!
val pMethod = tapSeekMethods["P"]!! val oMethod = tapSeekMethods["O"]!!
val oMethod = tapSeekMethods["O"]!!
val insertIndex = result.scanResult.patternScanResult!!.endIndex + 1 addInstructions(
insertIndex, """
invoke-static {}, $SEEKBAR_LAYOUT->enableSeekbarTapping()Z
move-result v0
if-eqz v0, :off
invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V
invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
""", listOf(ExternalLabel("off", instruction(insertIndex)))
)
}
} ?: return SeekbarTappingFingerprint.toErrorResult()
// get the required register
val instruction = implementation.instructions[insertIndex - 1]
if (instruction.opcode != Opcode.INVOKE_VIRTUAL) return PatchResultError("Could not find the correct register")
val register = (instruction as Instruction35c).registerC
val elseLabel = implementation.newLabelForIndex(insertIndex)
// the instructions are written in reverse order.
result.mutableMethod.addInstructions(
insertIndex, """
invoke-virtual { v$register, v2 }, ${oMethod.definingClass}->${oMethod.name}(I)V
invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
"""
)
// if tap-seeking is disabled, do not invoke the two methods above by jumping to the else label
implementation.addInstruction(
insertIndex, BuilderInstruction21t(Opcode.IF_EQZ, 0, elseLabel)
)
result.mutableMethod.addInstructions(
insertIndex, """
invoke-static { }, $SEEKBAR_LAYOUT->enableSeekbarTapping()Z
move-result v0
"""
)
return PatchResultSuccess() return PatchResultSuccess()
} }
} }

View File

@ -1,24 +1,15 @@
package app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints package app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(3)
object TimeCounterFingerprint : MethodFingerprint( object TimeCounterFingerprint : MethodFingerprint(
"V", AccessFlags.PUBLIC or AccessFlags.FINAL, listOf(), listOf( returnType = "V",
Opcode.IGET_OBJECT, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
Opcode.IGET_WIDE, opcodes = listOf(
Opcode.CONST_WIDE_16, Opcode.CONST_WIDE_16,
Opcode.CMP_LONG, Opcode.CMP_LONG
Opcode.IF_LEZ,
Opcode.IGET_OBJECT,
Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.GOTO,
) )
) )

View File

@ -0,0 +1,19 @@
package app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints
import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
object TimeCounterParentFingerprint : MethodFingerprint(
returnType = "V",
access = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction ->
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.timebarColorLabelId
} == true
}
)

View File

@ -5,42 +5,50 @@ import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint.Companion.resolve
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints.TimeCounterFingerprint import app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints.TimeCounterFingerprint
import app.revanced.patches.youtube.layout.seekbar.timeandseekbar.bytecode.fingerprints.TimeCounterParentFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.patches.timebar.HookTimebarPatch import app.revanced.shared.patches.timebar.HookTimebarPatch
import app.revanced.shared.util.integrations.Constants.SEEKBAR_LAYOUT import app.revanced.shared.util.integrations.Constants.SEEKBAR_LAYOUT
@DependsOn([HookTimebarPatch::class]) @DependsOn([HookTimebarPatch::class, SharedResourcdIdPatch::class])
@Name("hide-time-and-seekbar-bytecode-patch") @Name("hide-time-and-seekbar-bytecode-patch")
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideTimeAndSeekbarBytecodePatch : BytecodePatch( class HideTimeAndSeekbarBytecodePatch : BytecodePatch(
listOf( listOf(
TimeCounterFingerprint TimeCounterParentFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
listOf( TimeCounterParentFingerprint.result?.let { parentResult ->
HookTimebarPatch.SetTimbarFingerprintResult, TimeCounterFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { counterResult ->
TimeCounterFingerprint.result!! listOf(
).forEach { result -> HookTimebarPatch.SetTimbarFingerprintResult,
val method = result.mutableMethod counterResult
method.addInstructions( ).forEach {
0, """ val method = it.mutableMethod
const/4 v0, 0x0 method.addInstructions(
invoke-static { }, $SEEKBAR_LAYOUT->hideTimeAndSeekbar()Z 0, """
move-result v0 invoke-static {}, $SEEKBAR_LAYOUT->hideTimeAndSeekbar()Z
if-eqz v0, :hide_time_and_seekbar move-result v0
return-void if-eqz v0, :hide_time_and_seekbar
""", listOf(ExternalLabel("hide_time_and_seekbar", method.instruction(0))) return-void
) """, listOf(ExternalLabel("hide_time_and_seekbar", method.instruction(0)))
} )
}
} ?: return TimeCounterFingerprint.toErrorResult()
} ?: return TimeCounterParentFingerprint.toErrorResult()
return PatchResultSuccess() return PatchResultSuccess()
} }

View File

@ -36,10 +36,10 @@ class DoubleBackToClosePatch : BytecodePatch(
/* /*
Hook onBackPressed method inside WatchWhileActivity Hook onBackPressed method inside WatchWhileActivity
*/ */
OnBackPressedFingerprint.result?.let { result -> OnBackPressedFingerprint.result?.let {
val insertIndex = result.scanResult.patternScanResult!!.endIndex val insertIndex = it.scanResult.patternScanResult!!.endIndex
with(result.mutableMethod) { with(it.mutableMethod) {
addInstruction( addInstruction(
insertIndex, insertIndex,
"invoke-static {p0}, $INTEGRATIONS_CLASS_DESCRIPTOR" + "invoke-static {p0}, $INTEGRATIONS_CLASS_DESCRIPTOR" +
@ -53,9 +53,9 @@ class DoubleBackToClosePatch : BytecodePatch(
/* /*
Inject the methods which start of ScrollView Inject the methods which start of ScrollView
*/ */
ScrollPositionFingerprint.result?.let { result -> ScrollPositionFingerprint.result?.let {
val insertMethod = context.toMethodWalker(result.method) val insertMethod = context.toMethodWalker(it.method)
.nextMethod(result.scanResult.patternScanResult!!.startIndex + 1, true) .nextMethod(it.scanResult.patternScanResult!!.startIndex + 1, true)
.getMethod() as MutableMethod .getMethod() as MutableMethod
val insertIndex = insertMethod.implementation!!.instructions.size - 1 - 1 val insertIndex = insertMethod.implementation!!.instructions.size - 1 - 1
@ -68,9 +68,9 @@ class DoubleBackToClosePatch : BytecodePatch(
Inject the methods which stop of ScrollView Inject the methods which stop of ScrollView
*/ */
ScrollTopParentFingerprint.result?.let { parentResult -> ScrollTopParentFingerprint.result?.let { parentResult ->
ScrollTopFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { result -> ScrollTopFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val insertMethod = result.mutableMethod val insertMethod = it.mutableMethod
val insertIndex = result.scanResult.patternScanResult!!.endIndex val insertIndex = it.scanResult.patternScanResult!!.endIndex
injectScrollView(insertMethod, insertIndex, "onStopScrollView") injectScrollView(insertMethod, insertIndex, "onStopScrollView")
} ?: return ScrollTopFingerprint.toErrorResult() } ?: return ScrollTopFingerprint.toErrorResult()

View File

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

View File

@ -7,8 +7,10 @@ import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction import org.jf.dexlib2.iface.instruction.NarrowLiteralInstruction
object MinimizedPlaybackManagerFingerprint : MethodFingerprint( object MinimizedPlaybackManagerFingerprint : MethodFingerprint(
"Z", AccessFlags.PUBLIC or AccessFlags.STATIC, listOf("L"), returnType = "Z",
listOf(Opcode.AND_INT_LIT16), access = AccessFlags.PUBLIC or AccessFlags.STATIC,
parameters = listOf("L"),
opcodes = listOf(Opcode.AND_INT_LIT16),
customFingerprint = { methodDef -> customFingerprint = { methodDef ->
methodDef.implementation!!.instructions.any { methodDef.implementation!!.instructions.any {
((it as? NarrowLiteralInstruction)?.narrowLiteral == 64657230) ((it as? NarrowLiteralInstruction)?.narrowLiteral == 64657230)

View File

@ -1,15 +1,15 @@
package app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints package app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import org.jf.dexlib2.iface.instruction.WideLiteralInstruction
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2)
object MinimizedPlaybackSettingsFingerprint : MethodFingerprint( object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
"L", returnType = "L",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
opcodes = listOf( opcodes = listOf(
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
@ -17,8 +17,12 @@ object MinimizedPlaybackSettingsFingerprint : MethodFingerprint(
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.IF_NEZ, Opcode.IF_NEZ,
Opcode.GOTO, Opcode.GOTO
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST
), ),
customFingerprint = { methodDef ->
methodDef.implementation?.instructions?.any { instruction ->
instruction.opcode.ordinal == Opcode.CONST.ordinal &&
(instruction as? WideLiteralInstruction)?.wideLiteral == SharedResourcdIdPatch.backgroundCategoryLabelId
} == true
}
) )

View File

@ -9,15 +9,18 @@ import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints.* import app.revanced.patches.youtube.misc.minimizedplayback.bytecode.fingerprints.*
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourcdIdPatch
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.util.integrations.Constants.MISC_PATH import app.revanced.shared.util.integrations.Constants.MISC_PATH
import org.jf.dexlib2.iface.instruction.ReferenceInstruction import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.reference.MethodReference import org.jf.dexlib2.iface.reference.MethodReference
@Name("enable-minimized-playback-bytecode-patch") @Name("enable-minimized-playback-bytecode-patch")
@DependsOn([SharedResourcdIdPatch::class])
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class MinimizedPlaybackBytecodePatch : BytecodePatch( class MinimizedPlaybackBytecodePatch : BytecodePatch(

View File

@ -27,9 +27,9 @@ class PiPNotificationBytecodePatch : BytecodePatch(
SecondaryPiPFingerprint SecondaryPiPFingerprint
).map { ).map {
it.result ?: return it.toErrorResult() it.result ?: return it.toErrorResult()
}.forEach { result -> }.forEach {
val index = result.scanResult.patternScanResult!!.startIndex + 1 val index = it.scanResult.patternScanResult!!.startIndex + 1
result.mutableMethod.addInstruction(index, "return-void") it.mutableMethod.addInstruction(index, "return-void")
} }
return PatchResultSuccess() return PatchResultSuccess()

View File

@ -1,35 +1,19 @@
package app.revanced.patches.youtube.misc.playertype.fingerprint package app.revanced.patches.youtube.misc.playertype.fingerprint
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
//TODO constrain to only match in YoutubePlayerOverlaysLayout?
@FuzzyPatternScanMethod(2)
object UpdatePlayerTypeFingerprint : MethodFingerprint( object UpdatePlayerTypeFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PUBLIC or AccessFlags.FINAL, access = AccessFlags.PUBLIC or AccessFlags.FINAL,
null, parameters = listOf("L"),
listOf( opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.IF_NE, Opcode.IF_NE,
Opcode.RETURN_VOID,
Opcode.IPUT_OBJECT,
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.CONST_4,
Opcode.INVOKE_STATIC,
Opcode.RETURN_VOID,
Opcode.CONST_4,
Opcode.INVOKE_STATIC,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID Opcode.RETURN_VOID
) ),
customFingerprint = {
it.definingClass.endsWith("YouTubePlayerOverlaysLayout;")
}
) )

View File

@ -17,19 +17,23 @@ import app.revanced.shared.patches.mapping.ResourceMappingPatch
class SharedResourcdIdPatch : ResourcePatch { class SharedResourcdIdPatch : ResourcePatch {
internal companion object { internal companion object {
var abclistmenuitemLabelId: Long = -1 var abclistmenuitemLabelId: Long = -1
var accessibilityProgressTimeLabelId: Long = -1
var accountSwitcherAccessibilityLabelId: Long = -1 var accountSwitcherAccessibilityLabelId: Long = -1
var appearanceStringId: Long = -1 var appearanceStringId: Long = -1
var backgroundCategoryLabelId: Long = -1
var bottompaneloverlaytextLabelId: Long = -1 var bottompaneloverlaytextLabelId: Long = -1
var bottomUiContainerResourceId: Long = -1 var bottomUiContainerResourceId: Long = -1
var controlsLayoutStubResourceId: Long = -1 var controlsLayoutStubResourceId: Long = -1
var educationTextViewResourceId: Long = -1 var educationTextViewResourceId: Long = -1
var emptycolorLabelId: Long = -1 var emptycolorLabelId: Long = -1
var floatybarQueueLabelId: Long = -1
var imageOnlyTabId: Long = -1 var imageOnlyTabId: Long = -1
var imageWithTextTabId: Long = -1 var imageWithTextTabId: Long = -1
var layoutCircle: Long = -1 var layoutCircle: Long = -1
var layoutIcon: Long = -1 var layoutIcon: Long = -1
var layoutVideo: Long = -1 var layoutVideo: Long = -1
var scrubbingLabelId: Long = -1 var scrubbingLabelId: Long = -1
var timebarColorLabelId: Long = -1
var videoqualityfragmentLabelId: Long = -1 var videoqualityfragmentLabelId: Long = -1
} }
@ -40,19 +44,23 @@ class SharedResourcdIdPatch : ResourcePatch {
.single { it.type == type && it.name == name }.id .single { it.type == type && it.name == name }.id
abclistmenuitemLabelId = findSharedResourceId("layout", "abc_list_menu_item_layout") abclistmenuitemLabelId = findSharedResourceId("layout", "abc_list_menu_item_layout")
accessibilityProgressTimeLabelId = findSharedResourceId("string", "accessibility_player_progress_time")
accountSwitcherAccessibilityLabelId = findSharedResourceId("string", "account_switcher_accessibility_label") accountSwitcherAccessibilityLabelId = findSharedResourceId("string", "account_switcher_accessibility_label")
appearanceStringId = findSharedResourceId("string", "app_theme_appearance_dark") appearanceStringId = findSharedResourceId("string", "app_theme_appearance_dark")
backgroundCategoryLabelId = findSharedResourceId("string", "pref_background_and_offline_category")
bottompaneloverlaytextLabelId = findSharedResourceId("id", "bottom_panel_overlay_text") bottompaneloverlaytextLabelId = findSharedResourceId("id", "bottom_panel_overlay_text")
bottomUiContainerResourceId = findSharedResourceId("id", "bottom_ui_container_stub") bottomUiContainerResourceId = findSharedResourceId("id", "bottom_ui_container_stub")
controlsLayoutStubResourceId = findSharedResourceId("id", "controls_layout_stub") controlsLayoutStubResourceId = findSharedResourceId("id", "controls_layout_stub")
educationTextViewResourceId = findSharedResourceId("id", "user_education_text_view") educationTextViewResourceId = findSharedResourceId("id", "user_education_text_view")
emptycolorLabelId = findSharedResourceId("color", "inline_time_bar_colorized_bar_empty_color_dark") emptycolorLabelId = findSharedResourceId("color", "inline_time_bar_colorized_bar_empty_color_dark")
floatybarQueueLabelId = findSharedResourceId("string", "floaty_bar_queue_status")
imageOnlyTabId = findSharedResourceId("layout", "image_only_tab") imageOnlyTabId = findSharedResourceId("layout", "image_only_tab")
imageWithTextTabId = findSharedResourceId("layout", "image_with_text_tab") imageWithTextTabId = findSharedResourceId("layout", "image_with_text_tab")
layoutCircle = findSharedResourceId("layout", "endscreen_element_layout_circle") layoutCircle = findSharedResourceId("layout", "endscreen_element_layout_circle")
layoutIcon = findSharedResourceId("layout", "endscreen_element_layout_icon") layoutIcon = findSharedResourceId("layout", "endscreen_element_layout_icon")
layoutVideo = findSharedResourceId("layout", "endscreen_element_layout_video") layoutVideo = findSharedResourceId("layout", "endscreen_element_layout_video")
scrubbingLabelId = findSharedResourceId("dimen", "vertical_touch_offset_to_enter_fine_scrubbing") scrubbingLabelId = findSharedResourceId("dimen", "vertical_touch_offset_to_enter_fine_scrubbing")
timebarColorLabelId = findSharedResourceId("color", "inline_time_bar_progress_color")
videoqualityfragmentLabelId = findSharedResourceId("layout", "video_quality_bottom_sheet_list_fragment_title") videoqualityfragmentLabelId = findSharedResourceId("layout", "video_quality_bottom_sheet_list_fragment_title")
return PatchResultSuccess() return PatchResultSuccess()

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
object DislikeFingerprint : MethodFingerprint( object DislikeFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, access = AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
strings = listOf("like/dislike") strings = listOf("like/dislike")
) )

View File

@ -1,13 +1,11 @@
package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints package app.revanced.patches.youtube.misc.returnyoutubedislike.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
@FuzzyPatternScanMethod(2)
object LikeFingerprint : MethodFingerprint( object LikeFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, access = AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
strings = listOf("like/like") strings = listOf("like/like")
) )

View File

@ -5,7 +5,7 @@ import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
object RemoveLikeFingerprint : MethodFingerprint( object RemoveLikeFingerprint : MethodFingerprint(
"V", returnType = "V",
AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR, access = AccessFlags.PROTECTED or AccessFlags.CONSTRUCTOR,
strings = listOf("like/removelike") strings = listOf("like/removelike")
) )

View File

@ -1,23 +1,11 @@
package app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints package app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints
import app.revanced.patcher.extensions.or import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.method.annotation.FuzzyPatternScanMethod
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import org.jf.dexlib2.AccessFlags import org.jf.dexlib2.AccessFlags
import org.jf.dexlib2.Opcode
@FuzzyPatternScanMethod(2)
object SpeedArrayGeneratorFingerprint : MethodFingerprint( object SpeedArrayGeneratorFingerprint : MethodFingerprint(
"[L", returnType = "[L",
AccessFlags.PUBLIC or AccessFlags.STATIC, access = AccessFlags.PUBLIC or AccessFlags.STATIC,
null, strings = listOf("0.0#")
listOf(
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.GOTO,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
),
listOf("0.0#")
) )

View File

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

View File

@ -6,14 +6,15 @@ import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.replaceInstruction import app.revanced.patcher.extensions.replaceInstruction
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints.* import app.revanced.patches.youtube.video.customspeed.bytecode.fingerprints.*
import app.revanced.shared.annotation.YouTubeCompatibility import app.revanced.shared.annotation.YouTubeCompatibility
import app.revanced.shared.extensions.toErrorResult
import app.revanced.shared.patches.options.PatchOptions import app.revanced.shared.patches.options.PatchOptions
import app.revanced.shared.util.integrations.Constants.VIDEO_PATH import app.revanced.shared.util.integrations.Constants.VIDEO_PATH
import org.jf.dexlib2.builder.instruction.BuilderArrayPayload import org.jf.dexlib2.builder.instruction.BuilderArrayPayload
@ -34,117 +35,119 @@ class CustomVideoSpeedBytecodePatch : BytecodePatch(
VideoSpeedEntriesFingerprint VideoSpeedEntriesFingerprint
) )
) { ) {
private companion object {
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedPatch;"
const val INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedEntries;"
}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val speed = PatchOptions.CustomSpeedArrays val speed = PatchOptions.CustomSpeedArrays
val splits = speed!!.replace(" ","").split(",") val splits = speed!!.replace(" ","").split(",")
if (splits.isEmpty()) throw IllegalArgumentException("Invalid speed elements") if (splits.isEmpty()) throw IllegalArgumentException("Invalid speed elements")
val videoSpeedsArray = splits.map { it.toFloat().toRawBits() } val videoSpeedsArray = splits.map { it.toFloat().toRawBits() }
val arrayGenMethod = SpeedArrayGeneratorFingerprint.result?.mutableMethod!! SpeedArrayGeneratorFingerprint.result?.let { result ->
val arrayGenMethodImpl = arrayGenMethod.implementation!! with (result.mutableMethod) {
val sizeCallIndex = implementation!!.instructions
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
val sizeCallIndex = arrayGenMethodImpl.instructions if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()")
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()") val sizeCallResultRegister =
(implementation!!.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
val sizeCallResultRegister = addInstructions(
(arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA sizeCallIndex + 2,
"""
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z
move-result v9
if-eqz v9, :defaultspeed
const/4 v$sizeCallResultRegister, 0x0
""", listOf(ExternalLabel("defaultspeed", instruction(sizeCallIndex + 2)))
)
arrayGenMethod.addInstructions( val (arrayLengthConstIndex, arrayLengthConst) = implementation!!.instructions.withIndex()
sizeCallIndex + 2, .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
"""
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z
move-result v9
if-eqz v9, :defaultspeed
const/4 v$sizeCallResultRegister, 0x0
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(sizeCallIndex + 2)))
)
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex() val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F"
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA addInstructions(
arrayLengthConstIndex + 1,
"""
if-eqz v9, :defaultspeed
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
""", listOf(ExternalLabel("defaultspeed", instruction(arrayLengthConstIndex + 1)))
)
val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F" val (originalArrayFetchIndex, originalArrayFetch) = implementation!!.instructions.withIndex()
.first {
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
reference?.type == "[F"
}
arrayGenMethod.addInstructions( val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
arrayLengthConstIndex + 1,
"""
if-eqz v9, :defaultspeed
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(arrayLengthConstIndex + 1)))
)
val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex() addInstructions(
.first { originalArrayFetchIndex + 1,
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference) """
reference?.definingClass?.contains("PlayerConfigModel") ?: false && if-eqz v9, :defaultspeed
reference?.type == "[F" sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType
""", listOf(ExternalLabel("defaultspeed", instruction(originalArrayFetchIndex + 1)))
)
} }
} ?: return SpeedArrayGeneratorFingerprint.toErrorResult()
val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA SpeedLimiterFingerprint.result?.let { result ->
with (result.mutableMethod) {
val (limiterMinConstIndex, limiterMinConst) = implementation!!.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
val (limiterMaxConstIndex, limiterMaxConst) = implementation!!.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
arrayGenMethod.addInstructions( val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
originalArrayFetchIndex + 1, val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA
"""
if-eqz v9, :defaultspeed
sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(originalArrayFetchIndex + 1)))
)
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!; fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
val limiterMethodImpl = limiterMethod.implementation!!
val speedLimitMin = 0.0f replaceInstruction(
val speedLimitMax = 100f limiterMinConstIndex,
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
)
replaceInstruction(
limiterMaxConstIndex,
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}"
)
}
} ?: return SpeedLimiterFingerprint.toErrorResult()
val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex() VideoSpeedEntriesFingerprint.result?.let {
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } with (it.mutableMethod) {
val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex() val arrayPayloadIndex = implementation!!.instructions.size - 1
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA replaceInstruction(
val limiterMaxConstDestination = (limiterMaxConst as OneRegisterInstruction).registerA 0,
"const/16 v0, ${videoSpeedsArray.size}"
)
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits()) implementation!!.replaceInstruction(
arrayPayloadIndex,
limiterMethod.replaceInstruction( BuilderArrayPayload(
limiterMinConstIndex, 4,
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}" videoSpeedsArray
) )
limiterMethod.replaceInstruction( )
limiterMaxConstIndex, }
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}" } ?: return VideoSpeedEntriesFingerprint.toErrorResult()
)
val constructorResult = VideoSpeedEntriesFingerprint.result!!
val constructor = constructorResult.mutableMethod
val implementation = constructor.implementation!!
constructor.replaceInstruction(
0,
"const/16 v0, ${videoSpeedsArray.size}"
)
val arrayPayloadIndex = implementation.instructions.size - 1
implementation.replaceInstruction(
arrayPayloadIndex,
BuilderArrayPayload(
4,
videoSpeedsArray
)
)
return PatchResultSuccess() return PatchResultSuccess()
} }
companion object {
const val INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedPatch;"
const val INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR =
"$VIDEO_PATH/VideoSpeedEntries;"
const val speedLimitMin = 0.0f
const val speedLimitMax = 100f
}
} }

View File

@ -46,11 +46,11 @@ class VideoSpeedBytecodePatch : BytecodePatch(
VideoSpeedParentFingerprint.result?.let { parentResult -> VideoSpeedParentFingerprint.result?.let { parentResult ->
val parentClassDef = parentResult.classDef val parentClassDef = parentResult.classDef
VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let { result -> VideoSpeedChangedFingerprint.also { it.resolve(context, parentClassDef) }.result?.let {
startIndex = result.scanResult.patternScanResult!!.startIndex startIndex = it.scanResult.patternScanResult!!.startIndex
endIndex = result.scanResult.patternScanResult!!.endIndex endIndex = it.scanResult.patternScanResult!!.endIndex
with (result.method) { with (it.method) {
val speedInstruction = implementation!!.instructions val speedInstruction = implementation!!.instructions
firstRef = firstRef =
@ -65,7 +65,7 @@ class VideoSpeedBytecodePatch : BytecodePatch(
val register = val register =
(speedInstruction.elementAt(endIndex) as FiveRegisterInstruction).registerD (speedInstruction.elementAt(endIndex) as FiveRegisterInstruction).registerD
result.mutableMethod.addInstruction( it.mutableMethod.addInstruction(
endIndex, endIndex,
"invoke-static { v$register }, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR" + "invoke-static { v$register }, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR" +
"->" + "->" +
@ -104,12 +104,12 @@ class VideoSpeedBytecodePatch : BytecodePatch(
} ?: return VideoSpeedParentFingerprint.toErrorResult() } ?: return VideoSpeedParentFingerprint.toErrorResult()
VideoSpeedSetterFingerprint.result?.let { result -> VideoSpeedSetterFingerprint.result?.let {
result.mutableMethod.addInstructions( it.mutableMethod.addInstructions(
0, """ 0, """
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue()F invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->getSpeedValue()F
move-result v0 move-result v0
invoke-direct {p0, v0}, ${result.classDef.type}->overrideSpeed(F)V invoke-direct {p0, v0}, ${it.classDef.type}->overrideSpeed(F)V
""", """,
) )
} ?: return VideoSpeedSetterFingerprint.toErrorResult() } ?: return VideoSpeedSetterFingerprint.toErrorResult()