diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/ads/general/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/ads/general/Fingerprints.kt index 315b1d9ac..c8aa32933 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/ads/general/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/ads/general/Fingerprints.kt @@ -57,8 +57,6 @@ internal val showDialogCommandFingerprint = legacyFingerprint( name = "showDialogCommandFingerprint", returnType = "V", opcodes = listOf( - Opcode.IF_EQ, - Opcode.IGET_OBJECT, Opcode.INVOKE_VIRTUAL, Opcode.IGET, // get dialog code ), diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt index e9e4a2e29..8782607c6 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/Fingerprints.kt @@ -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.fab 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.getReference import app.revanced.util.indexOfFirstInstructionReversed @@ -19,13 +20,7 @@ internal val accountListFingerprint = legacyFingerprint( name = "accountListFingerprint", returnType = "V", accessFlags = AccessFlags.PROTECTED or AccessFlags.FINAL or AccessFlags.SYNTHETIC, - opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.IGET - ) + literals = listOf(ytCallToAction), ) internal val accountListParentFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt index 7782e7741..003903a3f 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/components/LayoutComponentsPatch.kt @@ -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.fab 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.settingsPatch import app.revanced.util.fingerprint.injectLiteralInstructionBooleanCall @@ -122,17 +123,19 @@ val layoutComponentsPatch = bytecodePatch( // region patch for hide account menu // for you tab - accountListFingerprint.matchOrThrow(accountListParentFingerprint).let { - it.method.apply { - val targetIndex = it.patternMatch!!.startIndex + 3 - val targetInstruction = getInstruction(targetIndex) - - addInstruction( - targetIndex, - "invoke-static {v${targetInstruction.registerC}, v${targetInstruction.registerD}}, " + - "$GENERAL_CLASS_DESCRIPTOR->hideAccountList(Landroid/view/View;Ljava/lang/CharSequence;)V" - ) + accountListFingerprint.methodOrThrow(accountListParentFingerprint).apply { + val literalIndex = indexOfFirstLiteralInstructionOrThrow(ytCallToAction) + val targetIndex = indexOfFirstInstructionOrThrow(literalIndex) { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "setText" } + val targetInstruction = getInstruction(targetIndex) + + addInstruction( + targetIndex, + "invoke-static {v${targetInstruction.registerC}, v${targetInstruction.registerD}}, " + + "$GENERAL_CLASS_DESCRIPTOR->hideAccountList(Landroid/view/View;Ljava/lang/CharSequence;)V" + ) } // for tablet and old clients diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt index f928fd94d..e701162e8 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/general/toolbar/ToolBarComponentsPatch.kt @@ -272,10 +272,11 @@ val toolBarComponentsPatch = bytecodePatch( opcode == Opcode.IGET_OBJECT && getReference()?.type == "Landroid/widget/ImageView;" } - val jumpIndex = indexOfFirstInstructionOrThrow(replaceIndex) { + val uriIndex = indexOfFirstInstructionOrThrow(replaceIndex) { opcode == Opcode.INVOKE_STATIC && getReference()?.toString() == "Landroid/net/Uri;->parse(Ljava/lang/String;)Landroid/net/Uri;" - } + 4 + } + val jumpIndex = indexOfFirstInstructionOrThrow(uriIndex, Opcode.CONST_4) val replaceIndexInstruction = getInstruction(replaceIndex) val freeRegister = replaceIndexInstruction.registerA val classRegister = replaceIndexInstruction.registerB diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt index 303b05170..cd274c9dc 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/Fingerprints.kt @@ -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.endScreenElementLayoutVideo 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.suggestedAction import app.revanced.patches.youtube.utils.resourceid.tapBloomView 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.util.fingerprint.legacyFingerprint import app.revanced.util.getReference @@ -126,6 +127,9 @@ internal val crowdfundingBoxFingerprint = legacyFingerprint( literals = listOf(donationCompanion), ) +/** + * ~ YouTube 20.11 + */ internal val filmStripOverlayConfigFingerprint = legacyFingerprint( name = "filmStripOverlayConfigFingerprint", returnType = "Z", @@ -140,11 +144,48 @@ internal val filmStripOverlayInteractionFingerprint = legacyFingerprint( parameters = listOf("L") ) -internal val filmStripOverlayParentFingerprint = legacyFingerprint( - name = "filmStripOverlayParentFingerprint", +internal val filmStripOverlayEnterParentFingerprint = legacyFingerprint( + name = "filmStripOverlayEnterParentFingerprint", returnType = "V", 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( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt index 81d9579d5..c3c3b5b21 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/components/PlayerComponentsPatch.kt @@ -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_03_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.resourceid.darkBackground import app.revanced.patches.youtube.utils.resourceid.fadeDurationFast @@ -399,18 +400,6 @@ val playerComponentsPatch = bytecodePatch( 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 youtubeControlsOverlayFingerprint.methodOrThrow().apply { @@ -581,12 +570,68 @@ val playerComponentsPatch = bytecodePatch( // region patch for hide filmstrip overlay - arrayOf( - filmStripOverlayConfigFingerprint, + fun MutableMethod.hookFilmstripOverlay( + 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, 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(index).registerA + + hookFilmstripOverlay(index, register) + } + } + + filmStripOverlayMotionEventSecondaryFingerprint.matchOrThrow(filmStripOverlayStartParentFingerprint).let { + it.method.apply { + val index = it.patternMatch!!.startIndex + 2 + val register = getInstruction(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+ diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/Fingerprints.kt index 19470906e..70d3db075 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/Fingerprints.kt @@ -1,8 +1,10 @@ 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.subtitleMenuSettingsFooterInfo import app.revanced.patches.youtube.utils.resourceid.videoQualityBottomSheet +import app.revanced.util.containsLiteralInstruction import app.revanced.util.fingerprint.legacyFingerprint import app.revanced.util.getReference import app.revanced.util.indexOfFirstInstruction @@ -18,33 +20,18 @@ internal val advancedQualityBottomSheetFingerprint = legacyFingerprint( returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L", "L", "L"), - opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.INVOKE_STATIC, - Opcode.CONST, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - 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), + customFingerprint = custom@{ method, _ -> + if (!method.containsLiteralInstruction(videoQualityBottomSheet)) { + return@custom false + } + if (indexOfAddHeaderViewInstruction(method) < 0) { + return@custom false + } + val implementation = method.implementation + ?: return@custom false + + implementation.instructions.elementAt(0).opcode == Opcode.IGET_OBJECT + } ) internal val captionsBottomSheetFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/PlayerFlyoutMenuPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/PlayerFlyoutMenuPatch.kt index 07c2df304..8f7ea6837 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/PlayerFlyoutMenuPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/flyoutmenu/hide/PlayerFlyoutMenuPatch.kt @@ -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.extension.Constants.COMPONENTS_PATH 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.playertype.playerTypeHookPatch 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.methodOrThrow import app.revanced.util.getReference -import app.revanced.util.indexOfFirstInstructionOrThrow import app.revanced.util.indexOfFirstInstructionReversedOrThrow import com.android.tools.smali.dexlib2.Opcode import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction @@ -75,10 +75,7 @@ val playerFlyoutMenuPatch = bytecodePatch( qualityMenuViewInflateFingerprint ).forEach { fingerprint -> fingerprint.methodOrThrow().apply { - val insertIndex = indexOfFirstInstructionOrThrow { - opcode == Opcode.INVOKE_VIRTUAL && - getReference()?.name == "addHeaderView" - } + val insertIndex = indexOfAddHeaderViewInstruction(this) val insertRegister = getInstruction(insertIndex).registerD addInstructions( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/miniplayer/general/MiniplayerPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/miniplayer/general/MiniplayerPatch.kt index bdd835f99..a5d331118 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/miniplayer/general/MiniplayerPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/miniplayer/general/MiniplayerPatch.kt @@ -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.TwoRegisterInstruction 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.immutable.ImmutableMethod import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter @@ -145,10 +146,15 @@ val miniplayerPatch = bytecodePatch( // region Legacy tablet Miniplayer hooks. miniplayerOverrideFingerprint.matchOrThrow().let { - val appNameStringIndex = it.stringMatches!!.first().index + 2 - it.method.apply { - val walkerMethod = getWalkerMethod(appNameStringIndex) + val stringIndex = it.stringMatches!!.first().index + val walkerIndex = indexOfFirstInstructionOrThrow(stringIndex) { + val reference = getReference() + reference?.returnType == "Z" && + reference.parameterTypes.size == 1 && + reference.parameterTypes.firstOrNull() == "Landroid/content/Context;" + } + val walkerMethod = getWalkerMethod(walkerIndex) walkerMethod.apply { findReturnIndicesReversed().forEach { index -> diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt index 22584d1ab..d0e9eac5c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/Fingerprints.kt @@ -7,9 +7,13 @@ 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 +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstructionReversed import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags 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 internal val shortsSeekbarColorFingerprint = legacyFingerprint( @@ -113,27 +117,21 @@ internal val seekbarTappingFingerprint = legacyFingerprint( name = "seekbarTappingFingerprint", returnType = "Z", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, - parameters = listOf("L"), - opcodes = listOf( - Opcode.IPUT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.RETURN, - Opcode.INVOKE_VIRTUAL, - 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" } + parameters = listOf("Landroid/view/MotionEvent;"), + customFingerprint = { method, classDef -> + classDef.interfaces.contains("Landroid/view/View${'$'}OnLayoutChangeListener;") && + classDef.fields.find { it.type == "[Lcom/google/android/libraries/youtube/player/features/overlay/timebar/TimelineMarker;" } != null && + method.name == "onTouchEvent" && + indexOfPointInstruction(method) >= 0 + } ) +internal fun indexOfPointInstruction(method: Method) = + method.indexOfFirstInstructionReversed { + opcode == Opcode.INVOKE_DIRECT && + getReference()?.toString() == "Landroid/graphics/Point;->(II)V" + } + internal val seekbarThumbnailsQualityFingerprint = legacyFingerprint( name = "seekbarThumbnailsQualityFingerprint", returnType = "Z", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt index 441ec5f4c..92bf1da06 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/player/seekbar/SeekbarComponentsPatch.kt @@ -132,60 +132,70 @@ val seekbarComponentsPatch = bytecodePatch( // region patch for enable seekbar tapping patch - seekbarTappingFingerprint.matchOrThrow().let { - it.method.apply { - val tapSeekIndex = it.patternMatch!!.startIndex + 1 - val tapSeekClass = getInstruction(tapSeekIndex) - .getReference()!! - .definingClass + seekbarTappingFingerprint.methodOrThrow().apply { + val pointIndex = indexOfPointInstruction(this) + val pointInstruction = getInstruction(pointIndex) + val freeRegister = pointInstruction.registerE + val xAxisRegister = pointInstruction.registerD - val tapSeekMethods = findMethodsOrThrow(tapSeekClass) - var pMethodCall = "" - var oMethodCall = "" - - for (method in tapSeekMethods) { - if (method.implementation == null) - continue - - val instructions = method.implementation!!.instructions - // here we make sure we actually find the method because it has more than 7 instructions - if (instructions.count() != 10) - continue - - // we know that the 7th instruction has the opcode CONST_4 - val instruction = instructions.elementAt(6) - if (instruction.opcode != Opcode.CONST_4) - continue - - // the literal for this instruction has to be either 1 or 2 - val literal = (instruction as NarrowLiteralInstruction).narrowLiteral - - // method founds - if (literal == 1) - pMethodCall = "${method.definingClass}->${method.name}(I)V" - else if (literal == 2) - oMethodCall = "${method.definingClass}->${method.name}(I)V" - } - - if (pMethodCall.isEmpty()) { - throw PatchException("pMethod not found") - } - if (oMethodCall.isEmpty()) { - throw PatchException("oMethod not found") - } - - val insertIndex = it.patternMatch!!.startIndex + 2 - - addInstructionsWithLabels( - insertIndex, """ - invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->enableSeekbarTapping()Z - move-result v0 - if-eqz v0, :disabled - invoke-virtual { p0, v2 }, $pMethodCall - invoke-virtual { p0, v2 }, $oMethodCall - """, ExternalLabel("disabled", getInstruction(insertIndex)) - ) + val tapSeekIndex = indexOfFirstInstructionOrThrow(pointIndex) { + val reference = getReference() + opcode == Opcode.INVOKE_VIRTUAL && + reference?.returnType == "V" && + reference.parameterTypes.isEmpty() } + val thisInstanceRegister = getInstruction(tapSeekIndex).registerC + + val tapSeekClass = getInstruction(tapSeekIndex) + .getReference()!! + .definingClass + + val tapSeekMethods = findMethodsOrThrow(tapSeekClass) + var pMethodCall = "" + var oMethodCall = "" + + for (method in tapSeekMethods) { + if (method.implementation == null) + continue + + val instructions = method.implementation!!.instructions + // here we make sure we actually find the method because it has more than 7 instructions + if (instructions.count() != 10) + continue + + // we know that the 7th instruction has the opcode CONST_4 + val instruction = instructions.elementAt(6) + if (instruction.opcode != Opcode.CONST_4) + continue + + // the literal for this instruction has to be either 1 or 2 + val literal = (instruction as NarrowLiteralInstruction).narrowLiteral + + // method founds + if (literal == 1) + pMethodCall = "${method.definingClass}->${method.name}(I)V" + else if (literal == 2) + oMethodCall = "${method.definingClass}->${method.name}(I)V" + } + + if (pMethodCall.isEmpty()) { + throw PatchException("pMethod not found") + } + if (oMethodCall.isEmpty()) { + throw PatchException("oMethod not found") + } + + val insertIndex = tapSeekIndex + 1 + + addInstructionsWithLabels( + insertIndex, """ + invoke-static {}, $PLAYER_CLASS_DESCRIPTOR->enableSeekbarTapping()Z + move-result v$freeRegister + if-eqz v$freeRegister, :disabled + invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $pMethodCall + invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $oMethodCall + """, ExternalLabel("disabled", getInstruction(insertIndex)) + ) } // endregion diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt index 6792d46bf..b7ecbe4cb 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/Fingerprints.kt @@ -109,25 +109,26 @@ internal val qualityMenuViewInflateFingerprint = legacyFingerprint( returnType = "L", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L", "L", "L"), - opcodes = listOf( - Opcode.INVOKE_SUPER, - Opcode.CONST, - Opcode.CONST_4, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CONST_16, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST - ), - literals = listOf(videoQualityBottomSheet), + customFingerprint = custom@{ method, _ -> + if (!method.containsLiteralInstruction(videoQualityBottomSheet)) { + return@custom false + } + if (indexOfAddHeaderViewInstruction(method) < 0) { + return@custom false + } + val implementation = method.implementation + ?: return@custom false + + implementation.instructions.elementAt(0).opcode == Opcode.INVOKE_SUPER + } ) +internal fun indexOfAddHeaderViewInstruction(method: Method) = + method.indexOfFirstInstruction { + opcode == Opcode.INVOKE_VIRTUAL && + getReference()?.name == "addHeaderView" + } + internal val rollingNumberTextViewAnimationUpdateFingerprint = legacyFingerprint( name = "rollingNumberTextViewAnimationUpdateFingerprint", returnType = "V", diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/splash/DarkModeSplashScreenPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/splash/DarkModeSplashScreenPatch.kt index 198a22138..f677f3965 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/splash/DarkModeSplashScreenPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/fix/splash/DarkModeSplashScreenPatch.kt @@ -8,25 +8,28 @@ import app.revanced.patches.youtube.utils.playservice.versionCheckPatch import app.revanced.util.getBooleanOptionValue import org.w3c.dom.Element +/** + * Fix the splash screen dark mode background color. + * In earlier versions of the app this is white and makes no sense for dark mode. + * This is only required for 19.32 and greater, but is applied to all targets. + * Only dark mode needs this fix as light mode correctly uses the custom color. + * + * This is a bug in unpatched YouTube. + * Should always be applied even if the `Theme` patch is excluded. + */ val darkModeSplashScreenPatch = resourcePatch( description = "darkModeSplashScreenPatch" ) { dependsOn(versionCheckPatch) finalize { - val restoreOldSplashAnimationIncluded = is_19_32_or_greater && - CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true && + if (!is_19_32_or_greater) { + return@finalize + } + + val restoreOldSplashAnimationIncluded = CUSTOM_BRANDING_ICON_FOR_YOUTUBE.included == true && customBrandingIconPatch.getBooleanOptionValue("restoreOldSplashAnimation").value == true - /** - * Fix the splash screen dark mode background color. - * In earlier versions of the app this is white and makes no sense for dark mode. - * This is only required for 19.32 and greater, but is applied to all targets. - * Only dark mode needs this fix as light mode correctly uses the custom color. - * - * This is a bug in unpatched YouTube. - * Should always be applied even if the `Theme` patch is excluded. - */ if (restoreOldSplashAnimationIncluded) { document("res/values-night/styles.xml").use { document -> val resourcesNode = document.getElementsByTagName("resources").item(0) as Element diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playservice/VersionCheckPatch.kt index 97966f6b9..fa38cf1db 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/playservice/VersionCheckPatch.kt @@ -71,6 +71,8 @@ var is_20_09_or_greater = false private set var is_20_10_or_greater = false private set +var is_20_12_or_greater = false + private set val versionCheckPatch = resourcePatch( description = "versionCheckPatch", @@ -119,5 +121,6 @@ val versionCheckPatch = resourcePatch( is_20_05_or_greater = 250605000 <= playStoreServicesVersion is_20_09_or_greater = 251006000 <= playStoreServicesVersion is_20_10_or_greater = 251105000 <= playStoreServicesVersion + is_20_12_or_greater = 251305000 <= playStoreServicesVersion } } diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt index b8598df1e..56194df98 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/resourceid/SharedResourceIdPatch.kt @@ -193,8 +193,6 @@ var rightComment = -1L private set var scrimOverlay = -1L private set -var scrubbing = -1L - private set var seekEasyHorizontalTouchOffsetToStartScrubbing = -1L private set var seekUndoEduOverlayStub = -1L @@ -225,6 +223,10 @@ var videoQualityBottomSheet = -1L private set var varispeedUnavailableTitle = -1L private set +var verticalTouchOffsetToEnterFineScrubbing = -1L + private set +var verticalTouchOffsetToStartFineScrubbing = -1L + private set var videoQualityUnavailableAnnouncement = -1L private set var videoZoomSnapIndicator = -1L @@ -235,6 +237,8 @@ var youTubeControlsOverlaySubtitleButton = -1L private set var youTubeLogo = -1L private set +var ytCallToAction = -1L + private set var ytFillBell = -1L private set var ytOutlineLibrary = -1L @@ -620,10 +624,6 @@ internal val sharedResourceIdPatch = resourcePatch( ID, "scrim_overlay" ] - scrubbing = resourceMappings[ - DIMEN, - "vertical_touch_offset_to_enter_fine_scrubbing" - ] seekEasyHorizontalTouchOffsetToStartScrubbing = resourceMappings[ DIMEN, "seek_easy_horizontal_touch_offset_to_start_scrubbing" @@ -684,6 +684,14 @@ internal val sharedResourceIdPatch = resourcePatch( STRING, "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[ STRING, "video_quality_unavailable_announcement" @@ -704,6 +712,10 @@ internal val sharedResourceIdPatch = resourcePatch( ID, "youtube_logo" ] + ytCallToAction = resourceMappings[ + ATTR, + "ytCallToAction" + ] ytFillBell = resourceMappings[ DRAWABLE, "yt_fill_bell_black_24" diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/Fingerprints.kt index 0a8ea07c6..c7d6c602e 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/utils/returnyoutubedislike/Fingerprints.kt @@ -7,6 +7,7 @@ import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode 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+ @@ -54,7 +55,14 @@ internal val rollingNumberMeasureTextParentFingerprint = legacyFingerprint( internal val rollingNumberSetterFingerprint = legacyFingerprint( name = "rollingNumberSetterFingerprint", opcodes = listOf(Opcode.CHECK_CAST), - literals = listOf(45427773L), + customFingerprint = { method, _ -> + method.indexOfFirstInstruction { + opcode == Opcode.CONST_STRING && + getReference() + ?.string.toString() + .startsWith("RollingNumberType required properties missing! Need") + } >= 0 + } ) internal val shortsTextViewFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/Fingerprints.kt index 28ede6d2b..0b8282018 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/playback/Fingerprints.kt @@ -2,9 +2,12 @@ package app.revanced.patches.youtube.video.playback import app.revanced.util.containsLiteralInstruction import app.revanced.util.fingerprint.legacyFingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.or import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.reference.FieldReference internal val av1CodecFingerprint = legacyFingerprint( name = "av1CodecFingerprint", @@ -61,16 +64,17 @@ internal val playbackSpeedChangedFromRecyclerViewFingerprint = legacyFingerprint accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, parameters = listOf("L"), opcodes = listOf( - Opcode.IGET_OBJECT, - Opcode.INVOKE_INTERFACE, - Opcode.MOVE_RESULT_OBJECT, - Opcode.IF_EQZ, - Opcode.IGET_OBJECT, Opcode.INVOKE_INTERFACE, Opcode.MOVE_RESULT_OBJECT, Opcode.IGET, Opcode.INVOKE_VIRTUAL - ) + ), + customFingerprint = { method, _ -> + method.indexOfFirstInstruction { + opcode == Opcode.IGET && + getReference()?.type == "F" + } >= 0 + } ) internal val playbackSpeedInitializeFingerprint = legacyFingerprint( diff --git a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt index 3567bf0fd..1a8979a08 100644 --- a/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/youtube/video/videoid/Fingerprints.kt @@ -29,7 +29,7 @@ internal val videoIdFingerprint = legacyFingerprint( ?: return@custom false val instructions = implementation.instructions val instructionCount = instructions.count() - if (instructionCount < 30) { + if (instructionCount < 25) { return@custom false }