mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-05-05 17:14:35 +02:00
feat(YouTube): add Spoof client
patch
This commit is contained in:
parent
d8d3f52e7f
commit
0b9ea6ac26
@ -0,0 +1,5 @@
|
||||
package app.revanced.patches.music.utils.fix.client
|
||||
|
||||
import app.revanced.patches.shared.spoofuseragent.BaseSpoofUserAgentPatch
|
||||
|
||||
object SpoofUserAgentPatch : BaseSpoofUserAgentPatch("com.google.android.apps.youtube.music")
|
@ -1,5 +0,0 @@
|
||||
package app.revanced.patches.music.utils.fix.clientspoof
|
||||
|
||||
import app.revanced.patches.shared.clientspoof.BaseClientSpoofPatch
|
||||
|
||||
object ClientSpoofPatch : BaseClientSpoofPatch("com.google.android.apps.youtube.music")
|
@ -1,7 +1,7 @@
|
||||
package app.revanced.patches.music.utils.gms
|
||||
|
||||
import app.revanced.patches.music.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.music.utils.fix.clientspoof.ClientSpoofPatch
|
||||
import app.revanced.patches.music.utils.fix.client.SpoofUserAgentPatch
|
||||
import app.revanced.patches.music.utils.fix.fileprovider.FileProviderPatch
|
||||
import app.revanced.patches.music.utils.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.music.utils.mainactivity.fingerprints.MainActivityFingerprint
|
||||
@ -14,7 +14,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
fromPackageName = ORIGINAL_PACKAGE_NAME_YOUTUBE,
|
||||
mainActivityOnCreateFingerprint = MainActivityFingerprint,
|
||||
integrationsPatchDependency = IntegrationsPatch::class,
|
||||
dependencies = setOf(ClientSpoofPatch::class, PackageNamePatch::class, FileProviderPatch::class),
|
||||
dependencies = setOf(SpoofUserAgentPatch::class, PackageNamePatch::class, FileProviderPatch::class),
|
||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
||||
compatiblePackages = COMPATIBLE_PACKAGE
|
||||
)
|
||||
|
@ -0,0 +1,33 @@
|
||||
package app.revanced.patches.shared.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfModelInstruction
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfReleaseInstruction
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.indexOfFirstInstruction
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.Method
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
|
||||
internal object CreatePlayerRequestBodyWithModelFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
opcodes = listOf(Opcode.OR_INT_LIT16),
|
||||
customFingerprint = { methodDef, _ ->
|
||||
indexOfModelInstruction(methodDef) >= 0
|
||||
&& indexOfReleaseInstruction(methodDef) >= 0
|
||||
}
|
||||
) {
|
||||
fun indexOfModelInstruction(methodDef: Method) =
|
||||
methodDef.indexOfFirstInstruction {
|
||||
getReference<FieldReference>().toString() == "Landroid/os/Build;->MODEL:Ljava/lang/String;"
|
||||
}
|
||||
|
||||
fun indexOfReleaseInstruction(methodDef: Method) =
|
||||
methodDef.indexOfFirstInstruction {
|
||||
getReference<FieldReference>().toString() == "Landroid/os/Build${'$'}VERSION;->RELEASE:Ljava/lang/String;"
|
||||
}
|
||||
}
|
@ -4,10 +4,9 @@ import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.patch.BytecodePatch
|
||||
import app.revanced.patches.shared.spoofappversion.fingerprints.ClientInfoFingerprint
|
||||
import app.revanced.patches.shared.spoofappversion.fingerprints.ClientInfoParentFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfReleaseInstruction
|
||||
import app.revanced.util.getTargetIndexReversed
|
||||
import app.revanced.util.getTargetIndexWithFieldReferenceName
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
@ -15,27 +14,21 @@ import com.android.tools.smali.dexlib2.iface.instruction.TwoRegisterInstruction
|
||||
abstract class BaseSpoofAppVersionPatch(
|
||||
private val descriptor: String
|
||||
) : BytecodePatch(
|
||||
setOf(ClientInfoParentFingerprint)
|
||||
setOf(CreatePlayerRequestBodyWithModelFingerprint)
|
||||
) {
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
ClientInfoParentFingerprint.resultOrThrow().let { parentResult ->
|
||||
ClientInfoFingerprint.resolve(context, parentResult.classDef)
|
||||
CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.apply {
|
||||
val versionIndex = indexOfReleaseInstruction(this) + 1
|
||||
val insertIndex = getTargetIndexReversed(versionIndex, Opcode.IPUT_OBJECT)
|
||||
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
ClientInfoFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val versionIndex = getTargetIndexWithFieldReferenceName("RELEASE") + 1
|
||||
val insertIndex = getTargetIndexReversed(versionIndex, Opcode.IPUT_OBJECT)
|
||||
val insertRegister = getInstruction<TwoRegisterInstruction>(insertIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $descriptor
|
||||
move-result-object v$insertRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
}
|
||||
addInstructions(
|
||||
insertIndex, """
|
||||
invoke-static {v$insertRegister}, $descriptor
|
||||
move-result-object v$insertRegister
|
||||
"""
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
package app.revanced.patches.shared.spoofappversion.fingerprints
|
||||
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object ClientInfoFingerprint : MethodFingerprint(
|
||||
returnType = "L",
|
||||
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
|
||||
parameters = emptyList(),
|
||||
opcodes = listOf(Opcode.OR_INT_LIT16)
|
||||
)
|
@ -1,8 +0,0 @@
|
||||
package app.revanced.patches.shared.spoofappversion.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
|
||||
internal object ClientInfoParentFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
strings = listOf("Android Wear")
|
||||
)
|
@ -1,4 +1,4 @@
|
||||
package app.revanced.patches.shared.clientspoof
|
||||
package app.revanced.patches.shared.spoofuseragent
|
||||
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.replaceInstruction
|
||||
@ -16,7 +16,7 @@ import com.android.tools.smali.dexlib2.iface.instruction.Instruction
|
||||
import com.android.tools.smali.dexlib2.iface.instruction.OneRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
|
||||
|
||||
abstract class BaseClientSpoofPatch(
|
||||
abstract class BaseSpoofUserAgentPatch(
|
||||
private val packageName: String
|
||||
) : BaseTransformInstructionsPatch<Instruction35cInfo>() {
|
||||
override fun filterMap(
|
@ -0,0 +1,239 @@
|
||||
package app.revanced.patches.youtube.utils.fix.client
|
||||
|
||||
import app.revanced.patcher.data.BytecodeContext
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstruction
|
||||
import app.revanced.patcher.extensions.InstructionExtensions.getInstructions
|
||||
import app.revanced.patcher.extensions.or
|
||||
import app.revanced.patcher.patch.PatchException
|
||||
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
|
||||
import app.revanced.patches.shared.fingerprints.CreatePlayerRequestBodyWithModelFingerprint.indexOfModelInstruction
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants
|
||||
import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildInitPlaybackRequestFingerprint
|
||||
import app.revanced.patches.youtube.utils.fix.client.fingerprints.BuildPlayerRequestURIFingerprint
|
||||
import app.revanced.patches.youtube.utils.fix.client.fingerprints.CreatePlayerRequestBodyFingerprint
|
||||
import app.revanced.patches.youtube.utils.fix.client.fingerprints.SetPlayerRequestClientTypeFingerprint
|
||||
import app.revanced.patches.youtube.utils.integrations.Constants.MISC_PATH
|
||||
import app.revanced.patches.youtube.utils.playertype.PlayerTypeHookPatch
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
import app.revanced.patches.youtube.video.information.VideoInformationPatch
|
||||
import app.revanced.patches.youtube.video.playerresponse.PlayerResponseMethodHookPatch
|
||||
import app.revanced.util.getReference
|
||||
import app.revanced.util.getStringInstructionIndex
|
||||
import app.revanced.util.patch.BaseBytecodePatch
|
||||
import app.revanced.util.resultOrThrow
|
||||
import com.android.tools.smali.dexlib2.AccessFlags
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation
|
||||
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.instruction.TwoRegisterInstruction
|
||||
import com.android.tools.smali.dexlib2.iface.reference.FieldReference
|
||||
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
|
||||
|
||||
object SpoofClientPatch : BaseBytecodePatch(
|
||||
name = "Spoof client",
|
||||
description = "Adds options to spoofs the client to allow video playback.",
|
||||
dependencies = setOf(
|
||||
PlayerTypeHookPatch::class,
|
||||
PlayerResponseMethodHookPatch::class,
|
||||
SettingsPatch::class,
|
||||
VideoInformationPatch::class,
|
||||
SpoofUserAgentPatch::class,
|
||||
),
|
||||
compatiblePackages = Constants.COMPATIBLE_PACKAGE,
|
||||
fingerprints = setOf(
|
||||
BuildInitPlaybackRequestFingerprint,
|
||||
BuildPlayerRequestURIFingerprint,
|
||||
SetPlayerRequestClientTypeFingerprint,
|
||||
CreatePlayerRequestBodyFingerprint,
|
||||
CreatePlayerRequestBodyWithModelFingerprint,
|
||||
)
|
||||
) {
|
||||
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
|
||||
"$MISC_PATH/SpoofClientPatch;"
|
||||
private const val CLIENT_INFO_CLASS_DESCRIPTOR =
|
||||
"Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;"
|
||||
|
||||
override fun execute(context: BytecodeContext) {
|
||||
|
||||
// region Block /initplayback requests to fall back to /get_watch requests.
|
||||
|
||||
BuildInitPlaybackRequestFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val moveUriStringIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val targetRegister = getInstruction<OneRegisterInstruction>(moveUriStringIndex).registerA
|
||||
|
||||
addInstructions(
|
||||
moveUriStringIndex + 1, """
|
||||
invoke-static { v$targetRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockInitPlaybackRequest(Ljava/lang/String;)Ljava/lang/String;
|
||||
move-result-object v$targetRegister
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Block /get_watch requests to fall back to /player requests.
|
||||
|
||||
BuildPlayerRequestURIFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val invokeToStringIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
val uriRegister = getInstruction<FiveRegisterInstruction>(invokeToStringIndex).registerC
|
||||
|
||||
addInstructions(
|
||||
invokeToStringIndex, """
|
||||
invoke-static { v$uriRegister }, $INTEGRATIONS_CLASS_DESCRIPTOR->blockGetWatchRequest(Landroid/net/Uri;)Landroid/net/Uri;
|
||||
move-result-object v$uriRegister
|
||||
""",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Get field references to be used below.
|
||||
|
||||
val (clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField) =
|
||||
SetPlayerRequestClientTypeFingerprint.resultOrThrow().let { result ->
|
||||
with (result.mutableMethod) {
|
||||
// Field in the player request object that holds the client info object.
|
||||
val clientInfoField = getInstructions().find { instruction ->
|
||||
// requestMessage.clientInfo = clientInfoBuilder.build();
|
||||
instruction.opcode == Opcode.IPUT_OBJECT &&
|
||||
instruction.getReference<FieldReference>()?.type == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoField")
|
||||
|
||||
// Client info object's client type field.
|
||||
val clientInfoClientTypeField = getInstruction(result.scanResult.patternScanResult!!.endIndex)
|
||||
.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientTypeField")
|
||||
|
||||
val clientInfoVersionIndex = getStringInstructionIndex("10.29")
|
||||
val clientInfoVersionRegister = getInstruction<OneRegisterInstruction>(clientInfoVersionIndex).registerA
|
||||
val clientInfoClientVersionFieldIndex = implementation!!.instructions.let {
|
||||
clientInfoVersionIndex + it.subList(clientInfoVersionIndex, it.size - 1).indexOfFirst { instruction ->
|
||||
instruction.opcode == Opcode.IPUT_OBJECT
|
||||
&& (instruction as TwoRegisterInstruction).registerA == clientInfoVersionRegister
|
||||
}
|
||||
}
|
||||
|
||||
// Client info object's client version field.
|
||||
val clientInfoClientVersionField = getInstruction(clientInfoClientVersionFieldIndex)
|
||||
.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientVersionField")
|
||||
|
||||
Triple(clientInfoField, clientInfoClientTypeField, clientInfoClientVersionField)
|
||||
}
|
||||
}
|
||||
|
||||
val clientInfoClientModelField = CreatePlayerRequestBodyWithModelFingerprint.resultOrThrow().mutableMethod.let {
|
||||
val instructions = it.getInstructions()
|
||||
val getClientModelIndex = indexOfModelInstruction(it)
|
||||
|
||||
// The next IPUT_OBJECT instruction after getting the client model is setting the client model field.
|
||||
instructions.subList(
|
||||
getClientModelIndex,
|
||||
instructions.size,
|
||||
).find { instruction ->
|
||||
val reference = instruction.getReference<FieldReference>()
|
||||
instruction.opcode == Opcode.IPUT_OBJECT
|
||||
&& reference?.definingClass == CLIENT_INFO_CLASS_DESCRIPTOR
|
||||
&& reference.type == "Ljava/lang/String;"
|
||||
}?.getReference<FieldReference>() ?: throw PatchException("Could not find clientInfoClientModelField")
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region Spoof client type for /player requests.
|
||||
|
||||
CreatePlayerRequestBodyFingerprint.resultOrThrow().let {
|
||||
it.mutableMethod.apply {
|
||||
val setClientInfoMethodName = "setClientInfo"
|
||||
val checkCastIndex = it.scanResult.patternScanResult!!.startIndex
|
||||
|
||||
val checkCastInstruction = getInstruction<OneRegisterInstruction>(checkCastIndex)
|
||||
val requestMessageInstanceRegister = checkCastInstruction.registerA
|
||||
val clientInfoContainerClassName = checkCastInstruction.getReference<TypeReference>()!!.type
|
||||
|
||||
addInstruction(
|
||||
checkCastIndex + 1,
|
||||
"invoke-static { v$requestMessageInstanceRegister }," +
|
||||
" $definingClass->$setClientInfoMethodName($clientInfoContainerClassName)V",
|
||||
)
|
||||
|
||||
// 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.
|
||||
it.mutableClass.methods.add(
|
||||
ImmutableMethod(
|
||||
definingClass,
|
||||
setClientInfoMethodName,
|
||||
listOf(ImmutableMethodParameter(clientInfoContainerClassName, annotations, "clientInfoContainer")),
|
||||
"V",
|
||||
AccessFlags.PRIVATE or AccessFlags.STATIC,
|
||||
annotations,
|
||||
null,
|
||||
MutableMethodImplementation(3),
|
||||
).toMutable().apply {
|
||||
addInstructions(
|
||||
"""
|
||||
invoke-static { }, $INTEGRATIONS_CLASS_DESCRIPTOR->isClientSpoofingEnabled()Z
|
||||
move-result v0
|
||||
if-eqz v0, :disabled
|
||||
|
||||
iget-object v0, p0, $clientInfoField
|
||||
|
||||
# Set client type to the spoofed value.
|
||||
iget v1, v0, $clientInfoClientTypeField
|
||||
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientTypeId(I)I
|
||||
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
|
||||
""",
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
// region check whether video is Shorts or Clips.
|
||||
|
||||
PlayerResponseMethodHookPatch += PlayerResponseMethodHookPatch.Hook.PlayerParameter(
|
||||
"$INTEGRATIONS_CLASS_DESCRIPTOR->setPlayerResponseVideoId(" +
|
||||
"Ljava/lang/String;Ljava/lang/String;Z)Ljava/lang/String;",
|
||||
)
|
||||
|
||||
// endregion
|
||||
|
||||
/**
|
||||
* Add settings
|
||||
*/
|
||||
SettingsPatch.addPreference(
|
||||
arrayOf(
|
||||
"PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS",
|
||||
"SETTINGS: SPOOF_CLIENT"
|
||||
)
|
||||
)
|
||||
|
||||
SettingsPatch.updatePatchStatus(this)
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package app.revanced.patches.youtube.utils.fix.client
|
||||
|
||||
import app.revanced.patches.shared.spoofuseragent.BaseSpoofUserAgentPatch
|
||||
|
||||
object SpoofUserAgentPatch : BaseSpoofUserAgentPatch("com.google.android.youtube")
|
@ -0,0 +1,16 @@
|
||||
package app.revanced.patches.youtube.utils.fix.client.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object BuildInitPlaybackRequestFingerprint : MethodFingerprint(
|
||||
returnType = "Lorg/chromium/net/UrlRequest\$Builder;",
|
||||
opcodes = listOf(
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IGET_OBJECT, // Moves the request URI string to a register to build the request with.
|
||||
),
|
||||
strings = listOf(
|
||||
"Content-Type",
|
||||
"Range",
|
||||
),
|
||||
)
|
@ -0,0 +1,20 @@
|
||||
package app.revanced.patches.youtube.utils.fix.client.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object BuildPlayerRequestURIFingerprint : MethodFingerprint(
|
||||
returnType = "Ljava/lang/String;",
|
||||
opcodes = listOf(
|
||||
Opcode.INVOKE_VIRTUAL, // Register holds player request URI.
|
||||
Opcode.MOVE_RESULT_OBJECT,
|
||||
Opcode.IPUT_OBJECT,
|
||||
Opcode.IGET_OBJECT,
|
||||
Opcode.MONITOR_EXIT,
|
||||
Opcode.RETURN_OBJECT,
|
||||
),
|
||||
strings = listOf(
|
||||
"key",
|
||||
"asig",
|
||||
),
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
package app.revanced.patches.youtube.utils.fix.client.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object CreatePlayerRequestBodyFingerprint : MethodFingerprint(
|
||||
returnType = "V",
|
||||
parameters = listOf("L"),
|
||||
opcodes = listOf(
|
||||
Opcode.CHECK_CAST,
|
||||
Opcode.IGET,
|
||||
Opcode.AND_INT_LIT16,
|
||||
),
|
||||
strings = listOf("ms"),
|
||||
)
|
@ -0,0 +1,12 @@
|
||||
package app.revanced.patches.youtube.utils.fix.client.fingerprints
|
||||
|
||||
import app.revanced.patcher.fingerprint.MethodFingerprint
|
||||
import com.android.tools.smali.dexlib2.Opcode
|
||||
|
||||
internal object SetPlayerRequestClientTypeFingerprint : MethodFingerprint(
|
||||
strings = listOf("10.29"),
|
||||
opcodes = listOf(
|
||||
Opcode.IGET,
|
||||
Opcode.IPUT, // Sets ClientInfo.clientId.
|
||||
),
|
||||
)
|
@ -1,5 +0,0 @@
|
||||
package app.revanced.patches.youtube.utils.fix.clientspoof
|
||||
|
||||
import app.revanced.patches.shared.clientspoof.BaseClientSpoofPatch
|
||||
|
||||
object ClientSpoofPatch : BaseClientSpoofPatch("com.google.android.youtube")
|
@ -4,7 +4,8 @@ import app.revanced.patches.shared.gms.BaseGmsCoreSupportPatch
|
||||
import app.revanced.patches.shared.packagename.PackageNamePatch
|
||||
import app.revanced.patches.shared.packagename.PackageNamePatch.ORIGINAL_PACKAGE_NAME_YOUTUBE
|
||||
import app.revanced.patches.youtube.utils.compatibility.Constants.COMPATIBLE_PACKAGE
|
||||
import app.revanced.patches.youtube.utils.fix.clientspoof.ClientSpoofPatch
|
||||
import app.revanced.patches.youtube.utils.fix.client.SpoofClientPatch
|
||||
import app.revanced.patches.youtube.utils.fix.client.SpoofUserAgentPatch
|
||||
import app.revanced.patches.youtube.utils.integrations.IntegrationsPatch
|
||||
import app.revanced.patches.youtube.utils.mainactivity.fingerprints.MainActivityFingerprint
|
||||
import app.revanced.patches.youtube.utils.settings.SettingsPatch
|
||||
@ -14,7 +15,7 @@ object GmsCoreSupportPatch : BaseGmsCoreSupportPatch(
|
||||
fromPackageName = ORIGINAL_PACKAGE_NAME_YOUTUBE,
|
||||
mainActivityOnCreateFingerprint = MainActivityFingerprint,
|
||||
integrationsPatchDependency = IntegrationsPatch::class,
|
||||
dependencies = setOf(ClientSpoofPatch::class, PackageNamePatch::class, SettingsPatch::class),
|
||||
dependencies = setOf(SpoofClientPatch::class, SpoofUserAgentPatch::class, PackageNamePatch::class, SettingsPatch::class),
|
||||
gmsCoreSupportResourcePatch = GmsCoreSupportResourcePatch,
|
||||
compatiblePackages = COMPATIBLE_PACKAGE
|
||||
)
|
||||
|
@ -1414,6 +1414,27 @@ Tap on the continue button and disable battery optimizations."</string>
|
||||
<string name="revanced_sanitize_sharing_links_summary">Removes tracking query parameters from the URLs when sharing links.</string>
|
||||
<string name="revanced_disable_quic_protocol_title">Disable QUIC protocol</string>
|
||||
<string name="revanced_disable_quic_protocol_summary">"Disable CronetEngine's QUIC protocol."</string>
|
||||
|
||||
<string name="revanced_spoof_client_title">Spoof client</string>
|
||||
<string name="revanced_spoof_client_summary_on">"Client is spoofed.
|
||||
|
||||
Side effects include:
|
||||
• No HDR video.
|
||||
• Watch history may not work."</string>
|
||||
<string name="revanced_spoof_client_summary_off">"Client is not spoofed. Video playback may not work."</string>
|
||||
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_on">"Client is currently spoofed to iOS.
|
||||
|
||||
Side effects include:
|
||||
• Playback speed menu is missing.
|
||||
• Background playback does not work on live streams.
|
||||
• Higher video qualities may be missing."</string>
|
||||
<string name="revanced_spoof_client_use_ios_summary_off">"Client is currently spoofed to Android VR. (iOS client is used for Clips or Shorts)
|
||||
|
||||
Side effects include:
|
||||
• Player swipe gestures do not work.
|
||||
• Kids videos do not playback.
|
||||
• Paused videos can randomly resume."</string>
|
||||
<string name="revanced_spoof_player_parameter_title">Spoof player parameter</string>
|
||||
<string name="revanced_spoof_player_parameter_summary">"Spoofs player parameters to prevent playback issues.
|
||||
|
||||
|
@ -564,6 +564,10 @@
|
||||
<!-- PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS
|
||||
<PreferenceCategory android:title="@string/revanced_preference_category_experimental_flag" android:layout="@layout/revanced_settings_preferences_category"/>PREFERENCE_CATEGORY: MISC_EXPERIMENTAL_FLAGS -->
|
||||
|
||||
<!-- SETTINGS: SPOOF_CLIENT
|
||||
<SwitchPreference android:title="@string/revanced_spoof_client_title" android:key="revanced_spoof_client" android:defaultValue="false" android:summaryOn="@string/revanced_spoof_client_summary_on" android:summaryOff="@string/revanced_spoof_client_summary_off" />
|
||||
<SwitchPreference android:title="@string/revanced_spoof_client_use_ios_title" android:key="revanced_spoof_client_use_ios" android:defaultValue="true" android:summaryOn="@string/revanced_spoof_client_use_ios_summary_on" android:summaryOff="@string/revanced_spoof_client_use_ios_summary_off" />SETTINGS: SPOOF_CLIENT -->
|
||||
|
||||
<!-- SETTINGS: SPOOF_PLAYER_PARAMETER
|
||||
<SwitchPreference android:title="@string/revanced_spoof_player_parameter_title" android:key="revanced_spoof_player_parameter" android:defaultValue="false" android:summary="@string/revanced_spoof_player_parameter_summary" />
|
||||
<SwitchPreference android:title="@string/revanced_spoof_player_parameter_in_feed_title" android:key="revanced_spoof_player_parameter_in_feed" android:defaultValue="false" android:summaryOn="@string/revanced_spoof_player_parameter_in_feed_summary_on" android:summaryOff="@string/revanced_spoof_player_parameter_in_feed_summary_off" android:dependency="revanced_spoof_player_parameter" />SETTINGS: SPOOF_PLAYER_PARAMETER -->
|
||||
@ -640,6 +644,7 @@
|
||||
<Preference android:title="Enable minimized playback" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
||||
<Preference android:title="Enable open links directly" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
||||
<Preference android:title="Sanitize sharing links" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
||||
<Preference android:title="Spoof client" android:summary="@string/revanced_patches_excluded" android:selectable="false"/>
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/revanced_preference_category_others" android:layout="@layout/revanced_settings_preferences_category">
|
||||
|
Loading…
x
Reference in New Issue
Block a user