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

This commit is contained in:
inotia00 2025-03-24 21:26:57 +09:00
parent 529e0163cc
commit 8666d14297
18 changed files with 301 additions and 189 deletions

View File

@ -57,8 +57,6 @@ internal val showDialogCommandFingerprint = legacyFingerprint(
name = "showDialogCommandFingerprint", name = "showDialogCommandFingerprint",
returnType = "V", returnType = "V",
opcodes = listOf( opcodes = listOf(
Opcode.IF_EQ,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.IGET, // get dialog code Opcode.IGET, // get dialog code
), ),

View File

@ -6,6 +6,7 @@ import app.revanced.patches.youtube.utils.resourceid.compactListItem
import app.revanced.patches.youtube.utils.resourceid.editSettingsAction import app.revanced.patches.youtube.utils.resourceid.editSettingsAction
import app.revanced.patches.youtube.utils.resourceid.fab import app.revanced.patches.youtube.utils.resourceid.fab
import app.revanced.patches.youtube.utils.resourceid.toolTipContentView import app.revanced.patches.youtube.utils.resourceid.toolTipContentView
import app.revanced.patches.youtube.utils.resourceid.ytCallToAction
import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed import app.revanced.util.indexOfFirstInstructionReversed
@ -19,13 +20,7 @@ internal val accountListFingerprint = legacyFingerprint(
name = "accountListFingerprint", name = "accountListFingerprint",
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL or AccessFlags.SYNTHETIC, accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL or AccessFlags.SYNTHETIC,
opcodes = listOf( literals = listOf(ytCallToAction),
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IGET
)
) )
internal val accountListParentFingerprint = legacyFingerprint( internal val accountListParentFingerprint = legacyFingerprint(

View File

@ -20,6 +20,7 @@ import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.accountSwitcherAccessibility import app.revanced.patches.youtube.utils.resourceid.accountSwitcherAccessibility
import app.revanced.patches.youtube.utils.resourceid.fab import app.revanced.patches.youtube.utils.resourceid.fab
import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch import app.revanced.patches.youtube.utils.resourceid.sharedResourceIdPatch
import app.revanced.patches.youtube.utils.resourceid.ytCallToAction
import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference import app.revanced.patches.youtube.utils.settings.ResourceUtils.addPreference
import app.revanced.patches.youtube.utils.settings.settingsPatch import app.revanced.patches.youtube.utils.settings.settingsPatch
import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
@ -122,9 +123,12 @@ val layoutComponentsPatch = bytecodePatch(
// region patch for hide account menu // region patch for hide account menu
// for you tab // for you tab
accountListFingerprint.matchOrThrow(accountListParentFingerprint).let { accountListFingerprint.methodOrThrow(accountListParentFingerprint).apply {
it.method.apply { val literalIndex = indexOfFirstLiteralInstructionOrThrow(ytCallToAction)
val targetIndex = it.patternMatch!!.startIndex + 3 val targetIndex = indexOfFirstInstructionOrThrow(literalIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "setText"
}
val targetInstruction = getInstruction<FiveRegisterInstruction>(targetIndex) val targetInstruction = getInstruction<FiveRegisterInstruction>(targetIndex)
addInstruction( addInstruction(
@ -133,7 +137,6 @@ val layoutComponentsPatch = bytecodePatch(
"$GENERAL_CLASS_DESCRIPTOR->hideAccountList(Landroid/view/View;Ljava/lang/CharSequence;)V" "$GENERAL_CLASS_DESCRIPTOR->hideAccountList(Landroid/view/View;Ljava/lang/CharSequence;)V"
) )
} }
}
// for tablet and old clients // for tablet and old clients
accountMenuFingerprint.matchOrThrow(accountMenuParentFingerprint).let { accountMenuFingerprint.matchOrThrow(accountMenuParentFingerprint).let {

View File

@ -272,10 +272,11 @@ val toolBarComponentsPatch = bytecodePatch(
opcode == Opcode.IGET_OBJECT && opcode == Opcode.IGET_OBJECT &&
getReference<FieldReference>()?.type == "Landroid/widget/ImageView;" getReference<FieldReference>()?.type == "Landroid/widget/ImageView;"
} }
val jumpIndex = indexOfFirstInstructionOrThrow(replaceIndex) { val uriIndex = indexOfFirstInstructionOrThrow(replaceIndex) {
opcode == Opcode.INVOKE_STATIC && opcode == Opcode.INVOKE_STATIC &&
getReference<MethodReference>()?.toString() == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;" getReference<MethodReference>()?.toString() == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;"
} + 4 }
val jumpIndex = indexOfFirstInstructionOrThrow(uriIndex, Opcode.CONST_4)
val replaceIndexInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex) val replaceIndexInstruction = getInstruction<TwoRegisterInstruction>(replaceIndex)
val freeRegister = replaceIndexInstruction.registerA val freeRegister = replaceIndexInstruction.registerA
val classRegister = replaceIndexInstruction.registerB val classRegister = replaceIndexInstruction.registerB

View File

@ -10,11 +10,12 @@ import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutCircl
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutIcon
import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutVideo import app.revanced.patches.youtube.utils.resourceid.endScreenElementLayoutVideo
import app.revanced.patches.youtube.utils.resourceid.offlineActionsVideoDeletedUndoSnackbarText import app.revanced.patches.youtube.utils.resourceid.offlineActionsVideoDeletedUndoSnackbarText
import app.revanced.patches.youtube.utils.resourceid.scrubbing import app.revanced.patches.youtube.utils.resourceid.verticalTouchOffsetToEnterFineScrubbing
import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing import app.revanced.patches.youtube.utils.resourceid.seekEasyHorizontalTouchOffsetToStartScrubbing
import app.revanced.patches.youtube.utils.resourceid.suggestedAction import app.revanced.patches.youtube.utils.resourceid.suggestedAction
import app.revanced.patches.youtube.utils.resourceid.tapBloomView import app.revanced.patches.youtube.utils.resourceid.tapBloomView
import app.revanced.patches.youtube.utils.resourceid.touchArea import app.revanced.patches.youtube.utils.resourceid.touchArea
import app.revanced.patches.youtube.utils.resourceid.verticalTouchOffsetToStartFineScrubbing
import app.revanced.patches.youtube.utils.resourceid.videoZoomSnapIndicator import app.revanced.patches.youtube.utils.resourceid.videoZoomSnapIndicator
import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference import app.revanced.util.getReference
@ -126,6 +127,9 @@ internal val crowdfundingBoxFingerprint = legacyFingerprint(
literals = listOf(donationCompanion), literals = listOf(donationCompanion),
) )
/**
* ~ YouTube 20.11
*/
internal val filmStripOverlayConfigFingerprint = legacyFingerprint( internal val filmStripOverlayConfigFingerprint = legacyFingerprint(
name = "filmStripOverlayConfigFingerprint", name = "filmStripOverlayConfigFingerprint",
returnType = "Z", returnType = "Z",
@ -140,11 +144,48 @@ internal val filmStripOverlayInteractionFingerprint = legacyFingerprint(
parameters = listOf("L") parameters = listOf("L")
) )
internal val filmStripOverlayParentFingerprint = legacyFingerprint( internal val filmStripOverlayEnterParentFingerprint = legacyFingerprint(
name = "filmStripOverlayParentFingerprint", name = "filmStripOverlayEnterParentFingerprint",
returnType = "V", returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR, accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
literals = listOf(scrubbing), literals = listOf(verticalTouchOffsetToEnterFineScrubbing),
)
/**
* YouTube 20.12 ~
*/
internal val filmStripOverlayMotionEventPrimaryFingerprint = legacyFingerprint(
name = "filmStripOverlayMotionEventPrimaryFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/MotionEvent;"),
opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
),
)
/**
* YouTube 20.12 ~
*/
internal val filmStripOverlayMotionEventSecondaryFingerprint = legacyFingerprint(
name = "filmStripOverlayMotionEventSecondaryFingerprint",
returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("Landroid/view/MotionEvent;"),
opcodes = listOf(
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.NEG_FLOAT,
),
)
internal val filmStripOverlayStartParentFingerprint = legacyFingerprint(
name = "filmStripOverlayStartParentFingerprint",
returnType = "V",
accessFlags = AccessFlags.PUBLIC or AccessFlags.CONSTRUCTOR,
literals = listOf(verticalTouchOffsetToStartFineScrubbing),
) )
internal val filmStripOverlayPreviewFingerprint = legacyFingerprint( internal val filmStripOverlayPreviewFingerprint = legacyFingerprint(

View File

@ -32,6 +32,7 @@ import app.revanced.patches.youtube.utils.playservice.is_19_18_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_02_or_greater 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_03_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_05_or_greater import app.revanced.patches.youtube.utils.playservice.is_20_05_or_greater
import app.revanced.patches.youtube.utils.playservice.is_20_12_or_greater
import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.patches.youtube.utils.resourceid.darkBackground import app.revanced.patches.youtube.utils.resourceid.darkBackground
import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast
@ -399,18 +400,6 @@ val playerComponentsPatch = bytecodePatch(
return "" return ""
} }
fun MutableMethod.hookFilmstripOverlay() {
addInstructionsWithLabels(
0, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->hideFilmstripOverlay()Z
move-result v0
if-eqz v0, :shown
const/4 v0, 0x0
return v0
""", ExternalLabel("shown", getInstruction(0))
)
}
// region patch for custom player overlay opacity // region patch for custom player overlay opacity
youtubeControlsOverlayFingerprint.methodOrThrow().apply { youtubeControlsOverlayFingerprint.methodOrThrow().apply {
@ -581,12 +570,68 @@ val playerComponentsPatch = bytecodePatch(
// region patch for hide filmstrip overlay // region patch for hide filmstrip overlay
arrayOf( fun MutableMethod.hookFilmstripOverlay(
filmStripOverlayConfigFingerprint, index: Int = 0,
register: Int = 0
) {
val stringInstructions = if (returnType == "Z")
"""
const/4 v$register, 0x0
return v$register
"""
else if (returnType == "V")
"""
return-void
"""
else
throw Exception("This case should never happen.")
addInstructionsWithLabels(
index, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->hideFilmstripOverlay()Z
move-result v$register
if-eqz v$register, :shown
""" + stringInstructions + """
:shown
nop
"""
)
}
val filmStripOverlayFingerprints = mutableListOf(
filmStripOverlayInteractionFingerprint, filmStripOverlayInteractionFingerprint,
filmStripOverlayPreviewFingerprint filmStripOverlayPreviewFingerprint
).forEach { fingerprint -> )
fingerprint.methodOrThrow(filmStripOverlayParentFingerprint).hookFilmstripOverlay()
if (is_20_12_or_greater) {
filmStripOverlayMotionEventPrimaryFingerprint.matchOrThrow(filmStripOverlayStartParentFingerprint).let {
it.method.apply {
val index = it.patternMatch!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(index).registerA
hookFilmstripOverlay(index, register)
}
}
filmStripOverlayMotionEventSecondaryFingerprint.matchOrThrow(filmStripOverlayStartParentFingerprint).let {
it.method.apply {
val index = it.patternMatch!!.startIndex + 2
val register = getInstruction<OneRegisterInstruction>(index).registerA
addInstructions(
index, """
invoke-static {v$register}, $PLAYER_CLASS_DESCRIPTOR->hideFilmstripOverlay(Z)Z
move-result v$register
"""
)
}
}
} else {
filmStripOverlayFingerprints += filmStripOverlayConfigFingerprint
}
filmStripOverlayFingerprints.forEach { fingerprint ->
fingerprint.methodOrThrow(filmStripOverlayEnterParentFingerprint).hookFilmstripOverlay()
} }
// Removed in YouTube 20.05+ // Removed in YouTube 20.05+

View File

@ -1,8 +1,10 @@
package app.revanced.patches.youtube.player.flyoutmenu.hide package app.revanced.patches.youtube.player.flyoutmenu.hide
import app.revanced.patches.youtube.utils.indexOfAddHeaderViewInstruction
import app.revanced.patches.youtube.utils.resourceid.bottomSheetFooterText import app.revanced.patches.youtube.utils.resourceid.bottomSheetFooterText
import app.revanced.patches.youtube.utils.resourceid.subtitleMenuSettingsFooterInfo import app.revanced.patches.youtube.utils.resourceid.subtitleMenuSettingsFooterInfo
import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
@ -18,33 +20,18 @@ internal val advancedQualityBottomSheetFingerprint = legacyFingerprint(
returnType = "L", returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L", "L"), parameters = listOf("L", "L", "L"),
opcodes = listOf( customFingerprint = custom@{ method, _ ->
Opcode.IGET_OBJECT, if (!method.containsLiteralInstruction(videoQualityBottomSheet)) {
Opcode.INVOKE_STATIC, return@custom false
Opcode.CONST, }
Opcode.CONST_4, if (indexOfAddHeaderViewInstruction(method) < 0) {
Opcode.INVOKE_VIRTUAL, return@custom false
Opcode.MOVE_RESULT_OBJECT, }
Opcode.CONST, val implementation = method.implementation
Opcode.INVOKE_VIRTUAL, ?: return@custom false
Opcode.MOVE_RESULT_OBJECT,
Opcode.CONST_16, implementation.instructions.elementAt(0).opcode == Opcode.IGET_OBJECT
Opcode.INVOKE_VIRTUAL, }
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST,
Opcode.CONST,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CONST_STRING
),
literals = listOf(videoQualityBottomSheet),
) )
internal val captionsBottomSheetFingerprint = legacyFingerprint( internal val captionsBottomSheetFingerprint = legacyFingerprint(

View File

@ -10,6 +10,7 @@ import app.revanced.patches.shared.litho.lithoFilterPatch
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH import app.revanced.patches.youtube.utils.extension.Constants.COMPONENTS_PATH
import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR import app.revanced.patches.youtube.utils.extension.Constants.PLAYER_CLASS_DESCRIPTOR
import app.revanced.patches.youtube.utils.indexOfAddHeaderViewInstruction
import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_PLAYER_FLYOUT_MENU import app.revanced.patches.youtube.utils.patch.PatchList.HIDE_PLAYER_FLYOUT_MENU
import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch import app.revanced.patches.youtube.utils.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.utils.playservice.is_18_39_or_greater import app.revanced.patches.youtube.utils.playservice.is_18_39_or_greater
@ -25,7 +26,6 @@ import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall
import app.revanced.util.fingerprint.injectLiteralInstructionViewCall import app.revanced.util.fingerprint.injectLiteralInstructionViewCall
import app.revanced.util.fingerprint.methodOrThrow import app.revanced.util.fingerprint.methodOrThrow
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstInstructionReversedOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -75,10 +75,7 @@ val playerFlyoutMenuPatch = bytecodePatch(
qualityMenuViewInflateFingerprint qualityMenuViewInflateFingerprint
).forEach { fingerprint -> ).forEach { fingerprint ->
fingerprint.methodOrThrow().apply { fingerprint.methodOrThrow().apply {
val insertIndex = indexOfFirstInstructionOrThrow { val insertIndex = indexOfAddHeaderViewInstruction(this)
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "addHeaderView"
}
val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD val insertRegister = getInstruction<FiveRegisterInstruction>(insertIndex).registerD
addInstructions( addInstructions(

View File

@ -50,6 +50,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.NarrowLiteralInstructio
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.FieldReference import com.android.tools.smali.dexlib2.iface.reference.FieldReference
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference import com.android.tools.smali.dexlib2.iface.reference.TypeReference
import com.android.tools.smali.dexlib2.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethod
import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
@ -145,10 +146,15 @@ val miniplayerPatch = bytecodePatch(
// region Legacy tablet Miniplayer hooks. // region Legacy tablet Miniplayer hooks.
miniplayerOverrideFingerprint.matchOrThrow().let { miniplayerOverrideFingerprint.matchOrThrow().let {
val appNameStringIndex = it.stringMatches!!.first().index + 2
it.method.apply { it.method.apply {
val walkerMethod = getWalkerMethod(appNameStringIndex) val stringIndex = it.stringMatches!!.first().index
val walkerIndex = indexOfFirstInstructionOrThrow(stringIndex) {
val reference = getReference<MethodReference>()
reference?.returnType == "Z" &&
reference.parameterTypes.size == 1 &&
reference.parameterTypes.firstOrNull() == "Landroid/content/Context;"
}
val walkerMethod = getWalkerMethod(walkerIndex)
walkerMethod.apply { walkerMethod.apply {
findReturnIndicesReversed().forEach { index -> findReturnIndicesReversed().forEach { index ->

View File

@ -7,9 +7,13 @@ import app.revanced.patches.youtube.utils.resourceid.ytTextSecondary
import app.revanced.patches.youtube.utils.resourceid.ytYoutubeMagenta import app.revanced.patches.youtube.utils.resourceid.ytYoutubeMagenta
import app.revanced.util.containsLiteralInstruction import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionReversed
import app.revanced.util.or import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import kotlin.collections.listOf import kotlin.collections.listOf
internal val shortsSeekbarColorFingerprint = legacyFingerprint( internal val shortsSeekbarColorFingerprint = legacyFingerprint(
@ -113,27 +117,21 @@ internal val seekbarTappingFingerprint = legacyFingerprint(
name = "seekbarTappingFingerprint", name = "seekbarTappingFingerprint",
returnType = "Z", returnType = "Z",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"), parameters = listOf("Landroid/view/MotionEvent;"),
opcodes = listOf( customFingerprint = { method, classDef ->
Opcode.IPUT_OBJECT, classDef.interfaces.contains("Landroid/view/View${'$'}OnLayoutChangeListener;") &&
Opcode.INVOKE_VIRTUAL, classDef.fields.find { it.type == "[Lcom/google/android/libraries/youtube/player/features/overlay/timebar/TimelineMarker;" } != null &&
Opcode.RETURN, method.name == "onTouchEvent" &&
Opcode.INVOKE_VIRTUAL, indexOfPointInstruction(method) >= 0
Opcode.MOVE_RESULT, }
Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ,
Opcode.INT_TO_FLOAT,
Opcode.INT_TO_FLOAT,
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT,
Opcode.IF_EQZ
),
customFingerprint = { method, _ -> method.name == "onTouchEvent" }
) )
internal fun indexOfPointInstruction(method: Method) =
method.indexOfFirstInstructionReversed {
opcode == Opcode.INVOKE_DIRECT &&
getReference<MethodReference>()?.toString() == "Landroid/graphics/Point;-><init>(II)V"
}
internal val seekbarThumbnailsQualityFingerprint = legacyFingerprint( internal val seekbarThumbnailsQualityFingerprint = legacyFingerprint(
name = "seekbarThumbnailsQualityFingerprint", name = "seekbarThumbnailsQualityFingerprint",
returnType = "Z", returnType = "Z",

View File

@ -132,9 +132,20 @@ val seekbarComponentsPatch = bytecodePatch(
// region patch for enable seekbar tapping patch // region patch for enable seekbar tapping patch
seekbarTappingFingerprint.matchOrThrow().let { seekbarTappingFingerprint.methodOrThrow().apply {
it.method.apply { val pointIndex = indexOfPointInstruction(this)
val tapSeekIndex = it.patternMatch!!.startIndex + 1 val pointInstruction = getInstruction<FiveRegisterInstruction>(pointIndex)
val freeRegister = pointInstruction.registerE
val xAxisRegister = pointInstruction.registerD
val tapSeekIndex = indexOfFirstInstructionOrThrow(pointIndex) {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_VIRTUAL &&
reference?.returnType == "V" &&
reference.parameterTypes.isEmpty()
}
val thisInstanceRegister = getInstruction<FiveRegisterInstruction>(tapSeekIndex).registerC
val tapSeekClass = getInstruction(tapSeekIndex) val tapSeekClass = getInstruction(tapSeekIndex)
.getReference<MethodReference>()!! .getReference<MethodReference>()!!
.definingClass .definingClass
@ -174,19 +185,18 @@ val seekbarComponentsPatch = bytecodePatch(
throw PatchException("oMethod not found") throw PatchException("oMethod not found")
} }
val insertIndex = it.patternMatch!!.startIndex + 2 val insertIndex = tapSeekIndex + 1
addInstructionsWithLabels( addInstructionsWithLabels(
insertIndex, """ insertIndex, """
invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->enableSeekbarTapping()Z invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->enableSeekbarTapping()Z
move-result v0 move-result v$freeRegister
if-eqz v0, :disabled if-eqz v$freeRegister, :disabled
invoke-virtual { p0, v2 }, $pMethodCall invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $pMethodCall
invoke-virtual { p0, v2 }, $oMethodCall invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $oMethodCall
""", ExternalLabel("disabled", getInstruction(insertIndex)) """, ExternalLabel("disabled", getInstruction(insertIndex))
) )
} }
}
// endregion // endregion

View File

@ -109,25 +109,26 @@ internal val qualityMenuViewInflateFingerprint = legacyFingerprint(
returnType = "L", returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L", "L", "L"), parameters = listOf("L", "L", "L"),
opcodes = listOf( customFingerprint = custom@{ method, _ ->
Opcode.INVOKE_SUPER, if (!method.containsLiteralInstruction(videoQualityBottomSheet)) {
Opcode.CONST, return@custom false
Opcode.CONST_4, }
Opcode.INVOKE_VIRTUAL, if (indexOfAddHeaderViewInstruction(method) < 0) {
Opcode.MOVE_RESULT_OBJECT, return@custom false
Opcode.CONST, }
Opcode.INVOKE_VIRTUAL, val implementation = method.implementation
Opcode.MOVE_RESULT_OBJECT, ?: return@custom false
Opcode.CONST_16,
Opcode.INVOKE_VIRTUAL, implementation.instructions.elementAt(0).opcode == Opcode.INVOKE_SUPER
Opcode.CONST, }
Opcode.INVOKE_VIRTUAL,
Opcode.MOVE_RESULT_OBJECT,
Opcode.CHECK_CAST
),
literals = listOf(videoQualityBottomSheet),
) )
internal fun indexOfAddHeaderViewInstruction(method: Method) =
method.indexOfFirstInstruction {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "addHeaderView"
}
internal val rollingNumberTextViewAnimationUpdateFingerprint = legacyFingerprint( internal val rollingNumberTextViewAnimationUpdateFingerprint = legacyFingerprint(
name = "rollingNumberTextViewAnimationUpdateFingerprint", name = "rollingNumberTextViewAnimationUpdateFingerprint",
returnType = "V", returnType = "V",

View File

@ -8,16 +8,6 @@ import app.revanced.patches.youtube.utils.playservice.versionCheckPatch
import app.revanced.util.getBooleanOptionValue import app.revanced.util.getBooleanOptionValue
import org.w3c.dom.Element import org.w3c.dom.Element
val darkModeSplashScreenPatch = resourcePatch(
description = "darkModeSplashScreenPatch"
) {
dependsOn(versionCheckPatch)
finalize {
val restoreOldSplashAnimationIncluded = is_19_32_or_greater &&
CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true &&
customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimation").value == true
/** /**
* Fix the splash screen dark mode background color. * Fix the splash screen dark mode background color.
* In earlier versions of the app this is white and makes no sense for dark mode. * In earlier versions of the app this is white and makes no sense for dark mode.
@ -27,6 +17,19 @@ val darkModeSplashScreenPatch = resourcePatch(
* This is a bug in unpatched YouTube. * This is a bug in unpatched YouTube.
* Should always be applied even if the `Theme` patch is excluded. * Should always be applied even if the `Theme` patch is excluded.
*/ */
val darkModeSplashScreenPatch = resourcePatch(
description = "darkModeSplashScreenPatch"
) {
dependsOn(versionCheckPatch)
finalize {
if (!is_19_32_or_greater) {
return@finalize
}
val restoreOldSplashAnimationIncluded = CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true &&
customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimation").value == true
if (restoreOldSplashAnimationIncluded) { if (restoreOldSplashAnimationIncluded) {
document("res/values-night/styles.xml").use { document -> document("res/values-night/styles.xml").use { document ->
val resourcesNode = document.getElementsByTagName("resources").item(0) as Element val resourcesNode = document.getElementsByTagName("resources").item(0) as Element

View File

@ -71,6 +71,8 @@ var is_20_09_or_greater = false
private set private set
var is_20_10_or_greater = false var is_20_10_or_greater = false
private set private set
var is_20_12_or_greater = false
private set
val versionCheckPatch = resourcePatch( val versionCheckPatch = resourcePatch(
description = "versionCheckPatch", description = "versionCheckPatch",
@ -119,5 +121,6 @@ val versionCheckPatch = resourcePatch(
is_20_05_or_greater = 250605000 <= playStoreServicesVersion is_20_05_or_greater = 250605000 <= playStoreServicesVersion
is_20_09_or_greater = 251006000 <= playStoreServicesVersion is_20_09_or_greater = 251006000 <= playStoreServicesVersion
is_20_10_or_greater = 251105000 <= playStoreServicesVersion is_20_10_or_greater = 251105000 <= playStoreServicesVersion
is_20_12_or_greater = 251305000 <= playStoreServicesVersion
} }
} }

View File

@ -193,8 +193,6 @@ var rightComment = -1L
private set private set
var scrimOverlay = -1L var scrimOverlay = -1L
private set private set
var scrubbing = -1L
private set
var seekEasyHorizontalTouchOffsetToStartScrubbing = -1L var seekEasyHorizontalTouchOffsetToStartScrubbing = -1L
private set private set
var seekUndoEduOverlayStub = -1L var seekUndoEduOverlayStub = -1L
@ -225,6 +223,10 @@ var videoQualityBottomSheet = -1L
private set private set
var varispeedUnavailableTitle = -1L var varispeedUnavailableTitle = -1L
private set private set
var verticalTouchOffsetToEnterFineScrubbing = -1L
private set
var verticalTouchOffsetToStartFineScrubbing = -1L
private set
var videoQualityUnavailableAnnouncement = -1L var videoQualityUnavailableAnnouncement = -1L
private set private set
var videoZoomSnapIndicator = -1L var videoZoomSnapIndicator = -1L
@ -235,6 +237,8 @@ var youTubeControlsOverlaySubtitleButton = -1L
private set private set
var youTubeLogo = -1L var youTubeLogo = -1L
private set private set
var ytCallToAction = -1L
private set
var ytFillBell = -1L var ytFillBell = -1L
private set private set
var ytOutlineLibrary = -1L var ytOutlineLibrary = -1L
@ -620,10 +624,6 @@ internal val sharedResourceIdPatch = resourcePatch(
ID, ID,
"scrim_overlay" "scrim_overlay"
] ]
scrubbing = resourceMappings[
DIMEN,
"vertical_touch_offset_to_enter_fine_scrubbing"
]
seekEasyHorizontalTouchOffsetToStartScrubbing = resourceMappings[ seekEasyHorizontalTouchOffsetToStartScrubbing = resourceMappings[
DIMEN, DIMEN,
"seek_easy_horizontal_touch_offset_to_start_scrubbing" "seek_easy_horizontal_touch_offset_to_start_scrubbing"
@ -684,6 +684,14 @@ internal val sharedResourceIdPatch = resourcePatch(
STRING, STRING,
"varispeed_unavailable_title" "varispeed_unavailable_title"
] ]
verticalTouchOffsetToEnterFineScrubbing = resourceMappings[
DIMEN,
"vertical_touch_offset_to_enter_fine_scrubbing"
]
verticalTouchOffsetToStartFineScrubbing = resourceMappings[
DIMEN,
"vertical_touch_offset_to_start_fine_scrubbing"
]
videoQualityUnavailableAnnouncement = resourceMappings[ videoQualityUnavailableAnnouncement = resourceMappings[
STRING, STRING,
"video_quality_unavailable_announcement" "video_quality_unavailable_announcement"
@ -704,6 +712,10 @@ internal val sharedResourceIdPatch = resourcePatch(
ID, ID,
"youtube_logo" "youtube_logo"
] ]
ytCallToAction = resourceMappings[
ATTR,
"ytCallToAction"
]
ytFillBell = resourceMappings[ ytFillBell = resourceMappings[
DRAWABLE, DRAWABLE,
"yt_fill_bell_black_24" "yt_fill_bell_black_24"

View File

@ -7,6 +7,7 @@ import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.StringReference
/** /**
* This fingerprint is compatible with YouTube v18.30.xx+ * This fingerprint is compatible with YouTube v18.30.xx+
@ -54,7 +55,14 @@ internal val rollingNumberMeasureTextParentFingerprint = legacyFingerprint(
internal val rollingNumberSetterFingerprint = legacyFingerprint( internal val rollingNumberSetterFingerprint = legacyFingerprint(
name = "rollingNumberSetterFingerprint", name = "rollingNumberSetterFingerprint",
opcodes = listOf(Opcode.CHECK_CAST), opcodes = listOf(Opcode.CHECK_CAST),
literals = listOf(45427773L), customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.CONST_STRING &&
getReference<StringReference>()
?.string.toString()
.startsWith("RollingNumberType required properties missing! Need")
} >= 0
}
) )
internal val shortsTextViewFingerprint = legacyFingerprint( internal val shortsTextViewFingerprint = legacyFingerprint(

View File

@ -2,9 +2,12 @@ package app.revanced.patches.youtube.video.playback
import app.revanced.util.containsLiteralInstruction import app.revanced.util.containsLiteralInstruction
import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.fingerprint.legacyFingerprint
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.or import app.revanced.util.or
import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
internal val av1CodecFingerprint = legacyFingerprint( internal val av1CodecFingerprint = legacyFingerprint(
name = "av1CodecFingerprint", name = "av1CodecFingerprint",
@ -61,16 +64,17 @@ internal val playbackSpeedChangedFromRecyclerViewFingerprint = legacyFingerprint
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf("L"), parameters = listOf("L"),
opcodes = listOf( opcodes = listOf(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IF_EQZ,
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE, Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET, Opcode.IGET,
Opcode.INVOKE_VIRTUAL Opcode.INVOKE_VIRTUAL
) ),
customFingerprint = { method, _ ->
method.indexOfFirstInstruction {
opcode == Opcode.IGET &&
getReference<FieldReference>()?.type == "F"
} >= 0
}
) )
internal val playbackSpeedInitializeFingerprint = legacyFingerprint( internal val playbackSpeedInitializeFingerprint = legacyFingerprint(

View File

@ -29,7 +29,7 @@ internal val videoIdFingerprint = legacyFingerprint(
?: return@custom false ?: return@custom false
val instructions = implementation.instructions val instructions = implementation.instructions
val instructionCount = instructions.count() val instructionCount = instructions.count()
if (instructionCount < 30) { if (instructionCount < 25) {
return@custom false return@custom false
} }