Skip to content

Commit d0d53d1

Browse files
feat(YouTube Music): Add Force original audio patch (#6036)
1 parent 9d67316 commit d0d53d1

File tree

17 files changed

+341
-226
lines changed

17 files changed

+341
-226
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package app.revanced.extension.music.patches;
2+
3+
import app.revanced.extension.music.settings.Settings;
4+
5+
@SuppressWarnings("unused")
6+
public class ForceOriginalAudioPatch {
7+
8+
/**
9+
* Injection point.
10+
*/
11+
public static void setPreferredLanguage() {
12+
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
13+
Settings.FORCE_ORIGINAL_AUDIO.get(),
14+
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
15+
);
16+
}
17+
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,6 @@ public class Settings extends BaseSettings {
3232
// Miscellaneous
3333
public static final EnumSetting<ClientType> SPOOF_VIDEO_STREAMS_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_video_streams_client_type",
3434
ClientType.ANDROID_VR_1_43_32, true, parent(SPOOF_VIDEO_STREAMS));
35+
36+
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", TRUE, true);
3537
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package app.revanced.extension.shared.patches;
2+
3+
import app.revanced.extension.shared.Logger;
4+
import app.revanced.extension.shared.settings.AppLanguage;
5+
import app.revanced.extension.shared.spoof.ClientType;
6+
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
7+
8+
@SuppressWarnings("unused")
9+
public class ForceOriginalAudioPatch {
10+
11+
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
12+
13+
private static volatile boolean enabled = false;
14+
15+
public static void setEnabled(boolean isEnabled, ClientType client) {
16+
enabled = isEnabled;
17+
18+
if (isEnabled
19+
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()
20+
&& !client.useAuth) {
21+
// If client spoofing does not use authentication and lacks multi-audio streams,
22+
// then can use any language code for the request and if that requested language is
23+
// not available YT uses the original audio language. Authenticated requests ignore
24+
// the language code and always use the account language. Use a language that is
25+
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
26+
// but the language is also supported natively by the Meta Quest device that
27+
// Android VR is spoofing.
28+
AppLanguage override = AppLanguage.NB; // Norwegian Bokmal.
29+
Logger.printDebug(() -> "Setting language override: " + override);
30+
SpoofVideoStreamsPatch.setLanguageOverride(override);
31+
}
32+
}
33+
34+
/**
35+
* Injection point.
36+
*/
37+
public static boolean ignoreDefaultAudioStream(boolean original) {
38+
if (enabled) {
39+
return false;
40+
}
41+
return original;
42+
}
43+
44+
/**
45+
* Injection point.
46+
*/
47+
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
48+
try {
49+
if (!enabled) {
50+
return isDefault;
51+
}
52+
53+
if (audioTrackId.isEmpty()) {
54+
// Older app targets can have empty audio tracks and these might be placeholders.
55+
// The real audio tracks are called after these.
56+
return isDefault;
57+
}
58+
59+
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
60+
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
61+
62+
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
63+
if (isOriginal) {
64+
Logger.printDebug(() -> "Using audio: " + audioTrackId);
65+
}
66+
67+
return isOriginal;
68+
} catch (Exception ex) {
69+
Logger.printException(() -> "isDefaultAudioStream failure", ex);
70+
return isDefault;
71+
}
72+
}
73+
}
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
1-
package app.revanced.extension.youtube.settings.preference;
1+
package app.revanced.extension.shared.settings.preference;
22

33
import static app.revanced.extension.shared.StringRef.str;
44

55
import android.content.Context;
66
import android.preference.SwitchPreference;
77
import android.util.AttributeSet;
88

9+
import app.revanced.extension.shared.settings.BaseSettings;
910
import app.revanced.extension.shared.spoof.ClientType;
1011
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
11-
import app.revanced.extension.youtube.settings.Settings;
1212

