feat(YouTube): Replace with a fingerprint that supports a wider range of versions (..20.06)

This commit is contained in:
inotia00
2025-02-07 18:18:05 +09:00
parent 08202866e7
commit a9d25bf9c2
16 changed files with 391 additions and 255 deletions

View File

@ -7,6 +7,7 @@ import app.revanced.patches.youtube.utils.resourceid.miniplayerMaxSize
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerForwardButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerOverlayActionButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerRewindButton
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
import app.revanced.patches.youtube.utils.resourceid.ytOutlinePictureInPictureWhite
@ -15,6 +16,8 @@ import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode
// region legacy miniplayer
internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint(
name = "miniplayerDimensionsCalculatorParentFingerprint",
returnType = "V",
@ -23,6 +26,68 @@ internal val miniplayerDimensionsCalculatorParentFingerprint = legacyFingerprint
literals = listOf(floatyBarTopMargin),
)
/**
* Matches using the class found in [miniplayerDimensionsCalculatorParentFingerprint].
*/
internal val miniplayerOverrideNoContextFingerprint = legacyFingerprint(
name = "miniplayerOverrideNoContextFingerprint",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "Z",
opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
)
internal val miniplayerOverrideFingerprint = legacyFingerprint(
name = "miniplayerOverrideFingerprint",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("appName")
)
internal val miniplayerResponseModelSizeCheckFingerprint = legacyFingerprint(
name = "miniplayerResponseModelSizeCheckFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "L",
parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
opcodes = listOf(
Opcode.RETURN_OBJECT,
Opcode.CHECK_CAST,
Opcode.CHECK_CAST,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
)
)
// endregion
// region modern miniplayer
internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
// In later targets this feature flag does nothing and is dead code.
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L
internal const val MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY = 45644360L
internal val miniplayerModernConstructorFingerprint = legacyFingerprint(
name = "miniplayerModernConstructorFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L"),
literals = listOf(45623000L),
)
internal val miniplayerModernViewParentFingerprint = legacyFingerprint(
name = "miniplayerModernViewParentFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Ljava/lang/String;",
parameters = listOf(),
strings = listOf("player_overlay_modern_mini_player_controls")
)
/**
* Matches using the class found in [miniplayerModernViewParentFingerprint].
*/
@ -38,43 +103,18 @@ internal val miniplayerModernAddViewListenerFingerprint = legacyFingerprint(
*/
internal val miniplayerModernCloseButtonFingerprint = legacyFingerprint(
name = "miniplayerModernCloseButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerClose),
)
internal const val MINIPLAYER_MODERN_FEATURE_KEY = 45622882L
// In later targets this feature flag does nothing and is dead code.
internal const val MINIPLAYER_MODERN_FEATURE_LEGACY_KEY = 45630429L
internal const val MINIPLAYER_DOUBLE_TAP_FEATURE_KEY = 45628823L
internal const val MINIPLAYER_DRAG_DROP_FEATURE_KEY = 45628752L
internal const val MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY = 45658112L
internal const val MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY = 45652224L
internal const val MINIPLAYER_INITIAL_SIZE_FEATURE_KEY = 45640023L
internal const val MINIPLAYER_DISABLED_FEATURE_KEY = 45657015L
internal val miniplayerModernConstructorFingerprint = legacyFingerprint(
name = "miniplayerModernConstructorFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("L"),
literals = listOf(45623000L),
)
internal val miniplayerOnCloseHandlerFingerprint = legacyFingerprint(
name = "miniplayerOnCloseHandlerFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Z",
literals = listOf(MINIPLAYER_DISABLED_FEATURE_KEY),
)
/**
* Matches using the class found in [miniplayerModernViewParentFingerprint].
*/
internal val miniplayerModernExpandButtonFingerprint = legacyFingerprint(
name = "miniplayerModernExpandButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerExpand),
@ -96,7 +136,7 @@ internal val miniplayerModernExpandCloseDrawablesFingerprint = legacyFingerprint
*/
internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
name = "miniplayerModernForwardButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerForwardButton),
@ -107,7 +147,6 @@ internal val miniplayerModernForwardButtonFingerprint = legacyFingerprint(
*/
internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
name = "miniplayerModernOverlayViewFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(scrimOverlay),
@ -118,18 +157,21 @@ internal val miniplayerModernOverlayViewFingerprint = legacyFingerprint(
*/
internal val miniplayerModernRewindButtonFingerprint = legacyFingerprint(
name = "miniplayerModernRewindButtonFingerprint",
returnType = "Landroid/widget/ImageView;",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = emptyList(),
literals = listOf(modernMiniPlayerRewindButton),
)
internal val miniplayerModernViewParentFingerprint = legacyFingerprint(
name = "miniplayerModernViewParentFingerprint",
/**
* Matches using the class found in [miniplayerModernViewParentFingerprint].
*/
internal val miniplayerModernActionButtonFingerprint = legacyFingerprint(
name = "miniplayerModernActionButtonFingerprint",
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "Ljava/lang/String;",
parameters = listOf(),
strings = listOf("player_overlay_modern_mini_player_controls")
parameters = emptyList(),
literals = listOf(modernMiniPlayerOverlayActionButton),
)
internal val miniplayerMinimumSizeFingerprint = legacyFingerprint(
@ -138,33 +180,11 @@ internal val miniplayerMinimumSizeFingerprint = legacyFingerprint(
literals = listOf(192L, 128L, miniplayerMaxSize),
)
internal val miniplayerOverrideFingerprint = legacyFingerprint(
name = "miniplayerOverrideFingerprint",
returnType = "L",
internal val miniplayerOnCloseHandlerFingerprint = legacyFingerprint(
name = "miniplayerOnCloseHandlerFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
strings = listOf("appName")
)
internal val miniplayerOverrideNoContextFingerprint = legacyFingerprint(
name = "miniplayerOverrideNoContextFingerprint",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
returnType = "Z",
opcodes = listOf(Opcode.IGET_BOOLEAN), // anchor to insert the instruction
)
internal val miniplayerResponseModelSizeCheckFingerprint = legacyFingerprint(
name = "miniplayerResponseModelSizeCheckFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
returnType = "L",
parameters = listOf("Ljava/lang/Object;", "Ljava/lang/Object;"),
opcodes = listOf(
Opcode.RETURN_OBJECT,
Opcode.CHECK_CAST,
Opcode.CHECK_CAST,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
)
literals = listOf(MINIPLAYER_DISABLED_FEATURE_KEY),
)
internal const val YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME =

View File

@ -11,16 +11,19 @@ import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PAC
import app.revanced.patches.youtube.utils.extension.Constants.GENERAL_PATH
import app.revanced.patches.youtube.utils.patch.PatchList.MINIPLAYER
import app.revanced.patches.youtube.utils.playservice.is_19_15_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_17_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_23_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_26_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_29_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_36_or_greater
import app.revanced.patches.youtube.utils.playservice.is_19_43_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_03_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerClose
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerExpand
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerForwardButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerOverlayActionButton
import app.revanced.patches.youtube.utils.resourceid.modernMiniPlayerRewindButton
import app.revanced.patches.youtube.utils.resourceid.scrimOverlay
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
@ -36,6 +39,7 @@ import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.fingerprint.mutableClassOrThrow
import app.revanced.util.getReference
import app.revanced.util.getWalkerMethod
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.AccessFlags
@ -116,25 +120,6 @@ val miniplayerPatch = bytecodePatch(
)
}
fun MutableMethod.hookInflatedView(
literalValue: Long,
hookedClassType: String,
extensionMethodName: String,
) {
val imageViewIndex = indexOfFirstInstructionOrThrow(
indexOfFirstLiteralInstructionOrThrow(literalValue)
) {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == hookedClassType
}
val register = getInstruction<OneRegisterInstruction>(imageViewIndex).registerA
addInstruction(
imageViewIndex + 1,
"invoke-static { v$register }, $extensionMethodName"
)
}
// Modern mini player is only present and functional in 19.15+.
// Resource is not present in older versions. Using it to determine, if patching an old version.
val isPatchingOldVersion = !is_19_15_or_greater
@ -212,7 +197,7 @@ val miniplayerPatch = bytecodePatch(
if (is_19_23_or_greater) {
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDragAndDrop(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDragAndDrop(Z)Z"
)
settingArray += "SETTINGS: MINIPLAYER_DRAG_AND_DROP"
}
@ -230,7 +215,7 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->enableMiniplayerDoubleTapAction(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDoubleTapAction(Z)Z"
)
if (!is_19_29_or_greater) {
@ -244,13 +229,11 @@ val miniplayerPatch = bytecodePatch(
MINIPLAYER_INITIAL_SIZE_FEATURE_KEY,
)
val targetIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.LONG_TO_INT)
val register = getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setMiniplayerDefaultSize(I)I
targetIndex + 1, """
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDefaultSize(I)I
move-result v$register
""",
)
@ -270,15 +253,17 @@ val miniplayerPatch = bytecodePatch(
replaceInstruction(index, "const/16 v$register, 170")
}
settingArray += "SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_26"
settingArray += "SETTINGS: MINIPLAYER_WIDTH_DIP"
} else {
settingArray += "SETTINGS: MINIPLAYER_OVERLAY_BUTTONS_19_25"
settingArray += "SETTINGS: MINIPLAYER_REWIND_FORWARD"
}
if (is_19_36_or_greater) {
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->setRoundedCorners(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getRoundedCorners(Z)Z"
)
settingArray += "SETTINGS: MINIPLAYER_ROUNDED_CORNERS"
@ -292,13 +277,23 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->setHorizontalDrag(Z)Z"
"$EXTENSION_CLASS_DESCRIPTOR->getHorizontalDrag(Z)Z"
)
miniplayerModernConstructorFingerprint.injectLiteralInstructionBooleanCall(
MINIPLAYER_ANIMATED_EXPAND_FEATURE_KEY,
"$EXTENSION_CLASS_DESCRIPTOR->getMaximizeAnimation(Z)Z"
)
settingArray += "SETTINGS: MINIPLAYER_HORIZONTAL_DRAG"
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_43"
}
settingArray += if (is_20_03_or_greater) {
"SETTINGS: MINIPLAYER_TYPE_20_03"
} else if (is_19_43_or_greater) {
"SETTINGS: MINIPLAYER_TYPE_19_43"
} else {
settingArray += "SETTINGS: MINIPLAYER_TYPE_19_16"
"SETTINGS: MINIPLAYER_TYPE_19_16"
}
// endregion
@ -339,6 +334,11 @@ val miniplayerPatch = bytecodePatch(
modernMiniPlayerClose,
"hideMiniplayerExpandClose"
),
Triple(
miniplayerModernActionButtonFingerprint,
modernMiniPlayerOverlayActionButton,
"hideMiniplayerActionButton"
),
Triple(
miniplayerModernRewindButtonFingerprint,
modernMiniPlayerRewindButton,
@ -355,11 +355,24 @@ val miniplayerPatch = bytecodePatch(
"adjustMiniplayerOpacity"
)
).forEach { (fingerprint, literalValue, methodName) ->
fingerprint.methodOrThrow(miniplayerModernViewParentFingerprint).hookInflatedView(
literalValue,
"Landroid/widget/ImageView;",
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V"
)
fingerprint.methodOrThrow(miniplayerModernViewParentFingerprint).apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literalValue)
val checkCastIndex = indexOfFirstInstruction(literalIndex) {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == "Landroid/widget/ImageView;"
}
val viewIndex = if (checkCastIndex >= 0) {
checkCastIndex
} else {
indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT)
}
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
addInstruction(
viewIndex + 1,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V"
)
}
}
miniplayerModernAddViewListenerFingerprint.methodOrThrow(
@ -374,39 +387,42 @@ val miniplayerPatch = bytecodePatch(
// Modern 2 uses the same overlay controls as the regular video player,
// and the overlay views are added at runtime.
// Add a hook to the overlay class, and pass the added views to extension.
// Problem is fixed in 19.21+
//
// NOTE: Modern 2 uses the same video UI as the regular player except resized to smaller.
// This patch code could be used to hide other player overlays that do not use Litho.
youTubePlayerOverlaysLayoutFingerprint.matchOrThrow().let {
it.method.apply {
it.classDef.methods.add(
ImmutableMethod(
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
"addView",
listOf(
ImmutableMethodParameter("Landroid/view/View;", annotations, null),
ImmutableMethodParameter("I", annotations, null),
ImmutableMethodParameter(
"Landroid/view/ViewGroup\$LayoutParams;",
annotations,
null
if (!is_19_17_or_greater) {
youTubePlayerOverlaysLayoutFingerprint.matchOrThrow().let {
it.method.apply {
it.classDef.methods.add(
ImmutableMethod(
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
"addView",
listOf(
ImmutableMethodParameter("Landroid/view/View;", annotations, null),
ImmutableMethodParameter("I", annotations, null),
ImmutableMethodParameter(
"Landroid/view/ViewGroup\$LayoutParams;",
annotations,
null
),
),
),
"V",
AccessFlags.PUBLIC.value,
annotations,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
""",
)
}
)
"V",
AccessFlags.PUBLIC.value,
annotations,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
""",
)
}
)
}
}
}

View File

@ -45,6 +45,8 @@ internal val nextGenWatchLayoutFingerprint = legacyFingerprint(
}
)
internal const val RESTORE_SLIDE_TO_SEEK_FEATURE_FLAG = 45411329L
/**
* This value restores the 'Slide to seek' behavior.
* Deprecated in YouTube v19.18.41+.
@ -54,7 +56,7 @@ internal val restoreSlideToSeekBehaviorFingerprint = legacyFingerprint(
returnType = "Z",
parameters = emptyList(),
opcodes = listOf(Opcode.MOVE_RESULT),
literals = listOf(45411329L),
literals = listOf(RESTORE_SLIDE_TO_SEEK_FEATURE_FLAG),
)
internal val slideToSeekMotionEventFingerprint = legacyFingerprint(
@ -72,6 +74,8 @@ internal val slideToSeekMotionEventFingerprint = legacyFingerprint(
)
)
internal const val SPEED_OVERLAY_FEATURE_FLAG = 45411330L
/**
* This value disables 'Playing at 2x speed' while holding down.
* Deprecated in YouTube v19.18.41+.
@ -81,7 +85,7 @@ internal val speedOverlayFingerprint = legacyFingerprint(
returnType = "Z",
parameters = emptyList(),
opcodes = listOf(Opcode.MOVE_RESULT),
literals = listOf(45411330L),
literals = listOf(SPEED_OVERLAY_FEATURE_FLAG),
)
/**
@ -152,6 +156,13 @@ internal val filmStripOverlayPreviewFingerprint = legacyFingerprint(
)
)
internal const val FILM_STRIP_OVERLAY_V2_FEATURE_FLAG = 45420198L
internal val filmStripOverlayConfigV2Fingerprint = legacyFingerprint(
name = "filmStripOverlayConfigV2Fingerprint",
literals = listOf(FILM_STRIP_OVERLAY_V2_FEATURE_FLAG),
)
internal val infoCardsIncognitoFingerprint = legacyFingerprint(
name = "infoCardsIncognitoFingerprint",
returnType = "Ljava/lang/Boolean;",

View File

@ -24,6 +24,8 @@ import app.revanced.patches.youtube.utils.fix.suggestedvideoendscreen.suggestedV
import app.revanced.patches.youtube.utils.patch.PatchList.PLAYER_COMPONENTS
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.utils.playservice.is_20_02_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_03_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_05_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.darkBackground
import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast
@ -91,8 +93,8 @@ private val speedOverlayPatch = bytecodePatch(
// region patch for Disable speed overlay (Enable slide to seek)
mapOf(
restoreSlideToSeekBehaviorFingerprint to 45411329L,
speedOverlayFingerprint to 45411330L
restoreSlideToSeekBehaviorFingerprint to RESTORE_SLIDE_TO_SEEK_FEATURE_FLAG,
speedOverlayFingerprint to SPEED_OVERLAY_FEATURE_FLAG
).forEach { (fingerprint, literal) ->
fingerprint.injectLiteralInstructionBooleanCall(
literal,
@ -237,18 +239,21 @@ private val speedOverlayPatch = bytecodePatch(
)
}
speedOverlayTextValueFingerprint.matchOrThrow().let {
it.method.apply {
val targetIndex = it.patternMatch!!.startIndex
val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex).registerA
// Removed in YouTube 20.03+
if (!is_20_03_or_greater) {
speedOverlayTextValueFingerprint.matchOrThrow().let {
it.method.apply {
val targetIndex = it.patternMatch!!.startIndex
val targetRegister =
getInstruction<OneRegisterInstruction>(targetIndex).registerA
addInstructions(
targetIndex + 1, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue()D
move-result-wide v$targetRegister
"""
)
addInstructions(
targetIndex + 1, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->speedOverlayValue()D
move-result-wide v$targetRegister
"""
)
}
}
}
@ -509,32 +514,42 @@ val playerComponentsPatch = bytecodePatch(
fingerprint.methodOrThrow(filmStripOverlayParentFingerprint).hookFilmstripOverlay()
}
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
val constIndex = indexOfFirstLiteralInstructionOrThrow(fadeDurationFast)
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
val insertIndex =
indexOfFirstInstructionReversedOrThrow(constIndex, Opcode.INVOKE_VIRTUAL) + 1
val jumpIndex = implementation!!.instructions.let { instruction ->
insertIndex + instruction.subList(insertIndex, instruction.size - 1)
.indexOfFirst { instructions ->
instructions.opcode == Opcode.GOTO || instructions.opcode == Opcode.GOTO_16
}
// Removed in YouTube 20.05+
if (!is_20_05_or_greater) {
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
val constIndex = indexOfFirstLiteralInstructionOrThrow(fadeDurationFast)
val constRegister = getInstruction<OneRegisterInstruction>(constIndex).registerA
val insertIndex =
indexOfFirstInstructionReversedOrThrow(constIndex, Opcode.INVOKE_VIRTUAL) + 1
val jumpIndex = implementation!!.instructions.let { instruction ->
insertIndex + instruction.subList(insertIndex, instruction.size - 1)
.indexOfFirst { instructions ->
instructions.opcode == Opcode.GOTO || instructions.opcode == Opcode.GOTO_16
}
}
val replaceInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
val replaceReference =
getInstruction<ReferenceInstruction>(insertIndex).reference
addInstructionsWithLabels(
insertIndex + 1, getAllLiteralComponent(insertIndex, jumpIndex - 1) + """
const v$constRegister, $fadeDurationFast
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->hideFilmstripOverlay()Z
move-result v${replaceInstruction.registerA}
if-nez v${replaceInstruction.registerA}, :hidden
iget-object v${replaceInstruction.registerA}, v${replaceInstruction.registerB}, $replaceReference
""", ExternalLabel("hidden", getInstruction(jumpIndex))
)
removeInstruction(insertIndex)
}
val replaceInstruction = getInstruction<TwoRegisterInstruction>(insertIndex)
val replaceReference =
getInstruction<ReferenceInstruction>(insertIndex).reference
addInstructionsWithLabels(
insertIndex + 1, getAllLiteralComponent(insertIndex, jumpIndex - 1) + """
const v$constRegister, $fadeDurationFast
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->hideFilmstripOverlay()Z
move-result v${replaceInstruction.registerA}
if-nez v${replaceInstruction.registerA}, :hidden
iget-object v${replaceInstruction.registerA}, v${replaceInstruction.registerB}, $replaceReference
""", ExternalLabel("hidden", getInstruction(jumpIndex))
} else {
// This is a new film strip overlay added to YouTube 20.05+
// Disabling this flag is not related to the operation of the patch.
filmStripOverlayConfigV2Fingerprint.injectLiteralInstructionBooleanCall(
FILM_STRIP_OVERLAY_V2_FEATURE_FLAG,
"0x0"
)
removeInstruction(insertIndex)
}
// endregion
@ -571,6 +586,7 @@ val playerComponentsPatch = bytecodePatch(
)
}
// Removed in YouTube 20.02+
if (!is_20_02_or_greater) {
youtubeControlsOverlayFingerprint.methodOrThrow().apply {
val insertIndex =

View File

@ -1,7 +1,9 @@
package app.revanced.patches.youtube.player.seekbar
import app.revanced.patches.youtube.utils.resourceid.inlineTimeBarLiveSeekAbleRange
import app.revanced.patches.youtube.utils.resourceid.reelTimeBarPlayedColor
import app.revanced.patches.youtube.utils.resourceid.ytStaticBrandRed
import app.revanced.patches.youtube.utils.resourceid.ytTextSecondary
import app.revanced.patches.youtube.utils.resourceid.ytYoutubeMagenta
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint
@ -35,11 +37,18 @@ internal val playerSeekbarGradientConfigFingerprint = legacyFingerprint(
literals = listOf(PLAYER_SEEKBAR_GRADIENT_FEATURE_FLAG),
)
internal val playerSeekbarHandleColorFingerprint = legacyFingerprint(
name = "playerSeekbarHandleColorFingerprint",
internal val playerSeekbarHandleColorPrimaryFingerprint = legacyFingerprint(
name = "playerSeekbarHandleColorPrimaryFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Landroid/content/Context;"),
literals = listOf(ytStaticBrandRed),
literals = listOf(ytTextSecondary, ytStaticBrandRed),
)
internal val playerSeekbarHandleColorSecondaryFingerprint = legacyFingerprint(
name = "playerSeekbarHandleColorSecondaryFingerprint",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
parameters = listOf("Landroid/content/Context;"),
literals = listOf(inlineTimeBarLiveSeekAbleRange, ytStaticBrandRed),
)
internal val watchHistoryMenuUseProgressDrawableFingerprint = legacyFingerprint(

View File

@ -265,8 +265,11 @@ val seekbarComponentsPatch = bytecodePatch(
"$EXTENSION_SEEKBAR_COLOR_CLASS_DESCRIPTOR->playerSeekbarGradientEnabled(Z)Z"
)
playerSeekbarHandleColorFingerprint.methodOrThrow().apply {
addColorChangeInstructions(ytStaticBrandRed, "getVideoPlayerSeekbarColorAccent")
arrayOf(
playerSeekbarHandleColorPrimaryFingerprint,
playerSeekbarHandleColorSecondaryFingerprint
).forEach {
it.methodOrThrow().addColorChangeInstructions(ytStaticBrandRed, "getVideoPlayerSeekbarColorAccent")
}
// If hiding feed seekbar thumbnails, then turn off the cairo gradient
// of the watch history menu items as they use the same gradient as the

View File

@ -95,7 +95,6 @@ internal val playerButtonsResourcesFingerprint = legacyFingerprint(
internal val playerButtonsVisibilityFingerprint = legacyFingerprint(
name = "playerButtonsVisibilityFingerprint",
returnType = "V",
accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL,
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,

View File

@ -16,6 +16,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.util.MethodUtil
private lateinit var engagementPanelBuilderMethod: MutableMethod
private lateinit var hideEngagementPanelMethod: MutableMethod
private var showEngagementPanelMethods = mutableListOf<MutableMethod>()
@ -26,8 +27,10 @@ val engagementPanelHookPatch = bytecodePatch(
execute {
engagementPanelBuilderFingerprint.matchOrThrow().let {
engagementPanelBuilderMethod = it.method
it.classDef.methods.filter { method ->
method.indexOfEngagementPanelBuilderInstruction(it.method) >= 0
method.indexOfEngagementPanelBuilderInstruction() >= 0
}.forEach { method ->
showEngagementPanelMethods.add(method)
}
@ -38,11 +41,11 @@ val engagementPanelHookPatch = bytecodePatch(
}
}
private fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: MutableMethod) =
private fun Method.indexOfEngagementPanelBuilderInstruction() =
indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_DIRECT &&
MethodUtil.methodSignaturesMatch(
targetMethod,
engagementPanelBuilderMethod,
getReference<MethodReference>()!!
)
}
@ -50,7 +53,7 @@ private fun Method.indexOfEngagementPanelBuilderInstruction(targetMethod: Mutabl
internal fun hookEngagementPanelState(classDescriptor: String) {
showEngagementPanelMethods.forEach { method ->
method.apply {
val index = indexOfEngagementPanelBuilderInstruction(this)
val index = indexOfEngagementPanelBuilderInstruction()
val register = getInstruction<OneRegisterInstruction>(index + 1).registerA
addInstruction(

View File

@ -55,6 +55,10 @@ var is_19_49_or_greater = false
private set
var is_20_02_or_greater = false
private set
var is_20_03_or_greater = false
private set
var is_20_05_or_greater = false
private set
val versionCheckPatch = resourcePatch(
description = "versionCheckPatch",
@ -95,5 +99,7 @@ val versionCheckPatch = resourcePatch(
is_19_46_or_greater = 244705000 <= playStoreServicesVersion
is_19_49_or_greater = 245005000 <= playStoreServicesVersion
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
}
}

View File

@ -115,6 +115,8 @@ var imageOnlyTab = -1L
private set
var inlineTimeBarColorizedBarPlayedColorDark = -1L
private set
var inlineTimeBarLiveSeekAbleRange = -1L
private set
var inlineTimeBarPlayedNotHighlightedColor = -1L
private set
var insetOverlayViewLayout = -1L
@ -135,6 +137,8 @@ var modernMiniPlayerExpand = -1L
private set
var modernMiniPlayerForwardButton = -1L
private set
var modernMiniPlayerOverlayActionButton = -1L
private set
var modernMiniPlayerRewindButton = -1L
private set
var musicAppDeeplinkButtonView = -1L
@ -241,6 +245,8 @@ var ytOutlineXWhite = -1L
private set
var ytPremiumWordMarkHeader = -1L
private set
var ytTextSecondary = -1L
private set
var ytStaticBrandRed = -1L
private set
var ytWordMarkHeader = -1L
@ -454,6 +460,10 @@ internal val sharedResourceIdPatch = resourcePatch(
COLOR,
"inline_time_bar_colorized_bar_played_color_dark"
]
inlineTimeBarLiveSeekAbleRange = resourceMappings[
COLOR,
"inline_time_bar_live_seekable_range"
]
inlineTimeBarPlayedNotHighlightedColor = resourceMappings[
COLOR,
"inline_time_bar_played_not_highlighted_color"
@ -494,6 +504,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ID,
"modern_miniplayer_forward_button"
]
modernMiniPlayerOverlayActionButton = resourceMappings[
ID,
"modern_miniplayer_overlay_action_button"
]
modernMiniPlayerRewindButton = resourceMappings[
ID,
"modern_miniplayer_rewind_button"
@ -706,6 +720,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ATTR,
"ytPremiumWordmarkHeader"
]
ytTextSecondary = resourceMappings[
ATTR,
"ytTextSecondary",
]
ytStaticBrandRed = resourceMappings[
ATTR,
"ytStaticBrandRed",