Skip to content

Commit

Permalink
fix(YouTube - Client Spoof): Restore missing high qualities by spoofi…
Browse files Browse the repository at this point in the history
…ng the iOS client user agent (#3468)

Co-authored-by: LisoUseInAIKyrios <[email protected]>
Co-authored-by: oSumAtrIX <[email protected]>
  • Loading branch information
3 people authored Jul 28, 2024
1 parent cf9f49b commit 0e6ae5f
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ 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.InstructionExtensions.replaceInstruction
import app.revanced.patcher.extensions.or
import app.revanced.patcher.patch.BytecodePatch
import app.revanced.patcher.patch.PatchException
Expand Down Expand Up @@ -77,13 +78,17 @@ object SpoofClientPatch : BytecodePatch(
SetPlayerRequestClientTypeFingerprint,
CreatePlayerRequestBodyFingerprint,
CreatePlayerRequestBodyWithModelFingerprint,
CreatePlayerRequestBodyWithVersionReleaseFingerprint,

// Player gesture config.
PlayerGestureConfigSyntheticFingerprint,

// Player speed menu item.
CreatePlaybackSpeedMenuItemFingerprint,

// Video qualities missing.
BuildRequestFingerprint,

// Watch history.
GetTrackingUriFingerprint,
),
Expand All @@ -92,6 +97,10 @@ object SpoofClientPatch : BytecodePatch(
"Lapp/revanced/integrations/youtube/patches/spoof/SpoofClientPatch;"
private const val CLIENT_INFO_CLASS_DESCRIPTOR =
"Lcom/google/protos/youtube/api/innertube/InnertubeContext\$ClientInfo;"
private const val REQUEST_CLASS_DESCRIPTOR =
"Lorg/chromium/net/ExperimentalUrlRequest;"
private const val REQUEST_BUILDER_CLASS_DESCRIPTOR =
"Lorg/chromium/net/ExperimentalUrlRequest\$Builder;"

override fun execute(context: BytecodeContext) {
AddResourcesPatch(this::class)
Expand Down Expand Up @@ -186,6 +195,19 @@ object SpoofClientPatch : BytecodePatch(
?: throw PatchException("Could not find clientInfoClientModelField")
}

val clientInfoOsVersionField = CreatePlayerRequestBodyWithVersionReleaseFingerprint.resultOrThrow().let {
val getOsVersionIndex =
CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction(it.method)

// The next IPUT_OBJECT instruction after getting the client os version is setting the client os version field.
val index = it.mutableMethod.indexOfFirstInstructionOrThrow(getOsVersionIndex) {
opcode == Opcode.IPUT_OBJECT
}

it.mutableMethod.getInstruction(index).getReference<FieldReference>()
?: throw PatchException("Could not find clientInfoOsVersionField")
}

// endregion

// region Spoof client type for /player requests.
Expand Down Expand Up @@ -245,6 +267,12 @@ object SpoofClientPatch : BytecodePatch(
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getClientVersion(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
iput-object v1, v0, $clientInfoClientVersionField
# Set client os version to the spoofed value.
iget-object v1, v0, $clientInfoOsVersionField
invoke-static { v1 }, $INTEGRATIONS_CLASS_DESCRIPTOR->getOsVersion(Ljava/lang/String;)Ljava/lang/String;
move-result-object v1
iput-object v1, v0, $clientInfoOsVersionField
:disabled
return-void
Expand Down Expand Up @@ -330,5 +358,28 @@ object SpoofClientPatch : BytecodePatch(
}

// endregion

// region Fix video qualities missing, if spoofing to iOS by overriding the user agent.

BuildRequestFingerprint.resultOrThrow().let { result ->
result.mutableMethod.apply {
val buildRequestIndex = getInstructions().lastIndex - 2
val requestBuilderRegister = getInstruction<FiveRegisterInstruction>(buildRequestIndex).registerC

val newRequestBuilderIndex = result.scanResult.patternScanResult!!.endIndex
val urlRegister = getInstruction<FiveRegisterInstruction>(newRequestBuilderIndex).registerD

// Replace "requestBuilder.build(): Request" with "overrideUserAgent(requestBuilder, url): Request".
replaceInstruction(
buildRequestIndex,
"invoke-static { v$requestBuilderRegister, v$urlRegister }, " +
"$INTEGRATIONS_CLASS_DESCRIPTOR->" +
"overrideUserAgent(${REQUEST_BUILDER_CLASS_DESCRIPTOR}Ljava/lang/String;)" +
REQUEST_CLASS_DESCRIPTOR
)
}
}

// endregion
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package app.revanced.patches.youtube.misc.fix.playback.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 BuildRequestFingerprint : MethodFingerprint(
accessFlags = AccessFlags.PUBLIC or AccessFlags.STATIC,
returnType = "Lorg/chromium/net/UrlRequest;",
opcodes = listOf(
Opcode.INVOKE_DIRECT,
Opcode.INVOKE_VIRTUAL
)
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package app.revanced.patches.youtube.misc.fix.playback.fingerprints

import app.revanced.patcher.extensions.or
import app.revanced.patcher.fingerprint.MethodFingerprint
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithVersionReleaseFingerprint.indexOfBuildVersionReleaseInstruction
import app.revanced.util.containsWideLiteralInstructionValue
import app.revanced.util.getReference
import app.revanced.util.indexOfFirstInstruction
import com.android.tools.smali.dexlib2.AccessFlags
import com.android.tools.smali.dexlib2.iface.Method
import com.android.tools.smali.dexlib2.iface.reference.FieldReference

internal object CreatePlayerRequestBodyWithVersionReleaseFingerprint : MethodFingerprint(
returnType = "L",
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
parameters = listOf(),
customFingerprint = { methodDef, _ ->
methodDef.containsWideLiteralInstructionValue(1073741824) &&
indexOfBuildVersionReleaseInstruction(methodDef) >= 0
},
) {
fun indexOfBuildVersionReleaseInstruction(methodDef: Method) =
methodDef.indexOfFirstInstruction {
val reference = getReference<FieldReference>()
reference?.definingClass == "Landroid/os/Build\$VERSION;" &&
reference.name == "RELEASE" &&
reference.type == "Ljava/lang/String;"
}
}


4 changes: 2 additions & 2 deletions src/main/resources/addresources/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1132,8 +1132,8 @@ This is because Crowdin requires temporarily flattening this file and removing t
<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_use_ios_title">Spoof client to iOS</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• Higher video qualities may be missing\n• Live streams cannot play as audio only\n• Live streams not available on Android 8.0</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• Kids videos do not playback\n• Paused videos can randomly resume\n• Low quality Shorts seekbar thumbnails\n• Download action button is always hidden\n• End screen cards are always hidden</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• Higher video qualities may be missing\n• Live streams cannot play as audio only</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• Kids videos do not playback\n• Paused videos can randomly resume\n• Low quality Shorts seekbar thumbnails\n• Download action button is hidden\n• End screen cards are hidden</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>
</patch>
Expand Down

0 comments on commit 0e6ae5f

Please sign in to comment.