Skip to content

Commit ea1deb6

Browse files
authored
fix(YouTube - Spoof client): Allow swipe gestures to enter/exit fullscreen when spoofing with Android VR client (#3259)
1 parent 9f11642 commit ea1deb6

File tree

3 files changed

+85
-1
lines changed

3 files changed

+85
-1
lines changed

src/main/kotlin/app/revanced/patches/youtube/misc/fix/playback/SpoofClientPatch.kt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import app.revanced.patcher.patch.BytecodePatch
1010
import app.revanced.patcher.patch.PatchException
1111
import app.revanced.patcher.patch.annotation.CompatiblePackage
1212
import app.revanced.patcher.patch.annotation.Patch
13+
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod
1314
import app.revanced.patcher.util.proxy.mutableTypes.MutableMethod.Companion.toMutable
1415
import app.revanced.patches.all.misc.resources.AddResourcesPatch
1516
import app.revanced.patches.shared.misc.settings.preference.PreferenceScreen
@@ -19,6 +20,7 @@ import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildInitPlay
1920
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.BuildPlayerRequestURIFingerprint
2021
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyFingerprint
2122
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.CreatePlayerRequestBodyWithModelFingerprint
23+
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerGestureConfigSyntheticFingerprint
2224
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.SetPlayerRequestClientTypeFingerprint
2325
import app.revanced.patches.youtube.misc.settings.SettingsPatch
2426
import app.revanced.util.getReference
@@ -69,11 +71,15 @@ import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter
6971
)
7072
object SpoofClientPatch : BytecodePatch(
7173
setOf(
74+
// Client type spoof.
7275
BuildInitPlaybackRequestFingerprint,
7376
BuildPlayerRequestURIFingerprint,
7477
SetPlayerRequestClientTypeFingerprint,
7578
CreatePlayerRequestBodyFingerprint,
7679
CreatePlayerRequestBodyWithModelFingerprint,
80+
81+
// Player gesture config.
82+
PlayerGestureConfigSyntheticFingerprint,
7783
),
7884
) {
7985
private const val INTEGRATIONS_CLASS_DESCRIPTOR =
@@ -115,6 +121,33 @@ object SpoofClientPatch : BytecodePatch(
115121

116122
// endregion
117123

124+
// region fix player gesture.
125+
126+
PlayerGestureConfigSyntheticFingerprint.resultOrThrow().let {
127+
val endIndex = it.scanResult.patternScanResult!!.endIndex
128+
129+
arrayOf(3, 9).forEach { offSet ->
130+
(context.toMethodWalker(it.mutableMethod)
131+
.nextMethod(endIndex - offSet, true)
132+
.getMethod() as MutableMethod)
133+
.apply {
134+
135+
val index = implementation!!.instructions.lastIndex
136+
val register = getInstruction<OneRegisterInstruction>(index).registerA
137+
138+
addInstructions(
139+
index,
140+
"""
141+
invoke-static {v$register}, $INTEGRATIONS_CLASS_DESCRIPTOR->enablePlayerGesture(Z)Z
142+
move-result v$register
143+
"""
144+
)
145+
}
146+
}
147+
}
148+
149+
// endregion
150+
118151
// region Block /get_watch requests to fall back to /player requests.
119152

120153
BuildPlayerRequestURIFingerprint.resultOrThrow().let {
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package app.revanced.patches.youtube.misc.fix.playback.fingerprints
2+
3+
import app.revanced.patcher.extensions.or
4+
import app.revanced.patcher.fingerprint.annotation.FuzzyPatternScanMethod
5+
import app.revanced.patcher.fingerprint.MethodFingerprint
6+
import app.revanced.patches.youtube.misc.fix.playback.fingerprints.PlayerGestureConfigSyntheticFingerprint.indexOfDownAndOutAllowedInstruction
7+
import app.revanced.util.getReference
8+
import app.revanced.util.indexOfFirstInstruction
9+
import com.android.tools.smali.dexlib2.AccessFlags
10+
import com.android.tools.smali.dexlib2.Opcode
11+
import com.android.tools.smali.dexlib2.iface.Method
12+
import com.android.tools.smali.dexlib2.iface.reference.MethodReference
13+
14+
internal object PlayerGestureConfigSyntheticFingerprint : MethodFingerprint(
15+
returnType = "V",
16+
accessFlags = AccessFlags.PUBLIC or AccessFlags.FINAL,
17+
parameters = listOf("Ljava/lang/Object;"),
18+
opcodes = listOf(
19+
Opcode.SGET_OBJECT,
20+
Opcode.INVOKE_VIRTUAL,
21+
Opcode.MOVE_RESULT,
22+
Opcode.IF_EQZ,
23+
Opcode.IF_EQZ,
24+
Opcode.IGET_OBJECT,
25+
Opcode.INVOKE_INTERFACE,
26+
Opcode.MOVE_RESULT_OBJECT,
27+
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutLandscapeAllowed
28+
Opcode.MOVE_RESULT,
29+
Opcode.CHECK_CAST,
30+
Opcode.IPUT_BOOLEAN,
31+
Opcode.INVOKE_INTERFACE,
32+
Opcode.MOVE_RESULT_OBJECT,
33+
Opcode.INVOKE_VIRTUAL, // playerGestureConfig.downAndOutPortraitAllowed
34+
Opcode.MOVE_RESULT,
35+
Opcode.IPUT_BOOLEAN,
36+
Opcode.RETURN_VOID,
37+
),
38+
customFingerprint = { methodDef, classDef ->
39+
// This method is always called "a" because this kind of class always has a single method.
40+
methodDef.name == "a" && classDef.methods.count() == 2 &&
41+
indexOfDownAndOutAllowedInstruction(methodDef) >= 0
42+
}
43+
) {
44+
fun indexOfDownAndOutAllowedInstruction(methodDef: Method) =
45+
methodDef.indexOfFirstInstruction {
46+
val reference = getReference<MethodReference>()
47+
reference?.definingClass == "Lcom/google/android/libraries/youtube/innertube/model/media/PlayerConfigModel;" &&
48+
reference.parameterTypes.isEmpty() &&
49+
reference.returnType == "Z"
50+
}
51+
}

src/main/resources/addresources/values/strings.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1097,7 +1097,7 @@
10971097
<string name="revanced_spoof_client_user_dialog_message">Turning off this setting may cause video playback issues.</string>
10981098
<string name="revanced_spoof_client_use_ios_title">Spoof client to iOS</string>
10991099
<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>
1100-
<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• Swipe to enter/exit fullscreen does not work\n• Kids videos do not playback\n• Paused videos can randomly resume</string>
1100+
<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</string>
11011101
<string name="revanced_spoof_client_storyboard_timeout">Spoof client thumbnails not available (API timed out)</string>
11021102
<string name="revanced_spoof_client_storyboard_io_exception">Spoof client thumbnails temporarily not available: %s</string>
11031103
</patch>

0 commit comments

Comments
 (0)