Abstract RequestModifier, AdHocRequestModifier, RequestModifierOptions

This commit is contained in:
Kelvin 2023-12-12 14:44:07 +01:00
commit 49b5b16641
11 changed files with 136 additions and 52 deletions

View file

@ -0,0 +1,14 @@
package com.futo.platformplayer.api.media.models.modifier
class AdhocRequestModifier: IRequestModifier {
val _handler: (String, Map<String,String>)->IRequest;
override var allowByteSkip: Boolean = false;
constructor(modifyReq: (String, Map<String,String>)->IRequest) {
_handler = modifyReq;
}
override fun modifyRequest(url: String, headers: Map<String, String>): IRequest {
return _handler(url, headers);
}
}

View file

@ -0,0 +1,6 @@
package com.futo.platformplayer.api.media.models.modifier
interface IModifierOptions {
val applyAuthClient: String?;
val applyCookieClient: String?;
}

View file

@ -0,0 +1,6 @@
package com.futo.platformplayer.api.media.models.modifier
interface IRequest {
val url: String?;
val headers: Map<String, String>;
}

View file

@ -0,0 +1,7 @@
package com.futo.platformplayer.api.media.models.modifier
interface IRequestModifier {
var allowByteSkip: Boolean;
fun modifyRequest(url: String, headers: Map<String, String>): IRequest
}

View file

