fix(YouTube - Spoof streaming data): Add patch option Use iOS client and add user dialog for warning

This commit is contained in:
inotia00
2025-03-26 21:03:35 +09:00
parent dcb72cc803
commit 0639b559b1
11 changed files with 155 additions and 25 deletions

View File

@ -1,6 +1,7 @@
package app.revanced.extension.shared.innertube.client
import android.os.Build
import app.revanced.extension.shared.patches.PatchStatus
import app.revanced.extension.shared.settings.BaseSettings
import app.revanced.extension.shared.utils.PackageUtils
import org.apache.commons.lang3.ArrayUtils
@ -11,6 +12,24 @@ import java.util.Locale
*/
object YouTubeAppClient {
// 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
"20.10.4"
private const val DEVICE_MAKE_IOS = "Apple"
private const val OS_NAME_IOS = "iOS"
@ -31,6 +50,7 @@ object YouTubeAppClient {
"13_7"
else
"18_3_2"
private val USER_AGENT_IOS = iOSUserAgent(PACKAGE_NAME_IOS, CLIENT_VERSION_IOS)
// IOS UNPLUGGED
@ -183,7 +203,6 @@ object YouTubeAppClient {
* Example: 'com.google.ios.youtube/16.38.2 (iPhone9,4; U; CPU iOS 14_7_1 like Mac OS X; en_AU)'
* Source: https://github.com/mitmproxy/mitmproxy/issues/4836.
*/
@Suppress("SameParameterValue")
private fun iOSUserAgent(
packageName: String,
clientVersion: String
@ -194,8 +213,15 @@ object YouTubeAppClient {
return BaseSettings.SPOOF_STREAMING_DATA_IOS_FORCE_AVC.get()
}
private fun useIOS(): Boolean {
return PatchStatus.SpoofStreamingDataIOS() && BaseSettings.SPOOF_STREAMING_DATA_TYPE_IOS.get()
}
fun availableClientTypes(preferredClient: ClientType): Array<ClientType> {
val availableClientTypes = ClientType.CLIENT_ORDER_TO_USE
val availableClientTypes = if (useIOS())
ClientType.CLIENT_ORDER_TO_USE_IOS
else
ClientType.CLIENT_ORDER_TO_USE
if (ArrayUtils.contains(availableClientTypes, preferredClient)) {
val clientToUse: Array<ClientType?> = arrayOfNulls(availableClientTypes.size)
@ -340,6 +366,21 @@ object YouTubeAppClient {
"iOS TV Force AVC"
else
"iOS TV"
),
IOS_DEPRECATED(
id = 5,
deviceMake = DEVICE_MAKE_IOS,
deviceModel = DEVICE_MODEL_IOS,
osName = OS_NAME_IOS,
osVersion = OS_VERSION_IOS,
userAgent = USER_AGENT_IOS,
clientVersion = CLIENT_VERSION_IOS,
supportsCookies = false,
clientName = "IOS",
friendlyName = if (forceAVC())
"iOS Force AVC"
else
"iOS"
);
companion object {
@ -350,6 +391,15 @@ object YouTubeAppClient {
IOS_UNPLUGGED,
ANDROID_VR,
)
val CLIENT_ORDER_TO_USE_IOS: Array<ClientType> = arrayOf(
ANDROID_VR_NO_AUTH,
ANDROID_UNPLUGGED,
ANDROID_CREATOR,
IOS_UNPLUGGED,
IOS_DEPRECATED,
ANDROID_VR,
)
}
}
}

View File

@ -11,4 +11,8 @@ public class PatchStatus {
// Replace this with true If the Spoof streaming data patch succeeds in YouTube.
return false;
}
public static boolean SpoofStreamingDataIOS() {
return false;
}
}

View File

@ -11,16 +11,20 @@ import java.util.LinkedHashMap;
import java.util.Map;
import app.revanced.extension.shared.innertube.client.YouTubeAppClient.ClientType;
import app.revanced.extension.shared.patches.PatchStatus;
import app.revanced.extension.shared.patches.spoof.requests.StreamingDataRequest;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.Setting;
import app.revanced.extension.shared.utils.Logger;
import app.revanced.extension.shared.utils.ResourceUtils;
import app.revanced.extension.shared.utils.Utils;
@SuppressWarnings("unused")
public class SpoofStreamingDataPatch extends BlockRequestPatch {
private static final boolean SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION =
SPOOF_STREAMING_DATA && BaseSettings.SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION.get();
private static final boolean SPOOF_STREAMING_DATA_TYPE_IOS =
PatchStatus.SpoofStreamingDataIOS() && BaseSettings.SPOOF_STREAMING_DATA_TYPE_IOS.get();
/**
* Any unreachable ip address. Used to intentionally fail requests.
@ -206,6 +210,18 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
return videoFormat;
}
public static String[] getEntries() {
return SPOOF_STREAMING_DATA_TYPE_IOS
? ResourceUtils.getStringArray("revanced_spoof_streaming_data_type_ios_entries")
: ResourceUtils.getStringArray("revanced_spoof_streaming_data_type_entries");
}
public static String[] getEntryValues() {
return SPOOF_STREAMING_DATA_TYPE_IOS
? ResourceUtils.getStringArray("revanced_spoof_streaming_data_type_ios_entry_values")
: ResourceUtils.getStringArray("revanced_spoof_streaming_data_type_entry_values");
}
public static final class AudioStreamLanguageOverrideAvailability implements Setting.Availability {
@Override
public boolean isAvailable() {

View File

@ -43,6 +43,7 @@ public class BaseSettings {
"revanced_spoof_streaming_data_ios_force_avc_user_dialog_message");
public static final BooleanSetting SPOOF_STREAMING_DATA_SKIP_RESPONSE_ENCRYPTION = new BooleanSetting("revanced_spoof_streaming_data_skip_response_encryption", TRUE, true);
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE);
public static final BooleanSetting SPOOF_STREAMING_DATA_TYPE_IOS = new BooleanSetting("revanced_spoof_streaming_data_type_ios", FALSE, true, "revanced_spoof_streaming_data_type_ios_user_dialog_message");
// Client type must be last spoof setting due to cyclic references.
public static final EnumSetting<YouTubeAppClient.ClientType> SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", YouTubeAppClient.ClientType.ANDROID_VR, true);

View File

@ -75,30 +75,30 @@ public class CustomPlaybackSpeedPatch {
return isCustomPlaybackSpeedEnabled() ? 0 : original;
}
public static String[] getListEntries() {
public static String[] getEntries() {
return isCustomPlaybackSpeedEnabled()
? customSpeedEntries
: defaultSpeedEntries;
}
public static String[] getListEntryValues() {
public static String[] getEntryValues() {
return isCustomPlaybackSpeedEnabled()
? customSpeedEntryValues
: defaultSpeedEntryValues;
}
public static String[] getTrimmedListEntries() {
public static String[] getTrimmedEntries() {
if (playbackSpeedEntries == null) {
final String[] playbackSpeedWithAutoEntries = getListEntries();
final String[] playbackSpeedWithAutoEntries = getEntries();
playbackSpeedEntries = Arrays.copyOfRange(playbackSpeedWithAutoEntries, 1, playbackSpeedWithAutoEntries.length);
}
return playbackSpeedEntries;
}
public static String[] getTrimmedListEntryValues() {
public static String[] getTrimmedEntryValues() {
if (playbackSpeedEntryValues == null) {
final String[] playbackSpeedWithAutoEntryValues = getListEntryValues();
final String[] playbackSpeedWithAutoEntryValues = getEntryValues();
playbackSpeedEntryValues = Arrays.copyOfRange(playbackSpeedWithAutoEntryValues, 1, playbackSpeedWithAutoEntryValues.length);
}

View File

@ -1,6 +1,7 @@
package app.revanced.extension.youtube.settings.preference;
import static com.google.android.apps.youtube.app.settings.videoquality.VideoQualitySettingsActivity.setToolbarLayoutParams;
import static app.revanced.extension.shared.settings.BaseSettings.SPOOF_STREAMING_DATA_TYPE;
import static app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment.showRestartDialog;
import static app.revanced.extension.shared.settings.preference.AbstractPreferenceFragment.updateListPreferenceSummary;
import static app.revanced.extension.shared.utils.ResourceUtils.getXmlIdentifier;
@ -56,6 +57,7 @@ import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import app.revanced.extension.shared.patches.spoof.SpoofStreamingDataPatch;
import app.revanced.extension.shared.settings.BaseSettings;
import app.revanced.extension.shared.settings.BooleanSetting;
import app.revanced.extension.shared.settings.EnumSetting;
@ -118,8 +120,12 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
Setting.privateSetValueFromString(setting, listPreference.getValue());
}
if (setting.equals(DEFAULT_PLAYBACK_SPEED)) {
listPreference.setEntries(CustomPlaybackSpeedPatch.getListEntries());
listPreference.setEntryValues(CustomPlaybackSpeedPatch.getListEntryValues());
listPreference.setEntries(CustomPlaybackSpeedPatch.getEntries());
listPreference.setEntryValues(CustomPlaybackSpeedPatch.getEntryValues());
}
if (setting.equals(SPOOF_STREAMING_DATA_TYPE)) {
listPreference.setEntries(SpoofStreamingDataPatch.getEntries());
listPreference.setEntryValues(SpoofStreamingDataPatch.getEntryValues());
}
if (!(mPreference instanceof app.revanced.extension.youtube.settings.preference.SegmentCategoryListPreference)) {
updateListPreferenceSummary(listPreference, setting);
@ -305,8 +311,12 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
editTextPreference.setText(setting.get().toString());
} else if (preference instanceof ListPreference listPreference) {
if (setting.equals(DEFAULT_PLAYBACK_SPEED)) {
listPreference.setEntries(CustomPlaybackSpeedPatch.getListEntries());
listPreference.setEntryValues(CustomPlaybackSpeedPatch.getListEntryValues());
listPreference.setEntries(CustomPlaybackSpeedPatch.getEntries());
listPreference.setEntryValues(CustomPlaybackSpeedPatch.getEntryValues());
}
if (setting.equals(SPOOF_STREAMING_DATA_TYPE)) {
listPreference.setEntries(SpoofStreamingDataPatch.getEntries());
listPreference.setEntryValues(SpoofStreamingDataPatch.getEntryValues());
}
if (!(preference instanceof app.revanced.extension.youtube.settings.preference.SegmentCategoryListPreference)) {
updateListPreferenceSummary(listPreference, setting);

View File

@ -193,8 +193,8 @@ public class VideoUtils extends IntentUtils {
}
public static void showPlaybackSpeedDialog(@NonNull Context context) {
final String[] playbackSpeedEntries = CustomPlaybackSpeedPatch.getTrimmedListEntries();
final String[] playbackSpeedEntryValues = CustomPlaybackSpeedPatch.getTrimmedListEntryValues();
final String[] playbackSpeedEntries = CustomPlaybackSpeedPatch.getTrimmedEntries();
final String[] playbackSpeedEntryValues = CustomPlaybackSpeedPatch.getTrimmedEntryValues();
final float playbackSpeed = VideoInformation.getPlaybackSpeed();
final int index = Arrays.binarySearch(playbackSpeedEntryValues, String.valueOf(playbackSpeed));