1313
@SuppressWarnings({"deprecation", "unused"})
1414
public class ForceOriginalAudioSwitchPreference extends SwitchPreference {
1515

1616
// Spoof stream patch is not included, or is not currently spoofing to Android Studio.
1717
private static final boolean available = !SpoofVideoStreamsPatch.isPatchIncluded()
18-
|| !(Settings.SPOOF_VIDEO_STREAMS.get()
19-
&& Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get() == ClientType.ANDROID_CREATOR);
18+
|| !(BaseSettings.SPOOF_VIDEO_STREAMS.get()
19+
&& SpoofVideoStreamsPatch.getPreferredClient() == ClientType.ANDROID_CREATOR);
2020

2121
{
2222
if (!available) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public static void setClientsToUse(List<ClientType> availableClients, ClientType
6666
StreamingDataRequest.setClientOrderToUse(availableClients, client);
6767
}
6868

69+
public static ClientType getPreferredClient() {
70+
return preferredClient;
71+
}
72+
6973
public static boolean spoofingToClientWithNoMultiAudioStreams() {
7074
return isPatchIncluded()
7175
&& SPOOF_STREAMING_DATA
Lines changed: 4 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,72 +1,17 @@
11
package app.revanced.extension.youtube.patches;
22

3-
import app.revanced.extension.shared.Logger;
4-
import app.revanced.extension.shared.settings.AppLanguage;
5-
import app.revanced.extension.shared.spoof.SpoofVideoStreamsPatch;
63
import app.revanced.extension.youtube.settings.Settings;
74

85
@SuppressWarnings("unused")
96
public class ForceOriginalAudioPatch {
107

11-
private static final String DEFAULT_AUDIO_TRACKS_SUFFIX = ".4";
12-
138
/**
149
* Injection point.
1510
*/
1611
public static void setPreferredLanguage() {
17-
if (Settings.FORCE_ORIGINAL_AUDIO.get()
18-
&& SpoofVideoStreamsPatch.spoofingToClientWithNoMultiAudioStreams()
19-
&& !Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get().useAuth) {
20-
// If client spoofing does not use authentication and lacks multi-audio streams,
21-
// then can use any language code for the request and if that requested language is
22-
// not available YT uses the original audio language. Authenticated requests ignore
23-
// the language code and always use the account language. Use a language that is
24-
// not auto-dubbed by YouTube: https://support.google.com/youtube/answer/15569972
25-
// but the language is also supported natively by the Meta Quest device that
26-
// Android VR is spoofing.
27-
AppLanguage override = AppLanguage.NB; // Norwegian Bokmal.
28-
Logger.printDebug(() -> "Setting language override: " + override);
29-
SpoofVideoStreamsPatch.setLanguageOverride(override);
30-
}
31-
}
32-
33-
/**
34-
* Injection point.
35-
*/
36-
public static boolean ignoreDefaultAudioStream(boolean original) {
37-
if (Settings.FORCE_ORIGINAL_AUDIO.get()) {
38-
return false;
39-
}
40-
return original;
41-
}
42-
43-
/**
44-
* Injection point.
45-
*/
46-
public static boolean isDefaultAudioStream(boolean isDefault, String audioTrackId, String audioTrackDisplayName) {
47-
try {
48-
if (!Settings.FORCE_ORIGINAL_AUDIO.get()) {
49-
return isDefault;
50-
}
51-
52-
if (audioTrackId.isEmpty()) {
53-
// Older app targets can have empty audio tracks and these might be placeholders.
54-
// The real audio tracks are called after these.
55-
return isDefault;
56-
}
57-
58-
Logger.printDebug(() -> "default: " + String.format("%-5s", isDefault) + " id: "
59-
+ String.format("%-8s", audioTrackId) + " name:" + audioTrackDisplayName);
60-
61-
final boolean isOriginal = audioTrackId.endsWith(DEFAULT_AUDIO_TRACKS_SUFFIX);
62-
if (isOriginal) {
63-
Logger.printDebug(() -> "Using audio: " + audioTrackId);
64-
}
65-
66-
return isOriginal;
67-
} catch (Exception ex) {
68-
Logger.printException(() -> "isDefaultAudioStream failure", ex);
69-
return isDefault;
70-
}
12+
app.revanced.extension.shared.patches.ForceOriginalAudioPatch.setEnabled(
13+
Settings.FORCE_ORIGINAL_AUDIO.get(),
14+
Settings.SPOOF_VIDEO_STREAMS_CLIENT_TYPE.get()
15+
);
7116
}
7217
}

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

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public class Settings extends BaseSettings {
5555
public static final BooleanSetting ADVANCED_VIDEO_QUALITY_MENU = new BooleanSetting("revanced_advanced_video_quality_menu", TRUE);
5656
public static final BooleanSetting DISABLE_HDR_VIDEO = new BooleanSetting("revanced_disable_hdr_video", FALSE);
5757
public static final BooleanSetting FORCE_AVC_CODEC = new BooleanSetting("revanced_force_avc_codec", FALSE, true, "revanced_force_avc_codec_user_dialog_message");
58+
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
5859
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_WIFI = new IntegerSetting("revanced_video_quality_default_wifi", -2);
5960
public static final IntegerSetting VIDEO_QUALITY_DEFAULT_MOBILE = new IntegerSetting("revanced_video_quality_default_mobile", -2);
6061
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 {
7576
public static final StringSetting CUSTOM_PLAYBACK_SPEEDS = new StringSetting("revanced_custom_playback_speeds",
7677
"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);
7778

78-
// Audio
79-
public static final BooleanSetting FORCE_ORIGINAL_AUDIO = new BooleanSetting("revanced_force_original_audio", FALSE, true);
80-
8179
// Ads
8280
public static final BooleanSetting HIDE_CREATOR_STORE_SHELF = new BooleanSetting("revanced_hide_creator_store_shelf", TRUE);
8381
public static final BooleanSetting HIDE_END_SCREEN_STORE_BANNER = new BooleanSetting("revanced_hide_end_screen_store_banner", TRUE, true);

patches/api/patches.api

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -459,9 +459,14 @@ public final class app/revanced/patches/music/misc/spoof/UserAgentClientSpoofPat
459459
public static final fun getUserAgentClientSpoofPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
460460
}
461461

462+
public final class app/revanced/patches/music/misc/tracks/ForceOriginalAudioPatchKt {
463+
public static final fun getForceOriginalAudioPatch ()Lapp/revanced/patcher/patch/BytecodePatch;
464+
}
465+
462466
public final class app/revanced/patches/music/playservice/VersionCheckPatchKt {
463467
public static final fun getVersionCheckPatch ()Lapp/revanced/patcher/patch/ResourcePatch;
464468
public static final fun is_7_33_or_greater ()Z
469+
public static final fun is_8_10_or_greater ()Z
465470
public static final fun is_8_11_or_greater ()Z
466471
public static final fun is_8_15_or_greater ()Z
467472
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package app.revanced.patches.music.misc.tracks
2+
3+
import app.revanced.patches.music.misc.extension.sharedExtensionPatch
4+
import app.revanced.patches.music.misc.settings.PreferenceScreen
5+
import app.revanced.patches.music.misc.settings.settingsPatch
6+
import app.revanced.patches.music.playservice.is_8_10_or_greater
7+
import app.revanced.patches.music.playservice.versionCheckPatch
8+
import app.revanced.patches.music.shared.mainActivityOnCreateFingerprint
9+
import app.revanced.patches.shared.misc.audio.forceOriginalAudioPatch
10+
11+
private const val EXTENSION_CLASS_DESCRIPTOR =
12+
"Lapp/revanced/extension/music/patches/ForceOriginalAudioPatch;"
13+
14+
@Suppress("unused")
15+
val forceOriginalAudioPatch = forceOriginalAudioPatch(
16+
block = {
17+
dependsOn(
18+
sharedExtensionPatch,
19+
settingsPatch,
20+
versionCheckPatch
21+
)
22+
23+
compatibleWith(
24+
"com.google.android.apps.youtube.music"(
25+
"7.29.52",
26+
"8.10.52"
27+
)
28+
)
29+
},
30+
fixUseLocalizedAudioTrackFlag = is_8_10_or_greater,
31+
mainActivityOnCreateFingerprint = mainActivityOnCreateFingerprint,
32+
subclassExtensionClassDescriptor = EXTENSION_CLASS_DESCRIPTOR,
33+
preferenceScreen = PreferenceScreen.MISC,
34+
)

patches/src/main/kotlin/app/revanced/patches/music/playservice/VersionCheckPatch.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import app.revanced.util.findPlayStoreServicesVersion
77

88
var is_7_33_or_greater = false
99
private set
10+
var is_8_10_or_greater = false
11+
private set
1012
var is_8_11_or_greater = false
1113
private set
1214
var is_8_15_or_greater = false
@@ -22,6 +24,7 @@ val versionCheckPatch = resourcePatch(
2224

2325
// All bug fix releases always seem to use the same play store version as the minor version.
2426
is_7_33_or_greater = 245199000 <= playStoreServicesVersion
27+
is_8_10_or_greater = 244799000 <= playStoreServicesVersion
2528
is_8_11_or_greater = 251199000 <= playStoreServicesVersion
2629
is_8_15_or_greater = 251530000 <= playStoreServicesVersion
2730
}

0 commit comments

Comments
 (0)