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
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
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.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
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.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.util.integrations.Constants.FULLSCREEN
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@Patch
@Name("hide-endscreen-overlay")
@Description("Hide endscreen overlay on swipe controls.")
@DependsOn(
[
ResourceMappingPatch::class,
SettingsPatch::class
SettingsPatch::class,
SharedResourceIdPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class HideEndScreenOverlayPatch : BytecodePatch() {
// list of resource names to get the id of
private val resourceIds = arrayOf(
"app_related_endscreen_results"
).map { name ->
ResourceMappingPatch.resourceMappings.single { it.name == name }.id
}
private var patchSuccessArray = Array(resourceIds.size) {false}
class HideEndScreenOverlayPatch : BytecodePatch(
listOf(EndScreenResultsFingerprint)
) {
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] -> { // end screen result
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"
)
EndScreenResultsFingerprint.result?.mutableMethod?.let {
it.addInstructions(
0, """
invoke-static {}, $FULLSCREEN->hideEndScreenOverlay()Z
move-result v0
if-eqz v0, :show
return-void
""", listOf(ExternalLabel("show", it.instruction(0)))
)
} ?: return EndScreenResultsFingerprint.toErrorResult()
SettingsPatch.updatePatchStatus("hide-endscreen-overlay")
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: FULLSCREEN_SETTINGS",
"SETTINGS: HIDE_END_SCREEN_OVERLAY"
)
)
return PatchResultSuccess()
} else
return PatchResultError("Instruction not found: $errorIndex")
SettingsPatch.updatePatchStatus("hide-endscreen-overlay")
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.util.proxy.mutableTypes.MutableMethod
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.misc.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
@ -35,19 +34,11 @@ import org.jf.dexlib2.iface.instruction.TwoRegisterInstruction
@YouTubeCompatibility
@Version("0.0.1")
class HideFilmstripOverlayPatch : BytecodePatch(
listOf(
ScrubbingLabelFingerprint,
ScrubbingLabelAlternativeFingerprint
)
listOf(ScrubbingLabelFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
val result = try {
ScrubbingLabelFingerprint.result!!
} catch (_: Exception) {
ScrubbingLabelAlternativeFingerprint.result
?: return ScrubbingLabelAlternativeFingerprint.toErrorResult()
}
val result = ScrubbingLabelFingerprint.result?: return ScrubbingLabelFingerprint.toErrorResult()
result.mutableMethod.hook(result.scanResult.patternScanResult!!.endIndex - 1)

View File

@ -43,7 +43,7 @@ class HideEndscreenCardsPatch : BytecodePatch(
val index = this.scanResult.patternScanResult!!.endIndex
this.mutableMethod.apply {
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
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
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.annotations.DependsOn
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.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.util.bytecode.getWideLiteralIndex
import app.revanced.util.integrations.Constants.PLAYER
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction21c
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
@Patch
@Name("hide-player-overlay-filter")
@Description("Remove the dark filter layer from the player's background.")
@DependsOn(
[
ResourceMappingPatch::class,
SettingsPatch::class
SettingsPatch::class,
SharedResourceIdPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class PlayerOverlayFilterPatch : BytecodePatch() {
// 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}
class PlayerOverlayFilterPatch : BytecodePatch(
listOf(ScrimOverlayFingerprint)
) {
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)
val dummyRegister = (instructions.elementAt(index) as Instruction31i).registerA
val viewRegister = (invokeInstruction as Instruction21c).registerA
ScrimOverlayFingerprint.result?.mutableMethod?.let {
val targetIndex = it.getWideLiteralIndex(scrimOverlayId) + 3
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(
insertIndex + 1, """
invoke-static {}, $PLAYER->hidePlayerOverlayFilter()Z
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"
)
it.addInstruction(
targetIndex + 1,
"invoke-static {v$targetRegister}, $PLAYER->hidePlayerOverlayFilter(Landroid/widget/ImageView;)V"
)
} ?: return ScrimOverlayFingerprint.toErrorResult()
SettingsPatch.updatePatchStatus("hide-player-overlay-filter")
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: PLAYER_SETTINGS",
"SETTINGS: HIDE_PLAYER_OVERLAY_FILTER"
)
)
return PatchResultSuccess()
} else
return PatchResultError("Instruction not found: $errorIndex")
SettingsPatch.updatePatchStatus("hide-player-overlay-filter")
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
import app.revanced.extensions.findMutableMethodOf
import app.revanced.extensions.injectHideCall
import app.revanced.extensions.toErrorResult
import app.revanced.patcher.annotation.Description
import app.revanced.patcher.annotation.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
import app.revanced.patcher.patch.PatchResultError
import app.revanced.patcher.patch.PatchResultSuccess
import app.revanced.patcher.patch.annotations.DependsOn
import app.revanced.patcher.patch.annotations.Patch
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.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.util.bytecode.BytecodeHelper.updatePatchStatus
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.iface.instruction.formats.Instruction22c
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.instruction.OneRegisterInstruction
@Patch
@Name("hide-suggested-actions")
@ -28,71 +25,37 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction31i
@DependsOn(
[
ByteBufferFilterPatch::class,
PlayerTypeHookPatch::class,
ResourceMappingPatch::class,
SettingsPatch::class
SettingsPatch::class,
SharedResourceIdPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class SuggestedActionsPatch : BytecodePatch() {
// 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}
class SuggestedActionsPatch : BytecodePatch(
listOf(SuggestedActionsFingerprint)
) {
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] -> { // suggested_action
val insertIndex = index + 4
val iPutInstruction = instructions.elementAt(insertIndex)
if (iPutInstruction.opcode != Opcode.IPUT_OBJECT) return@forEachIndexed
SuggestedActionsFingerprint.result?.let{
it.mutableMethod.apply {
val targetIndex = it.scanResult.patternScanResult!!.endIndex
val targetRegister = instruction<OneRegisterInstruction>(targetIndex).registerA
val mutableMethod = context.proxy(classDef).mutableClass.findMutableMethodOf(method)
val viewRegister = (iPutInstruction as Instruction22c).registerA
mutableMethod.implementation!!.injectHideCall(insertIndex, viewRegister, "layout/PlayerPatch", "hideSuggestedActions")
patchSuccessArray[0] = true
}
}
}
else -> return@forEachIndexed
}
}
}
implementation!!.injectHideCall(targetIndex + 1, targetRegister, "layout/PlayerPatch", "hideSuggestedActions")
}
}
} ?: return SuggestedActionsFingerprint.toErrorResult()
val errorIndex: Int = patchSuccessArray.indexOf(false)
if (errorIndex == -1) {
context.updatePatchStatus("SuggestedActions")
/*
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: PLAYER_SETTINGS",
"SETTINGS: HIDE_SUGGESTED_ACTION"
)
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: PLAYER_SETTINGS",
"SETTINGS: HIDE_SUGGESTED_ACTION"
)
)
SettingsPatch.updatePatchStatus("hide-suggested-actions")
SettingsPatch.updatePatchStatus("hide-suggested-actions")
return PatchResultSuccess()
} else
return PatchResultError("Instruction not found: $errorIndex")
return PatchResultSuccess()
}
}

View File

@ -1,11 +1,12 @@
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.Name
import app.revanced.patcher.annotation.Version
import app.revanced.patcher.data.BytecodeContext
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchResult
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.Patch
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.resourceid.patch.SharedResourceIdPatch
import app.revanced.patches.youtube.misc.settings.resource.patch.SettingsPatch
import app.revanced.util.integrations.Constants.SEEKBAR
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.dexbacked.instruction.DexBackedInstruction35c
import org.jf.dexlib2.iface.instruction.formats.Instruction31i
import org.jf.dexlib2.iface.instruction.ReferenceInstruction
import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@Patch
@ -28,78 +29,55 @@ import org.jf.dexlib2.iface.instruction.formats.Instruction35c
@DependsOn(
[
OverrideSpeedHookPatch::class,
ResourceMappingPatch::class,
SettingsPatch::class
SettingsPatch::class,
SharedResourceIdPatch::class
]
)
@YouTubeCompatibility
@Version("0.0.1")
class AppendSpeedPatch : BytecodePatch() {
// 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}
class AppendSpeedPatch : BytecodePatch(
listOf(TotalTimeFingerprint)
) {
override fun execute(context: BytecodeContext): PatchResult {
context.classes.forEach { classDef ->
classDef.methods.forEach { method ->
with(method.implementation) {
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)
TotalTimeFingerprint.result?.mutableMethod?.let {
it.implementation!!.instructions.apply {
var insertIndex = -1
for ((targetIndex, targetInstruction) in instructions.withIndex()) {
if (targetInstruction.opcode != Opcode.INVOKE_VIRTUAL) continue
for ((targetIndex, targetInstruction) in withIndex()) {
if (targetInstruction.opcode != Opcode.INVOKE_VIRTUAL) continue
if ((targetInstruction as DexBackedInstruction35c).reference.toString() ==
"Landroid/widget/TextView;->getText()Ljava/lang/CharSequence;") {
val insertIndex = targetIndex + 2
val insertRegister = (instructions.elementAt(insertIndex) as Instruction35c).registerC
mutableMethod.addInstructions(
insertIndex, """
invoke-static {v$insertRegister}, $SEEKBAR->enableTimeStampSpeed(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$insertRegister
"""
)
patchSuccessArray[0] = true
break
}
}
}
}
}
else -> return@forEachIndexed
}
if (it.instruction<ReferenceInstruction>(targetIndex).reference.toString() ==
"Landroid/widget/TextView;->getText()Ljava/lang/CharSequence;") {
insertIndex = targetIndex + 2
val insertRegister = it.instruction<Instruction35c>(insertIndex).registerC
it.addInstructions(
insertIndex, """
invoke-static {v$insertRegister}, $SEEKBAR->enableTimeStampSpeed(Ljava/lang/String;)Ljava/lang/String;
move-result-object v$insertRegister
"""
)
break
}
}
if (insertIndex == -1)
return PatchResultError("target Instruction not found!")
}
}
val errorIndex: Int = patchSuccessArray.indexOf(false)
} ?: return TotalTimeFingerprint.toErrorResult()
if (errorIndex == -1) {
/*
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: SEEKBAR_SETTINGS",
"SETTINGS: ENABLE_TIME_STAMP_SPEED"
)
/**
* Add settings
*/
SettingsPatch.addPreference(
arrayOf(
"PREFERENCE: SEEKBAR_SETTINGS",
"SETTINGS: ENABLE_TIME_STAMP_SPEED"
)
)
SettingsPatch.updatePatchStatus("enable-timestamps-speed")
SettingsPatch.updatePatchStatus("enable-timestamps-speed")
return PatchResultSuccess()
} else
return PatchResultError("Instruction not found: $errorIndex")
return PatchResultSuccess()
}
}

View File

@ -19,10 +19,10 @@ import app.revanced.util.enum.ResourceType.*
class SharedResourceIdPatch : ResourcePatch {
internal companion object {
var accessibilityProgressTimeId: Long = -1
var accessibilityVideoTimeId: Long = -1
var accountSwitcherAccessibilityId: Long = -1
var adAttributionId: Long = -1
var appearanceStringId: Long = -1
var appRelatedEndScreenResultsId: Long = -1
var autoNavPreviewId: Long = -1
var backgroundCategoryId: Long = -1
var barContainerHeightId: Long = -1
@ -42,6 +42,7 @@ class SharedResourceIdPatch : ResourcePatch {
var imageOnlyTabId: Long = -1
var inlineTimeBarColorizedBarPlayedColorDarkId: Long = -1
var inlineTimeBarPlayedNotHighlightedColorId: Long = -1
var insetOverlayViewLayoutId: Long = -1
var layoutCircleId: Long = -1
var layoutIconId: Long = -1
var layoutVideoId: Long = -1
@ -55,9 +56,12 @@ class SharedResourceIdPatch : ResourcePatch {
var reelRemixId: Long = -1
var relatedChipCloudMarginId: Long = -1
var rightCommentId: Long = -1
var scrimOverlayId: Long = -1
var searchSuggestionEntryId: Long = -1
var scrubbingId: Long = -1
var slimMetadataToggleButtonId: Long = -1
var suggestedActionId: Long = -1
var totalTimeId: Long = -1
var toolTipId: Long = -1
var videoQualityFragmentId: Long = -1
}
@ -69,10 +73,10 @@ class SharedResourceIdPatch : ResourcePatch {
.single { it.type == type.value && it.name == name }.id
accessibilityProgressTimeId = find(STRING, "accessibility_player_progress_time")
accessibilityVideoTimeId = find(STRING, "accessibility_video_time")
accountSwitcherAccessibilityId = find(STRING, "account_switcher_accessibility_label")
adAttributionId = find(ID, "ad_attribution")
appearanceStringId = find(STRING, "app_theme_appearance_dark")
appRelatedEndScreenResultsId = find(LAYOUT, "app_related_endscreen_results")
autoNavPreviewId = find(ID, "autonav_preview_stub")
backgroundCategoryId = find(STRING, "pref_background_and_offline_category")
barContainerHeightId = find(DIMEN, "bar_container_height")
@ -92,6 +96,7 @@ class SharedResourceIdPatch : ResourcePatch {
imageOnlyTabId = find(LAYOUT, "image_only_tab")
inlineTimeBarColorizedBarPlayedColorDarkId = find(COLOR, "inline_time_bar_colorized_bar_played_color_dark")
inlineTimeBarPlayedNotHighlightedColorId = find(COLOR, "inline_time_bar_played_not_highlighted_color")
insetOverlayViewLayoutId = find(ID, "inset_overlay_view_layout")
layoutCircleId = find(LAYOUT, "endscreen_element_layout_circle")
layoutIconId = find(LAYOUT, "endscreen_element_layout_icon")
layoutVideoId = find(LAYOUT, "endscreen_element_layout_video")
@ -105,9 +110,12 @@ class SharedResourceIdPatch : ResourcePatch {
reelRemixId = find(ID, "reel_dyn_remix")
relatedChipCloudMarginId = find(LAYOUT, "related_chip_cloud_reduced_margins")
rightCommentId = find(DRAWABLE, "ic_right_comment_32c")
scrimOverlayId = find(ID, "scrim_overlay")
searchSuggestionEntryId = find(LAYOUT, "search_suggestion_entry")
scrubbingId = find(DIMEN, "vertical_touch_offset_to_enter_fine_scrubbing")
slimMetadataToggleButtonId = find(COLOR, "slim_metadata_toggle_button")
suggestedActionId = find(LAYOUT, "suggested_action")
totalTimeId = find(STRING, "total_time")
toolTipId = find(LAYOUT, "tooltip_content_view")
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.data.BytecodeContext
import app.revanced.patcher.extensions.addInstruction
import app.revanced.patcher.extensions.addInstructions
import app.revanced.patcher.extensions.instruction
import app.revanced.patcher.extensions.replaceInstruction
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.util.proxy.mutableTypes.MutableMethod
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.playercontrols.patch.PlayerControlsPatch
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.timebar.patch.HookTimeBarPatch
import app.revanced.patches.youtube.misc.videoid.legacy.patch.LegacyVideoIdPatch
import app.revanced.patches.youtube.misc.videoid.mainstream.patch.MainstreamVideoIdPatch
import app.revanced.util.bytecode.BytecodeHelper.injectInit
import app.revanced.util.bytecode.BytecodeHelper.updatePatchStatus
import app.revanced.util.bytecode.getWideLiteralIndex
import org.jf.dexlib2.Opcode
import org.jf.dexlib2.builder.BuilderInstruction
import org.jf.dexlib2.builder.instruction.BuilderInstruction3rc
@ -48,7 +53,9 @@ import org.jf.dexlib2.iface.reference.MethodReference
class SponsorBlockBytecodePatch : BytecodePatch(
listOf(
EndScreenEngagementPanelsFingerprint,
PlayerControllerFingerprint
OverlayViewLayoutFingerprint,
PlayerControllerFingerprint,
TotalTimeFingerprint
)
) {
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

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.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.SponsorBlockSecondaryBytecodePatch
import app.revanced.util.resources.ResourceUtils
import app.revanced.util.resources.ResourceUtils.copyResources
import app.revanced.util.resources.ResourceUtils.copyXmlNode
@ -23,8 +22,7 @@ import app.revanced.util.resources.ResourceUtils.copyXmlNode
@DependsOn(
[
SettingsPatch::class,
SponsorBlockBytecodePatch::class,
SponsorBlockSecondaryBytecodePatch::class
SponsorBlockBytecodePatch::class
]
)
@YouTubeCompatibility