feat(YouTube): Support version 20.12.46 (#4779)

This commit is contained in:
LisoUseInAIKyrios 2025-04-16 10:24:35 +02:00 committed by GitHub
parent e2b9d65bc6
commit 703359f0c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
73 changed files with 283 additions and 145 deletions

View File

@ -1416,6 +1416,8 @@ public final class app/revanced/patches/youtube/misc/playservice/VersionCheckPat
public static final fun is_20_07_or_greater ()Z public static final fun is_20_07_or_greater ()Z
public static final fun is_20_09_or_greater ()Z public static final fun is_20_09_or_greater ()Z
public static final fun is_20_10_or_greater ()Z public static final fun is_20_10_or_greater ()Z
public static final fun is_20_14_or_greater ()Z
public static final fun is_20_15_or_greater ()Z
} }
public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt { public final class app/revanced/patches/youtube/misc/privacy/RemoveTrackingQueryParameterPatchKt {

View File

@ -84,7 +84,8 @@ val hideAdsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -31,7 +31,8 @@ val hideGetPremiumPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -29,7 +29,8 @@ val videoAdsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -59,7 +59,8 @@ val copyVideoUrlPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -30,7 +30,8 @@ val removeViewerDiscretionDialogPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
val extensionMethodDescriptor = val extensionMethodDescriptor =

View File

@ -74,7 +74,8 @@ val downloadsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -10,10 +10,15 @@ import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.findFreeRegister
import app.revanced.util.indexOfFirstInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction
import com.android.tools.smali.dexlib2.iface.instruction.formats.Instruction35c
import com.android.tools.smali.dexlib2.iface.reference.MethodReference import com.android.tools.smali.dexlib2.iface.reference.MethodReference
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/SeekbarTappingPatch;"
val enableSeekbarTappingPatch = bytecodePatch( val enableSeekbarTappingPatch = bytecodePatch(
description = "Adds an option to enable tap to seek on the seekbar of the video player.", description = "Adds an option to enable tap to seek on the seekbar of the video player.",
) { ) {
@ -31,38 +36,36 @@ val enableSeekbarTappingPatch = bytecodePatch(
) )
// Find the required methods to tap the seekbar. // Find the required methods to tap the seekbar.
val patternMatch = onTouchEventHandlerFingerprint.patternMatch!! val seekbarTappingMethods = onTouchEventHandlerFingerprint.let {
fun getMethodReference(index: Int) = it.method.getInstruction<ReferenceInstruction>(index)
fun getReference(index: Int) = onTouchEventHandlerFingerprint.method.getInstruction<ReferenceInstruction>(index)
.reference as MethodReference .reference as MethodReference
val seekbarTappingMethods = buildMap { listOf(
put("N", getReference(patternMatch.startIndex)) getMethodReference(it.patternMatch!!.startIndex),
put("O", getReference(patternMatch.endIndex)) getMethodReference(it.patternMatch!!.endIndex)
)
} }
val insertIndex = seekbarTappingFingerprint.patternMatch!!.endIndex - 1
seekbarTappingFingerprint.method.apply { seekbarTappingFingerprint.method.apply {
val thisInstanceRegister = getInstruction<Instruction35c>(insertIndex - 1).registerC val pointIndex = indexOfNewPointInstruction(this)
val invokeIndex = indexOfFirstInstructionOrThrow(pointIndex, Opcode.INVOKE_VIRTUAL)
val insertIndex = invokeIndex + 1
val freeRegister = 0 val thisInstanceRegister = getInstruction<FiveRegisterInstruction>(invokeIndex).registerC
val xAxisRegister = 2 val xAxisRegister = this.getInstruction<FiveRegisterInstruction>(pointIndex).registerD
val freeRegister = findFreeRegister(insertIndex, thisInstanceRegister, xAxisRegister)
val oMethod = seekbarTappingMethods["O"]!! val oMethod = seekbarTappingMethods[0]
val nMethod = seekbarTappingMethods["N"]!! val nMethod = seekbarTappingMethods[1]
fun MethodReference.toInvokeInstructionString() =
"invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $this"
addInstructionsWithLabels( addInstructionsWithLabels(
insertIndex, insertIndex,
""" """
invoke-static { }, Lapp/revanced/extension/youtube/patches/SeekbarTappingPatch;->seekbarTappingEnabled()Z invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->seekbarTappingEnabled()Z
move-result v$freeRegister move-result v$freeRegister
if-eqz v$freeRegister, :disabled if-eqz v$freeRegister, :disabled
${oMethod.toInvokeInstructionString()} invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $oMethod
${nMethod.toInvokeInstructionString()} invoke-virtual { v$thisInstanceRegister, v$xAxisRegister }, $nMethod
""", """,
ExternalLabel("disabled", getInstruction(insertIndex)), ExternalLabel("disabled", getInstruction(insertIndex)),
) )

View File

@ -1,11 +1,15 @@
package app.revanced.patches.youtube.interaction.seekbar package app.revanced.patches.youtube.interaction.seekbar
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.containsLiteralInstruction
import app.revanced.util.getReference import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction import app.revanced.util.indexOfFirstInstruction
import app.revanced.util.indexOfFirstInstructionReversed
import app.revanced.util.literal import app.revanced.util.literal
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 com.android.tools.smali.dexlib2.iface.reference.StringReference import com.android.tools.smali.dexlib2.iface.reference.StringReference
internal val swipingUpGestureParentFingerprint = fingerprint { internal val swipingUpGestureParentFingerprint = fingerprint {
@ -101,14 +105,17 @@ internal val seekbarTappingFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Z") returns("Z")
parameters("L") parameters("L")
opcodes( custom { method, _ ->
Opcode.IPUT_OBJECT, method.name == "onTouchEvent"
Opcode.INVOKE_VIRTUAL, && method.containsLiteralInstruction(Integer.MAX_VALUE.toLong())
// Insert seekbar tapping instructions here. && indexOfNewPointInstruction(method) >= 0
Opcode.RETURN, }
Opcode.INVOKE_VIRTUAL, }
)
literal { Integer.MAX_VALUE.toLong() } internal fun indexOfNewPointInstruction(method: Method) = method.indexOfFirstInstructionReversed {
val reference = getReference<MethodReference>()
reference?.definingClass == "Landroid/graphics/Point;"
&& reference.name == "<init>"
} }
internal val slideToSeekFingerprint = fingerprint { internal val slideToSeekFingerprint = fingerprint {

View File

@ -26,6 +26,7 @@ val seekbarPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
"20.12.46",
) )
) )
} }

View File

@ -87,7 +87,8 @@ val swipeControlsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -28,7 +28,8 @@ val autoCaptionsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -49,7 +49,8 @@ val customBrandingPatch = resourcePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
val appName by stringOption( val appName by stringOption(

View File

@ -47,6 +47,7 @@ val changeHeaderPatch = resourcePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
"20.12.46",
) )
) )

