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
with (it.mutableMethod) {
val register = (instruction(insertIndex - 1) as OneRegisterInstruction).registerA + 2
addInstructions(
insertIndex, """
invoke-static { }, $GENERAL_LAYOUT->hideStartupShortsPlayer()Z invoke-static { }, $GENERAL_LAYOUT->hideStartupShortsPlayer()Z
move-result v5 move-result v$register
if-eqz v5, :show_startup_shorts_player if-eqz v$register, :show_startup_shorts_player
return-void return-void
""", listOf(ExternalLabel("show_startup_shorts_player", userWasInShortsMethod.instruction(moveResultIndex + 1))) """, 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 {
MiniPlayerDimensionsCalculatorFingerprint.result?.let { parentResult ->
// first resolve the fingerprints via the parent fingerprint // first resolve the fingerprints via the parent fingerprint
val miniPlayerClass = MiniPlayerDimensionsCalculatorFingerprint.result!!.classDef val miniPlayerClass = parentResult.classDef
/* arrayOf(
* no context parameter method MiniPlayerOverrideNoContextFingerprint,
*/ MiniPlayerOverrideFingerprint,
MiniPlayerOverrideNoContextFingerprint.resolve(context, miniPlayerClass) MiniPlayerResponseModelSizeCheckFingerprint
val (method, _, parameterRegister) = MiniPlayerOverrideNoContextFingerprint.addProxyCall() ).map {
// - 1 means to insert before the return instruction it to (it.also { it.resolve(context, miniPlayerClass) }.result ?: return it.toErrorResult())
val secondInsertIndex = method.implementation!!.instructions.size - 1 }.forEach { (fingerprint, result) ->
method.insertOverride(secondInsertIndex, parameterRegister /** same register used to return **/) if (fingerprint == MiniPlayerOverrideNoContextFingerprint) {
val (method, _, parameterRegister) = result.addProxyCall()
/* method.insertOverride(method.implementation!!.instructions.size - 1, parameterRegister)
* method with context parameter } else {
*/ val (_, _, _) = result.addProxyCall()
MiniPlayerOverrideFingerprint.resolve(context, miniPlayerClass) }
val (_, _, _) = MiniPlayerOverrideFingerprint.addProxyCall() }
} ?: return MiniPlayerDimensionsCalculatorFingerprint.toErrorResult()
/*
* size check return value override
*/
val (_, _, _) = MiniPlayerResponseModelSizeCheckFingerprint.addProxyCall()
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,
WideSearchbarTwoParentFingerprint to WideSearchbarTwoFingerprint
).map { (parentFingerprint, fingerprint) ->
parentFingerprint.result?.let { parentResult ->
fingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let {
val targetMethod =
context context
.toMethodWalker(resultOne!!.method) .toMethodWalker(it.method)
.nextMethod(resultOne.scanResult.patternScanResult!!.endIndex, true) .nextMethod(it.scanResult.patternScanResult!!.endIndex, true)
.getMethod() as MutableMethod .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)
addInstructions(
insertIndex, """
invoke-static {}, $PLAYER_LAYOUT->hideChannelWatermark()Z invoke-static {}, $PLAYER_LAYOUT->hideChannelWatermark()Z
move-result p2 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,12 +31,10 @@ 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
@ -50,42 +52,30 @@ class SeekbarTappingBytecodePatch : BytecodePatch(
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(
// 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, """ 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 }, ${oMethod.definingClass}->${oMethod.name}(I)V
invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V invoke-virtual { v$register, v2 }, ${pMethod.definingClass}->${pMethod.name}(I)V
""" """, listOf(ExternalLabel("off", instruction(insertIndex)))
) )
}
} ?: return SeekbarTappingFingerprint.toErrorResult()
// 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,36 +5,41 @@ 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 {
TimeCounterParentFingerprint.result?.let { parentResult ->
TimeCounterFingerprint.also { it.resolve(context, parentResult.classDef) }.result?.let { counterResult ->
listOf( listOf(
HookTimebarPatch.SetTimbarFingerprintResult, HookTimebarPatch.SetTimbarFingerprintResult,
TimeCounterFingerprint.result!! counterResult
).forEach { result -> ).forEach {
val method = result.mutableMethod val method = it.mutableMethod
method.addInstructions( method.addInstructions(
0, """ 0, """
const/4 v0, 0x0 invoke-static {}, $SEEKBAR_LAYOUT->hideTimeAndSeekbar()Z
invoke-static { }, $SEEKBAR_LAYOUT->hideTimeAndSeekbar()Z
move-result v0 move-result v0
if-eqz v0, :hide_time_and_seekbar if-eqz v0, :hide_time_and_seekbar
return-void return-void
@ -42,6 +47,9 @@ class HideTimeAndSeekbarBytecodePatch : BytecodePatch(
) )
} }
} ?: 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,58 +35,49 @@ 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
val sizeCallIndex = arrayGenMethodImpl.instructions
.indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" } .indexOfFirst { ((it as? ReferenceInstruction)?.reference as? MethodReference)?.name == "size" }
if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()") if (sizeCallIndex == -1) return PatchResultError("Couldn't find call to size()")
val sizeCallResultRegister = val sizeCallResultRegister =
(arrayGenMethodImpl.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA (implementation!!.instructions.elementAt(sizeCallIndex + 1) as OneRegisterInstruction).registerA
arrayGenMethod.addInstructions( addInstructions(
sizeCallIndex + 2, sizeCallIndex + 2,
""" """
invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z invoke-static {}, $INTEGRATIONS_VIDEO_SPEED_CLASS_DESCRIPTOR->isCustomVideoSpeedEnabled()Z
move-result v9 move-result v9
if-eqz v9, :defaultspeed if-eqz v9, :defaultspeed
const/4 v$sizeCallResultRegister, 0x0 const/4 v$sizeCallResultRegister, 0x0
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(sizeCallIndex + 2))) """, listOf(ExternalLabel("defaultspeed", instruction(sizeCallIndex + 2)))
) )
val (arrayLengthConstIndex, arrayLengthConst) = implementation!!.instructions.withIndex()
val (arrayLengthConstIndex, arrayLengthConst) = arrayGenMethodImpl.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 } .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 7 }
val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA val arrayLengthConstDestination = (arrayLengthConst as OneRegisterInstruction).registerA
val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F" val videoSpeedsArrayType = "$INTEGRATIONS_VIDEO_SPEED_ENTRIES_CLASS_DESCRIPTOR->videoSpeed:[F"
arrayGenMethod.addInstructions( addInstructions(
arrayLengthConstIndex + 1, arrayLengthConstIndex + 1,
""" """
if-eqz v9, :defaultspeed if-eqz v9, :defaultspeed
sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType sget-object v$arrayLengthConstDestination, $videoSpeedsArrayType
array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination array-length v$arrayLengthConstDestination, v$arrayLengthConstDestination
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(arrayLengthConstIndex + 1))) """, listOf(ExternalLabel("defaultspeed", instruction(arrayLengthConstIndex + 1)))
) )
val (originalArrayFetchIndex, originalArrayFetch) = arrayGenMethodImpl.instructions.withIndex() val (originalArrayFetchIndex, originalArrayFetch) = implementation!!.instructions.withIndex()
.first { .first {
val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference) val reference = ((it.value as? ReferenceInstruction)?.reference as? FieldReference)
reference?.definingClass?.contains("PlayerConfigModel") ?: false && reference?.definingClass?.contains("PlayerConfigModel") ?: false &&
@ -94,23 +86,21 @@ class CustomVideoSpeedBytecodePatch : BytecodePatch(
val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA val originalArrayFetchDestination = (originalArrayFetch as OneRegisterInstruction).registerA
arrayGenMethod.addInstructions( addInstructions(
originalArrayFetchIndex + 1, originalArrayFetchIndex + 1,
""" """
if-eqz v9, :defaultspeed if-eqz v9, :defaultspeed
sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType sget-object v$originalArrayFetchDestination, $videoSpeedsArrayType
""", listOf(ExternalLabel("defaultspeed", arrayGenMethod.instruction(originalArrayFetchIndex + 1))) """, listOf(ExternalLabel("defaultspeed", instruction(originalArrayFetchIndex + 1)))
) )
}
} ?: return SpeedArrayGeneratorFingerprint.toErrorResult()
val limiterMethod = SpeedLimiterFingerprint.result?.mutableMethod!!; SpeedLimiterFingerprint.result?.let { result ->
val limiterMethodImpl = limiterMethod.implementation!! with (result.mutableMethod) {
val (limiterMinConstIndex, limiterMinConst) = implementation!!.instructions.withIndex()
val speedLimitMin = 0.0f
val speedLimitMax = 100f
val (limiterMinConstIndex, limiterMinConst) = limiterMethodImpl.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() } .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 0.25f.toRawBits() }
val (limiterMaxConstIndex, limiterMaxConst) = limiterMethodImpl.instructions.withIndex() val (limiterMaxConstIndex, limiterMaxConst) = implementation!!.instructions.withIndex()
.first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() } .first { (it.value as? NarrowLiteralInstruction)?.narrowLiteral == 2.0f.toRawBits() }
val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA val limiterMinConstDestination = (limiterMinConst as OneRegisterInstruction).registerA
@ -118,33 +108,46 @@ class CustomVideoSpeedBytecodePatch : BytecodePatch(
fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits()) fun hexFloat(float: Float): String = "0x%08x".format(float.toRawBits())
limiterMethod.replaceInstruction( replaceInstruction(
limiterMinConstIndex, limiterMinConstIndex,
"const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}" "const/high16 v$limiterMinConstDestination, ${hexFloat(speedLimitMin)}"
) )
limiterMethod.replaceInstruction( replaceInstruction(
limiterMaxConstIndex, limiterMaxConstIndex,
"const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}" "const/high16 v$limiterMaxConstDestination, ${hexFloat(speedLimitMax)}"
) )
}
} ?: return SpeedLimiterFingerprint.toErrorResult()
val constructorResult = VideoSpeedEntriesFingerprint.result!! VideoSpeedEntriesFingerprint.result?.let {
val constructor = constructorResult.mutableMethod with (it.mutableMethod) {
val implementation = constructor.implementation!! val arrayPayloadIndex = implementation!!.instructions.size - 1
constructor.replaceInstruction( replaceInstruction(
0, 0,
"const/16 v0, ${videoSpeedsArray.size}" "const/16 v0, ${videoSpeedsArray.size}"
) )
val arrayPayloadIndex = implementation.instructions.size - 1 implementation!!.replaceInstruction(
implementation.replaceInstruction(
arrayPayloadIndex, arrayPayloadIndex,
BuilderArrayPayload( BuilderArrayPayload(
4, 4,
videoSpeedsArray videoSpeedsArray
) )
) )
}
} ?: return VideoSpeedEntriesFingerprint.toErrorResult()
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()