Merge remote-tracking branch 'upstream/dev' into feat/patcher_instruction_filters

This commit is contained in:
LisoUseInAIKyrios 2025-09-16 17:27:38 +04:00
commit dcaa6feda0
90 changed files with 3874 additions and 1384 deletions

View file

@ -28,6 +28,9 @@ public class GoogleApiActivityHook extends BaseActivityHook {
// Logging anything under non debug ensures this is set.
Logger.printInfo(() -> "Permanent repeat enabled: " + Settings.PERMANENT_REPEAT.get());
// YT Music always uses dark mode.
Utils.setIsDarkModeEnabled(true);
return new GoogleApiActivityHook();
}

View file

@ -5,6 +5,7 @@ import static java.lang.Boolean.TRUE;
import static app.revanced.extension.shared.settings.Setting.parent;
import static app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.AudioStreamLanguageOverrideAvailability;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.spoof.ClientType;
/**
@ -32,4 +33,11 @@ public class BaseSettings {
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE, parent(SPOOF_VIDEO_STREAMS));
// Client type must be last spoof setting due to cyclic references.
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type", ClientType.ANDROID_VR_1_61_48, true, parent(SPOOF_VIDEO_STREAMS));
static {
if (SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.IOS_UNPLUGGED) {
Logger.printInfo(() -> "Migrating from iOS Unplugged to iPadOS");
SPOOF_VIDEO_STREAMS_CLIENT_TYPE.save(ClientType.IPADOS);
}
}
}

View file

@ -10,6 +10,7 @@ import java.util.Objects;
import app.revanced.extension.shared.Logger;
@SuppressWarnings("ConstantLocale")
public enum ClientType {
/**
* Video not playable: Kids / Paid / Movie / Private / Age-restricted.
@ -87,6 +88,48 @@ public enum ClientType {
false,
false,
"visionOS"
),
/**
* The device machine id for the iPad 6th Gen (iPad7,6).
* AV1 hardware decoding is not supported.
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
*
* Based on Google's actions to date, PoToken may not be required on devices with very low specs.
* For example, suppose the User-Agent for a PlayStation 3 (with 256MB of RAM) is used.
* Accessing 'Web' (https://www.youtube.com) will redirect to 'TV' (https://www.youtube.com/tv).
* 'TV' target devices with very low specs, such as embedded devices, game consoles, and blu-ray players, so PoToken is not required.
*
* For this reason, the device machine id for the iPad 6th Gen (with 2GB of RAM),
* the lowest spec device capable of running iPadOS 17, was used.
*/
IPADOS(5,
"IOS",
"Apple",
"iPad7,6",
"iPadOS",
"17.7.10.21H450",
"19.22.3",
"com.google.ios.youtube/19.22.3 (iPad7,6; U; CPU iPadOS 17_7_10 like Mac OS X; " + Locale.getDefault() + ")",
false,
false,
"iPadOS"
),
/**
* Obsolete and broken client. Here only to migrate data.
*/
@Deprecated
IOS_UNPLUGGED(
33,
"IOS_UNPLUGGED",
"Apple",
"iPhone16,2",
"iOS",
"18.2.22C152",
"8.49",
"dummy user-agent",
true,
true,
"iOS TV"
);
/**
@ -173,7 +216,6 @@ public enum ClientType {
/**
* Android constructor.
*/
@SuppressWarnings("ConstantLocale")
ClientType(int id,
String clientName,
@NonNull String packageName,

View file

@ -48,7 +48,9 @@ public class SpoofVideoStreamsPatch {
}
public static boolean spoofingToClientWithNoMultiAudioStreams() {
return isPatchIncluded() && BaseSettings.SPOOF_VIDEO_STREAMS.get();
return isPatchIncluded()
&& BaseSettings.SPOOF_VIDEO_STREAMS.get()
&& BaseSettings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() != ClientType.IPADOS;
}
/**

View file

@ -14,12 +14,13 @@ public class ForceOriginalAudioPatch {
* Injection point.
*/
public static void setPreferredLanguage() {
if (Settings.FORCE_ORIGINAL_AUDIO.get()) {
// None of the current spoof clients support audio track menu,
// And all are un-authenticated and can request any language code
// (authenticated requests ignore the language code and always use the account language).
// To still support force original audio, if it's enabled then pick a language
// that is not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
if (Settings.FORCE_ORIGINAL_AUDIO.get()
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
// If client spoofing does not use authentication and lacks multi-audio streams,
// then can use any language code for the request and if that requested language is
// not available YT uses the original audio language. Authenticated requests ignore
// the language code and always use the account language. Use a language that is
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
// but the language is also supported natively by the Meta Quest device that
// Android VR is spoofing.
AppLanguage override = AppLanguage.SV;

View file

@ -3,6 +3,7 @@ package app.revanced.extension.youtube.patches.spoof;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_CREATOR;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_43_32;
import static app.revanced.extension.shared.spoof.ClientType.ANDROID_VR_1_61_48;
import static app.revanced.extension.shared.spoof.ClientType.IPADOS;
import static app.revanced.extension.shared.spoof.ClientType.VISIONOS;
import java.util.List;
@ -20,8 +21,10 @@ public class SpoofVideoStreamsPatch {
public static void setClientOrderToUse() {
List<ClientType> availableClients = List.of(
ANDROID_VR_1_61_48,
ANDROID_CREATOR,
VISIONOS,
IPADOS,
// Creator must be next to last, because livestreams fetch successfully but don't playback.
ANDROID_CREATOR,
// VR 1.43 must be last as spoof streaming data handles it slightly differently.
ANDROID_VR_1_43_32
);

View file

@ -0,0 +1,57 @@
package app.revanced.extension.youtube.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import android.content.Context;
import android.util.AttributeSet;
import app.revanced.extension.shared.settings.preference.SortedListPreference;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
@SuppressWarnings({"deprecation", "unused"})
public class SpoofAudioSelectorListPreference extends SortedListPreference {
private final boolean available;
{
if (SpoofVideoStreamsPatch.getLanguageOverride() != null) {
available = false;
super.setEnabled(false);
super.setSummary(str("revanced_spoof_video_streams_language_not_available"));
} else {
available = true;
}
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public SpoofAudioSelectorListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SpoofAudioSelectorListPreference(Context context) {
super(context);
}
@Override
public void setEnabled(boolean enabled) {
if (!available) {
return;
}
super.setEnabled(enabled);
}
@Override
public void setSummary(CharSequence summary) {
if (!available) {
return;
}
super.setSummary(summary);
}
}

View file

@ -78,18 +78,25 @@ public class SpoofStreamingDataSideEffectsPreference extends Preference {
Logger.printDebug(() -> "Updating spoof stream side effects preference");
setEnabled(BaseSettings.SPOOF_VIDEO_STREAMS.get());
String title = str("revanced_spoof_video_streams_about_title");
// Currently only Android VR and VisionOS are supported, and both have the same base side effects.
String summary = str("revanced_spoof_video_streams_about_android_summary");
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
setTitle(str("revanced_spoof_video_streams_about_title"));
if (clientType == ClientType.VISIONOS) {
String summary = str(clientType == ClientType.IPADOS
? "revanced_spoof_video_streams_about_ipados_summary"
// visionOS has same base side effects as Android VR.
: "revanced_spoof_video_streams_about_android_summary");
if (clientType == ClientType.IPADOS) {
summary = str("revanced_spoof_video_streams_about_no_av1")
+ '\n' + summary;
} else if (clientType == ClientType.VISIONOS) {
summary = str("revanced_spoof_video_streams_about_experimental")
+ '\n' + summary
+ '\n' + str("revanced_spoof_video_streams_about_no_av1");
+ '\n' + str("revanced_spoof_video_streams_about_no_av1")
+ '\n' + str("revanced_spoof_video_streams_about_kids_videos");
} else {
summary += '\n' + str("revanced_spoof_video_streams_about_kids_videos");
}
setTitle(title);
setSummary(summary);
}
}