View File

@ -28,7 +28,8 @@ val hideButtonsPatch = resourcePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -46,7 +46,8 @@ val navigationButtonsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -60,7 +60,8 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -39,7 +39,8 @@ val changeFormFactorPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -65,7 +65,8 @@ val hideEndscreenCardsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -37,7 +37,8 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -35,7 +35,8 @@ val disableFullscreenAmbientModePatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -16,9 +16,22 @@ internal val hideShowMoreButtonFingerprint = fingerprint {
} }
/** /**
* 20.07+ * 20.12+
*/ */
internal val parseElementFromBufferFingerprint = fingerprint { internal val parseElementFromBufferFingerprint = fingerprint {
parameters("L", "L", "[B", "L", "L")
opcodes(
Opcode.IGET_OBJECT,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
)
strings("Failed to parse Element") // String is a partial match.
}
/**
* 20.07+
*/
internal val parseElementFromBufferLegacy2007Fingerprint = fingerprint {
parameters("L", "L", "[B", "L", "L") parameters("L", "L", "[B", "L", "L")
opcodes( opcodes(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,
@ -29,7 +42,10 @@ internal val parseElementFromBufferFingerprint = fingerprint {
strings("Failed to parse Element") // String is a partial match. strings("Failed to parse Element") // String is a partial match.
} }
internal val parseElementFromBufferLegacyFingerprint = fingerprint { /**
* 19.01 - 20.06
*/
internal val parseElementFromBufferLegacy1901Fingerprint = fingerprint {
parameters("L", "L", "[B", "L", "L") parameters("L", "L", "[B", "L", "L")
opcodes( opcodes(
Opcode.IGET_OBJECT, Opcode.IGET_OBJECT,

View File

@ -21,6 +21,7 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_09_or_greater
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.findFreeRegister import app.revanced.util.findFreeRegister
@ -132,7 +133,8 @@ val hideLayoutComponentsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {
@ -247,8 +249,9 @@ val hideLayoutComponentsPatch = bytecodePatch(
// region Mix playlists // region Mix playlists
(if (is_20_07_or_greater) parseElementFromBufferFingerprint (if (is_20_09_or_greater) parseElementFromBufferFingerprint
else parseElementFromBufferLegacyFingerprint).let { else if (is_20_07_or_greater) parseElementFromBufferLegacy2007Fingerprint
else parseElementFromBufferLegacy1901Fingerprint).let {
it.method.apply { it.method.apply {
val byteArrayParameter = "p3" val byteArrayParameter = "p3"
val startIndex = it.patternMatch!!.startIndex val startIndex = it.patternMatch!!.startIndex

View File

@ -63,7 +63,8 @@ val hideInfoCardsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -30,7 +30,8 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -35,7 +35,8 @@ val disableRollingNumberAnimationPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -178,7 +178,8 @@ val hideShortsComponentsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
hideShortsAppShortcutOption() hideShortsAppShortcutOption()

View File

@ -1,24 +1,16 @@
package app.revanced.patches.youtube.layout.hide.time package app.revanced.patches.youtube.layout.hide.time
import app.revanced.patcher.fingerprint
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 app.revanced.patcher.fingerprint
internal val timeCounterFingerprint = fingerprint( internal val timeCounterFingerprint = fingerprint {
fuzzyPatternScanThreshold = 1,
) {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters() parameters()
opcodes( opcodes(
Opcode.SUB_LONG_2ADDR, Opcode.SUB_LONG_2ADDR,
Opcode.IGET_WIDE, Opcode.IGET_WIDE,
Opcode.SUB_LONG_2ADDR,
Opcode.IGET_OBJECT,
Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_WIDE,
Opcode.IGET_WIDE,
Opcode.SUB_LONG_2ADDR Opcode.SUB_LONG_2ADDR
) )
} }

View File

@ -27,7 +27,8 @@ val hideTimestampPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -30,6 +30,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
@ -172,7 +173,8 @@ val miniplayerPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {
@ -346,7 +348,12 @@ val miniplayerPatch = bytecodePatch(
// endregion // endregion
// region Legacy tablet miniplayer hooks. // region Legacy tablet miniplayer hooks.
val appNameStringIndex = miniplayerOverrideFingerprint.stringMatches!!.first().index + 2 val appNameStringIndex = miniplayerOverrideFingerprint.let {
it.method.indexOfFirstInstructionOrThrow(it.stringMatches!!.first().index) {
val reference = getReference<MethodReference>()
reference?.parameterTypes?.firstOrNull() == "Landroid/content/Context;"
}
}
navigate(miniplayerOverrideFingerprint.originalMethod).to(appNameStringIndex).stop().apply { navigate(miniplayerOverrideFingerprint.originalMethod).to(appNameStringIndex).stop().apply {
findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) } findReturnIndicesReversed().forEach { index -> insertLegacyTabletMiniplayerOverride(index) }
} }

View File

@ -27,7 +27,8 @@ val playerPopupPanelsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -18,7 +18,8 @@ val playerControlsBackgroundPatch = resourcePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -27,6 +27,7 @@ internal val exitFullscreenPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
"20.12.46",
) )
) )

View File

@ -27,6 +27,7 @@ val openVideosFullscreenPatch = bytecodePatch(
"com.google.android.youtube"( "com.google.android.youtube"(
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
"20.12.46",
) )
) )

View File

@ -58,7 +58,8 @@ val customPlayerOverlayOpacityPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -1,6 +1,7 @@
package app.revanced.patches.youtube.layout.returnyoutubedislike package app.revanced.patches.youtube.layout.returnyoutubedislike
import app.revanced.patcher.fingerprint import app.revanced.patcher.fingerprint
import app.revanced.util.literal
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
@ -121,3 +122,12 @@ internal val textComponentLookupFingerprint = fingerprint {
parameters("L") parameters("L")
strings("") strings("")
} }
internal const val LITHO_NEW_TEXT_COMPONENT_FEATURE_FLAG = 45675738L
internal val textComponentFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.FINAL)
returns("Z")
parameters()
literal { LITHO_NEW_TEXT_COMPONENT_FEATURE_FLAG }
}

View File

@ -12,6 +12,7 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch import app.revanced.patches.youtube.misc.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_33_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_33_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.addSettingPreference import app.revanced.patches.youtube.misc.settings.addSettingPreference
@ -59,7 +60,8 @@ val returnYouTubeDislikePatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {
@ -174,6 +176,14 @@ val returnYouTubeDislikePatch = bytecodePatch(
// Filter that parses the video id from the UI // Filter that parses the video id from the UI
addLithoFilter(FILTER_CLASS_DESCRIPTOR) addLithoFilter(FILTER_CLASS_DESCRIPTOR)
if (is_20_07_or_greater) {
// Turn off a/b flag that enables new code for creating litho spans.
// If enabled then the litho text span hook is never called.
// Target code is very obfuscated and exactly what the code does is not clear.
// Return late so debug patch logs if the flag is enabled.
textComponentFeatureFlagFingerprint.method.returnLate(false)
}
// Player response video id is needed to search for the video ids in Shorts litho components. // Player response video id is needed to search for the video ids in Shorts litho components.
hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V") hookPlayerResponseVideoId("$FILTER_CLASS_DESCRIPTOR->newPlayerResponseVideoId(Ljava/lang/String;Z)V")

View File

@ -35,7 +35,8 @@ val wideSearchbarPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -39,7 +39,8 @@ val shortsAutoplayPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -47,7 +47,8 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -20,12 +20,6 @@ internal val appendTimeFingerprint = fingerprint {
Opcode.MOVE_RESULT_OBJECT, Opcode.MOVE_RESULT_OBJECT,
Opcode.INVOKE_STATIC, Opcode.INVOKE_STATIC,
Opcode.MOVE_RESULT, Opcode.MOVE_RESULT,
Opcode.IF_NEZ,
Opcode.IGET_OBJECT,
Opcode.IGET_OBJECT,
Opcode.CHECK_CAST,
Opcode.INVOKE_VIRTUAL,
Opcode.RETURN_VOID,
) )
} }

View File

@ -114,7 +114,8 @@ val sponsorBlockPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -64,7 +64,8 @@ val spoofAppVersionPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -35,7 +35,8 @@ val changeStartPagePatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -40,7 +40,8 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -10,13 +10,6 @@ internal val lithoThemeFingerprint = fingerprint {
returns("V") returns("V")
parameters("Landroid/graphics/Rect;") parameters("Landroid/graphics/Rect;")
opcodes( opcodes(
Opcode.APUT,
Opcode.NEW_INSTANCE,
Opcode.INVOKE_DIRECT,
Opcode.IGET_OBJECT,
Opcode.SGET_OBJECT,
Opcode.INVOKE_VIRTUAL,
Opcode.IPUT_OBJECT,
Opcode.IGET, Opcode.IGET,
Opcode.IF_EQZ, Opcode.IF_EQZ,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,

View File

@ -223,7 +223,8 @@ val themePatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -39,7 +39,8 @@ val alternativeThumbnailsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -33,7 +33,8 @@ val bypassImageRegionRestrictionsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -29,7 +29,8 @@ val announcementsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -30,7 +30,8 @@ val autoRepeatPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -57,7 +57,8 @@ val backgroundPlaybackPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -40,7 +40,8 @@ val enableDebuggingPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -30,7 +30,8 @@ val spoofDeviceDimensionsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -27,7 +27,8 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -9,9 +9,7 @@ internal val onBackPressedFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
opcodes(Opcode.RETURN_VOID) opcodes(Opcode.RETURN_VOID)
custom { method, classDef -> custom { method, classDef ->
method.name == "onBackPressed" && method.name == "onBackPressed" && classDef.endsWith("MainActivity;")
// Old versions of YouTube called this class "WatchWhileActivity" instead.
(classDef.endsWith("MainActivity;") || classDef.endsWith("WatchWhileActivity;"))
} }
} }
@ -27,6 +25,9 @@ internal val scrollPositionFingerprint = fingerprint {
strings("scroll_position") strings("scroll_position")
} }
/**
* Resolves using class found in [recyclerViewTopScrollingParentFingerprint].
*/
internal val recyclerViewTopScrollingFingerprint = fingerprint { internal val recyclerViewTopScrollingFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V") returns("V")

View File

@ -41,7 +41,8 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
} }

View File

@ -38,7 +38,8 @@ val bypassURLRedirectsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -47,7 +47,8 @@ val openLinksExternallyPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -47,11 +47,7 @@ internal val mainActivityOnBackPressedFingerprint = fingerprint {
returns("V") returns("V")
parameters() parameters()
custom { method, classDef -> custom { method, classDef ->
val matchesClass = classDef.endsWith("MainActivity;") || method.name == "onBackPressed" && classDef.endsWith("MainActivity;")
// Old versions of YouTube called this class "WatchWhileActivity" instead.
classDef.endsWith("WatchWhileActivity;")
matchesClass && method.name == "onBackPressed"
} }
} }

View File

@ -58,6 +58,10 @@ 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_14_or_greater = false
private set
var is_20_15_or_greater = false
private set
val versionCheckPatch = resourcePatch( val versionCheckPatch = resourcePatch(
description = "Uses the Play Store service version to find the major/minor version of the YouTube target app.", description = "Uses the Play Store service version to find the major/minor version of the YouTube target app.",
@ -98,5 +102,7 @@ val versionCheckPatch = resourcePatch(
is_20_07_or_greater = 250805000 <= playStoreServicesVersion is_20_07_or_greater = 250805000 <= 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_14_or_greater = 251505000 <= playStoreServicesVersion
is_20_15_or_greater = 251605000 <= playStoreServicesVersion
} }
} }

View File

@ -36,7 +36,8 @@ val removeTrackingQueryParameterPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -9,6 +9,7 @@ import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_34_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_03_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_03_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_14_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch import app.revanced.patches.youtube.misc.settings.settingsPatch
@ -22,7 +23,8 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
dependsOn( dependsOn(
@ -33,7 +35,8 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
}, { }, {
is_19_34_or_greater is_19_34_or_greater
}, { }, {
is_20_10_or_greater // In 20.14 the flag was merged with 20.03 start playback flag.
is_20_10_or_greater && !is_20_14_or_greater
}, { }, {
is_20_03_or_greater is_20_03_or_greater
}, { }, {

View File

@ -27,7 +27,8 @@ val zoomHapticsPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -33,8 +33,7 @@ internal val mainActivityFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR) accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters() parameters()
custom { _, classDef -> custom { _, classDef ->
// Old versions of YouTube called this class "WatchWhileActivity" instead. classDef.endsWith("MainActivity;")
classDef.endsWith("MainActivity;") || classDef.endsWith("WatchWhileActivity;")
} }
} }
@ -42,12 +41,7 @@ internal val mainActivityOnCreateFingerprint = fingerprint {
returns("V") returns("V")
parameters("Landroid/os/Bundle;") parameters("Landroid/os/Bundle;")
custom { method, classDef -> custom { method, classDef ->
method.name == "onCreate" && method.name == "onCreate" && classDef.endsWith("MainActivity;")
(
classDef.endsWith("MainActivity;") ||
// Old versions of YouTube called this class "WatchWhileActivity" instead.
classDef.endsWith("WatchWhileActivity;")
)
} }
} }

