mirror of
https://github.com/inotia00/revanced-patches.git
synced 2025-06-12 21:27:43 +02:00
feat(YouTube Music - Spoof client): Add support for latest versions, Remove 'Spoof streaming data' patch
- 'Spoof client' patch now supports YouTube Music 7.25.53+ - 'Spoof client' patch now spoofs as many innerTube contexts as possible, just like the 'Spoof streaming data' patch - 'Spoof streaming data' patch is no longer a shared patch - Nevertheless, 'BlockRequestPatch' is still a shared patch, so each setting is located in a shared path (BaseSettings) - In YouTube Music 7.16.53 or earlier, 'iOS YouTube Music 6.21' is the only client that does not require 'BlockRequestPatch' - 'iOS YouTube Music 7.04' supports opus codec when 'Enable OPUS codec' is turned on
This commit is contained in:
@ -1,118 +0,0 @@
|
||||
package app.revanced.extension.music.patches.misc.client;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
public class AppClient {
|
||||
|
||||
// Audio codec is MP4A.
|
||||
private static final String CLIENT_VERSION_ANDROID_MUSIC_4_27 = "4.27.53";
|
||||
|
||||
// Audio codec is OPUS.
|
||||
private static final String CLIENT_VERSION_ANDROID_MUSIC_5_29 = "5.29.53";
|
||||
|
||||
private static final String PACKAGE_NAME_ANDROID_MUSIC = "com.google.android.apps.youtube.music";
|
||||
private static final String DEVICE_MODEL_ANDROID_MUSIC = Build.MODEL;
|
||||
private static final String OS_VERSION_ANDROID_MUSIC = Build.VERSION.RELEASE;
|
||||
|
||||
// Audio codec is MP4A.
|
||||
private static final String CLIENT_VERSION_IOS_MUSIC_6_21 = "6.21";
|
||||
|
||||
// Audio codec is OPUS.
|
||||
private static final String CLIENT_VERSION_IOS_MUSIC_7_04 = "7.04";
|
||||
|
||||
private static final String PACKAGE_NAME_IOS_MUSIC = "com.google.ios.youtubemusic";
|
||||
private static final String DEVICE_MODEL_IOS_MUSIC = "iPhone14,3";
|
||||
private static final String OS_VERSION_IOS_MUSIC = "15.7.1.19H117";
|
||||
private static final String USER_AGENT_VERSION_IOS_MUSIC = "15_7_1";
|
||||
|
||||
private AppClient() {
|
||||
}
|
||||
|
||||
private static String androidUserAgent(String clientVersion) {
|
||||
return PACKAGE_NAME_ANDROID_MUSIC +
|
||||
"/" +
|
||||
clientVersion +
|
||||
" (Linux; U; Android " +
|
||||
OS_VERSION_ANDROID_MUSIC +
|
||||
"; GB) gzip";
|
||||
}
|
||||
|
||||
private static String iOSUserAgent(String clientVersion) {
|
||||
return PACKAGE_NAME_IOS_MUSIC +
|
||||
"/" +
|
||||
clientVersion +
|
||||
"(" +
|
||||
DEVICE_MODEL_IOS_MUSIC +
|
||||
"; U; CPU iOS " +
|
||||
USER_AGENT_VERSION_IOS_MUSIC +
|
||||
" like Mac OS X)";
|
||||
}
|
||||
|
||||
public enum ClientType {
|
||||
ANDROID_MUSIC_4_27(21,
|
||||
DEVICE_MODEL_ANDROID_MUSIC,
|
||||
OS_VERSION_ANDROID_MUSIC,
|
||||
androidUserAgent(CLIENT_VERSION_ANDROID_MUSIC_4_27),
|
||||
CLIENT_VERSION_ANDROID_MUSIC_4_27
|
||||
),
|
||||
ANDROID_MUSIC_5_29(21,
|
||||
DEVICE_MODEL_ANDROID_MUSIC,
|
||||
OS_VERSION_ANDROID_MUSIC,
|
||||
androidUserAgent(CLIENT_VERSION_ANDROID_MUSIC_5_29),
|
||||
CLIENT_VERSION_ANDROID_MUSIC_5_29
|
||||
),
|
||||
IOS_MUSIC_6_21(
|
||||
26,
|
||||
DEVICE_MODEL_IOS_MUSIC,
|
||||
OS_VERSION_IOS_MUSIC,
|
||||
iOSUserAgent(CLIENT_VERSION_IOS_MUSIC_6_21),
|
||||
CLIENT_VERSION_IOS_MUSIC_6_21
|
||||
),
|
||||
IOS_MUSIC_7_04(
|
||||
26,
|
||||
DEVICE_MODEL_IOS_MUSIC,
|
||||
OS_VERSION_IOS_MUSIC,
|
||||
iOSUserAgent(CLIENT_VERSION_IOS_MUSIC_7_04),
|
||||
CLIENT_VERSION_IOS_MUSIC_7_04
|
||||
);
|
||||
|
||||
/**
|
||||
* YouTube
|
||||
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
|
||||
*/
|
||||
public final int id;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* App version.
|
||||
*/
|
||||
public final String clientVersion;
|
||||
|
||||
ClientType(int id,
|
||||
String deviceModel,
|
||||
String osVersion,
|
||||
String userAgent,
|
||||
String clientVersion
|
||||
) {
|
||||
this.id = id;
|
||||
this.deviceModel = deviceModel;
|
||||
this.clientVersion = clientVersion;
|
||||
this.osVersion = osVersion;
|
||||
this.userAgent = userAgent;
|
||||
}
|
||||
}
|
||||
}
|
@ -8,7 +8,6 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import app.revanced.extension.music.patches.general.ChangeStartPagePatch.StartPage;
|
||||
import app.revanced.extension.music.patches.misc.AlbumMusicVideoPatch.RedirectType;
|
||||
import app.revanced.extension.music.patches.misc.client.AppClient.ClientType;
|
||||
import app.revanced.extension.music.patches.utils.PatchStatus;
|
||||
import app.revanced.extension.music.sponsorblock.SponsorBlockSettings;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
@ -186,9 +185,6 @@ public class Settings extends BaseSettings {
|
||||
public static final EnumSetting<RedirectType> DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE = new EnumSetting<>("revanced_disable_music_video_in_album_redirect_type", RedirectType.REDIRECT, true);
|
||||
public static final BooleanSetting ENABLE_OPUS_CODEC = new BooleanSetting("revanced_enable_opus_codec", FALSE, true);
|
||||
public static final BooleanSetting SETTINGS_IMPORT_EXPORT = new BooleanSetting("revanced_extended_settings_import_export", FALSE, false);
|
||||
public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", FALSE, true);
|
||||
public static final EnumSetting<ClientType> SPOOF_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_client_type", ClientType.IOS_MUSIC_6_21, true);
|
||||
|
||||
|
||||
// PreferenceScreen: Return YouTube Dislike
|
||||
public static final BooleanSetting RYD_ENABLED = new BooleanSetting("revanced_ryd_enabled", TRUE);
|
||||
@ -271,7 +267,6 @@ public class Settings extends BaseSettings {
|
||||
SETTINGS_IMPORT_EXPORT.key,
|
||||
SPOOF_APP_VERSION_TARGET.key,
|
||||
SPOOF_CLIENT_TYPE.key,
|
||||
SPOOF_STREAMING_DATA_TYPE.key,
|
||||
RETURN_YOUTUBE_USERNAME_ABOUT.key,
|
||||
RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT.key,
|
||||
RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY.key,
|
||||
|
@ -20,7 +20,6 @@ import static app.revanced.extension.music.utils.ExtendedUtils.getLayoutParams;
|
||||
import static app.revanced.extension.music.utils.RestartUtils.showRestartDialog;
|
||||
import static app.revanced.extension.shared.settings.BaseSettings.RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT;
|
||||
import static app.revanced.extension.shared.settings.BaseSettings.RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY;
|
||||
import static app.revanced.extension.shared.settings.BaseSettings.SPOOF_STREAMING_DATA_TYPE;
|
||||
import static app.revanced.extension.shared.settings.Setting.getSettingFromPath;
|
||||
import static app.revanced.extension.shared.utils.ResourceUtils.getStringArray;
|
||||
import static app.revanced.extension.shared.utils.StringRef.str;
|
||||
@ -165,7 +164,6 @@ public class ReVancedPreferenceFragment extends PreferenceFragment {
|
||||
|| settings.equals(DISABLE_MUSIC_VIDEO_IN_ALBUM_REDIRECT_TYPE)
|
||||
|| settings.equals(RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT)
|
||||
|| settings.equals(SPOOF_CLIENT_TYPE)
|
||||
|| settings.equals(SPOOF_STREAMING_DATA_TYPE)
|
||||
) {
|
||||
ResettableListPreference.showDialog(mActivity, enumSetting, 0);
|
||||
}
|
||||
|
@ -6,8 +6,13 @@ public class PatchStatus {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean SpoofStreamingDataMusic() {
|
||||
// Replace this with true If the Spoof streaming data patch succeeds in YouTube Music
|
||||
public static boolean SpoofClient() {
|
||||
// Replace this with true If the Spoof streaming data patch succeeds in YouTube Music.
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean SpoofStreamingData() {
|
||||
// Replace this with true If the Spoof streaming data patch succeeds in YouTube.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,189 @@
|
||||
package app.revanced.extension.shared.patches.client;
|
||||
|
||||
import android.os.Build;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class MusicAppClient {
|
||||
|
||||
// Audio codec is MP4A.
|
||||
private static final String CLIENT_VERSION_ANDROID_MUSIC_4_27 = "4.27.53";
|
||||
|
||||
// Audio codec is OPUS.
|
||||
private static final String CLIENT_VERSION_ANDROID_MUSIC_5_29 = "5.29.53";
|
||||
|
||||
private static final String PACKAGE_NAME_ANDROID_MUSIC = "com.google.android.apps.youtube.music";
|
||||
private static final String DEVICE_BRAND_ANDROID_MUSIC = Build.BRAND;
|
||||
private static final String DEVICE_MAKE_ANDROID_MUSIC = Build.MANUFACTURER;
|
||||
private static final String DEVICE_MODEL_ANDROID_MUSIC = Build.MODEL;
|
||||
private static final String BUILD_ID_ANDROID_MUSIC = Build.ID;
|
||||
private static final String OS_NAME_ANDROID_MUSIC = "Android Automotive";
|
||||
private static final String OS_VERSION_ANDROID_MUSIC = Build.VERSION.RELEASE;
|
||||
|
||||
// Audio codec is MP4A.
|
||||
private static final String CLIENT_VERSION_IOS_MUSIC_6_21 = "6.21";
|
||||
private static final String DEVICE_MODEL_IOS_MUSIC_6_21 = "iPhone14,3";
|
||||
private static final String OS_VERSION_IOS_MUSIC_6_21 = "15.7.1.19H117";
|
||||
private static final String USER_AGENT_VERSION_IOS_MUSIC_6_21 = "15_7_1";
|
||||
|
||||
// Audio codec is OPUS.
|
||||
private static final String CLIENT_VERSION_IOS_MUSIC_7_04 = "7.04";
|
||||
private static final String DEVICE_MODEL_IOS_MUSIC_7_04 = "iPhone17,2";
|
||||
private static final String OS_VERSION_IOS_MUSIC_7_04 = "18.2.1.22C161";
|
||||
private static final String USER_AGENT_VERSION_IOS_MUSIC_7_04 = "18_2_1";
|
||||
|
||||
private static final String PACKAGE_NAME_IOS_MUSIC = "com.google.ios.youtubemusic";
|
||||
private static final String DEVICE_BRAND_IOS_MUSIC = "Apple";
|
||||
private static final String DEVICE_MAKE_IOS_MUSIC = "Apple";
|
||||
private static final String OS_NAME_IOS_MUSIC = "iOS";
|
||||
|
||||
private MusicAppClient() {
|
||||
}
|
||||
|
||||
private static String androidUserAgent(String clientVersion) {
|
||||
return PACKAGE_NAME_ANDROID_MUSIC +
|
||||
"/" +
|
||||
clientVersion +
|
||||
"(Linux; U; Android " +
|
||||
OS_VERSION_ANDROID_MUSIC +
|
||||
"; " +
|
||||
Locale.getDefault() +
|
||||
"; " +
|
||||
DEVICE_MODEL_ANDROID_MUSIC +
|
||||
" Build/" +
|
||||
BUILD_ID_ANDROID_MUSIC +
|
||||
") gzip";
|
||||
}
|
||||
|
||||
private static String iOSUserAgent(String clientVersion, String deviceModel, String osVersion) {
|
||||
return PACKAGE_NAME_IOS_MUSIC +
|
||||
"/" +
|
||||
clientVersion +
|
||||
" (" +
|
||||
deviceModel +
|
||||
"; U; CPU iOS " +
|
||||
osVersion +
|
||||
" like Mac OS X; " +
|
||||
Locale.getDefault() +
|
||||
")";
|
||||
}
|
||||
|
||||
public enum ActionButtonType {
|
||||
NONE, // No action button (~ 6.14)
|
||||
YOUTUBE_BUTTON, // Type of action button is YouTubeButton (6.15 ~ 7.16)
|
||||
LITHO // Type of action button is ComponentHost (7.17 ~)
|
||||
}
|
||||
|
||||
public enum ClientType {
|
||||
ANDROID_MUSIC_4_27(21,
|
||||
DEVICE_BRAND_ANDROID_MUSIC,
|
||||
DEVICE_MAKE_ANDROID_MUSIC,
|
||||
DEVICE_MODEL_ANDROID_MUSIC,
|
||||
OS_NAME_ANDROID_MUSIC,
|
||||
OS_VERSION_ANDROID_MUSIC,
|
||||
androidUserAgent(CLIENT_VERSION_ANDROID_MUSIC_4_27),
|
||||
CLIENT_VERSION_ANDROID_MUSIC_4_27,
|
||||
ActionButtonType.NONE
|
||||
),
|
||||
ANDROID_MUSIC_5_29(21,
|
||||
DEVICE_BRAND_ANDROID_MUSIC,
|
||||
DEVICE_MAKE_ANDROID_MUSIC,
|
||||
DEVICE_MODEL_ANDROID_MUSIC,
|
||||
OS_NAME_ANDROID_MUSIC,
|
||||
OS_VERSION_ANDROID_MUSIC,
|
||||
androidUserAgent(CLIENT_VERSION_ANDROID_MUSIC_5_29),
|
||||
CLIENT_VERSION_ANDROID_MUSIC_5_29,
|
||||
ActionButtonType.NONE
|
||||
),
|
||||
IOS_MUSIC_6_21(
|
||||
26,
|
||||
DEVICE_BRAND_IOS_MUSIC,
|
||||
DEVICE_MAKE_IOS_MUSIC,
|
||||
DEVICE_MODEL_IOS_MUSIC_6_21,
|
||||
OS_NAME_IOS_MUSIC,
|
||||
OS_VERSION_IOS_MUSIC_6_21,
|
||||
iOSUserAgent(CLIENT_VERSION_IOS_MUSIC_6_21, DEVICE_MODEL_IOS_MUSIC_6_21, USER_AGENT_VERSION_IOS_MUSIC_6_21),
|
||||
CLIENT_VERSION_IOS_MUSIC_6_21,
|
||||
ActionButtonType.YOUTUBE_BUTTON
|
||||
),
|
||||
IOS_MUSIC_7_04(
|
||||
26,
|
||||
DEVICE_BRAND_IOS_MUSIC,
|
||||
DEVICE_MAKE_IOS_MUSIC,
|
||||
DEVICE_MODEL_IOS_MUSIC_7_04,
|
||||
OS_NAME_IOS_MUSIC,
|
||||
OS_VERSION_IOS_MUSIC_7_04,
|
||||
iOSUserAgent(CLIENT_VERSION_IOS_MUSIC_7_04, DEVICE_MODEL_IOS_MUSIC_7_04, USER_AGENT_VERSION_IOS_MUSIC_7_04),
|
||||
CLIENT_VERSION_IOS_MUSIC_7_04,
|
||||
ActionButtonType.LITHO
|
||||
);
|
||||
|
||||
/**
|
||||
* YouTube
|
||||
* <a href="https://github.com/zerodytrash/YouTube-Internal-Clients?tab=readme-ov-file#clients">client type</a>
|
||||
*/
|
||||
public final int id;
|
||||
|
||||
/**
|
||||
* Device brand, equivalent to {@link Build#BRAND} (System property: ro.product.vendor.brand)
|
||||
*/
|
||||
public final String deviceBrand;
|
||||
|
||||
/**
|
||||
* Device make, equivalent to {@link Build#MANUFACTURER} (System property: ro.product.vendor.manufacturer)
|
||||
*/
|
||||
public final String deviceMake;
|
||||
|
||||
/**
|
||||
* Device model, equivalent to {@link Build#MODEL} (System property: ro.product.model)
|
||||
*/
|
||||
public final String deviceModel;
|
||||
|
||||
/**
|
||||
* Device OS name.
|
||||
*/
|
||||
public final String osName;
|
||||
|
||||
/**
|
||||
* Device OS version.
|
||||
*/
|
||||
public final String osVersion;
|
||||
|
||||
/**
|
||||
* Player user-agent.
|
||||
*/
|
||||
public final String userAgent;
|
||||
|
||||
/**
|
||||
* App version.
|
||||
*/
|
||||
public final String clientVersion;
|
||||
|
||||
private final ActionButtonType actionButtonType;
|
||||
|
||||
ClientType(int id,
|
||||
String deviceBrand,
|
||||
String deviceMake,
|
||||
String deviceModel,
|
||||
String osName,
|
||||
String osVersion,
|
||||
String userAgent,
|
||||
String clientVersion,
|
||||
ActionButtonType actionButtonType
|
||||
) {
|
||||
this.id = id;
|
||||
this.deviceBrand = deviceBrand;
|
||||
this.deviceMake = deviceMake;
|
||||
this.deviceModel = deviceModel;
|
||||
this.clientVersion = clientVersion;
|
||||
this.osName = osName;
|
||||
this.osVersion = osVersion;
|
||||
this.userAgent = userAgent;
|
||||
this.actionButtonType = actionButtonType;
|
||||
}
|
||||
|
||||
public boolean isYouTubeButton() {
|
||||
return actionButtonType == ActionButtonType.YOUTUBE_BUTTON;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,6 @@
|
||||
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
|
||||
import org.apache.commons.lang3.ArrayUtils
|
||||
import java.util.Locale
|
||||
@ -9,7 +8,7 @@ import java.util.Locale
|
||||
/**
|
||||
* Used to fetch streaming data.
|
||||
*/
|
||||
object AppClient {
|
||||
object YouTubeAppClient {
|
||||
// IOS
|
||||
/**
|
||||
* Video not playable: Paid / Movie / Private / Age-restricted
|
||||
@ -108,7 +107,6 @@ object AppClient {
|
||||
*/
|
||||
private const val ANDROID_SDK_VERSION_ANDROID_VR = "32"
|
||||
private const val BUILD_ID_ANDROID_VR = "SQ3A.220605.009.A1"
|
||||
private const val CHIPSET_ANDROID_VR = "Qualcomm;SXR2230P"
|
||||
|
||||
private val USER_AGENT_ANDROID_VR = androidUserAgent(
|
||||
packageName = PACKAGE_NAME_ANDROID_VR,
|
||||
@ -137,7 +135,6 @@ object AppClient {
|
||||
private const val ANDROID_SDK_VERSION_ANDROID_UNPLUGGED = "34"
|
||||
private const val BUILD_ID_ANDROID_UNPLUGGED = "UTT3.240625.001.K5"
|
||||
private const val GMS_CORE_VERSION_CODE_ANDROID_UNPLUGGED = "244336107"
|
||||
private const val CHIPSET_ANDROID_UNPLUGGED = "Mediatek;MT8696"
|
||||
|
||||
private val USER_AGENT_ANDROID_UNPLUGGED = androidUserAgent(
|
||||
packageName = PACKAGE_NAME_ANDROID_UNPLUGGED,
|
||||
@ -166,7 +163,6 @@ object AppClient {
|
||||
private const val ANDROID_SDK_VERSION_ANDROID_CREATOR = "35"
|
||||
private const val BUILD_ID_ANDROID_CREATOR = "AP3A.241005.015.A2"
|
||||
private const val GMS_CORE_VERSION_CODE_ANDROID_CREATOR = "244738035"
|
||||
private const val CHIPSET_ANDROID_CREATOR = "Google;Tensor G4"
|
||||
|
||||
private val USER_AGENT_ANDROID_CREATOR = androidUserAgent(
|
||||
packageName = PACKAGE_NAME_ANDROID_CREATOR,
|
||||
@ -177,39 +173,6 @@ object AppClient {
|
||||
)
|
||||
|
||||
|
||||
// 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"
|
||||
|
||||
/**
|
||||
* The device machine id for the Google Pixel 4.
|
||||
* See [this GitLab](https://dumps.tadiphone.dev/dumps/google/flame) for more information.
|
||||
*/
|
||||
private const val DEVICE_MODEL_ANDROID_MUSIC = "Pixel 4"
|
||||
private const val DEVICE_MAKE_ANDROID_MUSIC = "Google"
|
||||
private const val OS_VERSION_ANDROID_MUSIC = "11"
|
||||
private const val ANDROID_SDK_VERSION_ANDROID_MUSIC = "30"
|
||||
private const val BUILD_ID_ANDROID_MUSIC = "SPP2.210219.008"
|
||||
private const val GMS_CORE_VERSION_CODE_ANDROID_MUSIC = "244738022"
|
||||
private const val CHIPSET_ANDROID_MUSIC = "Qualcomm;SM8150"
|
||||
|
||||
private val USER_AGENT_ANDROID_MUSIC = androidUserAgent(
|
||||
packageName = PACKAGE_NAME_ANDROID_MUSIC,
|
||||
clientVersion = CLIENT_VERSION_ANDROID_MUSIC,
|
||||
osVersion = OS_VERSION_ANDROID_MUSIC,
|
||||
deviceModel = DEVICE_MODEL_ANDROID_MUSIC,
|
||||
buildId = BUILD_ID_ANDROID_MUSIC
|
||||
)
|
||||
|
||||
|
||||
/**
|
||||
* Same format as Android YouTube User-Agent.
|
||||
* Example: 'com.google.android.youtube/19.46.40(Linux; U; Android 13; in_ID; 21061110AG Build/TP1A.220624.014) gzip'
|
||||
@ -240,10 +203,7 @@ object AppClient {
|
||||
}
|
||||
|
||||
fun availableClientTypes(preferredClient: ClientType): Array<ClientType> {
|
||||
val availableClientTypes = if (PatchStatus.SpoofStreamingDataMusic())
|
||||
ClientType.CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC
|
||||
else
|
||||
ClientType.CLIENT_ORDER_TO_USE_YOUTUBE
|
||||
val availableClientTypes = ClientType.CLIENT_ORDER_TO_USE_YOUTUBE
|
||||
|
||||
if (ArrayUtils.contains(availableClientTypes, preferredClient)) {
|
||||
val clientToUse: Array<ClientType?> = arrayOfNulls(availableClientTypes.size)
|
||||
@ -400,19 +360,6 @@ object AppClient {
|
||||
"iOS Force AVC"
|
||||
else
|
||||
"iOS"
|
||||
),
|
||||
ANDROID_MUSIC(
|
||||
id = 21,
|
||||
deviceMake = DEVICE_MAKE_ANDROID_MUSIC,
|
||||
deviceModel = DEVICE_MODEL_ANDROID_MUSIC,
|
||||
osVersion = OS_VERSION_ANDROID_MUSIC,
|
||||
userAgent = USER_AGENT_ANDROID_MUSIC,
|
||||
androidSdkVersion = ANDROID_SDK_VERSION_ANDROID_MUSIC,
|
||||
clientVersion = CLIENT_VERSION_ANDROID_MUSIC,
|
||||
gmscoreVersionCode = GMS_CORE_VERSION_CODE_ANDROID_MUSIC,
|
||||
requireAuth = true,
|
||||
clientName = "ANDROID_MUSIC",
|
||||
friendlyName = "Android Music"
|
||||
);
|
||||
|
||||
companion object {
|
||||
@ -424,11 +371,6 @@ object AppClient {
|
||||
IOS,
|
||||
ANDROID_VR_NO_AUTH,
|
||||
)
|
||||
|
||||
internal val CLIENT_ORDER_TO_USE_YOUTUBE_MUSIC: Array<ClientType> = arrayOf(
|
||||
ANDROID_VR,
|
||||
ANDROID_MUSIC,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ package app.revanced.extension.shared.patches.client
|
||||
* Used to fetch video information.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
object WebClient {
|
||||
object YouTubeWebClient {
|
||||
/**
|
||||
* This user agent does not require a PoToken in [ClientType.MWEB]
|
||||
* https://github.com/yt-dlp/yt-dlp/blob/0b6b7742c2e7f2a1fcb0b54ef3dd484bab404b3f/yt_dlp/extractor/youtube.py#L259
|
@ -0,0 +1,110 @@
|
||||
package app.revanced.extension.shared.patches.spoof;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import app.revanced.extension.shared.patches.PatchStatus;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.utils.Logger;
|
||||
import app.revanced.extension.shared.utils.PackageUtils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class BlockRequestPatch {
|
||||
/**
|
||||
* Used in YouTube.
|
||||
*/
|
||||
public static final boolean SPOOF_STREAMING_DATA =
|
||||
BaseSettings.SPOOF_STREAMING_DATA.get() && PatchStatus.SpoofStreamingData();
|
||||
|
||||
/**
|
||||
* Used in YouTube Music.
|
||||
*/
|
||||
public static final boolean SPOOF_CLIENT =
|
||||
BaseSettings.SPOOF_CLIENT.get() && PatchStatus.SpoofClient();
|
||||
|
||||
/**
|
||||
* In order to load the action bar normally,
|
||||
* Some versions must block the initplayback request.
|
||||
*/
|
||||
private static final boolean IS_7_17_OR_GREATER =
|
||||
PackageUtils.getAppVersionName().compareTo("7.17.00") >= 0;
|
||||
|
||||
private static final boolean IS_YOUTUBE_BUTTON =
|
||||
BaseSettings.SPOOF_CLIENT_TYPE.get().isYouTubeButton();
|
||||
|
||||
private static final boolean BLOCK_REQUEST;
|
||||
|
||||
static {
|
||||
if (SPOOF_STREAMING_DATA) {
|
||||
BLOCK_REQUEST = true;
|
||||
} else {
|
||||
if (!SPOOF_CLIENT) {
|
||||
BLOCK_REQUEST = false;
|
||||
} else {
|
||||
if (!IS_7_17_OR_GREATER && !IS_YOUTUBE_BUTTON) {
|
||||
// If the current version is lower than 7.16 and the client action button type is not YouTubeButton,
|
||||
// the initplayback request must be blocked.
|
||||
BLOCK_REQUEST = true;
|
||||
} else {
|
||||
// If the current version is higher than 7.17,
|
||||
// the initplayback request must always be blocked.
|
||||
BLOCK_REQUEST = IS_7_17_OR_GREATER;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Any unreachable ip address. Used to intentionally fail requests.
|
||||
*/
|
||||
private static final String UNREACHABLE_HOST_URI_STRING = "https://127.0.0.0";
|
||||
private static final Uri UNREACHABLE_HOST_URI = Uri.parse(UNREACHABLE_HOST_URI_STRING);
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Blocks /get_watch requests by returning an unreachable URI.
|
||||
*
|
||||
* @param playerRequestUri The URI of the player request.
|
||||
* @return An unreachable URI if the request is a /get_watch request, otherwise the original URI.
|
||||
*/
|
||||
public static Uri blockGetWatchRequest(Uri playerRequestUri) {
|
||||
if (BLOCK_REQUEST) {
|
||||
try {
|
||||
String path = playerRequestUri.getPath();
|
||||
|
||||
if (path != null && path.contains("get_watch")) {
|
||||
Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri");
|
||||
|
||||
return UNREACHABLE_HOST_URI;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "blockGetWatchRequest failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return playerRequestUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Blocks /initplayback requests.
|
||||
*/
|
||||
public static String blockInitPlaybackRequest(String originalUrlString) {
|
||||
if (BLOCK_REQUEST) {
|
||||
try {
|
||||
var originalUri = Uri.parse(originalUrlString);
|
||||
String path = originalUri.getPath();
|
||||
|
||||
if (path != null && path.contains("initplayback")) {
|
||||
Logger.printDebug(() -> "Blocking 'initplayback' by clearing query");
|
||||
|
||||
return originalUri.buildUpon().clearQuery().build().toString();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "blockInitPlaybackRequest failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return originalUrlString;
|
||||
}
|
||||
}
|
@ -1,66 +1,98 @@
|
||||
package app.revanced.extension.music.patches.misc;
|
||||
package app.revanced.extension.shared.patches.spoof;
|
||||
|
||||
import app.revanced.extension.music.patches.misc.client.AppClient.ClientType;
|
||||
import app.revanced.extension.shared.patches.client.MusicAppClient.ClientType;
|
||||
import app.revanced.extension.music.settings.Settings;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofClientPatch {
|
||||
public class SpoofClientPatch extends BlockRequestPatch {
|
||||
private static final ClientType CLIENT_TYPE = Settings.SPOOF_CLIENT_TYPE.get();
|
||||
public static final boolean SPOOF_CLIENT = Settings.SPOOF_CLIENT.get();
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static int getClientTypeId(int originalClientTypeId) {
|
||||
public static int getClientId(int original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.id;
|
||||
}
|
||||
|
||||
return originalClientTypeId;
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getClientVersion(String originalClientVersion) {
|
||||
public static String getClientVersion(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.clientVersion;
|
||||
}
|
||||
|
||||
return originalClientVersion;
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getClientModel(String originalClientModel) {
|
||||
public static String getDeviceBrand(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.deviceBrand;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getDeviceMake(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.deviceMake;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getDeviceModel(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.deviceModel;
|
||||
}
|
||||
|
||||
return originalClientModel;
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getOsVersion(String originalOsVersion) {
|
||||
public static String getOsName(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.osName;
|
||||
}
|
||||
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getOsVersion(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.osVersion;
|
||||
}
|
||||
|
||||
return originalOsVersion;
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static String getUserAgent(String originalUserAgent) {
|
||||
public static String getUserAgent(String original) {
|
||||
if (SPOOF_CLIENT) {
|
||||
return CLIENT_TYPE.userAgent;
|
||||
}
|
||||
|
||||
return originalUserAgent;
|
||||
return original;
|
||||
}
|
||||
|
||||
/**
|
@ -1,11 +1,8 @@
|
||||
package app.revanced.extension.shared.patches.spoof;
|
||||
|
||||
import static app.revanced.extension.shared.patches.PatchStatus.SpoofStreamingDataMusic;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@ -13,7 +10,7 @@ import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import app.revanced.extension.shared.patches.client.AppClient.ClientType;
|
||||
import app.revanced.extension.shared.patches.client.YouTubeAppClient.ClientType;
|
||||
import app.revanced.extension.shared.patches.spoof.requests.StreamingDataRequest;
|
||||
import app.revanced.extension.shared.settings.BaseSettings;
|
||||
import app.revanced.extension.shared.settings.Setting;
|
||||
@ -21,10 +18,7 @@ import app.revanced.extension.shared.utils.Logger;
|
||||
import app.revanced.extension.shared.utils.Utils;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class SpoofStreamingDataPatch {
|
||||
private static final boolean SPOOF_STREAMING_DATA = BaseSettings.SPOOF_STREAMING_DATA.get();
|
||||
private static final boolean SPOOF_STREAMING_DATA_YOUTUBE = SPOOF_STREAMING_DATA && !SpoofStreamingDataMusic();
|
||||
private static final boolean SPOOF_STREAMING_DATA_MUSIC = SPOOF_STREAMING_DATA && SpoofStreamingDataMusic();
|
||||
public class SpoofStreamingDataPatch extends BlockRequestPatch {
|
||||
private static final String PO_TOKEN =
|
||||
BaseSettings.SPOOF_STREAMING_DATA_PO_TOKEN.get();
|
||||
private static final String VISITOR_DATA =
|
||||
@ -50,58 +44,6 @@ public class SpoofStreamingDataPatch {
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* Blocks /get_watch requests by returning an unreachable URI.
|
||||
*
|
||||
* @param playerRequestUri The URI of the player request.
|
||||
* @return An unreachable URI if the request is a /get_watch request, otherwise the original URI.
|
||||
*/
|
||||
public static Uri blockGetWatchRequest(Uri playerRequestUri) {
|
||||
if (SPOOF_STREAMING_DATA) {
|
||||
// An exception may be thrown when the /get_watch request is blocked when connected to Wi-Fi in YouTube Music.
|
||||
if (SPOOF_STREAMING_DATA_YOUTUBE || Utils.getNetworkType() == Utils.NetworkType.MOBILE) {
|
||||
try {
|
||||
String path = playerRequestUri.getPath();
|
||||
|
||||
if (path != null && path.contains("get_watch")) {
|
||||
Logger.printDebug(() -> "Blocking 'get_watch' by returning unreachable uri");
|
||||
|
||||
return UNREACHABLE_HOST_URI;
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "blockGetWatchRequest failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return playerRequestUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
* <p>
|
||||
* Blocks /initplayback requests.
|
||||
*/
|
||||
public static String blockInitPlaybackRequest(String originalUrlString) {
|
||||
if (SPOOF_STREAMING_DATA) {
|
||||
try {
|
||||
var originalUri = Uri.parse(originalUrlString);
|
||||
String path = originalUri.getPath();
|
||||
|
||||
if (path != null && path.contains("initplayback")) {
|
||||
Logger.printDebug(() -> "Blocking 'initplayback' by clearing query");
|
||||
|
||||
return originalUri.buildUpon().clearQuery().build().toString();
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "blockInitPlaybackRequest failure", ex);
|
||||
}
|
||||
}
|
||||
|
||||
return originalUrlString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
@ -120,73 +62,20 @@ public class SpoofStreamingDataPatch {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static volatile String auth = "";
|
||||
private static volatile Map<String, String> requestHeader;
|
||||
|
||||
private static final String AUTHORIZATION_HEADER = "Authorization";
|
||||
|
||||
private static final String[] REQUEST_HEADER_KEYS = {
|
||||
AUTHORIZATION_HEADER,
|
||||
"X-GOOG-API-FORMAT-VERSION",
|
||||
"X-Goog-Visitor-Id"
|
||||
/**
|
||||
* Parameters causing playback issues.
|
||||
*/
|
||||
private static final String[] PATH_NO_VIDEO_ID = {
|
||||
"ad_break", // This request fetches a list of times when ads can be displayed.
|
||||
"get_drm_license", // Waiting for a paid video to start.
|
||||
"heartbeat", // This request determines whether to pause playback when the user is AFK.
|
||||
"refresh", // Waiting for a livestream to start.
|
||||
};
|
||||
|
||||
/**
|
||||
* If the /get_watch request is not blocked,
|
||||
* fetchRequest will not be invoked at the point where the video starts.
|
||||
* <p>
|
||||
* An additional method is used to invoke fetchRequest in YouTube Music:
|
||||
* 1. Save the requestHeader in a field.
|
||||
* 2. Invoke fetchRequest with the videoId used in PlaybackStartDescriptor.
|
||||
* <p>
|
||||
*
|
||||
* @param requestHeaders Save the request Headers used for login to a field.
|
||||
* Only used in YouTube Music where login is required.
|
||||
*/
|
||||
private static void setRequestHeaders(Map<String, String> requestHeaders) {
|
||||
if (SPOOF_STREAMING_DATA_MUSIC) {
|
||||
try {
|
||||
// Save requestHeaders whenever an account is switched.
|
||||
String authorization = requestHeaders.get(AUTHORIZATION_HEADER);
|
||||
if (authorization == null || auth.equals(authorization)) {
|
||||
return;
|
||||
}
|
||||
for (String key : REQUEST_HEADER_KEYS) {
|
||||
if (requestHeaders.get(key) == null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
auth = authorization;
|
||||
requestHeader = requestHeaders;
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "setRequestHeaders failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void fetchStreams(@NonNull String videoId) {
|
||||
if (SPOOF_STREAMING_DATA_MUSIC) {
|
||||
try {
|
||||
if (requestHeader != null) {
|
||||
StreamingDataRequest.fetchRequest(videoId, requestHeader, VISITOR_DATA, PO_TOKEN);
|
||||
} else {
|
||||
Logger.printDebug(() -> "Ignoring request with no header.");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Logger.printException(() -> "fetchStreams failure", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection point.
|
||||
*/
|
||||
public static void fetchStreams(String url, Map<String, String> requestHeaders) {
|
||||
setRequestHeaders(requestHeaders);
|
||||
|
||||
if (SPOOF_STREAMING_DATA) {
|
||||
try {
|
||||
Uri uri = Uri.parse(url);
|
||||
@ -195,11 +84,7 @@ public class SpoofStreamingDataPatch {
|
||||
return;
|
||||
}
|
||||
|
||||
// 'get_drm_license' has no video id and appears to happen when waiting for a paid video to start.
|
||||
// 'heartbeat' has no video id and appears to be only after playback has started.
|
||||
// 'refresh' has no video id and appears to happen when waiting for a livestream to start.
|
||||
// 'ad_break' has no video id.
|
||||
if (path.contains("get_drm_license") || path.contains("heartbeat") || path.contains("refresh") || path.contains("ad_break")) {
|
||||
if (Utils.containsAny(path, PATH_NO_VIDEO_ID)) {
|
||||
Logger.printDebug(() -> "Ignoring path: " + path);
|
||||
return;
|
||||
}
|
||||
@ -262,7 +147,7 @@ public class SpoofStreamingDataPatch {
|
||||
* Called after {@link #getStreamingData(String)}.
|
||||
*/
|
||||
public static void setApproxDurationMs(String videoId, long approxDurationMs) {
|
||||
if (SPOOF_STREAMING_DATA_YOUTUBE && approxDurationMs != Long.MAX_VALUE) {
|
||||
if (SPOOF_STREAMING_DATA && approxDurationMs != Long.MAX_VALUE) {
|
||||
approxDurationMsMap.put(videoId, approxDurationMs);
|
||||
Logger.printDebug(() -> "New approxDurationMs loaded, video id: " + videoId + ", video length: " + approxDurationMs);
|
||||
}
|
||||
@ -284,7 +169,7 @@ public class SpoofStreamingDataPatch {
|
||||
* Called after {@link #getStreamingData(String)}.
|
||||
*/
|
||||
public static long getApproxDurationMs(String videoId) {
|
||||
if (SPOOF_STREAMING_DATA_YOUTUBE && videoId != null) {
|
||||
if (SPOOF_STREAMING_DATA && videoId != null) {
|
||||
final Long approxDurationMs = approxDurationMsMap.get(videoId);
|
||||
if (approxDurationMs != null) {
|
||||
Logger.printDebug(() -> "Replacing video length: " + approxDurationMs + " for videoId: " + videoId);
|
||||
|
@ -1,7 +1,7 @@
|
||||
package app.revanced.extension.shared.patches.spoof.requests
|
||||
|
||||
import app.revanced.extension.shared.patches.client.AppClient
|
||||
import app.revanced.extension.shared.patches.client.WebClient
|
||||
import app.revanced.extension.shared.patches.client.YouTubeAppClient
|
||||
import app.revanced.extension.shared.patches.client.YouTubeWebClient
|
||||
import app.revanced.extension.shared.requests.Requester
|
||||
import app.revanced.extension.shared.requests.Route
|
||||
import app.revanced.extension.shared.requests.Route.CompiledRoute
|
||||
@ -69,7 +69,7 @@ object PlayerRoutes {
|
||||
|
||||
@JvmStatic
|
||||
fun createApplicationRequestBody(
|
||||
clientType: AppClient.ClientType,
|
||||
clientType: YouTubeAppClient.ClientType,
|
||||
videoId: String,
|
||||
playlistId: String? = null,
|
||||
botGuardPoToken: String = "",
|
||||
@ -130,7 +130,7 @@ object PlayerRoutes {
|
||||
|
||||
@JvmStatic
|
||||
fun createWebInnertubeBody(
|
||||
clientType: WebClient.ClientType,
|
||||
clientType: YouTubeWebClient.ClientType,
|
||||
videoId: String
|
||||
): ByteArray {
|
||||
val innerTubeBody = JSONObject()
|
||||
@ -161,7 +161,7 @@ object PlayerRoutes {
|
||||
@JvmStatic
|
||||
fun getPlayerResponseConnectionFromRoute(
|
||||
route: CompiledRoute,
|
||||
clientType: AppClient.ClientType
|
||||
clientType: YouTubeAppClient.ClientType
|
||||
): HttpURLConnection {
|
||||
return getPlayerResponseConnectionFromRoute(
|
||||
route,
|
||||
@ -174,7 +174,7 @@ object PlayerRoutes {
|
||||
@JvmStatic
|
||||
fun getPlayerResponseConnectionFromRoute(
|
||||
route: CompiledRoute,
|
||||
clientType: WebClient.ClientType
|
||||
clientType: YouTubeWebClient.ClientType
|
||||
): HttpURLConnection {
|
||||
return getPlayerResponseConnectionFromRoute(
|
||||
route,
|
||||
|
@ -1,8 +1,7 @@
|
||||
package app.revanced.extension.shared.patches.spoof.requests
|
||||
|
||||
import androidx.annotation.GuardedBy
|
||||
import app.revanced.extension.shared.patches.client.AppClient
|
||||
import app.revanced.extension.shared.patches.client.AppClient.availableClientTypes
|
||||
import app.revanced.extension.shared.patches.client.YouTubeAppClient
|
||||
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.GET_STREAMING_DATA
|
||||
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.createApplicationRequestBody
|
||||
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes.getPlayerResponseConnectionFromRoute
|
||||
@ -93,16 +92,16 @@ class StreamingDataRequest private constructor(
|
||||
"X-GOOG-API-FORMAT-VERSION",
|
||||
VISITOR_ID_HEADER
|
||||
)
|
||||
private val SPOOF_STREAMING_DATA_TYPE: AppClient.ClientType =
|
||||
private val SPOOF_STREAMING_DATA_TYPE: YouTubeAppClient.ClientType =
|
||||
BaseSettings.SPOOF_STREAMING_DATA_TYPE.get()
|
||||
|
||||
private val CLIENT_ORDER_TO_USE: Array<AppClient.ClientType> =
|
||||
availableClientTypes(SPOOF_STREAMING_DATA_TYPE)
|
||||
private val CLIENT_ORDER_TO_USE: Array<YouTubeAppClient.ClientType> =
|
||||
YouTubeAppClient.availableClientTypes(SPOOF_STREAMING_DATA_TYPE)
|
||||
|
||||
private val DEFAULT_CLIENT_IS_ANDROID_VR_NO_AUTH: Boolean =
|
||||
SPOOF_STREAMING_DATA_TYPE == AppClient.ClientType.ANDROID_VR_NO_AUTH
|
||||
SPOOF_STREAMING_DATA_TYPE == YouTubeAppClient.ClientType.ANDROID_VR_NO_AUTH
|
||||
|
||||
private var lastSpoofedClientType: AppClient.ClientType? = null
|
||||
private var lastSpoofedClientType: YouTubeAppClient.ClientType? = null
|
||||
|
||||
|
||||
/**
|
||||
@ -163,7 +162,7 @@ class StreamingDataRequest private constructor(
|
||||
}
|
||||
|
||||
private fun send(
|
||||
clientType: AppClient.ClientType,
|
||||
clientType: YouTubeAppClient.ClientType,
|
||||
videoId: String,
|
||||
playerHeaders: Map<String, String>,
|
||||
visitorId: String,
|
||||
@ -279,7 +278,7 @@ class StreamingDataRequest private constructor(
|
||||
} else {
|
||||
BufferedInputStream(connection.inputStream).use { inputStream ->
|
||||
ByteArrayOutputStream().use { stream ->
|
||||
val buffer = ByteArray(4096)
|
||||
val buffer = ByteArray(2048)
|
||||
var bytesRead: Int
|
||||
while ((inputStream.read(buffer)
|
||||
.also { bytesRead = it }) >= 0
|
||||
|
@ -5,7 +5,8 @@ import static java.lang.Boolean.TRUE;
|
||||
import static app.revanced.extension.shared.patches.PatchStatus.HideFullscreenAdsDefaultBoolean;
|
||||
|
||||
import app.revanced.extension.shared.patches.ReturnYouTubeUsernamePatch.DisplayFormat;
|
||||
import app.revanced.extension.shared.patches.client.AppClient.ClientType;
|
||||
import app.revanced.extension.shared.patches.client.MusicAppClient;
|
||||
import app.revanced.extension.shared.patches.client.YouTubeAppClient;
|
||||
import app.revanced.extension.shared.patches.spoof.SpoofStreamingDataPatch.AudioStreamLanguageOverrideAvailability;
|
||||
|
||||
/**
|
||||
@ -25,6 +26,28 @@ public class BaseSettings {
|
||||
|
||||
public static final EnumSetting<AppLanguage> REVANCED_LANGUAGE = new EnumSetting<>("revanced_language", AppLanguage.DEFAULT, true);
|
||||
|
||||
/**
|
||||
* These settings are used by YouTube Music.
|
||||
* Some patches are in a shared path, so they are declared here.
|
||||
*/
|
||||
public static final BooleanSetting SPOOF_CLIENT = new BooleanSetting("revanced_spoof_client", TRUE, true);
|
||||
public static final EnumSetting<MusicAppClient.ClientType> SPOOF_CLIENT_TYPE = new EnumSetting<>("revanced_spoof_client_type", MusicAppClient.ClientType.IOS_MUSIC_6_21, true);
|
||||
|
||||
/**
|
||||
* These settings are used by YouTube.
|
||||
* Some patches are in a shared path, so they are declared here.
|
||||
*/
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA = new BooleanSetting("revanced_spoof_streaming_data", TRUE, true, "revanced_spoof_streaming_data_user_dialog_message");
|
||||
public static final EnumSetting<AppLanguage> SPOOF_STREAMING_DATA_LANGUAGE = new EnumSetting<>("revanced_spoof_streaming_data_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_streaming_data_ios_force_avc", FALSE, true,
|
||||
"revanced_spoof_streaming_data_ios_force_avc_user_dialog_message");
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE);
|
||||
// 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);
|
||||
|
||||
public static final StringSetting SPOOF_STREAMING_DATA_PO_TOKEN = new StringSetting("revanced_spoof_streaming_data_po_token", "", true);
|
||||
public static final StringSetting SPOOF_STREAMING_DATA_VISITOR_DATA = new StringSetting("revanced_spoof_streaming_data_visitor_data", "", true);
|
||||
|
||||
/**
|
||||
* These settings are used by YouTube and YouTube Music.
|
||||
*/
|
||||
@ -39,17 +62,6 @@ public class BaseSettings {
|
||||
public static final EnumSetting<DisplayFormat> RETURN_YOUTUBE_USERNAME_DISPLAY_FORMAT = new EnumSetting<>("revanced_return_youtube_username_display_format", DisplayFormat.USERNAME_ONLY, true);
|
||||
public static final StringSetting RETURN_YOUTUBE_USERNAME_YOUTUBE_DATA_API_V3_DEVELOPER_KEY = new StringSetting("revanced_return_youtube_username_youtube_data_api_v3_developer_key", "", true, false);
|
||||
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA = new BooleanSetting("revanced_spoof_streaming_data", TRUE, true, "revanced_spoof_streaming_data_user_dialog_message");
|
||||
public static final EnumSetting<AppLanguage> SPOOF_STREAMING_DATA_LANGUAGE = new EnumSetting<>("revanced_spoof_streaming_data_language", AppLanguage.DEFAULT, new AudioStreamLanguageOverrideAvailability());
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA_IOS_FORCE_AVC = new BooleanSetting("revanced_spoof_streaming_data_ios_force_avc", FALSE, true,
|
||||
"revanced_spoof_streaming_data_ios_force_avc_user_dialog_message");
|
||||
public static final BooleanSetting SPOOF_STREAMING_DATA_STATS_FOR_NERDS = new BooleanSetting("revanced_spoof_streaming_data_stats_for_nerds", TRUE);
|
||||
// Client type must be last spoof setting due to cyclic references.
|
||||
public static final EnumSetting<ClientType> SPOOF_STREAMING_DATA_TYPE = new EnumSetting<>("revanced_spoof_streaming_data_type", ClientType.ANDROID_VR, true);
|
||||
|
||||
public static final StringSetting SPOOF_STREAMING_DATA_PO_TOKEN = new StringSetting("revanced_spoof_streaming_data_po_token", "", true);
|
||||
public static final StringSetting SPOOF_STREAMING_DATA_VISITOR_DATA = new StringSetting("revanced_spoof_streaming_data_visitor_data", "", true);
|
||||
|
||||
/**
|
||||
* @noinspection DeprecatedIsStillUsed
|
||||
*/
|
||||
|
@ -2,7 +2,7 @@ package app.revanced.extension.youtube.patches.general.requests
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.annotation.GuardedBy
|
||||
import app.revanced.extension.shared.patches.client.WebClient
|
||||
import app.revanced.extension.shared.patches.client.YouTubeWebClient
|
||||
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes
|
||||
import app.revanced.extension.shared.requests.Requester
|
||||
import app.revanced.extension.shared.utils.Logger
|
||||
@ -81,7 +81,7 @@ class VideoDetailsRequest private constructor(
|
||||
|
||||
private fun sendRequest(videoId: String): JSONObject? {
|
||||
val startTime = System.currentTimeMillis()
|
||||
val clientType = WebClient.ClientType.MWEB
|
||||
val clientType = YouTubeWebClient.ClientType.MWEB
|
||||
val clientTypeName = clientType.name
|
||||
Logger.printDebug { "Fetching video details request for: $videoId, using client: $clientTypeName" }
|
||||
|
||||
|
@ -2,8 +2,8 @@ package app.revanced.extension.youtube.patches.video.requests
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import androidx.annotation.GuardedBy
|
||||
import app.revanced.extension.shared.patches.client.AppClient
|
||||
import app.revanced.extension.shared.patches.client.WebClient
|
||||
import app.revanced.extension.shared.patches.client.YouTubeAppClient
|
||||
import app.revanced.extension.shared.patches.client.YouTubeWebClient
|
||||
import app.revanced.extension.shared.patches.spoof.requests.PlayerRoutes
|
||||
import app.revanced.extension.shared.requests.Requester
|
||||
import app.revanced.extension.shared.utils.Logger
|
||||
@ -119,7 +119,7 @@ class MusicRequest private constructor(
|
||||
Objects.requireNonNull(videoId)
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
val clientType = AppClient.ClientType.ANDROID_VR
|
||||
val clientType = YouTubeAppClient.ClientType.ANDROID_VR
|
||||
val clientTypeName = clientType.name
|
||||
Logger.printDebug { "Fetching playlist request for: $videoId, using client: $clientTypeName" }
|
||||
|
||||
@ -163,7 +163,7 @@ class MusicRequest private constructor(
|
||||
Objects.requireNonNull(videoId)
|
||||
|
||||
val startTime = System.currentTimeMillis()
|
||||
val clientType = WebClient.ClientType.MWEB
|
||||
val clientType = YouTubeWebClient.ClientType.MWEB
|
||||
val clientTypeName = clientType.name
|
||||
Logger.printDebug { "Fetching microformat request for: $videoId, using client: $clientTypeName" }
|
||||
|
||||
|
Reference in New Issue
Block a user