fix(Spoof Streaming Data): Performance degradation on iOS client (#110)

* fix(Spoof Streaming Data): Apply workarounds to the correct client

* Lint code

* Lint

* Correct the logic

* Use `put` to update the client type

* Fix build error

* Fix logic

* Apply HLS fix for all client

* Remove unused method

* fix: Apply code review suggestions

* fix: Apply code review suggestions

---------

Co-authored-by: inotia00 <108592928+inotia00@users.noreply.github.com>
This commit is contained in:
Hoàng Gia Bảo 2024-12-18 07:43:35 +07:00 committed by GitHub
parent 776c519b20
commit 5ffbb4714a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 32 additions and 34 deletions

View File

@ -1,5 +1,7 @@
package app.revanced.extension.shared.patches.spoof;
import static app.revanced.extension.shared.utils.Utils.isSDKAbove;
import android.net.Uri;
import android.text.TextUtils;
@ -24,8 +26,8 @@ import app.revanced.extension.shared.utils.Utils;
public class SpoofStreamingDataPatch extends BlockRequestPatch {
/**
* key: videoId
* value: android StreamingData
* Key: videoId.
* Value: Original StreamingData of Android client.
*/
private static final Map<String, StreamingDataOuterClass$StreamingData> streamingDataMap = Collections.synchronizedMap(
new LinkedHashMap<>(10) {
@ -37,20 +39,6 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
}
});
/**
* key: android StreamingData
* value: fetched ClientType
*/
private static final Map<StreamingDataOuterClass$StreamingData, ClientType> clientTypeMap = Collections.synchronizedMap(
new LinkedHashMap<>(10) {
private static final int CACHE_LIMIT = 5;
@Override
protected boolean removeEldestEntry(Entry eldest) {
return size() > CACHE_LIMIT; // Evict the oldest entry if over the cache limit.
}
});
/**
* Injection point.
*/
@ -120,12 +108,25 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
var stream = request.getStream();
if (stream != null) {
Logger.printDebug(() -> "Overriding video stream: " + videoId);
// Put the videoId, originalStreamingData, and the clientType used for spoofing into a HashMap.
streamingDataMap.put(videoId, originalStreamingData);
clientTypeMap.put(originalStreamingData, stream.second);
ByteBuffer spoofedStreamingData = stream.first;
ClientType spoofedClientType = stream.second;
return stream.first;
Logger.printDebug(() -> "Overriding video stream: " + videoId);
// Put the videoId and originalStreamingData into a HashMap.
if (spoofedClientType == ClientType.IOS) {
// For YT Music 6.20.51, which is supported by RVX, it can run on Android 5.0 (SDK 21).
// The IDE does not make any suggestions since the project's minSDK is 24, but you should check the SDK version for compatibility with SDK 21.
if (isSDKAbove(24)) {
streamingDataMap.putIfAbsent(videoId, originalStreamingData);
} else {
if (!streamingDataMap.containsKey(videoId)) {
streamingDataMap.put(videoId, originalStreamingData);
}
}
}
return spoofedStreamingData;
}
}
@ -141,11 +142,14 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
/**
* Injection point.
* <p>
* It seems that some 'adaptiveFormats' are missing from the initial response of streaming data on iOS.
* Since the {@link FormatStreamModel} class for measuring the video length is not initialized on iOS clients,
* The video length field is always initialized to an estimated value, not the actual value.
* In iOS Clients, Progressive Streaming are not available, so 'formats' field have been removed
* completely from the initial response of streaming data.
* Therefore, {@link FormatStreamModel} class is never be initialized, and the video length field
* is set with an estimated value from `adaptiveFormats` instead.
* <p>
* To fix this, replace streamingData (spoofedStreamingData) with originalStreamingData, which is only used to initialize the {@link FormatStreamModel} class to measure the video length.
* To get workaround with this, replace streamingData (spoofedStreamingData) with originalStreamingData,
* which is only used to initialize the {@link FormatStreamModel} class to calculate the video length.
* The playback issues shouldn't occur since the integrity check is not applied for Progressive Stream.
* <p>
* Called after {@link #getStreamingData(String, StreamingDataOuterClass$StreamingData)}.
*
@ -156,15 +160,10 @@ public class SpoofStreamingDataPatch extends BlockRequestPatch {
try {
StreamingDataOuterClass$StreamingData androidStreamingData = streamingDataMap.get(videoId);
if (androidStreamingData != null) {
ClientType clientType = clientTypeMap.get(androidStreamingData);
if (clientType == ClientType.IOS) {
Logger.printDebug(() -> "Overriding iOS streaming data to original streaming data: " + videoId);
return androidStreamingData;
} else {
Logger.printDebug(() -> "Not overriding original streaming data as spoofed client is not iOS: " + videoId + " (" + clientType + ")");
}
Logger.printDebug(() -> "Overriding iOS streaming data to original streaming data: " + videoId);
return androidStreamingData;
} else {
Logger.printDebug(() -> "Not overriding original streaming data (original streaming data is null): " + videoId);
Logger.printDebug(() -> "Not overriding original streaming data as spoofed client is not iOS: " + videoId);
}
} catch (Exception ex) {
Logger.printException(() -> "getOriginalStreamingData failure", ex);

View File

@ -189,7 +189,6 @@ public class StreamingDataRequest {
} else {
try (InputStream inputStream = new BufferedInputStream(connection.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) >= 0) {