feat(YouTube Music - Spoof streaming data): Remove Android Creator and iOS Music, add Android Music (Close https://github.com/inotia00/ReVanced_Extended/issues/2617)

This commit is contained in:
inotia00 2024-12-31 21:24:41 +09:00
parent 00fbd318e7
commit 2b61bfd71f
6 changed files with 306 additions and 355 deletions

View File

@ -1,327 +0,0 @@
package app.revanced.extension.shared.patches.client;
import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingDataMusic;
import android.os.Build;
import androidx.annotation.Nullable;
import app.revanced.extension.shared.settings.BaseSettings;
public class AppClient {
// IOS
/**
* Video not playable: Paid / Movie / Private / Age-restricted
* Note: Audio track available
*/
private static final String PACKAGE_NAME_IOS = "com.google.ios.youtube";
/**
* The hardcoded client version of the iOS app used for InnerTube requests with this client.
*
* <p>
* It can be extracted by getting the latest release version of the app on
* <a href="https://apps.apple.com/us/app/youtube-watch-listen-stream/id544007664/">the App
* Store page of the YouTube app</a>, in the {@code Whats New} section.
* </p>
*/
private static final String CLIENT_VERSION_IOS = forceAVC()
? "17.40.5"
: "19.29.1";
/**
* The device machine id for the iPhone 15 Pro Max (iPhone16,2), used to get HDR with AV1 hardware decoding.
*
* <p>
* See <a href="https://gist.github.com/adamawolf/3048717">this GitHub Gist</a> for more
* information.
* </p>
*/
private static final String DEVICE_MODEL_IOS = forceAVC()
? "iPhone12,5" // 11 Pro Max. (last device with iOS 13)
: "iPhone16,2"; // 15 Pro Max.
private static final String OS_VERSION_IOS = forceAVC()
? "13.7.17H35" // Last release of iOS 13.
: "17.7.2.21H221";
private static final String USER_AGENT_VERSION_IOS = forceAVC()
? "13_7"
: "17_7_2";
private static final String USER_AGENT_IOS =
iOSUserAgent(PACKAGE_NAME_IOS, CLIENT_VERSION_IOS);
// IOS UNPLUGGED
/**
* Video not playable: Paid / Movie
* Note: Audio track available
*/
private static final String PACKAGE_NAME_IOS_UNPLUGGED = "com.google.ios.youtubeunplugged";
/**
* The hardcoded client version of the iOS app used for InnerTube requests with this client.
*
* <p>
* It can be extracted by getting the latest release version of the app on
* <a href="https://apps.apple.com/us/app/youtube-tv/id1193350206/">the App
* Store page of the YouTube TV app</a>, in the {@code Whats New} section.
* </p>
*/
private static final String CLIENT_VERSION_IOS_UNPLUGGED = forceAVC()
? "6.45"
: "8.33";
private static final String USER_AGENT_IOS_UNPLUGGED =
iOSUserAgent(PACKAGE_NAME_IOS_UNPLUGGED, CLIENT_VERSION_IOS_UNPLUGGED);
// IOS MUSIC
/**
* Video not playable: All videos that can't be played on YouTube Music
*/
private static final String PACKAGE_NAME_IOS_MUSIC = "com.google.ios.youtubemusic";
/**
* The hardcoded client version of the iOS app used for InnerTube requests with this client.
*
* <p>
* It can be extracted by getting the latest release version of the app on
* <a href="https://apps.apple.com/us/app/youtube-music/id1017492454/">the App
* Store page of the YouTube Music app</a>, in the {@code Whats New} section.
* </p>
*/
private static final String CLIENT_VERSION_IOS_MUSIC = "7.04";
private static final String USER_AGENT_IOS_MUSIC =
iOSUserAgent(PACKAGE_NAME_IOS_MUSIC, CLIENT_VERSION_IOS_MUSIC);
// ANDROID VR
/**
* Video not playable: Kids
* Note: Audio track is not available
* <p>
* Package name for YouTube VR (Google DayDream): com.google.android.apps.youtube.vr (Deprecated)
* Package name for YouTube VR (Meta Quests): com.google.android.apps.youtube.vr.oculus
* Package name for YouTube VR (ByteDance Pico 4): com.google.android.apps.youtube.vr.pico
*/
private static final String PACKAGE_NAME_ANDROID_VR = "com.google.android.apps.youtube.vr.oculus";
/**
* The hardcoded client version of the Android VR app used for InnerTube requests with this client.
*
* <p>
* It can be extracted by getting the latest release version of the app on
* <a href="https://www.meta.com/en-us/experiences/2002317119880945/">the App
* Store page of the YouTube app</a>, in the {@code Additional details} section.
* </p>
*/
private static final String CLIENT_VERSION_ANDROID_VR = "1.61.48";
/**
* The device machine id for the Meta Quest 3, used to get opus codec with the Android VR client.
*
* <p>
* See <a href="https://dumps.tadiphone.dev/dumps/oculus/eureka">this GitLab</a> for more
* information.
* </p>
*/
private static final String DEVICE_MODEL_ANDROID_VR = "Quest 3";
private static final String OS_VERSION_ANDROID_VR = "12";
/**
* The SDK version for Android 12 is 31,
* but for some reason the build.props for the {@code Quest 3} state that the SDK version is 32.
*/
private static final String ANDROID_SDK_VERSION_ANDROID_VR = "32";
private static final String USER_AGENT_ANDROID_VR =
androidUserAgent(PACKAGE_NAME_ANDROID_VR, CLIENT_VERSION_ANDROID_VR, OS_VERSION_ANDROID_VR);
// ANDROID UNPLUGGED
/**
* Video not playable: Playlists / Music
* Note: Audio track is not available
*/
private static final String PACKAGE_NAME_ANDROID_UNPLUGGED = "com.google.android.apps.youtube.unplugged";
private static final String CLIENT_VERSION_ANDROID_UNPLUGGED = "8.16.0";
/**
* The device machine id for the Chromecast with Google TV 4K.
*
* <p>
* See <a href="https://dumps.tadiphone.dev/dumps/google/kirkwood">this GitLab</a> for more
* information.
* </p>
*/
private static final String DEVICE_MODEL_ANDROID_UNPLUGGED = "Google TV Streamer";
private static final String OS_VERSION_ANDROID_UNPLUGGED = "14";
private static final String ANDROID_SDK_VERSION_ANDROID_UNPLUGGED = "34";
private static final String USER_AGENT_ANDROID_UNPLUGGED =
androidUserAgent(PACKAGE_NAME_ANDROID_UNPLUGGED, CLIENT_VERSION_ANDROID_UNPLUGGED, OS_VERSION_ANDROID_UNPLUGGED);
private AppClient() {
}
private static String androidUserAgent(String packageName, String clientVersion, String osVersion) {
return packageName +
"/" +
clientVersion +
" (Linux; U; Android " +
osVersion +
"; GB) gzip";
}
private static String iOSUserAgent(String packageName, String clientVersion) {
return packageName +
"/" +
clientVersion +
"(" +
DEVICE_MODEL_IOS +
"; U; CPU iOS " +
USER_AGENT_VERSION_IOS +
" like Mac OS X)";
}
public enum ClientType {
ANDROID_VR(28,
DEVICE_MODEL_ANDROID_VR,
OS_VERSION_ANDROID_VR,
USER_AGENT_ANDROID_VR,
ANDROID_SDK_VERSION_ANDROID_VR,
CLIENT_VERSION_ANDROID_VR,
true,
false,
"Android VR"
),
ANDROID_UNPLUGGED(29,
DEVICE_MODEL_ANDROID_UNPLUGGED,
OS_VERSION_ANDROID_UNPLUGGED,
USER_AGENT_ANDROID_UNPLUGGED,
ANDROID_SDK_VERSION_ANDROID_UNPLUGGED,
CLIENT_VERSION_ANDROID_UNPLUGGED,
true,
false,
"Android TV"
),
IOS_UNPLUGGED(33,
DEVICE_MODEL_IOS,
OS_VERSION_IOS,
USER_AGENT_IOS_UNPLUGGED,
null,
CLIENT_VERSION_IOS_UNPLUGGED,
true,
false,
forceAVC()
? "iOS TV Force AVC"
: "iOS TV"
),
IOS(5,
DEVICE_MODEL_IOS,
OS_VERSION_IOS,
USER_AGENT_IOS,
null,
CLIENT_VERSION_IOS,
false,
true,
forceAVC()
? "iOS Force AVC"
: "iOS"
),
IOS_MUSIC(
26,
DEVICE_MODEL_IOS,
OS_VERSION_IOS,
USER_AGENT_IOS_MUSIC,
null,
CLIENT_VERSION_IOS_MUSIC,
true,
false,
"iOS Music"
);
/**
* YouTube
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
*/
public final int id;
public final String clientName;
/**
* Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model)
*/
public final String deviceModel;
/**
* Device OS version.
*/
public final String osVersion;
/**
* Player user-agent.
*/
public final String userAgent;
/**
* Android SDK version, equivalent to {@link Build.VERSION#SDK} (System property: ro.build.version.sdk)
* Field is null if not applicable.
*/
@Nullable
public final String androidSdkVersion;
/**
* App version.
*/
public final String clientVersion;
/**
* If the client can access the API logged in.
*/
public final boolean canLogin;
/**
* If a poToken should be used.
*/
public final boolean usePoToken;
/**
* Friendly name displayed in stats for nerds.
*/
public final String friendlyName;
ClientType(int id,
String deviceModel,
String osVersion,
String userAgent,
@Nullable String androidSdkVersion,
String clientVersion,
boolean canLogin,
boolean usePoToken,
String friendlyName
) {
this.id = id;
this.clientName = name();
this.deviceModel = deviceModel;
this.clientVersion = clientVersion;
this.osVersion = osVersion;
this.androidSdkVersion = androidSdkVersion;
this.userAgent = userAgent;
this.canLogin = canLogin;
this.usePoToken = usePoToken;
this.friendlyName = friendlyName;
}
private static final ClientType[] CLIENT_ORDER_TO_USE_YOUTUBE = {
ANDROID_VR,
ANDROID_UNPLUGGED,
IOS_UNPLUGGED,
IOS,
};
private static final ClientType[] CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC = {
ANDROID_VR,
IOS_MUSIC,
};
}
private static boolean forceAVC() {
return BaseSettings.SPOOF_STREAMING_DATA_IOS_FORCE_AVC.get();
}
public static ClientType[] getAvailableClientTypes() {
return SpoofStreamingDataMusic()
? ClientType.CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC
: ClientType.CLIENT_ORDER_TO_USE_YOUTUBE;
}
}

View File

@ -0,0 +1,294 @@
package app.revanced.extension.shared.patches.client
import android.os.Build
import app.revanced.extension.shared.patches.PatchStatus
import app.revanced.extension.shared.settings.BaseSettings
object AppClient {
// IOS
/**
* Video not playable: Paid / Movie / Private / Age-restricted
* Note: Audio track available
*/
private const val PACKAGE_NAME_IOS = "com.google.ios.youtube"
/**
* The hardcoded client version of the iOS app used for InnerTube requests with this client.
*
* It can be extracted by getting the latest release version of the app on
* [the App Store page of the YouTube app](https://apps.apple.com/us/app/youtube-watch-listen-stream/id544007664/),
* in the `Whats New` section.
*/
private val CLIENT_VERSION_IOS = if (forceAVC())
"17.40.5"
else
"19.29.1"
/**
* The device machine id for the iPhone 15 Pro Max (iPhone16,2),
* used to get HDR with AV1 hardware decoding.
* See [this GitHub Gist](https://gist.github.com/adamawolf/3048717) for more information.
*/
private val DEVICE_MODEL_IOS = if (forceAVC())
"iPhone12,5" // 11 Pro Max. (last device with iOS 13)
else
"iPhone16,2" // 15 Pro Max.
private val OS_VERSION_IOS = if (forceAVC())
"13.7.17H35" // Last release of iOS 13.
else
"17.7.2.21H221"
private val USER_AGENT_VERSION_IOS = if (forceAVC())
"13_7"
else
"17_7_2"
private val USER_AGENT_IOS = iOSUserAgent(PACKAGE_NAME_IOS, CLIENT_VERSION_IOS)
// IOS UNPLUGGED
/**
* Video not playable: Paid / Movie
* Note: Audio track available
*/
private const val PACKAGE_NAME_IOS_UNPLUGGED = "com.google.ios.youtubeunplugged"
/**
* The hardcoded client version of the iOS app used for InnerTube requests with this client.
*
* It can be extracted by getting the latest release version of the app on
* [the App Store page of the YouTube TV app](https://apps.apple.com/us/app/youtube-tv/id1193350206/),
* in the `Whats New` section.
*/
private val CLIENT_VERSION_IOS_UNPLUGGED = if (forceAVC())
"6.45"
else
"8.33"
private val USER_AGENT_IOS_UNPLUGGED =
iOSUserAgent(PACKAGE_NAME_IOS_UNPLUGGED, CLIENT_VERSION_IOS_UNPLUGGED)
// ANDROID VR
/**
* Video not playable: Kids
* Note: Audio track is not available
*
* Package name for YouTube VR (Google DayDream): com.google.android.apps.youtube.vr (Deprecated)
* Package name for YouTube VR (Meta Quests): com.google.android.apps.youtube.vr.oculus
* Package name for YouTube VR (ByteDance Pico 4): com.google.android.apps.youtube.vr.pico
*/
private const val PACKAGE_NAME_ANDROID_VR = "com.google.android.apps.youtube.vr.oculus"
/**
* The hardcoded client version of the Android VR app used for InnerTube requests with this client.
*
* It can be extracted by getting the latest release version of the app on
* [the App Store page of the YouTube app](https://www.meta.com/en-us/experiences/2002317119880945/),
* in the `Additional details` section.
*/
private const val CLIENT_VERSION_ANDROID_VR = "1.61.48"
/**
* The device machine id for the Meta Quest 3, used to get opus codec with the Android VR client.
* See [this GitLab](https://dumps.tadiphone.dev/dumps/oculus/eureka) for more information.
*/
private const val DEVICE_MODEL_ANDROID_VR = "Quest 3"
private const val OS_VERSION_ANDROID_VR = "12"
/**
* The SDK version for Android 12 is 31,
* but for some reason the build.props for the `Quest 3` state that the SDK version is 32.
*/
private const val ANDROID_SDK_VERSION_ANDROID_VR = "32"
private val USER_AGENT_ANDROID_VR =
androidUserAgent(PACKAGE_NAME_ANDROID_VR, CLIENT_VERSION_ANDROID_VR, OS_VERSION_ANDROID_VR)
// ANDROID UNPLUGGED
/**
* Video not playable: Playlists / Music
* Note: Audio track is not available
*/
private const val PACKAGE_NAME_ANDROID_UNPLUGGED = "com.google.android.apps.youtube.unplugged"
private const val CLIENT_VERSION_ANDROID_UNPLUGGED = "8.16.0"
/**
* The device machine id for the Chromecast with Google TV 4K.
* See [this GitLab](https://dumps.tadiphone.dev/dumps/google/kirkwood) for more information.
*/
private const val DEVICE_MODEL_ANDROID_UNPLUGGED = "Google TV Streamer"
private const val OS_VERSION_ANDROID_UNPLUGGED = "14"
private const val ANDROID_SDK_VERSION_ANDROID_UNPLUGGED = "34"
private val USER_AGENT_ANDROID_UNPLUGGED = androidUserAgent(
PACKAGE_NAME_ANDROID_UNPLUGGED,
CLIENT_VERSION_ANDROID_UNPLUGGED,
OS_VERSION_ANDROID_UNPLUGGED
)
// ANDROID MUSIC
/**
* Video not playable: All videos that can't be played on YouTube Music
*/
private const val PACKAGE_NAME_ANDROID_MUSIC = "com.google.android.apps.youtube.music"
/**
* Older client versions don't seem to require poToken.
* It is not the default client yet, as it requires sufficient testing.
*/
private const val CLIENT_VERSION_ANDROID_MUSIC = "4.27.53"
private val ANDROID_SDK_VERSION_ANDROID_MUSIC = Build.VERSION.SDK_INT.toString()
private val USER_AGENT_ANDROID_MUSIC = androidUserAgent(
PACKAGE_NAME_ANDROID_MUSIC,
CLIENT_VERSION_ANDROID_MUSIC
)
private fun androidUserAgent(
packageName: String,
clientVersion: String,
osVersion: String? = Build.VERSION.RELEASE
): String {
return packageName +
"/" +
clientVersion +
" (Linux; U; Android " +
osVersion +
"; GB) gzip"
}
private fun iOSUserAgent(packageName: String, clientVersion: String): String {
return packageName +
"/" +
clientVersion +
"(" +
DEVICE_MODEL_IOS +
"; U; CPU iOS " +
USER_AGENT_VERSION_IOS +
" like Mac OS X)"
}
private fun forceAVC(): Boolean {
return BaseSettings.SPOOF_STREAMING_DATA_IOS_FORCE_AVC.get()
}
@JvmStatic
val availableClientTypes: Array<ClientType>
get() = if (PatchStatus.SpoofStreamingDataMusic())
ClientType.CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC
else
ClientType.CLIENT_ORDER_TO_USE_YOUTUBE
enum class ClientType(
/**
* [YouTube client type](https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients)
*/
val id: Int,
/**
* Device model, equivalent to [Build.MODEL] (System property: ro.product.model)
*/
@JvmField
val deviceModel: String? = Build.MODEL,
/**
* Device OS version, equivalent to [Build.VERSION.RELEASE] (System property: ro.system.build.version.release)
*/
@JvmField
val osVersion: String? = Build.VERSION.RELEASE,
/**
* Client user-agent.
*/
@JvmField
val userAgent: String,
/**
* Android SDK version, equivalent to [Build.VERSION.SDK] (System property: ro.build.version.sdk)
* Field is null if not applicable.
*/
@JvmField
val androidSdkVersion: String? = null,
/**
* App version.
*/
@JvmField
val clientVersion: String,
/**
* If the client can access the API logged in.
*/
@JvmField
val canLogin: Boolean? = true,
/**
* If a poToken should be used.
*/
@JvmField
val usePoToken: Boolean? = false,
/**
* Friendly name displayed in stats for nerds.
*/
@JvmField
val friendlyName: String
) {
ANDROID_VR(
id = 28,
deviceModel = DEVICE_MODEL_ANDROID_VR,
osVersion = OS_VERSION_ANDROID_VR,
userAgent = USER_AGENT_ANDROID_VR,
androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_VR,
clientVersion = CLIENT_VERSION_ANDROID_VR,
friendlyName = "Android VR"
),
ANDROID_UNPLUGGED(
id = 29,
deviceModel = DEVICE_MODEL_ANDROID_UNPLUGGED,
osVersion = OS_VERSION_ANDROID_UNPLUGGED,
userAgent = USER_AGENT_ANDROID_UNPLUGGED,
androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_UNPLUGGED,
clientVersion = CLIENT_VERSION_ANDROID_UNPLUGGED,
friendlyName = "Android TV"
),
IOS_UNPLUGGED(
id = 33,
deviceModel = DEVICE_MODEL_IOS,
osVersion = OS_VERSION_IOS,
userAgent = USER_AGENT_IOS_UNPLUGGED,
clientVersion = CLIENT_VERSION_IOS_UNPLUGGED,
friendlyName = if (forceAVC())
"iOS TV Force AVC"
else
"iOS TV"
),
IOS(
id = 5,
deviceModel = DEVICE_MODEL_IOS,
osVersion = OS_VERSION_IOS,
userAgent = USER_AGENT_IOS,
clientVersion = CLIENT_VERSION_IOS,
canLogin = false,
usePoToken = true,
friendlyName = if (forceAVC())
"iOS Force AVC"
else
"iOS"
),
ANDROID_MUSIC(
id = 21,
userAgent = USER_AGENT_ANDROID_MUSIC,
androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_MUSIC,
clientVersion = CLIENT_VERSION_ANDROID_MUSIC,
friendlyName = "Android Music"
);
@JvmField
val clientName: String = name
companion object {
val CLIENT_ORDER_TO_USE_YOUTUBE: Array<ClientType> = arrayOf(
ANDROID_VR,
ANDROID_UNPLUGGED,
IOS_UNPLUGGED,
IOS,
)
internal val CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC: Array<ClientType> = arrayOf(
ANDROID_VR,
ANDROID_MUSIC,
)
}
}
}

View File

@ -67,12 +67,10 @@
</string-array>
<string-array name="revanced_spoof_streaming_data_type_entries">
<item>@string/revanced_spoof_streaming_data_type_entry_android_vr</item>
<item>@string/revanced_spoof_streaming_data_type_entry_ios</item>
<item>@string/revanced_spoof_streaming_data_type_entry_ios_music</item>
<item>@string/revanced_spoof_streaming_data_type_entry_android_music</item>
</string-array>
<string-array name="revanced_spoof_streaming_data_type_entry_values">
<item>ANDROID_VR</item>
<item>IOS</item>
<item>IOS_MUSIC</item>
<item>ANDROID_MUSIC</item>
</string-array>
</resources>

View File

@ -468,10 +468,8 @@ Tap the continue button and allow optimization changes."</string>
<string name="revanced_spoof_streaming_data_type_summary">Defines a default client that fetches streaming data.</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_title">Show in Stats for nerds</string>
<string name="revanced_spoof_streaming_data_stats_for_nerds_summary">Shows the client used to fetch streaming data in Stats for nerds.</string>
<string name="revanced_spoof_streaming_data_type_entry_ios">iOS</string>
<string name="revanced_spoof_streaming_data_type_entry_ios_music">iOS Music</string>
<string name="revanced_spoof_streaming_data_type_entry_android_unplugged">Android TV</string>
<string name="revanced_spoof_streaming_data_type_entry_android_vr">Android VR</string>
<string name="revanced_spoof_streaming_data_type_entry_android_music">Android Music</string>
<string name="revanced_sanitize_sharing_links_title">Sanitize sharing links</string>
<string name="revanced_sanitize_sharing_links_summary">Removes tracking query parameters from URLs when sharing links.</string>

View File

@ -241,25 +241,17 @@
<item>HEART_TINT</item>
<item>HIDDEN</item>
</string-array>
<string-array name="revanced_spoof_streaming_data_type_android_entries">
<item>@string/revanced_spoof_streaming_data_type_entry_android_unplugged</item>
<string-array name="revanced_spoof_streaming_data_type_entries">
<item>@string/revanced_spoof_streaming_data_type_entry_android_vr</item>
</string-array>
<string-array name="revanced_spoof_streaming_data_type_android_entry_values">
<item>ANDROID_UNPLUGGED</item>
<item>ANDROID_VR</item>
</string-array>
<string-array name="revanced_spoof_streaming_data_type_android_ios_entries">
<item>@string/revanced_spoof_streaming_data_type_entry_ios</item>
<item>@string/revanced_spoof_streaming_data_type_entry_android_unplugged</item>
<item>@string/revanced_spoof_streaming_data_type_entry_ios_unplugged</item>
<item>@string/revanced_spoof_streaming_data_type_entry_android_unplugged</item>
<item>@string/revanced_spoof_streaming_data_type_entry_android_vr</item>
<item>@string/revanced_spoof_streaming_data_type_entry_ios</item>
</string-array>
<string-array name="revanced_spoof_streaming_data_type_android_ios_entry_values">
<item>IOS</item>
<item>IOS_UNPLUGGED</item>
<item>ANDROID_UNPLUGGED</item>
<string-array name="revanced_spoof_streaming_data_type_entry_values">
<item>ANDROID_VR</item>
<item>ANDROID_UNPLUGGED</item>
<item>IOS_UNPLUGGED</item>
<item>IOS</item>
</string-array>
<string-array name="revanced_spoof_app_version_target_entries">
</string-array>

View File

@ -1906,15 +1906,11 @@ Tap the continue button and allow optimization changes."</string>
<string name="revanced_spoof_streaming_data_summary_off">"Streaming data is not spoofed. Video playback may not work."</string>
<string name="revanced_spoof_streaming_data_user_dialog_message">Turning off this setting may cause video playback issues.</string>
<string name="revanced_spoof_streaming_data_type_title">Default client</string>
<string name="revanced_spoof_streaming_data_type_entry_ios">iOS</string>
<string name="revanced_spoof_streaming_data_type_entry_ios_music">iOS Music</string>
<string name="revanced_spoof_streaming_data_type_entry_ios_unplugged">iOS TV</string>
<string name="revanced_spoof_streaming_data_type_entry_android_creator">Android Creator</string>
<string name="revanced_spoof_streaming_data_type_entry_android_unplugged">Android TV</string>
<string name="revanced_spoof_streaming_data_type_entry_android_vr">Android VR</string>
<string name="revanced_spoof_streaming_data_type_entry_ios">iOS</string>
<string name="revanced_spoof_streaming_data_type_entry_ios_unplugged">iOS TV</string>
<string name="revanced_spoof_streaming_data_side_effects_title">Spoofing side effects</string>
<string name="revanced_spoof_streaming_data_side_effects_ios">• Not yet found.</string>
<string name="revanced_spoof_streaming_data_side_effects_ios_unplugged">• Movies or paid videos may not play.</string>
<string name="revanced_spoof_streaming_data_side_effects_android">"• Audio track menu is missing.
• Stable volume is not available.
• Disable forced auto audio tracks is not available."</string>