fix(YouTube - Spoof client): Improve Android spoofing (#3230)
This commit is contained in:
		
							parent
							
								
									b72fe87cf9
								
							
						
					
					
						commit
						b688923c7e
					
				| 
						 | 
					@ -15,11 +15,13 @@ import app.revanced.patches.all.misc.resources.AddResourcesPatch
 | 
				
			||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
 | 
					import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
 | 
				
			||||||
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
 | 
					import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen.Sorting
 | 
				
			||||||
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
 | 
					import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
 | 
				
			||||||
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.*
 | 
					import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildInitPlaybackRequestFingerprint
 | 
				
			||||||
 | 
					import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildPlayerRequestURIFingerprint
 | 
				
			||||||
 | 
					import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyFingerprint
 | 
				
			||||||
 | 
					import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
 | 
				
			||||||
 | 
					import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SetPlayerRequestClientTypeFingerprint
 | 
				
			||||||
import app.revanced.patches.youtube.misc.settings.SettingsPatch
 | 
					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.getReference
 | 
				
			||||||
import app.revanced.util.indexOfFirstInstruction
 | 
					 | 
				
			||||||
import app.revanced.util.resultOrThrow
 | 
					import app.revanced.util.resultOrThrow
 | 
				
			||||||
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
 | 
				
			||||||
| 
						 | 
					@ -35,11 +37,9 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
 | 
				
			||||||
    name = "Spoof client",
 | 
					    name = "Spoof client",
 | 
				
			||||||
    description = "Spoofs the client to allow video playback.",
 | 
					    description = "Spoofs the client to allow video playback.",
 | 
				
			||||||
    dependencies = [
 | 
					    dependencies = [
 | 
				
			||||||
        PlayerResponseMethodHookPatch::class,
 | 
					 | 
				
			||||||
        SettingsPatch::class,
 | 
					        SettingsPatch::class,
 | 
				
			||||||
        AddResourcesPatch::class,
 | 
					        AddResourcesPatch::class,
 | 
				
			||||||
        UserAgentClientSpoofPatch::class,
 | 
					        UserAgentClientSpoofPatch::class,
 | 
				
			||||||
        PlayerResponseMethodHookPatch::class,
 | 
					 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
    compatiblePackages = [
 | 
					    compatiblePackages = [
 | 
				
			||||||
        CompatiblePackage(
 | 
					        CompatiblePackage(
 | 
				
			||||||
| 
						 | 
					@ -69,19 +69,11 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
object SpoofClientPatch : BytecodePatch(
 | 
					object SpoofClientPatch : BytecodePatch(
 | 
				
			||||||
    setOf(
 | 
					    setOf(
 | 
				
			||||||
        // Client type spoof.
 | 
					 | 
				
			||||||
        BuildInitPlaybackRequestFingerprint,
 | 
					        BuildInitPlaybackRequestFingerprint,
 | 
				
			||||||
        BuildPlayerRequestURIFingerprint,
 | 
					        BuildPlayerRequestURIFingerprint,
 | 
				
			||||||
        SetPlayerRequestClientTypeFingerprint,
 | 
					        SetPlayerRequestClientTypeFingerprint,
 | 
				
			||||||
        CreatePlayerRequestBodyFingerprint,
 | 
					        CreatePlayerRequestBodyFingerprint,
 | 
				
			||||||
        CreatePlayerRequestBodyWithModelFingerprint,
 | 
					        CreatePlayerRequestBodyWithModelFingerprint,
 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Storyboard spoof.
 | 
					 | 
				
			||||||
        StoryboardRendererSpecFingerprint,
 | 
					 | 
				
			||||||
        PlayerResponseModelImplRecommendedLevelFingerprint,
 | 
					 | 
				
			||||||
        StoryboardRendererDecoderRecommendedLevelFingerprint,
 | 
					 | 
				
			||||||
        PlayerResponseModelImplGeneralFingerprint,
 | 
					 | 
				
			||||||
        StoryboardRendererDecoderSpecFingerprint,
 | 
					 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    private const val INTEGRATIONS_CLASS_DESCRIPTOR =
 | 
					    private const val INTEGRATIONS_CLASS_DESCRIPTOR =
 | 
				
			||||||
| 
						 | 
					@ -98,7 +90,7 @@ object SpoofClientPatch : BytecodePatch(
 | 
				
			||||||
                sorting = Sorting.UNSORTED,
 | 
					                sorting = Sorting.UNSORTED,
 | 
				
			||||||
                preferences = setOf(
 | 
					                preferences = setOf(
 | 
				
			||||||
                    SwitchPreference("revanced_spoof_client"),
 | 
					                    SwitchPreference("revanced_spoof_client"),
 | 
				
			||||||
                    SwitchPreference("revanced_spoof_client_use_testsuite"),
 | 
					                    SwitchPreference("revanced_spoof_client_use_ios"),
 | 
				
			||||||
                ),
 | 
					                ),
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
| 
						 | 
					@ -149,11 +141,11 @@ object SpoofClientPatch : BytecodePatch(
 | 
				
			||||||
            SetPlayerRequestClientTypeFingerprint.resultOrThrow().let { result ->
 | 
					            SetPlayerRequestClientTypeFingerprint.resultOrThrow().let { result ->
 | 
				
			||||||
                // Field in the player request object that holds the client info object.
 | 
					                // Field in the player request object that holds the client info object.
 | 
				
			||||||
                val clientInfoField = result.mutableMethod
 | 
					                val clientInfoField = result.mutableMethod
 | 
				
			||||||
                    .getInstructions().first { instruction ->
 | 
					                    .getInstructions().find { instruction ->
 | 
				
			||||||
                        // requestMessage.clientInfo = clientInfoBuilder.build();
 | 
					                        // requestMessage.clientInfo = clientInfoBuilder.build();
 | 
				
			||||||
                        instruction.opcode == Opcode.IPUT_OBJECT &&
 | 
					                        instruction.opcode == Opcode.IPUT_OBJECT &&
 | 
				
			||||||
                            instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
 | 
					                            instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
 | 
				
			||||||
                    }.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
 | 
					                    }?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Client info object's client type field.
 | 
					                // Client info object's client type field.
 | 
				
			||||||
                val clientInfoClientTypeField = result.mutableMethod
 | 
					                val clientInfoClientTypeField = result.mutableMethod
 | 
				
			||||||
| 
						 | 
					@ -168,20 +160,17 @@ object SpoofClientPatch : BytecodePatch(
 | 
				
			||||||
                Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
 | 
					                Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.let {
 | 
					        val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().let {
 | 
				
			||||||
            val instructions = it.getInstructions()
 | 
					            val getClientModelIndex = CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction(it.method)
 | 
				
			||||||
 | 
					            val instructions = it.mutableMethod.getInstructions()
 | 
				
			||||||
            val getClientModelIndex = it.indexOfFirstInstruction {
 | 
					 | 
				
			||||||
                getReference<FieldReference>().toString() == "Landroid/os/Build;->MODEL:Ljava/lang/String;"
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
 | 
					            // The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
 | 
				
			||||||
            instructions.subList(
 | 
					            instructions.subList(
 | 
				
			||||||
                getClientModelIndex,
 | 
					                getClientModelIndex,
 | 
				
			||||||
                instructions.lastIndex,
 | 
					                instructions.size,
 | 
				
			||||||
            ).first { instruction ->
 | 
					            ).find { instruction ->
 | 
				
			||||||
                instruction.opcode == Opcode.IPUT_OBJECT
 | 
					                instruction.opcode == Opcode.IPUT_OBJECT
 | 
				
			||||||
            }.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientModelField")
 | 
					            }?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientModelField")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // endregion
 | 
					        // endregion
 | 
				
			||||||
| 
						 | 
					@ -243,6 +232,7 @@ object SpoofClientPatch : BytecodePatch(
 | 
				
			||||||
                            invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String;
 | 
					                            invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String;
 | 
				
			||||||
                            move-result-object v1
 | 
					                            move-result-object v1
 | 
				
			||||||
                            iput-object v1, v0, $clientInfoClientVersionField
 | 
					                            iput-object v1, v0, $clientInfoClientVersionField
 | 
				
			||||||
 | 
					                            
 | 
				
			||||||
                            :disabled
 | 
					                            :disabled
 | 
				
			||||||
                            return-void
 | 
					                            return-void
 | 
				
			||||||
                        """,
 | 
					                        """,
 | 
				
			||||||
| 
						 | 
					@ -253,104 +243,5 @@ object SpoofClientPatch : BytecodePatch(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // endregion
 | 
					        // endregion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // region Fix storyboard if Android Testsuite is used.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.ProtoBufferParameter(
 | 
					 | 
				
			||||||
            "$INTEGRATIONS_CLASS_DESCRIPTOR->setPlayerResponseVideoId(" +
 | 
					 | 
				
			||||||
                "Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;",
 | 
					 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Hook recommended seekbar thumbnails quality level for regular videos.
 | 
					 | 
				
			||||||
        StoryboardRendererDecoderRecommendedLevelFingerprint.resultOrThrow().let {
 | 
					 | 
				
			||||||
            val endIndex = it.scanResult.patternScanResult!!.endIndex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it.mutableMethod.apply {
 | 
					 | 
				
			||||||
                val originalValueRegister =
 | 
					 | 
				
			||||||
                    getInstruction<OneRegisterInstruction>(endIndex).registerA
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    endIndex + 1,
 | 
					 | 
				
			||||||
                    """
 | 
					 | 
				
			||||||
                        invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I
 | 
					 | 
				
			||||||
                        move-result v$originalValueRegister
 | 
					 | 
				
			||||||
                    """,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Hook the recommended precise seeking thumbnails quality.
 | 
					 | 
				
			||||||
        PlayerResponseModelImplRecommendedLevelFingerprint.resultOrThrow().let {
 | 
					 | 
				
			||||||
            val endIndex = it.scanResult.patternScanResult!!.endIndex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it.mutableMethod.apply {
 | 
					 | 
				
			||||||
                val originalValueRegister =
 | 
					 | 
				
			||||||
                    getInstruction<OneRegisterInstruction>(endIndex).registerA
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    endIndex,
 | 
					 | 
				
			||||||
                    """
 | 
					 | 
				
			||||||
                        invoke-static { v$originalValueRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getRecommendedLevel(I)I
 | 
					 | 
				
			||||||
                        move-result v$originalValueRegister
 | 
					 | 
				
			||||||
                    """,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // TODO: Hook the seekbar recommended level for Shorts to fix Shorts low quality seekbar thumbnails.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        /**
 | 
					 | 
				
			||||||
         * Hook StoryBoard renderer url.
 | 
					 | 
				
			||||||
         */
 | 
					 | 
				
			||||||
        PlayerResponseModelImplGeneralFingerprint.resultOrThrow().let {
 | 
					 | 
				
			||||||
            val getStoryBoardIndex = it.scanResult.patternScanResult!!.endIndex
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it.mutableMethod.apply {
 | 
					 | 
				
			||||||
                val getStoryBoardRegister = getInstruction<OneRegisterInstruction>(getStoryBoardIndex).registerA
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    getStoryBoardIndex,
 | 
					 | 
				
			||||||
                    """
 | 
					 | 
				
			||||||
                        invoke-static { v$getStoryBoardRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
 | 
					 | 
				
			||||||
                        move-result-object v$getStoryBoardRegister
 | 
					 | 
				
			||||||
                    """,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Hook the seekbar thumbnail decoder, required for Shorts.
 | 
					 | 
				
			||||||
        StoryboardRendererDecoderSpecFingerprint.resultOrThrow().let {
 | 
					 | 
				
			||||||
            val storyBoardUrlIndex = it.scanResult.patternScanResult!!.startIndex + 1
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it.mutableMethod.apply {
 | 
					 | 
				
			||||||
                val getStoryBoardRegister = getInstruction<OneRegisterInstruction>(storyBoardUrlIndex).registerA
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    storyBoardUrlIndex + 1,
 | 
					 | 
				
			||||||
                    """
 | 
					 | 
				
			||||||
                        invoke-static { v$getStoryBoardRegister }, ${INTEGRATIONS_CLASS_DESCRIPTOR}->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
 | 
					 | 
				
			||||||
                        move-result-object v$getStoryBoardRegister
 | 
					 | 
				
			||||||
                    """,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        StoryboardRendererSpecFingerprint.resultOrThrow().let {
 | 
					 | 
				
			||||||
            it.mutableMethod.apply {
 | 
					 | 
				
			||||||
                val storyBoardUrlParams = "p0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                addInstructions(
 | 
					 | 
				
			||||||
                    0,
 | 
					 | 
				
			||||||
                    """
 | 
					 | 
				
			||||||
                        if-nez $storyBoardUrlParams, :ignore
 | 
					 | 
				
			||||||
                        invoke-static { $storyBoardUrlParams }, $INTEGRATIONS_CLASS_DESCRIPTOR->getStoryboardRendererSpec(Ljava/lang/String;)Ljava/lang/String;
 | 
					 | 
				
			||||||
                        move-result-object $storyBoardUrlParams
 | 
					 | 
				
			||||||
                        :ignore
 | 
					 | 
				
			||||||
                        nop
 | 
					 | 
				
			||||||
                    """,
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // endregion
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,8 +2,12 @@ package app.revanced.patches.youtube.misc.fix.playback.fingerprints
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import app.revanced.patcher.extensions.or
 | 
					import app.revanced.patcher.extensions.or
 | 
				
			||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
 | 
					import app.revanced.patcher.fingerprint.MethodFingerprint
 | 
				
			||||||
 | 
					import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfBuildModelInstruction
 | 
				
			||||||
 | 
					import app.revanced.util.containsWideLiteralInstructionValue
 | 
				
			||||||
import app.revanced.util.getReference
 | 
					import app.revanced.util.getReference
 | 
				
			||||||
 | 
					import app.revanced.util.indexOfFirstInstruction
 | 
				
			||||||
import com.android.tools.smali.dexlib2.AccessFlags
 | 
					import com.android.tools.smali.dexlib2.AccessFlags
 | 
				
			||||||
 | 
					import com.android.tools.smali.dexlib2.iface.Method
 | 
				
			||||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
 | 
					import com.android.tools.smali.dexlib2.iface.reference.FieldReference
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint(
 | 
					internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint(
 | 
				
			||||||
| 
						 | 
					@ -11,8 +15,17 @@ internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint(
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
				
			||||||
    parameters = listOf(),
 | 
					    parameters = listOf(),
 | 
				
			||||||
    customFingerprint = { methodDef, _ ->
 | 
					    customFingerprint = { methodDef, _ ->
 | 
				
			||||||
        methodDef.implementation!!.instructions.any {
 | 
					        methodDef.containsWideLiteralInstructionValue(1073741824) &&
 | 
				
			||||||
            it.getReference<FieldReference>().toString() == "Landroid/os/Build;->MODEL:Ljava/lang/String;"
 | 
					                indexOfBuildModelInstruction(methodDef) >= 0
 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
)
 | 
					) {
 | 
				
			||||||
 | 
					    fun indexOfBuildModelInstruction(methodDef: Method) =
 | 
				
			||||||
 | 
					        methodDef.indexOfFirstInstruction {
 | 
				
			||||||
 | 
					            val reference = getReference<FieldReference>()
 | 
				
			||||||
 | 
					            reference?.definingClass == "Landroid/os/Build;" &&
 | 
				
			||||||
 | 
					                    reference.name == "MODEL" &&
 | 
				
			||||||
 | 
					                    reference.type == "Ljava/lang/String;"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import app.revanced.util.containsWideLiteralInstructionValue
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Fingerprint is obsolete and will be deleted soon")
 | 
				
			||||||
internal object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint(
 | 
					internal object PlayerResponseModelImplGeneralFingerprint : MethodFingerprint(
 | 
				
			||||||
    returnType = "Ljava/lang/String;",
 | 
					    returnType = "Ljava/lang/String;",
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,6 +6,7 @@ import app.revanced.util.containsWideLiteralInstructionValue
 | 
				
			||||||
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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Fingerprint is obsolete and will be deleted soon")
 | 
				
			||||||
internal object PlayerResponseModelImplRecommendedLevelFingerprint : MethodFingerprint(
 | 
					internal object PlayerResponseModelImplRecommendedLevelFingerprint : MethodFingerprint(
 | 
				
			||||||
    returnType = "I",
 | 
					    returnType = "I",
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,12 +1,13 @@
 | 
				
			||||||
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
 | 
					package app.revanced.patches.youtube.misc.fix.playback.fingerprints
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
 | 
					import app.revanced.util.patch.LiteralValueFingerprint
 | 
				
			||||||
import com.android.tools.smali.dexlib2.Opcode
 | 
					import com.android.tools.smali.dexlib2.Opcode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal object SetPlayerRequestClientTypeFingerprint : MethodFingerprint(
 | 
					internal object SetPlayerRequestClientTypeFingerprint : LiteralValueFingerprint(
 | 
				
			||||||
    strings = listOf("10.29"),
 | 
					 | 
				
			||||||
    opcodes = listOf(
 | 
					    opcodes = listOf(
 | 
				
			||||||
        Opcode.IGET,
 | 
					        Opcode.IGET,
 | 
				
			||||||
        Opcode.IPUT, // Sets ClientInfo.clientId.
 | 
					        Opcode.IPUT, // Sets ClientInfo.clientId.
 | 
				
			||||||
    ),
 | 
					    ),
 | 
				
			||||||
 | 
					    strings = listOf("10.29"),
 | 
				
			||||||
 | 
					    literalSupplier = { 134217728 }
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ import com.android.tools.smali.dexlib2.Opcode
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Resolves to the same method as [StoryboardRendererDecoderSpecFingerprint].
 | 
					 * Resolves to the same method as [StoryboardRendererDecoderSpecFingerprint].
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated("Fingerprint is obsolete and will be deleted soon")
 | 
				
			||||||
internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint(
 | 
					internal object StoryboardRendererDecoderRecommendedLevelFingerprint : MethodFingerprint(
 | 
				
			||||||
    returnType = "V",
 | 
					    returnType = "V",
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ import com.android.tools.smali.dexlib2.Opcode
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint].
 | 
					 * Resolves to the same method as [StoryboardRendererDecoderRecommendedLevelFingerprint].
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated("Fingerprint is obsolete and will be deleted soon")
 | 
				
			||||||
internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint(
 | 
					internal object StoryboardRendererDecoderSpecFingerprint : MethodFingerprint(
 | 
				
			||||||
    returnType = "V",
 | 
					    returnType = "V",
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ import app.revanced.patcher.extensions.or
 | 
				
			||||||
import app.revanced.patcher.fingerprint.MethodFingerprint
 | 
					import app.revanced.patcher.fingerprint.MethodFingerprint
 | 
				
			||||||
import com.android.tools.smali.dexlib2.AccessFlags
 | 
					import com.android.tools.smali.dexlib2.AccessFlags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@Deprecated("Fingerprint is obsolete and will be deleted soon")
 | 
				
			||||||
internal object StoryboardRendererSpecFingerprint : MethodFingerprint(
 | 
					internal object StoryboardRendererSpecFingerprint : MethodFingerprint(
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
 | 
				
			||||||
    returnType = "L",
 | 
					    returnType = "L",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@ import com.android.tools.smali.dexlib2.Opcode
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Resolves using the class found in [StoryboardThumbnailParentFingerprint].
 | 
					 * Resolves using the class found in [StoryboardThumbnailParentFingerprint].
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					@Deprecated("Fingerprint is obsolete and will be deleted soon")
 | 
				
			||||||
internal object StoryboardThumbnailFingerprint : MethodFingerprint(
 | 
					internal object StoryboardThumbnailFingerprint : MethodFingerprint(
 | 
				
			||||||
    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
					    accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
 | 
				
			||||||
    returnType = "Z",
 | 
					    returnType = "Z",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1092,10 +1092,9 @@
 | 
				
			||||||
            <string name="revanced_spoof_client_summary_on">Client is spoofed</string>
 | 
					            <string name="revanced_spoof_client_summary_on">Client is spoofed</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
 | 
					            <string name="revanced_spoof_client_summary_off">Client is not spoofed\n\nVideo playback may not work</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
 | 
					            <string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_use_testsuite_title">Spoof client to Android Testsuite</string>
 | 
					            <string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_use_testsuite_summary">Spoof the client to Android Testsuite</string>
 | 
					            <string name="revanced_spoof_client_use_ios_summary_on">Client is currently spoofed to iOS\n\nSide effects include:\n• No HDR video\n• Speed menu is missing\n• Watch history may not work\n• Live streams cannot play as audio only\n• Live streams not available on older devices</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_use_testsuite_summary_on">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</string>
 | 
					            <string name="revanced_spoof_client_use_ios_summary_off">Client is currently spoofed to Android VR\n\nSide effects include:\n• No HDR video\n• Player swipe gestures do not work\n• Kids videos do not playback\n• Paused videos can randomly resume</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_use_testsuite_summary_off">Client is spoofed to an iOS client\n\nSide effects include:\n• No HDR video\n• Speed flyout menu is missing</string>
 | 
					 | 
				
			||||||
            <string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
 | 
					            <string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
 | 
				
			||||||
            <string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
 | 
					            <string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
 | 
				
			||||||
        </patch>
 | 
					        </patch>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue