From 61cadf72cda08c62919d6cebd633f82a95a82ab9 Mon Sep 17 00:00:00 2001 From: LisoUseInAIKyrios <118716522+LisoUseInAIKyrios@users.noreply.github.com> Date: Sun, 14 Sep 2025 15:49:35 +0400 Subject: [PATCH] refactor(Spoof video streams): Back port code from v22 branch to support patching the latest YT Music. Using any target above 7.49.52 is untested and only recommended for experimental or development purposes. --- patches/api/patches.api | 1 + .../music/misc/spoof/SpoofVideoStreams.kt | 3 +- .../music/playservice/VersionCheckPatch.kt | 3 ++ .../patches/shared/misc/spoof/Fingerprints.kt | 29 ++++++++++++++++--- .../misc/spoof/SpoofVideoStreamsPatch.kt | 3 +- 5 files changed, 33 insertions(+), 6 deletions(-) diff --git a/patches/api/patches.api b/patches/api/patches.api index b222e63bd..7c09b37e4 100644 --- a/patches/api/patches.api +++ b/patches/api/patches.api @@ -404,6 +404,7 @@ public final class app/revanced/patches/music/playservice/VersionCheckPatchKt { public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch; public static final fun is_7_33_or_greater ()Z public static final fun is_8_11_or_greater ()Z + public static final fun is_8_15_or_greater ()Z } public final class app/revanced/patches/myexpenses/misc/pro/UnlockProPatchKt { diff --git a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreams.kt b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreams.kt index 10c65dae1..0dd9a4424 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreams.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreams.kt @@ -2,6 +2,7 @@ package app.revanced.patches.music.misc.spoof import app.revanced.patches.music.playservice.is_7_33_or_greater import app.revanced.patches.music.playservice.is_8_11_or_greater +import app.revanced.patches.music.playservice.is_8_15_or_greater import app.revanced.patches.music.playservice.versionCheckPatch import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch @@ -16,6 +17,6 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch( dependsOn(versionCheckPatch, userAgentClientSpoofPatch) }, fixMediaFetchHotConfigChanges = { true }, - fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater }, + fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater }, fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater } ) \ No newline at end of file diff --git a/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt b/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt index 86fbdc132..467498bf2 100644 --- a/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt @@ -9,6 +9,8 @@ var is_7_33_or_greater = false private set var is_8_11_or_greater = false private set +var is_8_15_or_greater = false + private set val versionCheckPatch = resourcePatch( description = "Uses the Play Store service version to find the major/minor version of the YouTube Music target app.", @@ -21,5 +23,6 @@ val versionCheckPatch = resourcePatch( // All bug fix releases always seem to use the same play store version as the minor version. is_7_33_or_greater = 245199000 <= playStoreServicesVersion is_8_11_or_greater = 251199000 <= playStoreServicesVersion + is_8_15_or_greater = 251530000 <= playStoreServicesVersion } } diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt index cbeea3f78..67ba7c80c 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/Fingerprints.kt @@ -1,9 +1,12 @@ package app.revanced.patches.shared.misc.spoof import app.revanced.patcher.fingerprint +import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.literal import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +import com.android.tools.smali.dexlib2.iface.reference.MethodReference internal val buildInitPlaybackRequestFingerprint = fingerprint { returns("Lorg/chromium/net/UrlRequest\$Builder;") @@ -35,8 +38,15 @@ internal val buildPlayerRequestURIFingerprint = fingerprint { internal val buildRequestFingerprint = fingerprint { accessFlags(AccessFlags.PUBLIC, AccessFlags.STATIC) - returns("Lorg/chromium/net/UrlRequest;") + returns("Lorg/chromium/net/UrlRequest") // UrlRequest; or UrlRequest$Builder; custom { methodDef, _ -> + if (methodDef.indexOfFirstInstruction { + val reference = getReference() + reference?.name == "newUrlRequestBuilder" + } < 0) { + return@custom false + } + // Different targets have slightly different parameters // Earlier targets have parameters: @@ -58,12 +68,22 @@ internal val buildRequestFingerprint = fingerprint { // Lorg/chromium/net/UrlRequest\$Callback; // L + // 20.16+ uses a refactored and extracted method: + // L + // Ljava/util/Map; + // [B + // L + // Lorg/chromium/net/UrlRequest$Callback; + // L + val parameterTypes = methodDef.parameterTypes - (parameterTypes.size == 7 || parameterTypes.size == 8) && - parameterTypes[1] == "Ljava/util/Map;" // URL headers. + val parameterTypesSize = parameterTypes.size + (parameterTypesSize == 6 || parameterTypesSize == 7 || parameterTypesSize == 8) && + parameterTypes[1] == "Ljava/util/Map;" // URL headers. } } + internal val protobufClassParseByteBufferFingerprint = fingerprint { accessFlags(AccessFlags.PROTECTED, AccessFlags.STATIC) returns("L") @@ -148,7 +168,8 @@ internal val mediaFetchHotConfigFingerprint = fingerprint { literal { MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG } } -// YT 20.10+, YT Music 8.11+ +// YT 20.10+, YT Music 8.11 - 8.14. +// Flag is missing in YT Music 8.15+, and it is not known if a replacement flag/feature exists. internal const val MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG = 45683169L internal val mediaFetchHotConfigAlternativeFingerprint = fingerprint { diff --git a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt index 4cb3ffac3..e30651041 100644 --- a/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt +++ b/patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt @@ -10,6 +10,7 @@ import app.revanced.patcher.patch.BytecodePatchContext import app.revanced.patcher.patch.bytecodePatch import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable import app.revanced.patches.all.misc.resources.addResourcesPatch +import app.revanced.patches.music.misc.extension.sharedExtensionPatch import app.revanced.util.findFreeRegister import app.revanced.util.findInstructionIndicesReversedOrThrow import app.revanced.util.getReference @@ -42,7 +43,7 @@ fun spoofVideoStreamsPatch( ) { block() - dependsOn(addResourcesPatch) + dependsOn(sharedExtensionPatch, addResourcesPatch) execute { // region Enable extension helper method used by other patches