View File

@ -47,7 +47,8 @@ val forceOriginalAudioPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -34,7 +34,8 @@ val disableHdrPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
), "20.12.46",
)
) )
execute { execute {

View File

@ -117,13 +117,6 @@ internal val playbackSpeedMenuSpeedChangedFingerprint = fingerprint {
returns("L") returns("L")
parameters("L") parameters("L")
opcodes( opcodes(
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.IGET,
Opcode.INVOKE_VIRTUAL, Opcode.INVOKE_VIRTUAL,
Opcode.SGET_OBJECT, Opcode.SGET_OBJECT,

View File

@ -5,9 +5,35 @@ import com.android.tools.smali.dexlib2.AccessFlags
import org.stringtemplate.v4.compiler.Bytecode.instructions import org.stringtemplate.v4.compiler.Bytecode.instructions
/** /**
* For targets 20.10 and later. * For targets 20.15 and later.
*/ */
internal val playerParameterBuilderFingerprint = fingerprint { internal val playerParameterBuilderFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters(
"Ljava/lang/String;", // VideoId.
"[B",
"Ljava/lang/String;", // Player parameters proto buffer.
"Ljava/lang/String;",
"I",
"Z",
"I",
"L",
"Ljava/util/Set;",
"Ljava/lang/String;",
"Ljava/lang/String;",
"L",
"Z", // Appears to indicate if the video id is being opened or is currently playing.
"Z",
"Z"
)
strings("psps")
}
/**
* For targets 20.10 to 20.14.
*/
internal val playerParameterBuilder2010Fingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL) accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L") returns("L")
parameters( parameters(

View File

@ -9,6 +9,7 @@ import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_23_or_greater import app.revanced.patches.youtube.misc.playservice.is_19_23_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_02_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_02_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_15_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
private val hooks = mutableSetOf<Hook>() private val hooks = mutableSetOf<Hook>()
@ -39,9 +40,12 @@ val playerResponseMethodHookPatch = bytecodePatch {
execute { execute {
val fingerprint : Fingerprint val fingerprint : Fingerprint
if (is_20_10_or_greater) { if (is_20_15_or_greater) {
parameterIsShortAndOpeningOrPlaying = 13 parameterIsShortAndOpeningOrPlaying = 13
fingerprint = playerParameterBuilderFingerprint fingerprint = playerParameterBuilderFingerprint
} else if (is_20_10_or_greater) {
parameterIsShortAndOpeningOrPlaying = 13
fingerprint = playerParameterBuilder2010Fingerprint
} else if (is_20_02_or_greater) { } else if (is_20_02_or_greater) {
parameterIsShortAndOpeningOrPlaying = 12 parameterIsShortAndOpeningOrPlaying = 12
fingerprint = playerParameterBuilder2002Fingerprint fingerprint = playerParameterBuilder2002Fingerprint

View File

@ -29,6 +29,7 @@ val videoQualityPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
"20.12.46",
) )
) )

View File

@ -34,6 +34,7 @@ val playbackSpeedPatch = bytecodePatch(
"19.43.41", "19.43.41",
"19.47.53", "19.47.53",
"20.07.39", "20.07.39",
"20.12.46",
) )
) )

View File

@ -698,29 +698,54 @@ fun BytecodePatchContext.forEachLiteralValueInstruction(
} }
/** /**
* Return the method early. * Overrides the first instruction of a method with a constant return value.
* None of the method code will ever execute.
*/ */
fun MutableMethod.returnEarly(bool: Boolean = false) { fun MutableMethod.returnEarly(overrideValue: Boolean = false) = overrideReturnValue(overrideValue, false)
/**
* Overrides all return statements with a constant value.
* All method code is executed the same as unpatched.
*
* @see returnEarly
*/
internal fun MutableMethod.returnLate(overrideValue: Boolean = false) = overrideReturnValue(overrideValue, true)
private fun MutableMethod.overrideReturnValue(bool: Boolean, returnLate: Boolean) {
val const = if (bool) "0x1" else "0x0" val const = if (bool) "0x1" else "0x0"
val stringInstructions = when (returnType.first()) { val instructions = when (returnType.first()) {
'L' -> 'L' -> {
""" """
const/4 v0, $const const/4 v0, $const
return-object v0 return-object v0
""" """
}
'V' -> "return-void" 'V' -> {
'I', 'Z' -> if (returnLate) throw IllegalArgumentException("Cannot return late for method of void type")
"return-void"
}
'I', 'Z' -> {
""" """
const/4 v0, $const const/4 v0, $const
return v0 return v0
""" """
}
else -> throw Exception("Return type is not supported: $this") else -> throw Exception("Return type is not supported: $this")
} }
addInstructions(0, stringInstructions) if (returnLate) {
findInstructionIndicesReversed {
opcode == RETURN || opcode == RETURN_OBJECT
}.forEach { index ->
addInstructionsAtControlFlowLabel(index, instructions)
}
} else {
addInstructions(0, instructions)
}
} }
/** /**