Skip to content

Commit f03256c

Browse files
fix(YouTube - Spoof video streams): Add "Allow Android VR AV1" setting (#6071)
1 parent fe16433 commit f03256c

File tree

10 files changed

+76
-64
lines changed

10 files changed

+76
-64
lines changed

extensions/shared/library/src/main/java/app/revanced/extension/shared/spoof/SpoofVideoStreamsPatch.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,14 @@
1919

2020
@SuppressWarnings("unused")
2121
public class SpoofVideoStreamsPatch {
22+
23+
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
24+
@Override
25+
public boolean isAvailable() {
26+
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
27+
}
28+
}
29+
2230
/**
2331
* Domain used for internet connectivity verification.
2432
* It has an empty response body and is only used to check for a 204 response code.
@@ -321,11 +329,4 @@ public static String appendSpoofedClient(String videoFormat) {
321329

322330
return videoFormat;
323331
}
324-
325-
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
326-
@Override
327-
public boolean isAvailable() {
328-
return BaseSettings.SPOOF_VIDEO_STREAMS.get() && !preferredClient.useAuth;
329-
}
330-
}
331332
}

extensions/youtube/src/main/java/app/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch.java

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,35 @@
88

99
import java.util.List;
1010

11+
import app.revanced.extension.shared.settings.Setting;
1112
import app.revanced.extension.shared.spoof.ClientType;
1213
import app.revanced.extension.youtube.settings.Settings;
1314

1415
@SuppressWarnings("unused")
1516
public class SpoofVideoStreamsPatch {
1617

18+
public static final class SpoofClientAv1Availability implements Setting.Availability {
19+
@Override
20+
public boolean isAvailable() {
21+
return Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.isAvailable()
22+
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ANDROID_VR_1_43_32;
23+
}
24+
}
25+
1726
/**
1827
* Injection point.
1928
*/
2029
public static void setClientOrderToUse() {
2130
ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
2231

23-
24-
if (Settings.FORCE_AVC_CODEC.get() && client == ANDROID_VR_1_61_48) {
25-
// VR 1.61 uses VP9/AV1, and cannot force AVC. Use 1.43 instead.
26-
client = ANDROID_VR_1_43_32;
32+
if (client == ANDROID_VR_1_43_32 && Settings.SPOOF_VIDEO_STREAMS_AV1.get()) {
33+
client = ANDROID_VR_1_61_48;
2734
}
2835

2936
List<ClientType> availableClients = List.of(
37+
ANDROID_CREATOR,
3038
ANDROID_VR_1_43_32,
3139
VISIONOS,
32-
ANDROID_CREATOR,
33-
ANDROID_VR_1_61_48,
3440
IPADOS);
3541

3642
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/Settings.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import static app.revanced.extension.youtube.patches.OpenShortsInRegularPlayerPatch.ShortsPlayerType;
2222
import static app.revanced.extension.youtube.patches.SeekbarThumbnailsPatch.SeekbarThumbnailsHighQualityAvailability;
2323
import static app.revanced.extension.youtube.patches.components.PlayerFlyoutMenuItemsFilter.HideAudioFlyoutMenuAvailability;
24+
import static app.revanced.extension.youtube.patches.spoof.SpoofVideoStreamsPatch.SpoofClientAv1Availability;
2425
import static app.revanced.extension.youtube.patches.theme.ThemePatch.SplashScreenAnimationStyle;
2526
import static app.revanced.extension.youtube.sponsorblock.SegmentPlaybackController.SponsorBlockDuration;
2627
import static app.revanced.extension.youtube.sponsorblock.objects.CategoryBehaviour.IGNORE;
@@ -357,6 +358,8 @@ public class Settings extends BaseSettings {
357358
public static final BooleanSetting SPOOF_DEVICE_DIMENSIONS = new BooleanSetting("revanced_spoof_device_dimensions", FALSE, true,
358359
"revanced_spoof_device_dimensions_user_dialog_message");
359360
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
361+
public static final BooleanSetting SPOOF_VIDEO_STREAMS_AV1 = new BooleanSetting("revanced_spoof_video_streams_av1", FALSE, true,
362+
"revanced_spoof_video_streams_av1_user_dialog_message", new SpoofClientAv1Availability());
360363
public static final BooleanSetting DEBUG_PROTOBUFFER = new BooleanSetting("revanced_debug_protobuffer", FALSE, false,
361364
"revanced_debug_protobuffer_user_dialog_message", parent(BaseSettings.DEBUG));
362365

@@ -524,6 +527,11 @@ public class Settings extends BaseSettings {
524527
SPOOF_APP_VERSION.resetToDefault();
525528
}
526529

530+
// VR 1.61 is not selectable in the settings, and it's selected by spoof stream patch if needed.
531+
if (SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_VR_1_61_48) {
532+
SPOOF_VIDEO_STREAMS_CLIENT_TYPE.resetToDefault();
533+
}
534+
527535
// RYD requires manually migrating old settings since the lack of
528536
// a "revanced_" on the old setting causes duplicate key exceptions during export.
529537
SharedPrefCategory revancedPrefs = Setting.preferences;

extensions/youtube/src/main/java/app/revanced/extension/youtube/settings/preference/SpoofStreamingDataSideEffectsPreference.java

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,9 @@ private void updateUI() {
8787
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
8888
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
8989
+ '\n' + str("revanced_spoof_video_streams_about_no_force_original_audio");
90-
case ANDROID_VR_1_43_32 ->
91-
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume")
92-
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
93-
case ANDROID_VR_1_61_48 ->
94-
summary = str("revanced_spoof_video_streams_about_dropped_frames")
95-
+ '\n' + summary
96-
+ '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
90+
// VR 1.61 is not exposed in the UI and should never be reached here.
91+
case ANDROID_VR_1_43_32, ANDROID_VR_1_61_48 ->
92+
summary += '\n' + str("revanced_spoof_video_streams_about_no_stable_volume");
9793
case IPADOS ->
9894
summary = str("revanced_spoof_video_streams_about_playback_failure")
9995
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");

patches/api/patches.api

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1026,11 +1026,6 @@ public final class app/revanced/patches/shared/misc/settings/preference/TextPref
10261026
public fun serialize (Lorg/w3c/dom/Document;Lkotlin/jvm/functions/Function1;)Lorg/w3c/dom/Element;
10271027
}
10281028

1029-
public final class app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatchKt {
1030-
public static final fun spoofVideoStreamsPatch (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;)Lapp/revanced/patcher/patch/BytecodePatch;
1031-
public static synthetic fun spoofVideoStreamsPatch$default (Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lapp/revanced/patcher/patch/BytecodePatch;
1032-
}
1033-
10341029
public final class app/revanced/patches/shared/misc/spoof/UserAgentClientSpoofPatchKt {
10351030
public static final fun userAgentClientSpoofPatch (Ljava/lang/String;)Lapp/revanced/patcher/patch/BytecodePatch;
10361031
}

patches/src/main/kotlin/app/revanced/patches/music/misc/spoof/SpoofVideoStreamsPatch.kt

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package app.revanced.patches.music.misc.spoof
22

3-
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
43
import app.revanced.patches.all.misc.resources.addResources
54
import app.revanced.patches.all.misc.resources.addResourcesPatch
65
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
@@ -16,12 +15,13 @@ import app.revanced.patches.shared.misc.settings.preference.PreferenceScreenPref
1615
import app.revanced.patches.shared.misc.settings.preference.SwitchPreference
1716
import app.revanced.patches.shared.misc.spoof.spoofVideoStreamsPatch
1817

19-
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;"
20-
2118
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
22-
fixMediaFetchHotConfigChanges = { true },
23-
fixMediaFetchHotConfigAlternativeChanges = { is_8_11_or_greater && !is_8_15_or_greater },
19+
extensionClassDescriptor = "Lapp/revanced/extension/music/patches/spoof/SpoofVideoStreamsPatch;",
20+
mainActivityOnCreateFingerprint = musicActivityOnCreateFingerprint,
21+
fixMediaFetchHotConfig = { true },
22+
fixMediaFetchHotConfigAlternative = { is_8_11_or_greater && !is_8_15_or_greater },
2423
fixParsePlaybackResponseFeatureFlag = { is_7_33_or_greater },
24+
2525
block = {
2626
dependsOn(
2727
sharedExtensionPatch,
@@ -38,6 +38,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
3838
)
3939
)
4040
},
41+
4142
executeBlock = {
4243
addResources("music", "misc.fix.playback.spoofVideoStreamsPatch")
4344

@@ -51,10 +52,5 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
5152
)
5253
)
5354
)
54-
55-
musicActivityOnCreateFingerprint.method.addInstruction(
56-
0,
57-
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
58-
)
5955
}
60-
)
56+
)