@ -57,11 +57,6 @@ class JSHttpClient : ManagedHttpClient {
return newClient; return newClient;
} }
fun applyRequest(req: JSRequestModifier.Request) {
}
//TODO: Use this in beforeRequest to remove dup code //TODO: Use this in beforeRequest to remove dup code
fun applyHeaders(url: Uri, headers: MutableMap<String, String>, applyAuth: Boolean = false, applyOtherCookies: Boolean = false) { fun applyHeaders(url: Uri, headers: MutableMap<String, String>, applyAuth: Boolean = false, applyOtherCookies: Boolean = false) {
val domain = url.host!!.lowercase(); val domain = url.host!!.lowercase();

View file

@ -1,18 +1,81 @@
package com.futo.platformplayer.api.media.platforms.js.models package com.futo.platformplayer.api.media.platforms.js.models
import android.net.Uri
import com.caoccao.javet.values.reference.V8ValueObject import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.api.media.models.modifier.IModifierOptions
import com.futo.platformplayer.api.media.models.modifier.IRequest
import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.engine.IV8PluginConfig import com.futo.platformplayer.engine.IV8PluginConfig
import com.futo.platformplayer.getOrThrow import com.futo.platformplayer.getOrDefault
import com.futo.platformplayer.logging.Logger
@kotlinx.serialization.Serializable @kotlinx.serialization.Serializable
class JSRequest : JSRequestModifier.IRequest { class JSRequest : IRequest {
override val url: String; private val _v8Url: String?;
override var headers: Map<String, String>; private val _v8Headers: Map<String, String>?;
private val _v8Options: Options?;
constructor(config: IV8PluginConfig, obj: V8ValueObject) { override var url: String? = null;
override lateinit var headers: Map<String, String>;
constructor(plugin: JSClient, url: String?, headers: Map<String, String>?, options: Options?, originalUrl: String?, originalHeaders: Map<String, String>?) {
_v8Url = url;
_v8Headers = headers;
_v8Options = options;
initialize(plugin, originalUrl, originalHeaders);
}
constructor(plugin: JSClient, obj: V8ValueObject, originalUrl: String?, originalHeaders: Map<String, String>?) {
val contextName = "ModifyRequestResponse"; val contextName = "ModifyRequestResponse";
url = obj.getOrThrow(config, "url", contextName); val config = plugin.config;
headers = obj.getOrThrow(config, "headers", contextName); _v8Url = obj.getOrDefault<String>(config, "url", contextName, null);
_v8Headers = obj.getOrDefault<Map<String, String>>(config, "headers", contextName, null);
_v8Options = obj.getOrDefault<V8ValueObject>(config, "options", "JSRequestModifier.options", null)?.let {
Options(config, it);
}
initialize(plugin, originalUrl, originalHeaders);
}
private fun initialize(plugin: JSClient, originalUrl: String?, originalHeaders: Map<String, String>?) {
val config = plugin.config;
url = _v8Url ?: originalUrl;
headers = _v8Headers ?: originalHeaders ?: mapOf();
if(_v8Options != null) {
if(_v8Options.applyCookieClient != null && url != null) {
val client = plugin.getHttpClientById(_v8Options.applyCookieClient);
if(client != null) {
val toModifyHeaders = headers.toMutableMap();
client.applyHeaders(Uri.parse(url), toModifyHeaders, false, true);
headers = toModifyHeaders;
}
}
if(_v8Options.applyAuthClient != null && url != null) {
val client = plugin.getHttpClientById(_v8Options.applyAuthClient);
if(client != null) {
val toModifyHeaders = headers.toMutableMap();
client.applyHeaders(Uri.parse(url), toModifyHeaders, true, false);
headers = toModifyHeaders;
}
}
}
}
fun modify(plugin: JSClient, originalUrl: String?, originalHeaders: Map<String, String>?): JSRequest {
return JSRequest(plugin, _v8Url, _v8Headers, _v8Options, originalUrl, originalHeaders);
}
@kotlinx.serialization.Serializable
class Options: IModifierOptions {
override val applyAuthClient: String?;
override val applyCookieClient: String?;
constructor(config: IV8PluginConfig, obj: V8ValueObject) {
applyAuthClient = obj.getOrDefault(config, "applyAuthClient", "JSRequestModifier.options.applyAuthClient", null);
applyCookieClient = obj.getOrDefault(config, "applyCookieClient", "JSRequestModifier.options.applyCookieClient", null);
}
}
companion object {
} }
} }

View file

@ -2,6 +2,8 @@ package com.futo.platformplayer.api.media.platforms.js.models
import android.net.Uri import android.net.Uri
import com.caoccao.javet.values.reference.V8ValueObject 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
import com.futo.platformplayer.api.media.platforms.js.JSClient import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.engine.IV8PluginConfig import com.futo.platformplayer.engine.IV8PluginConfig
import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.engine.V8Plugin
@ -10,11 +12,11 @@ import com.futo.platformplayer.getOrDefault
import com.futo.platformplayer.getOrNull import com.futo.platformplayer.getOrNull
import com.futo.platformplayer.getOrThrow import com.futo.platformplayer.getOrThrow
class JSRequestModifier { class JSRequestModifier: IRequestModifier {
private val _plugin: JSClient; private val _plugin: JSClient;
private val _config: IV8PluginConfig; private val _config: IV8PluginConfig;
private var _modifier: V8ValueObject; private var _modifier: V8ValueObject;
val allowByteSkip: Boolean; override var allowByteSkip: Boolean;
constructor(plugin: JSClient, modifier: V8ValueObject) { constructor(plugin: JSClient, modifier: V8ValueObject) {
this._plugin = plugin; this._plugin = plugin;
@ -28,7 +30,7 @@ class JSRequestModifier {
throw ScriptImplementationException(config, "RequestModifier is missing modifyRequest", null); throw ScriptImplementationException(config, "RequestModifier is missing modifyRequest", null);
} }
fun modifyRequest(url: String, headers: Map<String, String>): IRequest { override fun modifyRequest(url: String, headers: Map<String, String>): IRequest {
if (_modifier.isClosed) { if (_modifier.isClosed) {
return Request(url, headers); return Request(url, headers);
} }
@ -37,35 +39,10 @@ class JSRequestModifier {
_modifier.invoke("modifyRequest", url, headers); _modifier.invoke("modifyRequest", url, headers);
} as V8ValueObject; } as V8ValueObject;
val req = JSRequest(_config, result); val req = JSRequest(_plugin, result, url, headers);
val options: V8ValueObject? = result.getOrDefault(_config, "options", "JSRequestModifier.options", null);
if(options != null) {
if(options.has("applyCookieClient")) {
val clientId: String = options.getOrThrow(_config, "applyCookieClient", "JSRequestModifier.options.applyCookieClient", false)
val client = _plugin.getHttpClientById(clientId);
if(client != null) {
val toModifyHeaders = req.headers.toMutableMap();
client.applyHeaders(Uri.parse(req.url), toModifyHeaders, false, true);
req.headers = toModifyHeaders;
}
}
if(options.has("applyAuthClient")) {
val clientId: String = options.getOrThrow(_config, "applyAuthClient", "JSRequestModifier.options.applyAuthClient", false)
val client = _plugin.getHttpClientById(clientId);
if(client != null) {
val toModifyHeaders = req.headers.toMutableMap();
client.applyHeaders(Uri.parse(req.url), toModifyHeaders, true, false);
req.headers = toModifyHeaders;
}
}
}
return req; return req;
} }
interface IRequest {
val url: String;
val headers: Map<String, String>;
}
data class Request(override val url: String, override val headers: Map<String, String>) : IRequest; data class Request(override val url: String, override val headers: Map<String, String>) : IRequest;
} }

View file

@ -4,12 +4,16 @@ package com.futo.platformplayer.api.media.platforms.js.models.sources
import com.caoccao.javet.values.V8Value import com.caoccao.javet.values.V8Value
import com.caoccao.javet.values.reference.V8ValueObject import com.caoccao.javet.values.reference.V8ValueObject
import com.futo.platformplayer.api.media.models.modifier.AdhocRequestModifier
import com.futo.platformplayer.api.media.models.modifier.IRequestModifier
import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource
import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource
import com.futo.platformplayer.api.media.platforms.js.JSClient import com.futo.platformplayer.api.media.platforms.js.JSClient
import com.futo.platformplayer.api.media.platforms.js.models.JSRequest
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestModifier import com.futo.platformplayer.api.media.platforms.js.models.JSRequestModifier
import com.futo.platformplayer.engine.IV8PluginConfig import com.futo.platformplayer.engine.IV8PluginConfig
import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.engine.V8Plugin
import com.futo.platformplayer.getOrDefault
import com.futo.platformplayer.orNull import com.futo.platformplayer.orNull
import com.futo.platformplayer.views.video.datasources.JSHttpDataSource import com.futo.platformplayer.views.video.datasources.JSHttpDataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
@ -20,6 +24,7 @@ abstract class JSSource {
protected val _config: IV8PluginConfig; protected val _config: IV8PluginConfig;
protected val _obj: V8ValueObject; protected val _obj: V8ValueObject;
val hasRequestModifier: Boolean; val hasRequestModifier: Boolean;
private val _requestModifier: JSRequest?;
val type : String; val type : String;
@ -29,10 +34,18 @@ abstract class JSSource {
this._obj = obj; this._obj = obj;
this.type = type; this.type = type;
hasRequestModifier = obj.has("getRequestModifier"); _requestModifier = obj.getOrDefault<V8ValueObject>(_config, "requestModifier", "JSSource.requestModifier", null)?.let {
JSRequest(plugin, it, null, null);
}
hasRequestModifier = _requestModifier != null || obj.has("getRequestModifier");
} }
fun getRequestModifier(): JSRequestModifier? { fun getRequestModifier(): IRequestModifier? {
if(_requestModifier != null)
return AdhocRequestModifier { url, headers ->
return@AdhocRequestModifier _requestModifier.modify(_plugin, url, headers);
};
if (!hasRequestModifier || _obj.isClosed) { if (!hasRequestModifier || _obj.isClosed) {
return null; return null;
} }

View file

@ -9,6 +9,8 @@ import android.net.Uri;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
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; import com.futo.platformplayer.api.media.platforms.js.models.JSRequestModifier;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
@ -57,7 +59,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
private int readTimeoutMs; private int readTimeoutMs;
private boolean allowCrossProtocolRedirects; private boolean allowCrossProtocolRedirects;
private boolean keepPostFor302Redirects; private boolean keepPostFor302Redirects;
@Nullable private JSRequestModifier requestModifier = null; @Nullable private IRequestModifier requestModifier = null;
/** Creates an instance. */ /** Creates an instance. */
public Factory() { public Factory() {
@ -80,7 +82,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
* @param requestModifier The request modifier that will be used, or {@code null} to use no request modifier * @param requestModifier The request modifier that will be used, or {@code null} to use no request modifier
* @return This factory. * @return This factory.
*/ */
public Factory setRequestModifier(@Nullable JSRequestModifier requestModifier) { public Factory setRequestModifier(@Nullable IRequestModifier requestModifier) {
this.requestModifier = requestModifier; this.requestModifier = requestModifier;
return this; return this;
} }
@ -225,7 +227,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
private int responseCode; private int responseCode;
private long bytesToRead; private long bytesToRead;
private long bytesRead; private long bytesRead;
@Nullable private JSRequestModifier requestModifier; @Nullable private IRequestModifier requestModifier;
private JSHttpDataSource( private JSHttpDataSource(
@Nullable String userAgent, @Nullable String userAgent,
@ -235,7 +237,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
@Nullable RequestProperties defaultRequestProperties, @Nullable RequestProperties defaultRequestProperties,
@Nullable Predicate<String> contentTypePredicate, @Nullable Predicate<String> contentTypePredicate,
boolean keepPostFor302Redirects, boolean keepPostFor302Redirects,
@Nullable JSRequestModifier requestModifier) { @Nullable IRequestModifier requestModifier) {
super(/* isNetwork= */ true); super(/* isNetwork= */ true);
this.userAgent = userAgent; this.userAgent = userAgent;
this.connectTimeoutMillis = connectTimeoutMillis; this.connectTimeoutMillis = connectTimeoutMillis;
@ -571,8 +573,9 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
String requestUrl = url.toString(); String requestUrl = url.toString();
if (requestModifier != null) { if (requestModifier != null) {
JSRequestModifier.IRequest result = requestModifier.modifyRequest(requestUrl, requestHeaders); IRequest result = requestModifier.modifyRequest(requestUrl, requestHeaders);
requestUrl = result.getUrl(); String modifiedUrl = result.getUrl();
requestUrl = (modifiedUrl != null) ? modifiedUrl : requestUrl;
requestHeaders = result.getHeaders(); requestHeaders = result.getHeaders();
} }

@ -1 +1 @@
Subproject commit f2086dc2cf6387f692049f52cdf938313dc53654 Subproject commit f031e10d3852dd7138f2ed312c5e74466f23da32

@ -1 +1 @@
Subproject commit fad5e14f84573796b3989794c35f34a1f88f03a6 Subproject commit d41cc8e848891ef8e949e6d49384b754e7c305c7