diff --git a/app/src/main/assets/devportal/plugin.d.ts b/app/src/main/assets/devportal/plugin.d.ts index 23db7d2f..f0660730 100644 --- a/app/src/main/assets/devportal/plugin.d.ts +++ b/app/src/main/assets/devportal/plugin.d.ts @@ -243,7 +243,9 @@ declare class DashSource implements IVideoSource { declare interface IRequest { url: string, - headers: Map + headers: Map, + method: string, + body?: string } declare interface IRequestModifierDef { allowByteSkip: boolean @@ -251,7 +253,7 @@ declare interface IRequestModifierDef { declare class RequestModifier { constructor(obj: IRequestModifierDef) { } - modifyRequest(url: string, headers: Map): IRequest; + modifyRequest(url: string, headers: Map, method: string, body?: string): IRequest; } //Channel diff --git a/app/src/main/java/com/futo/platformplayer/Extensions_Content.kt b/app/src/main/java/com/futo/platformplayer/Extensions_Content.kt index 71516d7f..008ffab6 100644 --- a/app/src/main/java/com/futo/platformplayer/Extensions_Content.kt +++ b/app/src/main/java/com/futo/platformplayer/Extensions_Content.kt @@ -1,4 +1,4 @@ -import androidx.annotation.OptIn + import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.DefaultHttpDataSource import androidx.media3.datasource.HttpDataSource diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/AdhocRequestModifier.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/AdhocRequestModifier.kt index ea250ae4..6a1679bf 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/AdhocRequestModifier.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/AdhocRequestModifier.kt @@ -1,14 +1,14 @@ package com.futo.platformplayer.api.media.models.modifier class AdhocRequestModifier: IRequestModifier { - val _handler: (String, Map)->IRequest; + val _handler: (String, Map, String, String?)->IRequest; override var allowByteSkip: Boolean = false; - constructor(modifyReq: (String, Map)->IRequest) { + constructor(modifyReq: (String, Map, String, String?)->IRequest) { _handler = modifyReq; } - override fun modifyRequest(url: String, headers: Map): IRequest { - return _handler(url, headers); + override fun modifyRequest(url: String, headers: Map, method: String, body: String?): IRequest { + return _handler(url, headers, method, body); } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequest.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequest.kt index 43cd502c..abb9f3dd 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequest.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequest.kt @@ -1,6 +1,8 @@ package com.futo.platformplayer.api.media.models.modifier interface IRequest { + val method: String?; val url: String?; - val headers: Map; + val headers: Map?; + val body: String?; } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequestModifier.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequestModifier.kt index f15ee477..0b8f12cb 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequestModifier.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/modifier/IRequestModifier.kt @@ -3,5 +3,5 @@ package com.futo.platformplayer.api.media.models.modifier interface IRequestModifier { var allowByteSkip: Boolean; - fun modifyRequest(url: String, headers: Map): IRequest + fun modifyRequest(url: String, headers: Map, method: String, body: String?): IRequest } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequest.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequest.kt index bc3b6bfc..0f84d071 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequest.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequest.kt @@ -12,31 +12,40 @@ import com.futo.platformplayer.getOrDefault class JSRequest : IRequest { private val _v8Url: String?; private val _v8Headers: Map?; + private val _v8Method: String?; + private val _v8Body: String?; private val _v8Options: Options?; override var url: String? = null; override lateinit var headers: Map; + override var method: String? = null; + override var body: String? = null; - constructor(plugin: JSClient, url: String?, headers: Map?, options: Options?, originalUrl: String?, originalHeaders: Map?) { + constructor(plugin: JSClient, url: String?, headers: Map?, method: String?, body: String?, options: Options?, originalUrl: String?, originalHeaders: Map?, originalMethod: String?, originalBody: String?) { _v8Url = url; _v8Headers = headers; + _v8Method = method; + _v8Body = body; _v8Options = options; - initialize(plugin, originalUrl, originalHeaders); + initialize(plugin, originalUrl, originalHeaders, originalMethod, originalBody); } - constructor(plugin: JSClient, obj: V8ValueObject, originalUrl: String?, originalHeaders: Map?, applyOtherHeadersByDefault: Boolean = false) { + constructor(plugin: JSClient, obj: V8ValueObject, originalUrl: String?, originalHeaders: Map?, originalMethod: String?, originalBody: String?, applyOtherHeadersByDefault: Boolean = false) { val contextName = "ModifyRequestResponse"; val config = plugin.config; _v8Url = obj.getOrDefault(config, "url", contextName, null); _v8Headers = obj.getOrDefault>(config, "headers", contextName, null); + _v8Method = obj.getOrDefault(config, "method", contextName, null); + _v8Body = obj.getOrDefault(config, "body", contextName, null); _v8Options = obj.getOrDefault(config, "options", "JSRequestModifier.options", null)?.let { Options(config, it, applyOtherHeadersByDefault); } ?: Options(null, null, applyOtherHeadersByDefault); - initialize(plugin, originalUrl, originalHeaders); + initialize(plugin, originalUrl, originalHeaders, originalMethod, originalBody); } - private fun initialize(plugin: JSClient, originalUrl: String?, originalHeaders: Map?) { - val config = plugin.config; + private fun initialize(plugin: JSClient, originalUrl: String?, originalHeaders: Map?, originalMethod: String?, originalBody: String?) { url = _v8Url ?: originalUrl; + method = _v8Method ?: originalMethod; + body = _v8Body ?: originalBody; if(_v8Options?.applyOtherHeaders ?: false) { val headersToSet = _v8Headers?.toMutableMap() ?: mutableMapOf(); @@ -69,8 +78,8 @@ class JSRequest : IRequest { } } - fun modify(plugin: JSClient, originalUrl: String?, originalHeaders: Map?): JSRequest { - return JSRequest(plugin, _v8Url, _v8Headers, _v8Options, originalUrl, originalHeaders); + fun modify(plugin: JSClient, originalUrl: String?, originalHeaders: Map?, originalMethod: String?, originalBody: String?): JSRequest { + return JSRequest(plugin, _v8Url, _v8Headers, _v8Method, _v8Body, _v8Options, originalUrl, originalHeaders, originalMethod, originalBody); } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequestModifier.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequestModifier.kt index 150189e7..1222d318 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequestModifier.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSRequestModifier.kt @@ -1,6 +1,5 @@ package com.futo.platformplayer.api.media.platforms.js.models -import android.net.Uri import com.caoccao.javet.values.reference.V8ValueObject import com.futo.platformplayer.api.media.models.modifier.IRequest import com.futo.platformplayer.api.media.models.modifier.IRequestModifier @@ -8,9 +7,7 @@ import com.futo.platformplayer.api.media.platforms.js.JSClient import com.futo.platformplayer.engine.IV8PluginConfig import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.engine.exceptions.ScriptImplementationException -import com.futo.platformplayer.getOrDefault import com.futo.platformplayer.getOrNull -import com.futo.platformplayer.getOrThrow class JSRequestModifier: IRequestModifier { private val _plugin: JSClient; @@ -30,20 +27,20 @@ class JSRequestModifier: IRequestModifier { throw ScriptImplementationException(config, "RequestModifier is missing modifyRequest", null); } - override fun modifyRequest(url: String, headers: Map): IRequest { + override fun modifyRequest(url: String, headers: Map, method: String, body: String?): IRequest { if (_modifier.isClosed) { - return Request(url, headers); + return Request(url, headers, method, body); } val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSRequestModifier", "builder.modifyRequest()") { - _modifier.invoke("modifyRequest", url, headers); + _modifier.invoke("modifyRequest", url, headers, method, body); } as V8ValueObject; - val req = JSRequest(_plugin, result, url, headers); + val req = JSRequest(_plugin, result, url, headers, method, body); result.close(); return req; } - data class Request(override val url: String, override val headers: Map) : IRequest; + data class Request(override val url: String, override val headers: Map, override val method: String, override val body: String?) : IRequest; } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt index 9074e28e..dda615db 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSSource.kt @@ -1,7 +1,5 @@ package com.futo.platformplayer.api.media.platforms.js.models.sources -import androidx.media3.datasource.DefaultHttpDataSource -import androidx.media3.datasource.HttpDataSource import com.caoccao.javet.values.V8Value import com.caoccao.javet.values.reference.V8ValueObject import com.futo.platformplayer.api.media.models.modifier.AdhocRequestModifier @@ -15,7 +13,6 @@ import com.futo.platformplayer.engine.IV8PluginConfig import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrDefault import com.futo.platformplayer.orNull -import com.futo.platformplayer.views.video.datasources.JSHttpDataSource abstract class JSSource { protected val _plugin: JSClient; @@ -33,15 +30,15 @@ abstract class JSSource { this.type = type; _requestModifier = obj.getOrDefault(_config, "requestModifier", "JSSource.requestModifier", null)?.let { - JSRequest(plugin, it, null, null, true); + JSRequest(plugin, it, null, null, null, null, true); } hasRequestModifier = _requestModifier != null || obj.has("getRequestModifier"); } fun getRequestModifier(): IRequestModifier? { if(_requestModifier != null) - return AdhocRequestModifier { url, headers -> - return@AdhocRequestModifier _requestModifier.modify(_plugin, url, headers); + return AdhocRequestModifier { url, headers, method, body -> + return@AdhocRequestModifier _requestModifier.modify(_plugin, url, headers, method, body); }; if (!hasRequestModifier || _obj.isClosed) { diff --git a/app/src/main/java/com/futo/platformplayer/views/video/datasources/JSHttpDataSource.java b/app/src/main/java/com/futo/platformplayer/views/video/datasources/JSHttpDataSource.java index 4c99ccb9..e32339bf 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/datasources/JSHttpDataSource.java +++ b/app/src/main/java/com/futo/platformplayer/views/video/datasources/JSHttpDataSource.java @@ -6,11 +6,13 @@ import static androidx.media3.datasource.HttpUtil.buildRangeRequestHeader; import static java.lang.Math.min; import android.net.Uri; +import android.util.Base64; import android.util.Log; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; +import com.futo.platformplayer.api.http.ManagedHttpClient; import com.futo.platformplayer.api.media.models.modifier.IRequest; import com.futo.platformplayer.api.media.models.modifier.IRequestModifier; import com.futo.platformplayer.api.media.platforms.js.models.JSRequestModifier; @@ -24,6 +26,7 @@ import androidx.media3.datasource.DataSpec; import androidx.media3.datasource.HttpDataSource; import androidx.media3.datasource.HttpUtil; import androidx.media3.datasource.TransferListener; +import androidx.work.impl.utils.PackageManagerHelper; import com.google.common.base.Predicate; import com.google.common.collect.ForwardingMap; @@ -39,12 +42,16 @@ import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.NoRouteToHostException; import java.net.URL; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.zip.GZIPInputStream; +import okhttp3.OkHttpClient; + /* * Based on the default ExoPlayer DefaultHttpDataSource */ @@ -315,6 +322,12 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource { responseMessage = connection.getResponseMessage(); } catch (IOException e) { closeConnectionQuietly(); + Log.e(TAG, "Failed to open: " + dataSpec.uri, e); + + ManagedHttpClient client = new ManagedHttpClient(new OkHttpClient.Builder()); + ManagedHttpClient.Response response = client.head(dataSpec.uri.toString(), new HashMap<>()); + Log.i(TAG, "ManagedHttpClient response code: " + response.getCode()); + throw HttpDataSourceException.createForIOException( e, dataSpec, HttpDataSourceException.TYPE_OPEN); } @@ -574,12 +587,26 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource { requestHeaders.put(HttpHeaders.ACCEPT_ENCODING, allowGzip ? "gzip" : "identity"); + String requestMethod = DataSpec.getStringForHttpMethod(httpMethod); String requestUrl = url.toString(); if (requestModifier != null) { - IRequest result = requestModifier.modifyRequest(requestUrl, requestHeaders); + IRequest result = requestModifier.modifyRequest(requestUrl, requestHeaders, requestMethod, httpBody != null ? new String(httpBody, StandardCharsets.UTF_8) : null); + String modifiedUrl = result.getUrl(); - requestUrl = (modifiedUrl != null) ? modifiedUrl : requestUrl; - requestHeaders = result.getHeaders(); + if (modifiedUrl != null) + requestUrl = modifiedUrl; + + Map modifiedHeaders = result.getHeaders(); + if (modifiedHeaders != null) + requestHeaders = modifiedHeaders; + + String modifiedMethod = result.getMethod(); + if (modifiedMethod != null) + requestMethod = modifiedMethod; + + String modifiedBody = result.getBody(); + if (modifiedBody != null) + httpBody = modifiedBody.getBytes(StandardCharsets.UTF_8); } HttpURLConnection connection = openConnection(new URL(requestUrl)); @@ -592,7 +619,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource { connection.setInstanceFollowRedirects(followRedirects); connection.setDoOutput(httpBody != null); - connection.setRequestMethod(DataSpec.getStringForHttpMethod(httpMethod)); + connection.setRequestMethod(requestMethod); if (httpBody != null) { connection.setFixedLengthStreamingMode(httpBody.length); diff --git a/app/src/unstable/assets/sources/youtube b/app/src/unstable/assets/sources/youtube index c86c73db..512c76a5 160000 --- a/app/src/unstable/assets/sources/youtube +++ b/app/src/unstable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit c86c73db0cdde3371c7944dd82c34ea4e5c725d9 +Subproject commit 512c76a52bb39f2c9280cbd0d99d8e334bd71f5f