feat(YouTube): Add Disable video codecs patch (#5981)

This commit is contained in:
LisoUseInAIKyrios
2025-09-23 22:06:02 +04:00
committed by GitHub
parent ee4755646b
commit bfbffbd1f5
15 changed files with 181 additions and 94 deletions
@@ -53,7 +53,7 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
* Set by subclasses if Strings cannot be added as a resource.
*/
@Nullable
protected static String restartDialogTitle, restartDialogMessage, restartDialogButtonText, confirmDialogTitle;
protected static CharSequence restartDialogTitle, restartDialogMessage, restartDialogButtonText, confirmDialogTitle;
private final SharedPreferences.OnSharedPreferenceChangeListener listener = (sharedPreferences, str) -> {
try {
@@ -125,10 +125,13 @@ public abstract class AbstractPreferenceFragment extends PreferenceFragment {
showingUserDialogMessage = true;
CharSequence message = BulletPointPreference.formatIntoBulletPoints(
Objects.requireNonNull(setting.userDialogMessage).toString());
Pair<Dialog, LinearLayout> dialogPair = CustomDialog.create(
context,
confirmDialogTitle, // Title.
Objects.requireNonNull(setting.userDialogMessage).toString(), // No message.
message,
null, // No EditText.
null, // OK button text.
() -> {
@@ -15,7 +15,15 @@ import android.util.AttributeSet;
@SuppressWarnings({"unused", "deprecation"})
public class BulletPointPreference extends Preference {
public static SpannedString formatIntoBulletPoints(CharSequence source) {
/**
* Replaces bullet points with styled spans.
*/
public static CharSequence formatIntoBulletPoints(CharSequence source) {
final char bulletPoint = '•';
if (TextUtils.indexOf(source, bulletPoint) < 0) {
return source; // Nothing to do.
}
SpannableStringBuilder builder = new SpannableStringBuilder(source);
int lineStart = 0;
@@ -26,7 +34,7 @@ public class BulletPointPreference extends Preference {
if (lineEnd < 0) lineEnd = length;
// Apply BulletSpan only if the line starts with the '•' character.
if (lineEnd > lineStart && builder.charAt(lineStart) == '•') {
if (lineEnd > lineStart && builder.charAt(lineStart) == bulletPoint) {
int deleteEnd = lineStart + 1; // remove the bullet itself
// If there's a single space right after the bullet, remove that too.
@@ -42,11 +42,8 @@ final class PlayerRoutes {
JSONObject context = new JSONObject();
AppLanguage language = SpoofVideoStreamsPatch.getLanguageOverride();
if (language == null || clientType == ANDROID_VR_1_43_32) {
if (language == null) {
// Force original audio has not overrode the language.
// Or if YT has fallen over to the last unauthenticated client (VR 1.43), then
// always use the app language because forcing an audio stream of specific languages
// can sometimes fail so it's better to try and load something rather than nothing.
language = BaseSettings.SPOOF_VIDEO_STREAMS_LANGUAGE.get();
}
//noinspection ExtractMethodRecommender
@@ -58,10 +58,10 @@ public class CustomDialog {
* @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked.
* @return The Dialog and its main LinearLayout container.
*/
public static Pair<Dialog, LinearLayout> create(Context context, String title, CharSequence message,
@Nullable EditText editText, String okButtonText,
public static Pair<Dialog, LinearLayout> create(Context context, CharSequence title, CharSequence message,
@Nullable EditText editText, CharSequence okButtonText,
Runnable onOkClick, Runnable onCancelClick,
@Nullable String neutralButtonText,
@Nullable CharSequence neutralButtonText,
@Nullable Runnable onNeutralClick,
boolean dismissDialogOnNeutralClick) {
Logger.printDebug(() -> "Creating custom dialog with title: " + title);
@@ -85,9 +85,9 @@ public class CustomDialog {
* @param onNeutralClick Action to perform when the Neutral button is clicked, or null if no Neutral button is needed.
* @param dismissDialogOnNeutralClick If the dialog should be dismissed when the Neutral button is clicked.
*/
private CustomDialog(Context context, String title, CharSequence message, @Nullable EditText editText,
String okButtonText, Runnable onOkClick, Runnable onCancelClick,
@Nullable String neutralButtonText, @Nullable Runnable onNeutralClick,
private CustomDialog(Context context, CharSequence title, CharSequence message, @Nullable EditText editText,
CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick,
@Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick,
boolean dismissDialogOnNeutralClick) {
this.context = context;
this.dialog = new Dialog(context);
@@ -139,7 +139,7 @@ public class CustomDialog {
*
* @param title The title text to display.
*/
private void addTitle(String title) {
private void addTitle(CharSequence title) {
if (TextUtils.isEmpty(title)) return;
TextView titleView = new TextView(context);
@@ -232,8 +232,8 @@ public class CustomDialog {
* @param onNeutralClick Action for the Neutral button click, or null if no Neutral button.
* @param dismissDialogOnNeutralClick If the dialog should dismiss on Neutral button click.
*/
private void addButtons(String okButtonText, Runnable onOkClick, Runnable onCancelClick,
@Nullable String neutralButtonText, @Nullable Runnable onNeutralClick,
private void addButtons(CharSequence okButtonText, Runnable onOkClick, Runnable onCancelClick,
@Nullable CharSequence neutralButtonText, @Nullable Runnable onNeutralClick,
boolean dismissDialogOnNeutralClick) {
// Button container.
LinearLayout buttonContainer = new LinearLayout(context);
@@ -280,7 +280,7 @@ public class CustomDialog {
* @param dismissDialog If the dialog should dismiss when the button is clicked.
* @return The created Button.
*/
private Button createButton(String text, Runnable onClick, boolean isOkButton, boolean dismissDialog) {
private Button createButton(CharSequence text, Runnable onClick, boolean isOkButton, boolean dismissDialog) {
Button button = new Button(context, null, 0);
button.setText(text);
button.setTextSize(14);
@@ -5,7 +5,7 @@ import android.view.Display;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class DisableHdrPatch {
public class DisableVideoCodecsPatch {
/**
* Injection point.
@@ -15,5 +15,12 @@ public class DisableHdrPatch {
? new int[0]
: capabilities.getSupportedHdrTypes();
}
/**
* Injection point.
*/
public static boolean allowVP9() {
return !Settings.FORCE_AVC_CODEC.get();
}
}
@@ -15,7 +15,8 @@ public class ForceOriginalAudioPatch {
*/
public static void setPreferredLanguage() {
if (Settings.FORCE_ORIGINAL_AUDIO.get()
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()) {
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()
&& !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) {
// 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
@@ -18,7 +18,22 @@ public class SpoofVideoStreamsPatch {
* Injection point.
*/
public static void setClientOrderToUse() {
List<ClientType> availableClients = List.of(
final boolean forceAVC = Settings.FORCE_AVC_CODEC.get();
// VR 1.61 uses VP9/AV1, and cannot force AVC.
ClientType client = Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get();
if (forceAVC && client == ANDROID_VR_1_61_48) {
client = ANDROID_VR_1_43_32; // Use VR 1.43 instead.
}
List<ClientType> availableClients = forceAVC
? List.of(
ANDROID_VR_1_43_32,
VISIONOS,
ANDROID_CREATOR,
ANDROID_VR_1_61_48,
IPADOS)
: List.of(
ANDROID_VR_1_61_48,
VISIONOS,
ANDROID_CREATOR,
@@ -27,6 +42,6 @@ public class SpoofVideoStreamsPatch {
);
app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch.setClientsToUse(
availableClients, Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get());
availableClients, client);
}
}
@@ -48,6 +48,9 @@ import app.revanced.extension.youtube.swipecontrols.SwipeControlsConfigurationPr
public class Settings extends BaseSettings {
// Video
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message");
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_video_quality_last_selected", FALSE);
@@ -56,8 +59,6 @@ public class Settings extends BaseSettings {
public static final BooleanSetting REMEMBER_SHORTS_QUALITY_LAST_SELECTED = new BooleanSetting("revanced_remember_shorts_quality_last_selected", FALSE);
public static final BooleanSetting REMEMBER_VIDEO_QUALITY_LAST_SELECTED_TOAST = new BooleanSetting("revanced_remember_video_quality_last_selected_toast", TRUE, false,
parentsAny(REMEMBER_VIDEO_QUALITY_LAST_SELECTED, REMEMBER_SHORTS_QUALITY_LAST_SELECTED));
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
// Speed
public static final FloatSetting SPEED_TAP_AND_HOLD = new FloatSetting("revanced_speed_tap_and_hold", 2.0f, true);