feat(YouTube): Support version 20.07.39 (#4677)

This commit is contained in:
LisoUseInAIKyrios
2025-03-28 17:49:12 +01:00
committed by GitHub
parent f191ab63fd
commit c1379f6e52
127 changed files with 877 additions and 598 deletions

View File

@ -145,7 +145,25 @@ internal val patchIncludedExtensionMethodFingerprint = fingerprint {
internal const val MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG = 45645570L
internal val mediaFetchHotConfigFingerprint = fingerprint {
literal {
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG
}
literal { MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG }
}
// 20.10+
internal const val MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG = 45683169L
internal val mediaFetchHotConfigAlternativeFingerprint = fingerprint {
literal { MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG }
}
// Feature flag that enables different code for parsing and starting video playback,
// but it's exact purpose is not known. If this flag is enabled while stream spoofing
// then videos will never start playback and load forever.
// Flag does not seem to affect playback if spoofing is off.
internal const val PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG = 45665455L
internal val playbackStartDescriptorFeatureFlagFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters()
returns("Z")
literal { PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG }
}

View File

@ -31,7 +31,9 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
fun spoofVideoStreamsPatch(
block: BytecodePatchBuilder.() -> Unit = {},
applyMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
fixMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
fixMediaFetchHotConfigAlternativeChanges: BytecodePatchBuilder.() -> Boolean = { false },
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
executeBlock: BytecodePatchContext.() -> Unit = {},
) = bytecodePatch(
name = "Spoof video streams",
@ -241,13 +243,27 @@ fun spoofVideoStreamsPatch(
// region turn off stream config replacement feature flag.
if (applyMediaFetchHotConfigChanges()) {
if (fixMediaFetchHotConfigChanges()) {
mediaFetchHotConfigFingerprint.method.insertFeatureFlagBooleanOverride(
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
if (fixMediaFetchHotConfigAlternativeChanges()) {
mediaFetchHotConfigAlternativeFingerprint.method.insertFeatureFlagBooleanOverride(
MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
)
}
if (fixParsePlaybackResponseFeatureFlag()) {
playbackStartDescriptorFeatureFlagFingerprint.method.insertFeatureFlagBooleanOverride(
PLAYBACK_START_CHECK_ENDPOINT_USED_FEATURE_FLAG,
"$EXTENSION_CLASS_DESCRIPTOR->usePlaybackStartFeatureFlag(Z)Z"
)
}
// endregion
executeBlock()

View File

@ -82,9 +82,8 @@ val hideAdsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -29,9 +29,8 @@ val hideGetPremiumPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -27,9 +27,8 @@ val videoAdsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -57,9 +57,8 @@ val copyVideoUrlPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -28,9 +28,8 @@ val removeViewerDiscretionDialogPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -72,9 +72,8 @@ val downloadsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -27,9 +27,8 @@ val disablePreciseSeekingGesturePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -30,9 +30,8 @@ val enableSeekbarTappingPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -39,9 +39,8 @@ val enableSlideToSeekPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -33,9 +33,8 @@ val seekbarThumbnailsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@ -84,9 +84,8 @@ val swipeControlsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -26,9 +26,8 @@ val autoCaptionsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -47,9 +47,8 @@ val customBrandingPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -45,9 +45,8 @@ val changeHeaderPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@ -26,9 +26,8 @@ val hideButtonsPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -44,9 +44,8 @@ val navigationButtonsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -58,9 +58,8 @@ val hidePlayerOverlayButtonsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -37,9 +37,8 @@ val changeFormFactorPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -63,9 +63,8 @@ val hideEndscreenCardsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -35,9 +35,8 @@ val hideEndScreenSuggestedVideoPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -33,9 +33,8 @@ val disableFullscreenAmbientModePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -15,7 +15,21 @@ internal val hideShowMoreButtonFingerprint = fingerprint {
literal { expandButtonDownId }
}
/**
* 20.07+
*/
internal val parseElementFromBufferFingerprint = fingerprint {
parameters("L", "L", "[B", "L", "L")
opcodes(
Opcode.IGET_OBJECT,
Opcode.IGET_BOOLEAN,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
)
strings("Failed to parse Element") // String is a partial match.
}
internal val parseElementFromBufferLegacyFingerprint = fingerprint {
parameters("L", "L", "[B", "L", "L")
opcodes(
Opcode.IGET_OBJECT,
@ -110,7 +124,6 @@ internal val showFloatingMicrophoneButtonFingerprint = fingerprint {
opcodes(
Opcode.IGET_BOOLEAN,
Opcode.IF_EQZ,
Opcode.RETURN_VOID,
)
literal { fabButtonId }
}

View File

@ -21,11 +21,14 @@ import app.revanced.patches.youtube.misc.litho.filter.addLithoFilter
import app.revanced.patches.youtube.misc.litho.filter.lithoFilterPatch
import app.revanced.patches.youtube.misc.navigation.navigationBarHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_47_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_07_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.findInstructionIndicesReversedOrThrow
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
import app.revanced.util.indexOfFirstLiteralInstructionOrThrow
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
@ -132,6 +135,7 @@ val hideLayoutComponentsPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@ -247,29 +251,32 @@ val hideLayoutComponentsPatch = bytecodePatch(
// region Mix playlists
parseElementFromBufferFingerprint.method.apply {
val startIndex = parseElementFromBufferFingerprint.patternMatch!!.startIndex
// Target code is a mess with a lot of register moves.
// There is no simple way to find a free register for all versions so this is hard coded.
val freeRegister = if (is_19_47_or_greater) 6 else 0
val byteArrayParameter = "p3"
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC }
val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC
(if (is_20_07_or_greater) parseElementFromBufferFingerprint
else parseElementFromBufferLegacyFingerprint).let {
it.method.apply {
// Target code is a mess with a lot of register moves.
// There is no simple way to find a free register for all versions so this is hard coded.
val freeRegister = if (is_19_47_or_greater) 6 else 0
val byteArrayParameter = "p3"
val startIndex = it.patternMatch!!.startIndex
val conversionContextRegister = getInstruction<TwoRegisterInstruction>(startIndex).registerA
val returnEmptyComponentInstruction = instructions.last { it.opcode == Opcode.INVOKE_STATIC }
val returnEmptyComponentRegister = (returnEmptyComponentInstruction as FiveRegisterInstruction).registerC
addInstructionsWithLabels(
startIndex + 1,
"""
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
goto :return_empty_component
:show
const/4 v$freeRegister, 0x0 # Restore register, required for 19.16
""",
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
)
addInstructionsWithLabels(
startIndex + 1,
"""
invoke-static { v$conversionContextRegister, $byteArrayParameter }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->filterMixPlaylists(Ljava/lang/Object;[B)Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
move-object v$returnEmptyComponentRegister, p1 # Required for 19.47
goto :return_empty_component
:show
const/4 v$freeRegister, 0x0 # Restore register, required for 19.16
""",
ExternalLabel("return_empty_component", returnEmptyComponentInstruction),
)
}
}
// endregion
@ -345,19 +352,18 @@ val hideLayoutComponentsPatch = bytecodePatch(
// region hide floating microphone
showFloatingMicrophoneButtonFingerprint.let {
it.method.apply {
val startIndex = it.patternMatch!!.startIndex
val register = getInstruction<TwoRegisterInstruction>(startIndex).registerA
showFloatingMicrophoneButtonFingerprint.method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(fabButtonId)
val booleanIndex = indexOfFirstInstructionOrThrow(literalIndex, Opcode.IGET_BOOLEAN)
val register = getInstruction<TwoRegisterInstruction>(booleanIndex).registerA
addInstructions(
startIndex + 1,
"""
addInstructions(
booleanIndex + 1,
"""
invoke-static { v$register }, $LAYOUT_COMPONENTS_FILTER_CLASS_DESCRIPTOR->hideFloatingMicrophoneButton(Z)Z
move-result v$register
""",
)
}
"""
)
}
// endregion

View File

@ -61,9 +61,8 @@ val hideInfoCardsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -28,9 +28,8 @@ val hidePlayerFlyoutMenuPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -33,9 +33,8 @@ val disableRollingNumberAnimationPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -29,9 +29,8 @@ val hideSeekbarPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -176,9 +176,8 @@ val hideShortsComponentsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -25,9 +25,8 @@ val hideTimestampPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -30,7 +30,7 @@ internal val miniplayerModernAddViewListenerFingerprint = fingerprint {
internal val miniplayerModernCloseButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerClose }
}
@ -62,7 +62,7 @@ internal val miniplayerOnCloseHandlerFingerprint = fingerprint {
*/
internal val miniplayerModernExpandButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerExpand }
}
@ -82,7 +82,7 @@ internal val miniplayerModernExpandCloseDrawablesFingerprint = fingerprint {
*/
internal val miniplayerModernForwardButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerForwardButton }
}
@ -92,7 +92,6 @@ internal val miniplayerModernForwardButtonFingerprint = fingerprint {
*/
internal val miniplayerModernOverlayViewFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")
parameters()
literal { scrimOverlay }
}
@ -102,7 +101,7 @@ internal val miniplayerModernOverlayViewFingerprint = fingerprint {
*/
internal val miniplayerModernRewindButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Landroid/widget/ImageView;")
returns("L")
parameters()
literal { modernMiniplayerRewindButton }
}
@ -114,6 +113,13 @@ internal val miniplayerModernViewParentFingerprint = fingerprint {
strings("player_overlay_modern_mini_player_controls")
}
internal val miniplayerModernActionButtonFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters()
literal { modernMiniPlayerOverlayActionButton }
}
internal val miniplayerMinimumSizeFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
custom { method, _ ->

View File

@ -34,27 +34,29 @@ 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
var floatyBarButtonTopMargin = -1L
internal var floatyBarButtonTopMargin = -1L
private set
// Only available in 19.15 and upwards.
var ytOutlineXWhite24 = -1L
internal var ytOutlineXWhite24 = -1L
private set
var ytOutlinePictureInPictureWhite24 = -1L
internal var ytOutlinePictureInPictureWhite24 = -1L
private set
var scrimOverlay = -1L
internal var scrimOverlay = -1L
private set
var modernMiniplayerClose = -1L
internal var modernMiniplayerClose = -1L
private set
var modernMiniplayerExpand = -1L
internal var modernMiniplayerExpand = -1L
private set
var modernMiniplayerRewindButton = -1L
internal var modernMiniplayerRewindButton = -1L
private set
var modernMiniplayerForwardButton = -1L
internal var modernMiniplayerForwardButton = -1L
private set
var playerOverlays = -1L
internal var modernMiniPlayerOverlayActionButton = -1L
private set
var miniplayerMaxSize = -1L
internal var playerOverlays = -1L
private set
internal var miniplayerMaxSize = -1L
private set
private val miniplayerResourcePatch = resourcePatch {
@ -100,6 +102,11 @@ private val miniplayerResourcePatch = resourcePatch {
"modern_miniplayer_forward_button",
]
modernMiniPlayerOverlayActionButton = resourceMappings[
"id",
"modern_miniplayer_overlay_action_button"
]
// Resource id is not used during patching, but is used by extension.
// Verify the resource is present while patching.
resourceMappings[
@ -167,6 +174,7 @@ val miniplayerPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@ -175,19 +183,25 @@ val miniplayerPatch = bytecodePatch(
val preferences = mutableSetOf<BasePreference>()
preferences +=
if (is_19_43_or_greater) {
if (is_20_03_or_greater) {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
)
} else if (is_19_43_or_greater) {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
entriesKey = "revanced_miniplayer_type_legacy_19_43_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_19_43_entry_values",
)
} else {
ListPreference(
"revanced_miniplayer_type",
summaryKey = null,
entriesKey = "revanced_miniplayer_type_legacy_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_entry_values",
entriesKey = "revanced_miniplayer_type_legacy_19_16_entries",
entryValuesKey = "revanced_miniplayer_type_legacy_19_16_entry_values",
)
}
@ -209,13 +223,13 @@ val miniplayerPatch = bytecodePatch(
preferences += SwitchPreference("revanced_miniplayer_hide_subtext")
preferences += if (is_19_26_or_greater) {
SwitchPreference("revanced_miniplayer_hide_expand_close")
SwitchPreference("revanced_miniplayer_hide_overlay_buttons")
} else {
SwitchPreference(
key = "revanced_miniplayer_hide_expand_close",
titleKey = "revanced_miniplayer_hide_expand_close_legacy_title",
summaryOnKey = "revanced_miniplayer_hide_expand_close_legacy_summary_on",
summaryOffKey = "revanced_miniplayer_hide_expand_close_legacy_summary_off",
key = "revanced_miniplayer_hide_overlay_buttons",
titleKey = "revanced_miniplayer_hide_overlay_buttons_legacy_title",
summaryOnKey = "revanced_miniplayer_hide_overlay_buttons_legacy_summary_on",
summaryOffKey = "revanced_miniplayer_hide_overlay_buttons_legacy_summary_off",
)
}
@ -365,7 +379,7 @@ val miniplayerPatch = bytecodePatch(
if (is_19_23_or_greater) {
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DRAG_DROP_FEATURE_KEY,
"enableMiniplayerDragAndDrop",
"getMiniplayerDragAndDrop",
)
}
@ -382,7 +396,7 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_DOUBLE_TAP_FEATURE_KEY,
"enableMiniplayerDoubleTapAction",
"getMiniplayerDoubleTapAction",
)
}
@ -398,7 +412,7 @@ val miniplayerPatch = bytecodePatch(
addInstructions(
targetIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->setMiniplayerDefaultSize(I)I
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getMiniplayerDefaultSize(I)I
move-result v$register
""",
)
@ -421,7 +435,7 @@ val miniplayerPatch = bytecodePatch(
if (is_19_36_or_greater) {
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_ROUNDED_CORNERS_FEATURE_KEY,
"setRoundedCorners",
"getRoundedCorners",
)
}
@ -433,7 +447,7 @@ val miniplayerPatch = bytecodePatch(
miniplayerModernConstructorFingerprint.insertMiniplayerFeatureFlagBooleanOverride(
MINIPLAYER_HORIZONTAL_DRAG_FEATURE_KEY,
"setHorizontalDrag",
"getHorizontalDrag",
)
}
@ -473,6 +487,11 @@ val miniplayerPatch = bytecodePatch(
modernMiniplayerClose,
"hideMiniplayerExpandClose",
),
Triple(
miniplayerModernActionButtonFingerprint,
modernMiniPlayerOverlayActionButton,
"hideMiniplayerActionButton"
),
Triple(
miniplayerModernRewindButtonFingerprint,
modernMiniplayerRewindButton,
@ -490,12 +509,25 @@ val miniplayerPatch = bytecodePatch(
),
).forEach { (fingerprint, literalValue, methodName) ->
fingerprint.match(
miniplayerModernViewParentFingerprint.classDef,
).method.hookInflatedView(
literalValue,
"Landroid/widget/ImageView;",
"$EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/widget/ImageView;)V",
)
miniplayerModernViewParentFingerprint.originalClassDef
).method.apply {
val literalIndex = indexOfFirstLiteralInstructionOrThrow(literalValue)
val checkCastIndex = indexOfFirstInstruction(literalIndex) {
opcode == Opcode.CHECK_CAST &&
getReference<TypeReference>()?.type == "Landroid/widget/ImageView;"
}
val viewIndex = if (checkCastIndex >= 0) {
checkCastIndex
} else {
indexOfFirstInstructionOrThrow(literalIndex, Opcode.MOVE_RESULT_OBJECT)
}
val viewRegister = getInstruction<OneRegisterInstruction>(viewIndex).registerA
addInstruction(
viewIndex + 1,
"invoke-static { v$viewRegister }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(Landroid/view/View;)V"
)
}
}
miniplayerModernAddViewListenerFingerprint.match(
@ -510,33 +542,40 @@ val miniplayerPatch = bytecodePatch(
// Modern 2 uses the same overlay controls as the regular video player,
// and the overlay views are added at runtime.
// Add a hook to the overlay class, and pass the added views to extension.
// Problem is fixed in 19.21+
//
// NOTE: Modern 2 uses the same video UI as the regular player except resized to smaller.
// This patch code could be used to hide other player overlays that do not use Litho.
playerOverlaysLayoutFingerprint.classDef.methods.add(
ImmutableMethod(
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
"addView",
listOf(
ImmutableMethodParameter("Landroid/view/View;", null, null),
ImmutableMethodParameter("I", null, null),
ImmutableMethodParameter("Landroid/view/ViewGroup\$LayoutParams;", null, null),
),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
"""
)
}
)
if (!is_19_17_or_greater) {
playerOverlaysLayoutFingerprint.classDef.methods.add(
ImmutableMethod(
YOUTUBE_PLAYER_OVERLAYS_LAYOUT_CLASS_NAME,
"addView",
listOf(
ImmutableMethodParameter("Landroid/view/View;", null, null),
ImmutableMethodParameter("I", null, null),
ImmutableMethodParameter(
"Landroid/view/ViewGroup\$LayoutParams;",
null,
null
),
),
"V",
AccessFlags.PUBLIC.value,
null,
null,
MutableMethodImplementation(4),
).toMutable().apply {
addInstructions(
"""
invoke-super { p0, p1, p2, p3 }, Landroid/view/ViewGroup;->addView(Landroid/view/View;ILandroid/view/ViewGroup${'$'}LayoutParams;)V
invoke-static { p1 }, $EXTENSION_CLASS_DESCRIPTOR->playerOverlayGroupCreated(Landroid/view/View;)V
return-void
"""
)
}
)
}
// endregion
}

View File

@ -25,9 +25,8 @@ val playerPopupPanelsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -16,9 +16,8 @@ val playerControlsBackgroundPatch = resourcePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -25,9 +25,8 @@ internal val exitFullscreenPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

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

View File

@ -56,9 +56,8 @@ val customPlayerOverlayOpacityPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

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.playertype.playerTypeHookPatch
import app.revanced.patches.youtube.misc.playservice.is_19_33_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.settings.addSettingPreference
import app.revanced.patches.youtube.misc.settings.newIntent
@ -56,9 +57,8 @@ val returnYouTubeDislikePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@ -121,7 +121,7 @@ val returnYouTubeDislikePatch = bytecodePatch(
val tempRegister: Int
val charSequenceRegister: Int
if (is_19_33_or_greater) {
if (is_19_33_or_greater && !is_20_10_or_greater) {
insertIndex = indexOfFirstInstructionOrThrow {
(opcode == Opcode.INVOKE_STATIC || opcode == Opcode.INVOKE_STATIC_RANGE)
&& getReference<MethodReference>()?.returnType == textDataClassType

View File

@ -33,9 +33,8 @@ val wideSearchbarPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -37,12 +37,25 @@ internal val shortsSeekbarColorFingerprint = fingerprint {
literal { reelTimeBarPlayedColorId }
}
internal val playerSeekbarHandleColorFingerprint = fingerprint {
internal val playerSeekbarHandle1ColorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("Landroid/content/Context;")
literal { ytStaticBrandRedId }
custom { method, _ ->
method.containsLiteralInstruction(ytTextSecondaryId) &&
method.containsLiteralInstruction(ytStaticBrandRedId)
}
}
internal val playerSeekbarHandle2ColorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.CONSTRUCTOR)
parameters("Landroid/content/Context;")
custom { method, _ ->
method.containsLiteralInstruction(inlineTimeBarLiveSeekableRangeId) &&
method.containsLiteralInstruction(ytStaticBrandRedId)
}
}
internal val watchHistoryMenuUseProgressDrawableFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("V")

View File

@ -53,6 +53,10 @@ internal var ytYoutubeMagentaColorId = -1L
private set
internal var ytStaticBrandRedId = -1L
private set
internal var ytTextSecondaryId = -1L
private set
internal var inlineTimeBarLiveSeekableRangeId = -1L
private set
internal const val splashSeekbarColorAttributeName = "splash_custom_seekbar_color"
@ -76,6 +80,18 @@ private val seekbarColorResourcePatch = resourcePatch {
"color",
"inline_time_bar_played_not_highlighted_color",
]
ytStaticBrandRedId = resourceMappings[
"attr",
"ytStaticBrandRed"
]
ytTextSecondaryId = resourceMappings[
"attr",
"ytTextSecondary"
]
inlineTimeBarLiveSeekableRangeId = resourceMappings[
"color",
"inline_time_bar_live_seekable_range"
]
// Modify the resume playback drawable and replace the progress bar with a custom drawable.
document("res/drawable/resume_playback_progressbar_drawable.xml").use { document ->
@ -211,7 +227,7 @@ val seekbarColorPatch = bytecodePatch(
)
execute {
fun MutableMethod.addColorChangeInstructions(resourceId: Long, methodName: String) {
fun MutableMethod.addColorChangeInstructions(resourceId: Long) {
val index = indexOfFirstLiteralInstructionOrThrow(resourceId)
val insertIndex = indexOfFirstInstructionOrThrow(index, Opcode.MOVE_RESULT)
val register = getInstruction<OneRegisterInstruction>(insertIndex).registerA
@ -219,19 +235,19 @@ val seekbarColorPatch = bytecodePatch(
addInstructions(
insertIndex + 1,
"""
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->$methodName(I)I
invoke-static { v$register }, $EXTENSION_CLASS_DESCRIPTOR->getVideoPlayerSeekbarColor(I)I
move-result v$register
"""
)
}
playerSeekbarColorFingerprint.method.apply {
addColorChangeInstructions(inlineTimeBarColorizedBarPlayedColorDarkId, "getVideoPlayerSeekbarColor")
addColorChangeInstructions(inlineTimeBarPlayedNotHighlightedColorId, "getVideoPlayerSeekbarColor")
addColorChangeInstructions(inlineTimeBarColorizedBarPlayedColorDarkId)
addColorChangeInstructions(inlineTimeBarPlayedNotHighlightedColorId)
}
shortsSeekbarColorFingerprint.method.apply {
addColorChangeInstructions(reelTimeBarPlayedColorId, "getVideoPlayerSeekbarColor")
addColorChangeInstructions(reelTimeBarPlayedColorId)
}
setSeekbarClickedColorFingerprint.originalMethod.let {
@ -257,8 +273,11 @@ val seekbarColorPatch = bytecodePatch(
// 19.25+ changes
playerSeekbarHandleColorFingerprint.method.apply {
addColorChangeInstructions(ytStaticBrandRedId, "getVideoPlayerSeekbarColor")
arrayOf(
playerSeekbarHandle1ColorFingerprint,
playerSeekbarHandle2ColorFingerprint
).forEach {
it.method.addColorChangeInstructions(ytStaticBrandRedId)
}
// If hiding feed seekbar thumbnails, then turn off the cairo gradient

View File

@ -37,9 +37,8 @@ val shortsAutoplayPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -45,9 +45,8 @@ val openShortsInRegularPlayerPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -110,9 +110,8 @@ val sponsorBlockPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -62,9 +62,8 @@ val spoofAppVersionPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -33,9 +33,8 @@ val changeStartPagePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -1,18 +1,22 @@
package app.revanced.patches.youtube.layout.startupshortsreset
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
import app.revanced.patcher.extensions.InstructionExtensions.removeInstruction
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patches.all.misc.resources.addResources
import app.revanced.patches.all.misc.resources.addResourcesPatch
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_20_02_or_greater
import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.addInstructionsAtControlFlowLabel
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
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
@ -38,6 +42,7 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@ -48,25 +53,51 @@ val disableResumingShortsOnStartupPatch = bytecodePatch(
SwitchPreference("revanced_disable_resuming_shorts_player"),
)
userWasInShortsFingerprint.method.apply {
val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
opcode == Opcode.INVOKE_INTERFACE &&
getReference<MethodReference>()?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
getReference<MethodReference>()?.name == "isDone"
}
val freeRegister = getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA
if (is_20_02_or_greater) {
userWasInShortsAlternativeFingerprint.let {
it.method.apply {
val stringIndex = it.stringMatches!!.first().index
val booleanValueIndex = indexOfFirstInstructionReversedOrThrow(stringIndex) {
opcode == Opcode.INVOKE_VIRTUAL &&
getReference<MethodReference>()?.name == "booleanValue"
}
val booleanValueRegister =
getInstruction<OneRegisterInstruction>(booleanValueIndex + 1).registerA
addInstructionsAtControlFlowLabel(
listenableInstructionIndex,
"""
invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z
move-result v$freeRegister
if-eqz v$freeRegister, :show_startup_shorts_player
return-void
:show_startup_shorts_player
nop
""",
)
addInstructions(
booleanValueIndex + 2, """
invoke-static {v$booleanValueRegister}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer(Z)Z
move-result v$booleanValueRegister
"""
)
}
}
} else {
userWasInShortsLegacyFingerprint.method.apply {
val listenableInstructionIndex = indexOfFirstInstructionOrThrow {
val reference = getReference<MethodReference>()
opcode == Opcode.INVOKE_INTERFACE &&
reference?.definingClass == "Lcom/google/common/util/concurrent/ListenableFuture;" &&
reference.name == "isDone"
}
val originalInstructionRegister =
getInstruction<FiveRegisterInstruction>(listenableInstructionIndex).registerC
val freeRegister =
getInstruction<OneRegisterInstruction>(listenableInstructionIndex + 1).registerA
addInstructionsWithLabels(
listenableInstructionIndex + 1,
"""
invoke-static {}, $EXTENSION_CLASS_DESCRIPTOR->disableResumingStartupShortsPlayer()Z
move-result v$freeRegister
if-eqz v$freeRegister, :show
return-void
:show
invoke-interface {v$originalInstructionRegister}, Lcom/google/common/util/concurrent/ListenableFuture;->isDone()Z
"""
)
removeInstruction(listenableInstructionIndex)
}
}
userWasInShortsConfigFingerprint.method.addInstructions(

View File

@ -4,7 +4,17 @@ import app.revanced.patcher.fingerprint
import app.revanced.util.literal
import com.android.tools.smali.dexlib2.AccessFlags
internal val userWasInShortsFingerprint = fingerprint {
/**
* YouTube 20.02.08 ~
*/
internal val userWasInShortsAlternativeFingerprint = fingerprint {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Ljava/lang/Object;")
strings("userIsInShorts: ")
}
internal val userWasInShortsLegacyFingerprint = fingerprint {
returns("V")
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
parameters("Ljava/lang/Object;")

View File

@ -221,9 +221,8 @@ val themePatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -37,9 +37,8 @@ val alternativeThumbnailsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -31,9 +31,8 @@ val bypassImageRegionRestrictionsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -27,9 +27,8 @@ val announcementsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -28,9 +28,8 @@ val autoRepeatPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -52,9 +52,8 @@ val backgroundPlaybackPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -38,9 +38,8 @@ val enableDebuggingPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -28,9 +28,8 @@ val spoofDeviceDimensionsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -25,9 +25,8 @@ val checkWatchHistoryDomainNameResolutionPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -39,9 +39,8 @@ val gmsCoreSupportPatch = gmsCoreSupportPatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
}

View File

@ -13,9 +13,11 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.Opcode
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.instruction.FiveRegisterInstruction
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
import com.android.tools.smali.dexlib2.iface.reference.TypeReference
val bypassURLRedirectsPatch = bytecodePatch(
name = "Bypass URL redirects",
@ -37,6 +39,7 @@ val bypassURLRedirectsPatch = bytecodePatch(
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@ -80,3 +83,8 @@ internal fun Method.findUriParseIndex() = indexOfFirstInstruction {
val reference = getReference<MethodReference>()
reference?.returnType == "Landroid/net/Uri;" && reference.name == "parse"
}
internal fun Method.findWebViewCheckCastIndex() = indexOfFirstInstruction {
val reference = getReference<TypeReference>()
opcode == Opcode.CHECK_CAST && reference?.type?.endsWith("/WebviewEndpointOuterClass${'$'}WebviewEndpoint;") == true
}

View File

@ -11,12 +11,21 @@ internal val abUriParserFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("Ljava/lang/Object")
parameters("Ljava/lang/Object")
strings(
"Found entityKey=`",
"` that does not contain a PlaylistVideoEntityId message as it's identifier.",
)
custom { method, _ ->
method.findUriParseIndex() >= 0
method.findUriParseIndex() >= 0 && method.findWebViewCheckCastIndex() >= 0
}
}
/**
* Target 19.33+
*/
internal val httpUriParserFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Landroid/net/Uri")
parameters("Ljava/lang/String")
strings("https", "://", "https:")
custom { methodDef, _ ->
methodDef.findUriParseIndex() >= 0
}
}
@ -47,19 +56,6 @@ internal val abUriParserLegacyFingerprint = fingerprint {
}
}
/**
* Target 19.33+
*/
internal val httpUriParserFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Landroid/net/Uri")
parameters("Ljava/lang/String")
strings("https", "https:", "://")
custom { methodDef, _ ->
methodDef.findUriParseIndex() >= 0
}
}
internal val httpUriParserLegacyFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("Landroid/net/Uri")

View File

@ -45,9 +45,8 @@ val openLinksExternallyPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -10,7 +10,11 @@ import com.android.tools.smali.dexlib2.Opcode
* In 19.18+ this resolves to a different method.
*/
internal val componentContextParserFingerprint = fingerprint {
strings("Component was not found %s because it was removed due to duplicate converter bindings.")
strings(
"TreeNode result must be set.",
// String is a partial match and changed slightly in 20.03+
"it was removed due to duplicate converter bindings."
)
}
internal val lithoFilterFingerprint = fingerprint {

View File

@ -14,6 +14,7 @@ import app.revanced.patcher.util.smali.ExternalLabel
import app.revanced.patches.youtube.misc.extension.sharedExtensionPatch
import app.revanced.patches.youtube.misc.playservice.is_19_18_or_greater
import app.revanced.patches.youtube.misc.playservice.is_19_25_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_05_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstructionOrThrow
@ -235,7 +236,10 @@ val lithoFilterPatch = bytecodePatch(
// Turn off native code that handles litho component names. If this feature is on then nearly
// all litho components have a null name and identifier/path filtering is completely broken.
if (is_19_25_or_greater) {
//
// Flag was removed in 20.05. It appears a new flag might be used instead (45660109L),
// but if the flag is forced on then litho filtering still works correctly.
if (is_19_25_or_greater && !is_20_05_or_greater) {
lithoComponentNameUpbFeatureFlagFingerprint.method.apply {
// Don't use return early, so the debug patch logs if this was originally on.
val insertIndex = indexOfFirstInstructionOrThrow(Opcode.RETURN)

View File

@ -46,6 +46,18 @@ var is_19_47_or_greater = false
private set
var is_19_49_or_greater = false
private set
var is_20_02_or_greater = false
private set
var is_20_03_or_greater = false
private set
var is_20_05_or_greater = false
private set
var is_20_07_or_greater = false
private set
var is_20_09_or_greater = false
private set
var is_20_10_or_greater = false
private set
val versionCheckPatch = resourcePatch(
description = "Uses the Play Store service version to find the major/minor version of the YouTube target app.",
@ -80,5 +92,11 @@ val versionCheckPatch = resourcePatch(
is_19_46_or_greater = 244705000 <= playStoreServicesVersion
is_19_47_or_greater = 244799000 <= playStoreServicesVersion
is_19_49_or_greater = 245005000 <= playStoreServicesVersion
is_20_02_or_greater = 250299000 <= playStoreServicesVersion
is_20_03_or_greater = 250405000 <= playStoreServicesVersion
is_20_05_or_greater = 250605000 <= playStoreServicesVersion
is_20_07_or_greater = 250805000 <= playStoreServicesVersion
is_20_09_or_greater = 251006000 <= playStoreServicesVersion
is_20_10_or_greater = 251105000 <= playStoreServicesVersion
}
}

View File

@ -34,9 +34,8 @@ val removeTrackingQueryParameterPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -7,6 +7,8 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPref
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
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_20_03_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.settings.PreferenceScreen
import app.revanced.patches.youtube.misc.settings.settingsPatch
@ -18,9 +20,8 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)
@ -31,6 +32,10 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch({
)
}, {
is_19_34_or_greater
}, {
is_20_10_or_greater
}, {
is_20_03_or_greater
}, {
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")

View File

@ -25,9 +25,8 @@ val zoomHapticsPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -45,9 +45,8 @@ val forceOriginalAudioPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -32,9 +32,8 @@ val disableHdrPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
),
)

View File

@ -2,11 +2,65 @@ package app.revanced.patches.youtube.video.playerresponse
import app.revanced.patcher.fingerprint
import com.android.tools.smali.dexlib2.AccessFlags
import org.stringtemplate.v4.compiler.Bytecode.instructions
/**
* For targets 19.25 and later.
* For targets 20.10 and later.
*/
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",
"Z"
)
strings("psps")
}
/**
* For targets 20.02 to 20.09.
*/
internal val playerParameterBuilder2002Fingerprint = 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",
"I",
"L", // 19.25+ parameter
"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",
"Z",
)
strings("psps")
}
/**
* For targets 19.25 to 19.50.
*/
internal val playerParameterBuilder1925Fingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.FINAL)
returns("L")
parameters(

View File

@ -1,11 +1,14 @@
package app.revanced.patches.youtube.video.playerresponse
import app.revanced.patcher.Fingerprint
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
import app.revanced.patcher.patch.bytecodePatch
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
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_20_02_or_greater
import app.revanced.patches.youtube.misc.playservice.is_20_10_or_greater
import app.revanced.patches.youtube.misc.playservice.versionCheckPatch
private val hooks = mutableSetOf<Hook>()
@ -35,15 +38,21 @@ val playerResponseMethodHookPatch = bytecodePatch {
)
execute {
playerResponseMethod = if (is_19_23_or_greater) {
val fingerprint : Fingerprint
if (is_20_10_or_greater) {
parameterIsShortAndOpeningOrPlaying = 13
fingerprint = playerParameterBuilderFingerprint
} else if (is_20_02_or_greater) {
parameterIsShortAndOpeningOrPlaying = 12
playerParameterBuilderFingerprint
fingerprint = playerParameterBuilder2002Fingerprint
} else if (is_19_23_or_greater) {
parameterIsShortAndOpeningOrPlaying = 12
fingerprint = playerParameterBuilder1925Fingerprint
} else {
parameterIsShortAndOpeningOrPlaying = 11
playerParameterBuilderLegacyFingerprint
}.method
fingerprint = playerParameterBuilderLegacyFingerprint
}
playerResponseMethod = fingerprint.method
// On some app targets the method has too many registers pushing the parameters past v15.
// If needed, move the parameters to 4-bit registers, so they can be passed to the extension.

View File

@ -27,9 +27,8 @@ val videoQualityPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@ -32,9 +32,8 @@ val playbackSpeedPatch = bytecodePatch(
"19.25.37",
"19.34.42",
"19.43.41",
"19.45.38",
"19.46.42",
"19.47.53",
"20.07.39",
)
)

View File

@ -22,14 +22,6 @@ internal val speedArrayGeneratorFingerprint = fingerprint {
accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC)
returns("[L")
parameters("Lcom/google/android/libraries/youtube/innertube/model/player/PlayerResponseModel;")
opcodes(
Opcode.IF_NEZ,
Opcode.SGET_OBJECT,
Opcode.GOTO_16,
Opcode.INVOKE_INTERFACE,
Opcode.MOVE_RESULT_OBJECT,
Opcode.IGET_OBJECT,
)
strings("0.0#")
}