patches/src/main/kotlin/app/revanced/patches/shared/misc/spoof/SpoofVideoStreamsPatch.kt

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package app.revanced.patches.shared.misc.spoof
22

3+
import app.revanced.patcher.Fingerprint
34
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
45
import app.revanced.patcher.extensions.InstructionExtensions.addInstructions
56
import app.revanced.patcher.extensions.InstructionExtensions.addInstructionsWithLabels
@@ -36,11 +37,13 @@ internal const val EXTENSION_CLASS_DESCRIPTOR =
3637
private lateinit var buildRequestMethod: MutableMethod
3738
private var buildRequestMethodUrlRegister = -1
3839

39-
fun spoofVideoStreamsPatch(
40-
block: BytecodePatchBuilder.() -> Unit = {},
41-
fixMediaFetchHotConfigChanges: BytecodePatchBuilder.() -> Boolean = { false },
42-
fixMediaFetchHotConfigAlternativeChanges: BytecodePatchBuilder.() -> Boolean = { false },
40+
internal fun spoofVideoStreamsPatch(
41+
extensionClassDescriptor: String,
42+
mainActivityOnCreateFingerprint: Fingerprint,
43+
fixMediaFetchHotConfig: BytecodePatchBuilder.() -> Boolean = { false },
44+
fixMediaFetchHotConfigAlternative: BytecodePatchBuilder.() -> Boolean = { false },
4345
fixParsePlaybackResponseFeatureFlag: BytecodePatchBuilder.() -> Boolean = { false },
46+
block: BytecodePatchBuilder.() -> Unit = {},
4447
executeBlock: BytecodePatchContext.() -> Unit = {},
4548
) = bytecodePatch(
4649
name = "Spoof video streams",
@@ -53,6 +56,11 @@ fun spoofVideoStreamsPatch(
5356
execute {
5457
addResources("shared", "misc.fix.playback.spoofVideoStreamsPatch")
5558

59+
mainActivityOnCreateFingerprint.method.addInstruction(
60+
0,
61+
"invoke-static { }, $extensionClassDescriptor->setClientOrderToUse()V"
62+
)
63+
5664
// region Enable extension helper method used by other patches
5765

5866
patchIncludedExtensionMethodFingerprint.method.returnEarly(true)
@@ -308,14 +316,14 @@ fun spoofVideoStreamsPatch(
308316

309317
// region turn off stream config replacement feature flag.
310318

311-
if (fixMediaFetchHotConfigChanges()) {
319+
if (fixMediaFetchHotConfig()) {
312320
mediaFetchHotConfigFingerprint.method.insertLiteralOverride(
313321
MEDIA_FETCH_HOT_CONFIG_FEATURE_FLAG,
314322
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"
315323
)
316324
}
317325

318-
if (fixMediaFetchHotConfigAlternativeChanges()) {
326+
if (fixMediaFetchHotConfigAlternative()) {
319327
mediaFetchHotConfigAlternativeFingerprint.method.insertLiteralOverride(
320328
MEDIA_FETCH_HOT_CONFIG_ALTERNATIVE_FEATURE_FLAG,
321329
"$EXTENSION_CLASS_DESCRIPTOR->useMediaFetchHotConfigReplacement(Z)Z"

patches/src/main/kotlin/app/revanced/patches/youtube/misc/spoof/SpoofVideoStreamsPatch.kt

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package app.revanced.patches.youtube.misc.spoof
22

3-
import app.revanced.patcher.extensions.InstructionExtensions.addInstruction
43
import app.revanced.patches.all.misc.resources.addResources
54
import app.revanced.patches.shared.misc.settings.preference.ListPreference
65
import app.revanced.patches.shared.misc.settings.preference.NonInteractivePreference
@@ -16,9 +15,20 @@ import app.revanced.patches.youtube.misc.settings.PreferenceScreen
1615
import app.revanced.patches.youtube.misc.settings.settingsPatch
1716
import app.revanced.patches.youtube.shared.mainActivityOnCreateFingerprint
1817

19-
private const val EXTENSION_CLASS_DESCRIPTOR = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;"
20-
2118
val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
19+
extensionClassDescriptor = "Lapp/revanced/extension/youtube/patches/spoof/SpoofVideoStreamsPatch;",
20+
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
21+
fixMediaFetchHotConfig = {
22+
is_19_34_or_greater
23+
},
24+
fixMediaFetchHotConfigAlternative = {
25+
// In 20.14 the flag was merged with 20.03 start playback flag.
26+
is_20_10_or_greater && !is_20_14_or_greater
27+
},
28+
fixParsePlaybackResponseFeatureFlag = {
29+
is_20_03_or_greater
30+
},
31+
2232
block = {
2333
compatibleWith(
2434
"com.google.android.youtube"(
@@ -35,16 +45,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
3545
versionCheckPatch
3646
)
3747
},
38-
fixMediaFetchHotConfigChanges = {
39-
is_19_34_or_greater
40-
},
41-
fixMediaFetchHotConfigAlternativeChanges = {
42-
// In 20.14 the flag was merged with 20.03 start playback flag.
43-
is_20_10_or_greater && !is_20_14_or_greater
44-
},
45-
fixParsePlaybackResponseFeatureFlag = {
46-
is_20_03_or_greater
47-
},
48+
4849
executeBlock = {
4950
addResources("youtube", "misc.fix.playback.spoofVideoStreamsPatch")
5051

@@ -61,6 +62,7 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
6162
summaryKey = null,
6263
tag = "app.revanced.extension.youtube.settings.preference.SpoofStreamingDataSideEffectsPreference"
6364
),
65+
SwitchPreference("revanced_spoof_video_streams_av1"),
6466
ListPreference(
6567
key = "revanced_spoof_video_streams_language",
6668
// Language strings are declared in Setting patch.
@@ -72,10 +74,5 @@ val spoofVideoStreamsPatch = spoofVideoStreamsPatch(
7274
)
7375
)
7476
)
75-
76-
mainActivityOnCreateFingerprint.method.addInstruction(
77-
0,
78-
"invoke-static { }, $EXTENSION_CLASS_DESCRIPTOR->setClientOrderToUse()V"
79-
)
8077
}
8178
)

patches/src/main/resources/addresources/values/arrays.xml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,13 @@
137137
<app id="youtube">
138138
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
139139
<string-array name="revanced_spoof_video_streams_client_type_entries">
140-
<item>Android VR 1.43</item>
141-
<item>Android VR 1.61</item>
140+
<item>Android VR</item>
142141
<item>Android Studio</item>
143142
<item>visionOS</item>
144143
<item>iPadOS</item>
145144
</string-array>
146145
<string-array name="revanced_spoof_video_streams_client_type_entry_values">
147146
<item>ANDROID_VR_1_43_32</item>
148-
<item>ANDROID_VR_1_61_48</item>
149147
<item>ANDROID_CREATOR</item>
150148
<item>VISIONOS</item>
151149
<item>IPADOS</item>

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1681,13 +1681,20 @@ Limitations:
16811681
<string name="revanced_slide_to_seek_summary_off">Slide to seek is not enabled</string>
16821682
</patch>
16831683
<patch id="misc.fix.playback.spoofVideoStreamsPatch">
1684+
<string name="revanced_spoof_video_streams_av1_title">Allow Android VR AV1</string>
1685+
<string name="revanced_spoof_video_streams_av1_summary_on">"Video codec is AVC (H.264), VP9, or AV1
1686+
1687+
Playback may stutter or drop frames"</string>
1688+
<string name="revanced_spoof_video_streams_av1_summary_off">Video codec is AVC (H.264) or VP9</string>
1689+
<string name="revanced_spoof_video_streams_av1_user_dialog_message">"Enabling this setting may use software AV1 decoding.
1690+
1691+
Video playback with AV1 may stutter or drop frames."</string>
16841692
<string name="revanced_spoof_video_streams_about_title">Spoofing side effects</string>
16851693
<string name="revanced_spoof_video_streams_about_experimental">• Experimental client and may stop working anytime</string>
16861694
<string name="revanced_spoof_video_streams_about_playback_failure">• Video may stop at 1:00, or may not be available in some regions</string>
16871695
<string name="revanced_spoof_video_streams_about_no_audio_tracks">• Audio track menu is missing</string>
16881696
<string name="revanced_spoof_video_streams_about_no_av1">• No AV1 video codec</string>
16891697
<string name="revanced_spoof_video_streams_about_no_stable_volume">• Stable volume is not available</string>
1690-
<string name="revanced_spoof_video_streams_about_dropped_frames">• Playback may stutter or drop frames</string>
16911698
<string name="revanced_spoof_video_streams_about_kids_videos">• Kids videos may not play when logged out or in incognito mode</string>
16921699
<!-- "Force original audio" should use the same text as revanced_force_original_audio_title -->
16931700
<string name="revanced_spoof_video_streams_about_no_force_original_audio">• Force original audio is not available</string>

0 commit comments

Comments
 (0)