refactor: simplify casting instructions

This commit is contained in:
inotia00 2023-05-11 16:35:02 +09:00
parent 2b70050200
commit 3b6848ab1a
16 changed files with 247 additions and 384 deletions

View File

@ -0,0 +1,10 @@
package app.revanced.patches.shared.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.totalTimeId
import app.revanced.util.bytecode.isWideLiteralExists
object TotalTimeFingerprint : MethodFingerprint(
returnType = "V",
customFingerprint = { it.isWideLiteralExists(totalTimeId) }
)

View File

@ -0,0 +1,10 @@
package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.appRelatedEndScreenResultsId
import app.revanced.util.bytecode.isWideLiteralExists
object EndScreenResultsFingerprint : MethodFingerprint(
returnType = "V",
customFingerprint = { it.isWideLiteralExists(appRelatedEndScreenResultsId) }
)

View File

@ -1,6 +1,6 @@
package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.patch package app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.patch
import app.revanced.extensions.findMutableMethodOf import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
@ -9,91 +9,54 @@ import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction 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.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch import app.revanced.patches.youtube.layout.fullscreen.endscreenoverlay.fingerprints.EndScreenResultsFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.util.integrations.Constants.FULLSCREEN import app.revanced.util.integrations.Constants.FULLSCREEN
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch @Patch
@Name("hide-endscreen-overlay") @Name("hide-endscreen-overlay")
@Description("Hide endscreen overlay on swipe controls.") @Description("Hide endscreen overlay on swipe controls.")
@DependsOn( @DependsOn(
[ [
ResourceMappingPatch::class, SettingsPatch::class,
SettingsPatch::class SharedResourceIdPatch::class
] ]
) )
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideEndScreenOverlayPatch : BytecodePatch() { class HideEndScreenOverlayPatch : BytecodePatch(
// list of resource names to get the id of listOf(EndScreenResultsFingerprint)
private val resourceIds = arrayOf( ) {
"app_related_endscreen_results"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef -> EndScreenResultsFingerprint.result?.mutableMethod?.let {
classDef.methods.forEach { method -> it.addInstructions(
with(method.implementation) { 0, """
this?.instructions?.forEachIndexed { index, instruction -> invoke-static {}, $FULLSCREEN->hideEndScreenOverlay()Z
when (instruction.opcode) { move-result v0
Opcode.CONST -> { if-eqz v0, :show
when ((instruction as Instruction31i).wideLiteral) { return-void
resourceIds[0] -> { // end screen result """, listOf(ExternalLabel("show", it.instruction(0)))
val insertIndex = index - 13
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.IF_NEZ) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
mutableMethod.addInstructions(
insertIndex, """
invoke-static {}, $FULLSCREEN->hideEndScreenOverlay()Z
move-result v$dummyRegister
if-eqz v$dummyRegister, :on
return-void
""", listOf(ExternalLabel("on", mutableMethod.instruction(insertIndex)))
)
patchSuccessArray[0] = true
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
val errorIndex: Int = patchSuccessArray.indexOf(false)
if (errorIndex == -1) {
/*
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: FULLSCREEN_SETTINGS",
"SETTINGS: HIDE_END_SCREEN_OVERLAY"
)
) )
} ?: return EndScreenResultsFingerprint.toErrorResult()
SettingsPatch.updatePatchStatus("hide-endscreen-overlay") /**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: FULLSCREEN_SETTINGS",
"SETTINGS: HIDE_END_SCREEN_OVERLAY"
)
)
return PatchResultSuccess() SettingsPatch.updatePatchStatus("hide-endscreen-overlay")
} else
return PatchResultError("Instruction not found: $errorIndex") return PatchResultSuccess()
} }
} }

View File

@ -1,16 +0,0 @@
package app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.accessibilityVideoTimeId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.Opcode
object ScrubbingLabelAlternativeFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.IF_NEZ,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_BOOLEAN,
Opcode.RETURN_VOID
),
customFingerprint = { it.isWideLiteralExists(accessibilityVideoTimeId) }
)

View File

@ -15,7 +15,6 @@ import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.fingerprints.ScrubbingLabelAlternativeFingerprint
import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.fingerprints.ScrubbingLabelFingerprint import app.revanced.patches.youtube.layout.fullscreen.flimstripoverlay.fingerprints.ScrubbingLabelFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
@ -35,19 +34,11 @@ import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class HideFilmstripOverlayPatch : BytecodePatch( class HideFilmstripOverlayPatch : BytecodePatch(
listOf( listOf(ScrubbingLabelFingerprint)
ScrubbingLabelFingerprint,
ScrubbingLabelAlternativeFingerprint
)
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
val result = try { val result = ScrubbingLabelFingerprint.result?: return ScrubbingLabelFingerprint.toErrorResult()
ScrubbingLabelFingerprint.result!!
} catch (_: Exception) {
ScrubbingLabelAlternativeFingerprint.result
?: return ScrubbingLabelAlternativeFingerprint.toErrorResult()
}
result.mutableMethod.hook(result.scanResult.patternScanResult!!.endIndex - 1) result.mutableMethod.hook(result.scanResult.patternScanResult!!.endIndex - 1)

View File

@ -43,7 +43,7 @@ class HideEndscreenCardsPatch : BytecodePatch(
val index = this.scanResult.patternScanResult!!.endIndex val index = this.scanResult.patternScanResult!!.endIndex
this.mutableMethod.apply { this.mutableMethod.apply {
val register = this.instruction<OneRegisterInstruction>(index).registerA val register = this.instruction<OneRegisterInstruction>(index).registerA
this.implementation!!.injectHideCall(index + 1, register, "layout/PlayerPatch", "hideEndscreen") this.implementation!!.injectHideCall(index + 1, register, "layout/PlayerPatch", "hideEndScreen")
} }
} }

View File

@ -0,0 +1,9 @@
package app.revanced.patches.youtube.layout.player.playeroverlayfilter.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.scrimOverlayId
import app.revanced.util.bytecode.isWideLiteralExists
object ScrimOverlayFingerprint : MethodFingerprint(
customFingerprint = { it.definingClass.endsWith("YouTubeControlsOverlay;") && it.isWideLiteralExists(scrimOverlayId) }
)

View File

@ -1,11 +1,11 @@
package app.revanced.patches.youtube.layout.player.playeroverlayfilter.patch package app.revanced.patches.youtube.layout.player.playeroverlayfilter.patch
import app.revanced.extensions.findMutableMethodOf import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction 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
@ -13,95 +13,58 @@ 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.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch import app.revanced.patches.youtube.layout.player.playeroverlayfilter.fingerprints.ScrimOverlayFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.scrimOverlayId
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.util.bytecode.getWideLiteralIndex
import app.revanced.util.integrations.Constants.PLAYER import app.revanced.util.integrations.Constants.PLAYER
import org.jf.dexlib2.Opcode import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction21c import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch @Patch
@Name("hide-player-overlay-filter") @Name("hide-player-overlay-filter")
@Description("Remove the dark filter layer from the player's background.") @Description("Remove the dark filter layer from the player's background.")
@DependsOn( @DependsOn(
[ [
ResourceMappingPatch::class, SettingsPatch::class,
SettingsPatch::class SharedResourceIdPatch::class
] ]
) )
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class PlayerOverlayFilterPatch : BytecodePatch() { class PlayerOverlayFilterPatch : BytecodePatch(
listOf(ScrimOverlayFingerprint)
// list of resource names to get the id of ) {
private val resourceIds = arrayOf(
"scrim_overlay",
"google_transparent"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // player overlay filter
val insertIndex = index + 3
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) ScrimOverlayFingerprint.result?.mutableMethod?.let {
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA val targetIndex = it.getWideLiteralIndex(scrimOverlayId) + 3
val viewRegister = (invokeInstruction as Instruction21c).registerA val targetParameter = it.instruction<ReferenceInstruction>(targetIndex).reference
val targetRegister = it.instruction<OneRegisterInstruction>(targetIndex).registerA
val transparent = resourceIds[1] if (!targetParameter.toString().endsWith("Landroid/widget/ImageView;"))
return PatchResultError("Method signature parameter did not match: $targetParameter")
mutableMethod.addInstructions( it.addInstruction(
insertIndex + 1, """ targetIndex + 1,
invoke-static {}, $PLAYER->hidePlayerOverlayFilter()Z "invoke-static {v$targetRegister}, $PLAYER->hidePlayerOverlayFilter(Landroid/widget/ImageView;)V"
move-result v$dummyRegister
if-eqz v$dummyRegister, :currentcolor
const v$dummyRegister, $transparent
invoke-virtual {v$viewRegister, v$dummyRegister}, Landroid/widget/ImageView;->setImageResource(I)V
""", listOf(ExternalLabel("currentcolor", mutableMethod.instruction(insertIndex + 1)))
)
patchSuccessArray[0] = true
patchSuccessArray[1] = true
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
val errorIndex: Int = patchSuccessArray.indexOf(false)
if (errorIndex == -1) {
/*
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: PLAYER_SETTINGS",
"SETTINGS: HIDE_PLAYER_OVERLAY_FILTER"
)
) )
} ?: return ScrimOverlayFingerprint.toErrorResult()
SettingsPatch.updatePatchStatus("hide-player-overlay-filter") /**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: PLAYER_SETTINGS",
"SETTINGS: HIDE_PLAYER_OVERLAY_FILTER"
)
)
return PatchResultSuccess() SettingsPatch.updatePatchStatus("hide-player-overlay-filter")
} else
return PatchResultError("Instruction not found: $errorIndex") return PatchResultSuccess()
} }
} }

View File

@ -0,0 +1,17 @@
package app.revanced.patches.youtube.layout.player.suggestactions.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.suggestedActionId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.Opcode
object SuggestedActionsFingerprint : MethodFingerprint(
returnType = "V",
opcodes = listOf(
Opcode.CONST,
Opcode.CONST_4,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT
),
customFingerprint = { it.isWideLiteralExists(suggestedActionId) }
)

View File

@ -1,26 +1,23 @@
package app.revanced.patches.youtube.layout.player.suggestactions.patch package app.revanced.patches.youtube.layout.player.suggestactions.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.injectHideCall import app.revanced.extensions.injectHideCall
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.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.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch import app.revanced.patches.youtube.layout.player.suggestactions.fingerprints.SuggestedActionsFingerprint
import app.revanced.patches.youtube.misc.litho.patch.ByteBufferFilterPatch import app.revanced.patches.youtube.misc.litho.patch.ByteBufferFilterPatch
import app.revanced.patches.youtube.misc.playertype.patch.PlayerTypeHookPatch import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch @Patch
@Name("hide-suggested-actions") @Name("hide-suggested-actions")
@ -28,71 +25,37 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@DependsOn( @DependsOn(
[ [
ByteBufferFilterPatch::class, ByteBufferFilterPatch::class,
PlayerTypeHookPatch::class, SettingsPatch::class,
ResourceMappingPatch::class, SharedResourceIdPatch::class
SettingsPatch::class
] ]
) )
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class SuggestedActionsPatch : BytecodePatch() { class SuggestedActionsPatch : BytecodePatch(
listOf(SuggestedActionsFingerprint)
// list of resource names to get the id of ) {
private val resourceIds = arrayOf(
"suggested_action"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef -> SuggestedActionsFingerprint.result?.let{
classDef.methods.forEach { method -> it.mutableMethod.apply {
with(method.implementation) { val targetIndex = it.scanResult.patternScanResult!!.endIndex
this?.instructions?.forEachIndexed { index, instruction -> val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // suggested_action
val insertIndex = index + 4
val iPutInstruction = instructions.elementAt(insertIndex)
if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method) implementation!!.injectHideCall(targetIndex + 1, targetRegister, "layout/PlayerPatch", "hideSuggestedActions")
val viewRegister = (iPutInstruction as Instruction22c).registerA
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/PlayerPatch", "hideSuggestedActions")
patchSuccessArray[0] = true
}
}
}
else -> return@forEachIndexed
}
}
}
} }
} } ?: return SuggestedActionsFingerprint.toErrorResult()
val errorIndex: Int = patchSuccessArray.indexOf(false) /**
* Add settings
if (errorIndex == -1) { */
context.updatePatchStatus("SuggestedActions") SettingsPatch.addPreference(
arrayOf(
/* "PREFERENCE: PLAYER_SETTINGS",
* Add settings "SETTINGS: HIDE_SUGGESTED_ACTION"
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: PLAYER_SETTINGS",
"SETTINGS: HIDE_SUGGESTED_ACTION"
)
) )
)
SettingsPatch.updatePatchStatus("hide-suggested-actions") SettingsPatch.updatePatchStatus("hide-suggested-actions")
return PatchResultSuccess() return PatchResultSuccess()
} else
return PatchResultError("Instruction not found: $errorIndex")
} }
} }

View File

@ -1,11 +1,12 @@
package app.revanced.patches.youtube.layout.seekbar.speed.patch package app.revanced.patches.youtube.layout.seekbar.speed.patch
import app.revanced.extensions.findMutableMethodOf import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.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.PatchResultError
@ -13,13 +14,13 @@ import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch import app.revanced.patches.shared.fingerprints.TotalTimeFingerprint
import app.revanced.patches.youtube.misc.overridespeed.bytecode.patch.OverrideSpeedHookPatch import app.revanced.patches.youtube.misc.overridespeed.bytecode.patch.OverrideSpeedHookPatch
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.util.integrations.Constants.SEEKBAR import app.revanced.util.integrations.Constants.SEEKBAR
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction35c import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.instruction.formats.Instruction35c import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch @Patch
@ -28,78 +29,55 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@DependsOn( @DependsOn(
[ [
OverrideSpeedHookPatch::class, OverrideSpeedHookPatch::class,
ResourceMappingPatch::class, SettingsPatch::class,
SettingsPatch::class SharedResourceIdPatch::class
] ]
) )
@YouTubeCompatibility @YouTubeCompatibility
@Version("0.0.1") @Version("0.0.1")
class AppendSpeedPatch : BytecodePatch() { class AppendSpeedPatch : BytecodePatch(
listOf(TotalTimeFingerprint)
// list of resource names to get the id of ) {
private val resourceIds = arrayOf(
"string" to "total_time"
).map { (type, name) ->
ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef -> TotalTimeFingerprint.result?.mutableMethod?.let {
classDef.methods.forEach { method -> it.implementation!!.instructions.apply {
with(method.implementation) { var insertIndex = -1
this?.instructions?.forEachIndexed { _, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // total time
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
for ((targetIndex, targetInstruction) in instructions.withIndex()) { for ((targetIndex, targetInstruction) in withIndex()) {
if (targetInstruction.opcode != Opcode.INVOKE_VIRTUAL) continue if (targetInstruction.opcode != Opcode.INVOKE_VIRTUAL) continue
if ((targetInstruction as DexBackedInstruction35c).reference.toString() == if (it.instruction<ReferenceInstruction>(targetIndex).reference.toString() ==
"Landroid/widget/TextView;->getText()Ljava/lang/CharSequence;") { "Landroid/widget/TextView;->getText()Ljava/lang/CharSequence;") {
val insertIndex = targetIndex + 2 insertIndex = targetIndex + 2
val insertRegister = (instructions.elementAt(insertIndex) as Instruction35c).registerC val insertRegister = it.instruction<Instruction35c>(insertIndex).registerC
mutableMethod.addInstructions(
insertIndex, """ it.addInstructions(
invoke-static {v$insertRegister}, $SEEKBAR->enableTimeStampSpeed(Ljava/lang/String;)Ljava/lang/String; insertIndex, """
move-result-object v$insertRegister invoke-static {v$insertRegister}, $SEEKBAR->enableTimeStampSpeed(Ljava/lang/String;)Ljava/lang/String;
""" move-result-object v$insertRegister
) """
patchSuccessArray[0] = true )
break break
}
}
}
}
}
else -> return@forEachIndexed
}
} }
} }
if (insertIndex == -1)
return PatchResultError("target Instruction not found!")
} }
} } ?: return TotalTimeFingerprint.toErrorResult()
val errorIndex: Int = patchSuccessArray.indexOf(false)
if (errorIndex == -1) { /**
/* * Add settings
* Add settings */
*/ SettingsPatch.addPreference(
SettingsPatch.addPreference( arrayOf(
arrayOf( "PREFERENCE: SEEKBAR_SETTINGS",
"PREFERENCE: SEEKBAR_SETTINGS", "SETTINGS: ENABLE_TIME_STAMP_SPEED"
"SETTINGS: ENABLE_TIME_STAMP_SPEED"
)
) )
)
SettingsPatch.updatePatchStatus("enable-timestamps-speed") SettingsPatch.updatePatchStatus("enable-timestamps-speed")
return PatchResultSuccess() return PatchResultSuccess()
} else
return PatchResultError("Instruction not found: $errorIndex")
} }
} }

View File

@ -19,10 +19,10 @@ import app.revanced.util.enum.ResourceType.*
class SharedResourceIdPatch : ResourcePatch { class SharedResourceIdPatch : ResourcePatch {
internal companion object { internal companion object {
var accessibilityProgressTimeId: Long = -1 var accessibilityProgressTimeId: Long = -1
var accessibilityVideoTimeId: Long = -1
var accountSwitcherAccessibilityId: Long = -1 var accountSwitcherAccessibilityId: Long = -1
var adAttributionId: Long = -1 var adAttributionId: Long = -1
var appearanceStringId: Long = -1 var appearanceStringId: Long = -1
var appRelatedEndScreenResultsId: Long = -1
var autoNavPreviewId: Long = -1 var autoNavPreviewId: Long = -1
var backgroundCategoryId: Long = -1 var backgroundCategoryId: Long = -1
var barContainerHeightId: Long = -1 var barContainerHeightId: Long = -1
@ -42,6 +42,7 @@ class SharedResourceIdPatch : ResourcePatch {
var imageOnlyTabId: Long = -1 var imageOnlyTabId: Long = -1
var inlineTimeBarColorizedBarPlayedColorDarkId: Long = -1 var inlineTimeBarColorizedBarPlayedColorDarkId: Long = -1
var inlineTimeBarPlayedNotHighlightedColorId: Long = -1 var inlineTimeBarPlayedNotHighlightedColorId: Long = -1
var insetOverlayViewLayoutId: Long = -1
var layoutCircleId: Long = -1 var layoutCircleId: Long = -1
var layoutIconId: Long = -1 var layoutIconId: Long = -1
var layoutVideoId: Long = -1 var layoutVideoId: Long = -1
@ -55,9 +56,12 @@ class SharedResourceIdPatch : ResourcePatch {
var reelRemixId: Long = -1 var reelRemixId: Long = -1
var relatedChipCloudMarginId: Long = -1 var relatedChipCloudMarginId: Long = -1
var rightCommentId: Long = -1 var rightCommentId: Long = -1
var scrimOverlayId: Long = -1
var searchSuggestionEntryId: Long = -1 var searchSuggestionEntryId: Long = -1
var scrubbingId: Long = -1 var scrubbingId: Long = -1
var slimMetadataToggleButtonId: Long = -1 var slimMetadataToggleButtonId: Long = -1
var suggestedActionId: Long = -1
var totalTimeId: Long = -1
var toolTipId: Long = -1 var toolTipId: Long = -1
var videoQualityFragmentId: Long = -1 var videoQualityFragmentId: Long = -1
} }
@ -69,10 +73,10 @@ class SharedResourceIdPatch : ResourcePatch {
.single { it.type == type.value && it.name == name }.id .single { it.type == type.value && it.name == name }.id
accessibilityProgressTimeId = find(STRING, "accessibility_player_progress_time") accessibilityProgressTimeId = find(STRING, "accessibility_player_progress_time")
accessibilityVideoTimeId = find(STRING, "accessibility_video_time")
accountSwitcherAccessibilityId = find(STRING, "account_switcher_accessibility_label") accountSwitcherAccessibilityId = find(STRING, "account_switcher_accessibility_label")
adAttributionId = find(ID, "ad_attribution") adAttributionId = find(ID, "ad_attribution")
appearanceStringId = find(STRING, "app_theme_appearance_dark") appearanceStringId = find(STRING, "app_theme_appearance_dark")
appRelatedEndScreenResultsId = find(LAYOUT, "app_related_endscreen_results")
autoNavPreviewId = find(ID, "autonav_preview_stub") autoNavPreviewId = find(ID, "autonav_preview_stub")
backgroundCategoryId = find(STRING, "pref_background_and_offline_category") backgroundCategoryId = find(STRING, "pref_background_and_offline_category")
barContainerHeightId = find(DIMEN, "bar_container_height") barContainerHeightId = find(DIMEN, "bar_container_height")
@ -92,6 +96,7 @@ class SharedResourceIdPatch : ResourcePatch {
imageOnlyTabId = find(LAYOUT, "image_only_tab") imageOnlyTabId = find(LAYOUT, "image_only_tab")
inlineTimeBarColorizedBarPlayedColorDarkId = find(COLOR, "inline_time_bar_colorized_bar_played_color_dark") inlineTimeBarColorizedBarPlayedColorDarkId = find(COLOR, "inline_time_bar_colorized_bar_played_color_dark")
inlineTimeBarPlayedNotHighlightedColorId = find(COLOR, "inline_time_bar_played_not_highlighted_color") inlineTimeBarPlayedNotHighlightedColorId = find(COLOR, "inline_time_bar_played_not_highlighted_color")
insetOverlayViewLayoutId = find(ID, "inset_overlay_view_layout")
layoutCircleId = find(LAYOUT, "endscreen_element_layout_circle") layoutCircleId = find(LAYOUT, "endscreen_element_layout_circle")
layoutIconId = find(LAYOUT, "endscreen_element_layout_icon") layoutIconId = find(LAYOUT, "endscreen_element_layout_icon")
layoutVideoId = find(LAYOUT, "endscreen_element_layout_video") layoutVideoId = find(LAYOUT, "endscreen_element_layout_video")
@ -105,9 +110,12 @@ class SharedResourceIdPatch : ResourcePatch {
reelRemixId = find(ID, "reel_dyn_remix") reelRemixId = find(ID, "reel_dyn_remix")
relatedChipCloudMarginId = find(LAYOUT, "related_chip_cloud_reduced_margins") relatedChipCloudMarginId = find(LAYOUT, "related_chip_cloud_reduced_margins")
rightCommentId = find(DRAWABLE, "ic_right_comment_32c") rightCommentId = find(DRAWABLE, "ic_right_comment_32c")
scrimOverlayId = find(ID, "scrim_overlay")
searchSuggestionEntryId = find(LAYOUT, "search_suggestion_entry") searchSuggestionEntryId = find(LAYOUT, "search_suggestion_entry")
scrubbingId = find(DIMEN, "vertical_touch_offset_to_enter_fine_scrubbing") scrubbingId = find(DIMEN, "vertical_touch_offset_to_enter_fine_scrubbing")
slimMetadataToggleButtonId = find(COLOR, "slim_metadata_toggle_button") slimMetadataToggleButtonId = find(COLOR, "slim_metadata_toggle_button")
suggestedActionId = find(LAYOUT, "suggested_action")
totalTimeId = find(STRING, "total_time")
toolTipId = find(LAYOUT, "tooltip_content_view") toolTipId = find(LAYOUT, "tooltip_content_view")
videoQualityFragmentId = find(LAYOUT, "video_quality_bottom_sheet_list_fragment_title") videoQualityFragmentId = find(LAYOUT, "video_quality_bottom_sheet_list_fragment_title")

View File

@ -0,0 +1,16 @@
package app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints
import app.revanced.patcher.fingerprint.method.impl.MethodFingerprint
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.insetOverlayViewLayoutId
import app.revanced.util.bytecode.isWideLiteralExists
import org.jf.dexlib2.Opcode
object OverlayViewLayoutFingerprint : MethodFingerprint(
opcodes = listOf(
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST
),
customFingerprint = { it.definingClass.endsWith("YouTubeControlsOverlay;") && it.isWideLiteralExists(insetOverlayViewLayoutId) }
)

View File

@ -5,6 +5,7 @@ import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.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.BytecodePatch import app.revanced.patcher.patch.BytecodePatch
@ -14,15 +15,19 @@ 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.proxy.mutableTypes.MutableMethod import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.fingerprints.TotalTimeFingerprint
import app.revanced.patches.youtube.misc.overridespeed.bytecode.patch.OverrideSpeedHookPatch import app.revanced.patches.youtube.misc.overridespeed.bytecode.patch.OverrideSpeedHookPatch
import app.revanced.patches.youtube.misc.playercontrols.patch.PlayerControlsPatch import app.revanced.patches.youtube.misc.playercontrols.patch.PlayerControlsPatch
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.insetOverlayViewLayoutId
import app.revanced.patches.youtube.misc.resourceid.patch.SharedResourceIdPatch.Companion.totalTimeId
import app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints.* import app.revanced.patches.youtube.misc.sponsorblock.bytecode.fingerprints.*
import app.revanced.patches.youtube.misc.timebar.patch.HookTimeBarPatch import app.revanced.patches.youtube.misc.timebar.patch.HookTimeBarPatch
import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
import app.revanced.util.bytecode.BytecodeHelper.injectInit import app.revanced.util.bytecode.BytecodeHelper.injectInit
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus
import app.revanced.util.bytecode.getWideLiteralIndex
import org.jf.dexlib2.Opcode import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.BuilderInstruction import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.instruction.BuilderInstruction3rc import org.jf.dexlib2.builder.instruction.BuilderInstruction3rc
@ -48,7 +53,9 @@ import org.jf.dexlib2.iface.reference.MethodReference
class SponsorBlockBytecodePatch : BytecodePatch( class SponsorBlockBytecodePatch : BytecodePatch(
listOf( listOf(
EndScreenEngagementPanelsFingerprint, EndScreenEngagementPanelsFingerprint,
PlayerControllerFingerprint OverlayViewLayoutFingerprint,
PlayerControllerFingerprint,
TotalTimeFingerprint
) )
) { ) {
override fun execute(context: BytecodeContext): PatchResult { override fun execute(context: BytecodeContext): PatchResult {
@ -158,6 +165,37 @@ class SponsorBlockBytecodePatch : BytecodePatch(
) )
} }
/**
* Append the new time to the player layout
*/
TotalTimeFingerprint.result?.mutableMethod?.let {
it.apply {
val targetIndex = getWideLiteralIndex(totalTimeId) + 2
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
invoke-static {v$targetRegister}, $INTEGRATIONS_PLAYER_CONTROLLER_CLASS_DESCRIPTOR->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
"""
)
}
} ?: return TotalTimeFingerprint.toErrorResult()
/**
* Initialize the SponsorBlock view
*/
OverlayViewLayoutFingerprint.result?.mutableMethod?.let{
it.apply{
val targetIndex = getWideLiteralIndex(insetOverlayViewLayoutId) + 3
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
addInstruction(
targetIndex + 1,
"invoke-static {v$targetRegister}, $INTEGRATIONS_BUTTON_CLASS_DESCRIPTOR/ui/SponsorBlockViewController;->initialize(Landroid/view/ViewGroup;)V"
)
}
} ?: return OverlayViewLayoutFingerprint.toErrorResult()
/** /**
* Replace strings * Replace strings

View File

@ -1,85 +0,0 @@
package app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toResult
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.shared.patch.mapping.ResourceMappingPatch
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Name("sponsorblock-secondary-bytecode-patch")
@DependsOn([ResourceMappingPatch::class])
@YouTubeCompatibility
@Version("0.0.1")
class SponsorBlockSecondaryBytecodePatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"string" to "total_time",
"id" to "inset_overlay_view_layout"
).map { (type, name) ->
ResourceMappingPatch
.resourceMappings
.single { it.type == type && it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
this?.instructions?.forEachIndexed { index, instruction ->
when (instruction.opcode) {
Opcode.CONST -> {
when ((instruction as Instruction31i).wideLiteral) {
resourceIds[0] -> { // total time
val targetIndex = index + 2
val targetInstruction = instructions.elementAt(targetIndex)
val targetRegister = (targetInstruction as OneRegisterInstruction).registerA
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
mutableMethod.addInstructions(
targetIndex + 1, """
invoke-static {v$targetRegister}, Lapp/revanced/integrations/sponsorblock/SegmentPlaybackController;->appendTimeWithoutSegments(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$targetRegister
"""
)
patchSuccessArray[0] = true
}
resourceIds[1] -> { // player overlay
val insertIndex = index + 3
val invokeInstruction = instructions.elementAt(insertIndex)
if (invokeInstruction.opcode != Opcode.CHECK_CAST) return@forEachIndexed
val targetRegister = (invokeInstruction as OneRegisterInstruction).registerA
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
mutableMethod.addInstruction(
insertIndex + 1,
"invoke-static {v$targetRegister}, Lapp/revanced/integrations/sponsorblock/ui/SponsorBlockViewController;->initialize(Landroid/view/ViewGroup;)V"
)
patchSuccessArray[1] = true
}
}
}
else -> return@forEachIndexed
}
}
}
}
}
return toResult(patchSuccessArray.indexOf(false))
}
}

View File

@ -12,7 +12,6 @@ import app.revanced.patcher.patch.annotations.Patch
import app.revanced.patches.shared.annotation.YouTubeCompatibility import app.revanced.patches.shared.annotation.YouTubeCompatibility
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch.SponsorBlockBytecodePatch import app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch.SponsorBlockBytecodePatch
import app.revanced.patches.youtube.misc.sponsorblock.bytecode.patch.SponsorBlockSecondaryBytecodePatch
import app.revanced.util.resources.ResourceUtils import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.copyResources import app.revanced.util.resources.ResourceUtils.copyResources
import app.revanced.util.resources.ResourceUtils.copyXmlNode import app.revanced.util.resources.ResourceUtils.copyXmlNode
@ -23,8 +22,7 @@ import app.revanced.util.resources.ResourceUtils.copyXmlNode
@DependsOn( @DependsOn(
[ [
SettingsPatch::class, SettingsPatch::class,
SponsorBlockBytecodePatch::class, SponsorBlockBytecodePatch::class
SponsorBlockSecondaryBytecodePatch::class
] ]
) )
@YouTubeCompatibility @YouTubeCompatibility