diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt index f843c85f..8ef61738 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt @@ -19,6 +19,7 @@ import app.revanced.patches.youtube.misc.fix.playback.fingerprints.* import app.revanced.patches.youtube.misc.settings.SettingsPatch import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch import app.revanced.util.getReference +import app.revanced.util.indexOfFirstInstruction import app.revanced.util.resultOrThrow import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode @@ -34,7 +35,6 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter name = "Spoof client", description = "Spoofs the client to allow video playback.", dependencies = [ - SpoofClientResourcePatch::class, PlayerResponseMethodHookPatch::class, SettingsPatch::class, AddResourcesPatch::class, @@ -74,6 +74,7 @@ object SpoofClientPatch : BytecodePatch( BuildPlayerRequestURIFingerprint, SetPlayerRequestClientTypeFingerprint, CreatePlayerRequestBodyFingerprint, + CreatePlayerRequestBodyWithModelFingerprint, // Storyboard spoof. StoryboardRendererSpecFingerprint, @@ -97,10 +98,9 @@ object SpoofClientPatch : BytecodePatch( sorting = Sorting.UNSORTED, preferences = setOf( SwitchPreference("revanced_spoof_client"), - SwitchPreference("revanced_spoof_client_use_ios"), + SwitchPreference("revanced_spoof_client_use_testsuite"), ), ), - ) // region Block /initplayback requests to fall back to /get_watch requests. @@ -168,6 +168,22 @@ object SpoofClientPatch : BytecodePatch( Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField) } + val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.let { + val instructions = it.getInstructions() + + val getClientModelIndex = it.indexOfFirstInstruction { + getReference().toString() == "Landroid/os/Build;->MODEL:Ljava/lang/String;" + } + + // The next IPUT_OBJECT instruction after getting the client model is setting the client model field. + instructions.subList( + getClientModelIndex, + instructions.lastIndex, + ).first { instruction -> + instruction.opcode == Opcode.IPUT_OBJECT + }.getReference() ?: throw PatchException("Could not find clientInfoClientModelField") + } + // endregion // region Spoof client type for /player requests. @@ -189,7 +205,7 @@ object SpoofClientPatch : BytecodePatch( ) } - // Change requestMessage.clientInfo.clientType and requestMessage.clientInfo.clientVersion to the spoofed values. + // Change client info to use the spoofed values. // Do this in a helper method, to remove the need of picking out multiple free registers from the hooked code. result.mutableClass.methods.add( ImmutableMethod( @@ -216,12 +232,17 @@ object SpoofClientPatch : BytecodePatch( move-result v1 iput v1, v0, $clientInfoClientTypeField + # Set client model to the spoofed value. + iget-object v1, v0, $clientInfoClientModelField + invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientModel(Ljava/lang/String;)Ljava/lang/String; + move-result-object v1 + iput-object v1, v0, $clientInfoClientModelField + # Set client version to the spoofed value. iget-object v1, v0, $clientInfoClientVersionField invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String; move-result-object v1 iput-object v1, v0, $clientInfoClientVersionField - :disabled return-void """, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientResourcePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientResourcePatch.kt deleted file mode 100644 index 0de192e3..00000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientResourcePatch.kt +++ /dev/null @@ -1,18 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback - -import app.revanced.patcher.data.ResourceContext -import app.revanced.patcher.patch.ResourcePatch -import app.revanced.patcher.patch.annotation.Patch -import app.revanced.patches.shared.misc.mapping.ResourceMappingPatch - -@Patch(dependencies = [ResourceMappingPatch::class]) -internal object SpoofClientResourcePatch : ResourcePatch() { - internal var scrubbedPreviewThumbnailResourceId: Long = -1 - - override fun execute(context: ResourceContext) { - scrubbedPreviewThumbnailResourceId = ResourceMappingPatch[ - "id", - "thumbnail", - ] - } -} diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt index 5593ee72..c82597b3 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofSignaturePatch.kt @@ -43,7 +43,7 @@ object SpoofSignaturePatch : BytecodePatch( StoryboardRendererDecoderSpecFingerprint, StoryboardRendererDecoderRecommendedLevelFingerprint, StoryboardThumbnailParentFingerprint, - ScrubbedPreviewLayoutFingerprint, + SpoofSignaturePatchScrubbedPreviewLayoutFingerprint, StatsQueryParameterFingerprint, ParamsMapPutFingerprint, ), diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt new file mode 100644 index 00000000..bdf6f8ab --- /dev/null +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/CreatePlayerRequestBodyWithModelFingerprint.kt @@ -0,0 +1,18 @@ +package app.revanced.patches.youtube.misc.fix.playback.fingerprints + +import app.revanced.patcher.extensions.or +import app.revanced.patcher.fingerprint.MethodFingerprint +import app.revanced.util.getReference +import com.android.tools.smali.dexlib2.AccessFlags +import com.android.tools.smali.dexlib2.iface.reference.FieldReference + +internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint( + returnType = "L", + accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, + parameters = listOf(), + customFingerprint = { methodDef, _ -> + methodDef.implementation!!.instructions.any { + it.getReference().toString() == "Landroid/os/Build;->MODEL:Ljava/lang/String;" + } + }, +) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt index 1a60c306..bb93acc8 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ParamsMapPutFingerprint.kt @@ -5,6 +5,7 @@ import app.revanced.patcher.fingerprint.MethodFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +@Deprecated("Fingerprint is obsolete and will be deleted soon") internal object ParamsMapPutFingerprint : MethodFingerprint( returnType = "V", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt index fbd9b0b8..480bdb11 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/PlayerResponseModelImplLiveStreamFingerprint.kt @@ -6,6 +6,7 @@ import app.revanced.util.containsWideLiteralInstructionValue import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +@Deprecated("Fingerprint is obsolete and will be deleted soon") internal object PlayerResponseModelImplLiveStreamFingerprint : MethodFingerprint( returnType = "Ljava/lang/String;", accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt deleted file mode 100644 index 08e48652..00000000 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/ScrubbedPreviewLayoutFingerprint.kt +++ /dev/null @@ -1,27 +0,0 @@ -package app.revanced.patches.youtube.misc.fix.playback.fingerprints - -import app.revanced.patcher.extensions.or -import app.revanced.patches.youtube.misc.fix.playback.SpoofClientResourcePatch -import app.revanced.util.patch.LiteralValueFingerprint -import com.android.tools.smali.dexlib2.AccessFlags -import com.android.tools.smali.dexlib2.Opcode - -internal object ScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint( - accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, - returnType = "V", - parameters = listOf("Landroid/content/Context;", "Landroid/util/AttributeSet;", "I", "I"), - opcodes = listOf( - Opcode.INVOKE_STATIC, - Opcode.MOVE_RESULT_OBJECT, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT, - Opcode.INVOKE_VIRTUAL, - Opcode.CONST, - Opcode.INVOKE_VIRTUAL, - Opcode.MOVE_RESULT_OBJECT, - Opcode.CHECK_CAST, - Opcode.IPUT_OBJECT, // preview imageview - ), - // This resource is used in ~ 40 different locations, but this method has a distinct list of parameters to match to. - literalSupplier = { SpoofClientResourcePatch.scrubbedPreviewThumbnailResourceId }, -) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt index 90220a1c..c15d94db 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/SpoofSignaturePatchScrubbedPreviewLayoutFingerprint.kt @@ -6,6 +6,7 @@ import app.revanced.util.patch.LiteralValueFingerprint import com.android.tools.smali.dexlib2.AccessFlags import com.android.tools.smali.dexlib2.Opcode +@Deprecated("Fingerprint is obsolete and will be deleted soon") internal object SpoofSignaturePatchScrubbedPreviewLayoutFingerprint : LiteralValueFingerprint( accessFlags = AccessFlags.PRIVATE or AccessFlags.FINAL, returnType = "V", diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt index a9cc5304..24c81213 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StatsQueryParameterFingerprint.kt @@ -2,6 +2,7 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints import app.revanced.patcher.fingerprint.MethodFingerprint +@Deprecated("Fingerprint is obsolete and will be deleted soon") internal object StatsQueryParameterFingerprint : MethodFingerprint( strings = listOf("adunit"), ) diff --git a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt index 172001c5..f8e44940 100644 --- a/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt +++ b/src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/fingerprints/StoryboardThumbnailParentFingerprint.kt @@ -10,6 +10,7 @@ import com.android.tools.smali.dexlib2.AccessFlags * An additional change here might force the thumbnails to be created, * or possibly a change somewhere else (maybe involving YouTube 18.23.35 class `hte`) */ +@Deprecated("Fingerprint is obsolete and will be deleted soon") internal object StoryboardThumbnailParentFingerprint : MethodFingerprint( accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL, returnType = "Landroid/graphics/Bitmap;", diff --git a/src/main/resources/addresources/values/strings.xml b/src/main/resources/addresources/values/strings.xml index 621b7c43..89ba652c 100644 --- a/src/main/resources/addresources/values/strings.xml +++ b/src/main/resources/addresources/values/strings.xml @@ -1092,11 +1092,10 @@ Client is spoofed Client is not spoofed\n\nVideo playback may not work Turning off this setting may cause video playback issues. - - Spoof client to iOS - Spoof the client to iOS instead of an Android Testsuite - Client is spoofed to an iOS client\n\nSide effects include:\n• 60 fps video may not be available\n• No HDR video\n• Some videos may not load\n• Higher video qualities may be missing - Client is spoofed to an Android Testsuite client (iOS client is used for live streams)\n\nSide effects include:\n• Subtitles are missing\n• Player gestures may not work\n• Low quality Shorts seekbar thumbnails + Spoof client to Android Testsuite + Spoof the client to Android Testsuite + Client is spoofed to an Android Testsuite client (iOS client is used for live streams)\n\nSide effects include, but are not limited to:\n• Speed flyout menu is missing\n• Captions are missing\n• Player swipe gestures may not work\n• Low quality Shorts seekbar thumbnails\n• Watch history may not work + Client is spoofed to an iOS client\n\nSide effects include:\n• No HDR video\n• Speed flyout menu is missing Spoof client thumbnails not available (API timed out) Spoof client thumbnails temporarily not available: %s