feat(YouTube Music): Add Force original audio patch (#6036)

This commit is contained in:
LisoUseInAIKyrios 2025-10-01 18:59:16 +04:00 committed by GitHub
parent 9d6731660b
commit d0d53d109e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 341 additions and 226 deletions

View file

@ -1,72 +1,17 @@
package app.revanced.extension.youtube.patches;
import app.revanced.extension.shared.Logger;
import app.revanced.extension.shared.settings.AppLanguage;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings("unused")
public class ForceOriginalAudioPatch {
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
/**
* Injection point.
*/
public static void setPreferredLanguage() {
if (Settings.FORCE_ORIGINAL_AUDIO.get()
&& 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
// 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.NB; // Norwegian Bokmal.
Logger.printDebug(() -> "Setting language override: " + override);
SpoofVideoStreamsPatch.setLanguageOverride(override);
}
}
/**
* Injection point.
*/
public static boolean ignoreDefaultAudioStream(boolean original) {
if (Settings.FORCE_ORIGINAL_AUDIO.get()) {
return false;
}
return original;
}
/**
* Injection point.
*/
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
try {
if (!Settings.FORCE_ORIGINAL_AUDIO.get()) {
return isDefault;
}
if (audioTrackId.isEmpty()) {
// Older app targets can have empty audio tracks and these might be placeholders.
// The real audio tracks are called after these.
return isDefault;
}
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
if (isOriginal) {
Logger.printDebug(() -> "Using audio: " + audioTrackId);
}
return isOriginal;
} catch (Exception ex) {
Logger.printException(() -> "isDefaultAudioStream failure", ex);
return isDefault;
}
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
Settings.FORCE_ORIGINAL_AUDIO.get(),
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
);
}
}

View file

@ -55,6 +55,7 @@ public class Settings extends BaseSettings {
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 BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
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);
@ -75,9 +76,6 @@ public class Settings extends BaseSettings {
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
"0.25\n0.5\n0.75\n1.0\n1.25\n1.5\n1.75\n2.0\n2.5\n3.0\n4.0\n5.0\n6.0\n7.0\n8.0", true);
// Audio
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
// Ads
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true);

View file

@ -1,63 +0,0 @@
package app.revanced.extension.youtube.settings.preference;
import static app.revanced.extension.shared.StringRef.str;
import android.content.Context;
import android.preference.SwitchPreference;
import android.util.AttributeSet;
import app.revanced.extension.shared.spoof.ClientType;
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
import app.revanced.extension.youtube.settings.Settings;
@SuppressWarnings({"deprecation", "unused"})
public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
|| !(Settings.SPOOF_VIDEO_STREAMS.get()
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR);
{
if (!available) {
// Show why force audio is not available.
String summary = str("revanced_force_original_audio_not_available");
super.setSummary(summary);
super.setSummaryOn(summary);
super.setSummaryOff(summary);
super.setEnabled(false);
}
}
public ForceOriginalAudioSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public ForceOriginalAudioSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public ForceOriginalAudioSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ForceOriginalAudioSwitchPreference(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);
}
}