mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-05-01 07:04:35 +02:00
switch to executor structure
This commit is contained in:
parent
a41b138d3c
commit
09c09f3d64
@ -367,6 +367,16 @@ class VideoUrlSource {
|
|||||||
this.requestModifier = obj.requestModifier;
|
this.requestModifier = obj.requestModifier;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
class VideoUrlWidevineSource extends VideoUrlSource {
|
||||||
|
constructor(obj) {
|
||||||
|
super(obj);
|
||||||
|
this.plugin_type = "VideoUrlWidevineSource";
|
||||||
|
|
||||||
|
this.licenseUri = obj.licenseUri;
|
||||||
|
if(obj.getLicenseExecutor)
|
||||||
|
this.getLicenseExecutor = obj.getLicenseExecutor;
|
||||||
|
}
|
||||||
|
}
|
||||||
class VideoUrlRangeSource extends VideoUrlSource {
|
class VideoUrlRangeSource extends VideoUrlSource {
|
||||||
constructor(obj) {
|
constructor(obj) {
|
||||||
super(obj);
|
super(obj);
|
||||||
@ -399,16 +409,26 @@ class AudioUrlWidevineSource extends AudioUrlSource {
|
|||||||
super(obj);
|
super(obj);
|
||||||
this.plugin_type = "AudioUrlWidevineSource";
|
this.plugin_type = "AudioUrlWidevineSource";
|
||||||
|
|
||||||
if(obj.bearerToken) {
|
|
||||||
this.licenseHeaders = {
|
|
||||||
Authorization: `Bearer ${obj.bearerToken}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.licenseUri = obj.licenseUri;
|
this.licenseUri = obj.licenseUri;
|
||||||
if(obj.licenseHeaders) {
|
if(obj.getLicenseExecutor)
|
||||||
this.licenseHeaders = obj.licenseHeaders;
|
this.getLicenseExecutor = obj.getLicenseExecutor;
|
||||||
|
|
||||||
|
// deprecated api conversion
|
||||||
|
if(obj.bearerToken) {
|
||||||
|
this.getLicenseExecutor = () => {
|
||||||
|
return {
|
||||||
|
executeRequest: (url, _headers, _method, license_request_data) => {
|
||||||
|
return http.POST(
|
||||||
|
url,
|
||||||
|
license_request_data,
|
||||||
|
{ Authorization: `Bearer ${obj.bearerToken}` },
|
||||||
|
false,
|
||||||
|
true
|
||||||
|
).body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.decodeLicenseResponse = obj.decodeLicenseResponse ?? false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class AudioUrlRangeSource extends AudioUrlSource {
|
class AudioUrlRangeSource extends AudioUrlSource {
|
||||||
@ -457,10 +477,8 @@ class DashWidevineSource extends DashSource {
|
|||||||
this.plugin_type = "DashWidevineSource";
|
this.plugin_type = "DashWidevineSource";
|
||||||
|
|
||||||
this.licenseUri = obj.licenseUri;
|
this.licenseUri = obj.licenseUri;
|
||||||
if(obj.licenseHeaders) {
|
if(obj.getLicenseExecutor)
|
||||||
this.licenseHeaders = obj.licenseHeaders;
|
this.getLicenseExecutor = obj.getLicenseExecutor;
|
||||||
}
|
|
||||||
this.decodeLicenseResponse = obj.decodeLicenseResponse
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class DashManifestRawSource {
|
class DashManifestRawSource {
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
package com.futo.platformplayer.api.media.models.streams.sources
|
||||||
|
|
||||||
|
interface IVideoUrlWidevineSource : IVideoUrlSource, IWidevineSource
|
@ -1,10 +1,9 @@
|
|||||||
package com.futo.platformplayer.api.media.models.streams.sources
|
package com.futo.platformplayer.api.media.models.streams.sources
|
||||||
|
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||||
|
|
||||||
interface IWidevineSource {
|
interface IWidevineSource {
|
||||||
val licenseUri: String
|
val licenseUri: String
|
||||||
val licenseHeaders: Map<String, String>?
|
val hasLicenseExecutor: Boolean
|
||||||
/**
|
fun getLicenseExecutor(): JSRequestExecutor?
|
||||||
* Set this to true if the license response is Base64 encoded
|
|
||||||
*/
|
|
||||||
val decodeLicenseResponse: Boolean
|
|
||||||
}
|
}
|
@ -42,7 +42,7 @@ class JSRequestExecutor {
|
|||||||
|
|
||||||
//TODO: Executor properties?
|
//TODO: Executor properties?
|
||||||
@Throws(ScriptException::class)
|
@Throws(ScriptException::class)
|
||||||
open fun executeRequest(url: String, headers: Map<String, String>): ByteArray {
|
open fun executeRequest(method: String, url: String, body: ByteArray?, headers: Map<String, String>): ByteArray {
|
||||||
if (_executor.isClosed)
|
if (_executor.isClosed)
|
||||||
throw IllegalStateException("Executor object is closed");
|
throw IllegalStateException("Executor object is closed");
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ class JSRequestExecutor {
|
|||||||
"[${_config.name}] JSRequestExecutor",
|
"[${_config.name}] JSRequestExecutor",
|
||||||
"builder.modifyRequest()"
|
"builder.modifyRequest()"
|
||||||
) {
|
) {
|
||||||
_executor.invoke("executeRequest", url, headers);
|
_executor.invoke("executeRequest", url, headers, method, body);
|
||||||
} as V8Value;
|
} as V8Value;
|
||||||
}
|
}
|
||||||
else V8Plugin.catchScriptErrors<Any>(
|
else V8Plugin.catchScriptErrors<Any>(
|
||||||
@ -61,7 +61,7 @@ class JSRequestExecutor {
|
|||||||
"[${_config.name}] JSRequestExecutor",
|
"[${_config.name}] JSRequestExecutor",
|
||||||
"builder.modifyRequest()"
|
"builder.modifyRequest()"
|
||||||
) {
|
) {
|
||||||
_executor.invoke("executeRequest", url, headers);
|
_executor.invoke("executeRequest", url, headers, method, body);
|
||||||
} as V8Value;
|
} as V8Value;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -3,26 +3,39 @@ package com.futo.platformplayer.api.media.platforms.js.models.sources
|
|||||||
import com.caoccao.javet.values.reference.V8ValueObject
|
import com.caoccao.javet.values.reference.V8ValueObject
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlWidevineSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlWidevineSource
|
||||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||||
import com.futo.platformplayer.getOrDefault
|
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||||
|
import com.futo.platformplayer.engine.V8Plugin
|
||||||
import com.futo.platformplayer.getOrThrow
|
import com.futo.platformplayer.getOrThrow
|
||||||
|
|
||||||
class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource {
|
class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource {
|
||||||
override val licenseHeaders: Map<String, String>?
|
|
||||||
override val licenseUri: String
|
override val licenseUri: String
|
||||||
override val decodeLicenseResponse: Boolean
|
override val hasLicenseExecutor: Boolean
|
||||||
|
|
||||||
@Suppress("ConvertSecondaryConstructorToPrimary")
|
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||||
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) {
|
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) {
|
||||||
val contextName = "JSAudioUrlWidevineSource"
|
val contextName = "JSAudioUrlWidevineSource"
|
||||||
val config = plugin.config
|
val config = plugin.config
|
||||||
licenseHeaders =
|
|
||||||
obj.getOrDefault<Map<String, String>>(config, "licenseHeaders", contextName, null)
|
|
||||||
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
||||||
decodeLicenseResponse = _obj.getOrThrow(config, "decodeLicenseResponse", contextName)
|
hasLicenseExecutor = obj.has("getLicenseExecutor")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLicenseExecutor(): JSRequestExecutor? {
|
||||||
|
if (!hasLicenseExecutor || _obj.isClosed)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSDashManifestWidevineSource", "obj.getLicenseExecutor()") {
|
||||||
|
_obj.invoke("getLicenseExecutor", arrayOf<Any>())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result !is V8ValueObject)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return JSRequestExecutor(_plugin, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val url = getAudioUrl()
|
val url = getAudioUrl()
|
||||||
return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, licenseHeaders=${licenseHeaders.toString()}, licenseUri=$licenseUri)"
|
return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseExecutor=${hasLicenseExecutor}, licenseUri=$licenseUri)"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,8 @@ import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSou
|
|||||||
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestWidevineSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestWidevineSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
|
||||||
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||||
import com.futo.platformplayer.getOrDefault
|
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||||
|
import com.futo.platformplayer.engine.V8Plugin
|
||||||
import com.futo.platformplayer.getOrNull
|
import com.futo.platformplayer.getOrNull
|
||||||
import com.futo.platformplayer.getOrThrow
|
import com.futo.platformplayer.getOrThrow
|
||||||
|
|
||||||
@ -22,9 +23,8 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource,
|
|||||||
|
|
||||||
override var priority: Boolean = false
|
override var priority: Boolean = false
|
||||||
|
|
||||||
override val licenseHeaders: Map<String, String>?
|
|
||||||
override val licenseUri: String
|
override val licenseUri: String
|
||||||
override val decodeLicenseResponse: Boolean
|
override val hasLicenseExecutor: Boolean
|
||||||
|
|
||||||
@Suppress("ConvertSecondaryConstructorToPrimary")
|
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||||
constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH, plugin, obj) {
|
constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH, plugin, obj) {
|
||||||
@ -36,10 +36,22 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource,
|
|||||||
|
|
||||||
priority = obj.getOrNull(config, "priority", contextName) ?: false
|
priority = obj.getOrNull(config, "priority", contextName) ?: false
|
||||||
|
|
||||||
licenseHeaders =
|
|
||||||
obj.getOrDefault<Map<String, String>>(config, "licenseHeaders", contextName, null)
|
|
||||||
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
||||||
decodeLicenseResponse = _obj.getOrThrow(config, "decodeLicenseResponse", contextName)
|
hasLicenseExecutor = obj.has("getLicenseExecutor")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLicenseExecutor(): JSRequestExecutor? {
|
||||||
|
if (!hasLicenseExecutor || _obj.isClosed)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSDashManifestWidevineSource", "obj.getLicenseExecutor()") {
|
||||||
|
_obj.invoke("getLicenseExecutor", arrayOf<Any>())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result !is V8ValueObject)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return JSRequestExecutor(_plugin, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getVideoUrl(): String {
|
override fun getVideoUrl(): String {
|
||||||
|
@ -103,12 +103,14 @@ abstract class JSSource {
|
|||||||
const val TYPE_DASH_RAW_AUDIO = "DashRawAudioSource";
|
const val TYPE_DASH_RAW_AUDIO = "DashRawAudioSource";
|
||||||
const val TYPE_HLS = "HLSSource";
|
const val TYPE_HLS = "HLSSource";
|
||||||
const val TYPE_AUDIOURL_WIDEVINE = "AudioUrlWidevineSource"
|
const val TYPE_AUDIOURL_WIDEVINE = "AudioUrlWidevineSource"
|
||||||
|
const val TYPE_VIDEOURL_WIDEVINE = "VideoUrlWidevineSource"
|
||||||
|
|
||||||
fun fromV8VideoNullable(plugin: JSClient, obj: V8Value?) : IVideoSource? = obj.orNull { fromV8Video(plugin, it as V8ValueObject) };
|
fun fromV8VideoNullable(plugin: JSClient, obj: V8Value?) : IVideoSource? = obj.orNull { fromV8Video(plugin, it as V8ValueObject) };
|
||||||
fun fromV8Video(plugin: JSClient, obj: V8ValueObject) : IVideoSource? {
|
fun fromV8Video(plugin: JSClient, obj: V8ValueObject) : IVideoSource? {
|
||||||
val type = obj.getString("plugin_type");
|
val type = obj.getString("plugin_type");
|
||||||
return when(type) {
|
return when(type) {
|
||||||
TYPE_VIDEOURL -> JSVideoUrlSource(plugin, obj);
|
TYPE_VIDEOURL -> JSVideoUrlSource(plugin, obj);
|
||||||
|
TYPE_VIDEOURL_WIDEVINE -> JSVideoUrlWidevineSource(plugin, obj);
|
||||||
TYPE_VIDEO_WITH_METADATA -> JSVideoUrlRangeSource(plugin, obj);
|
TYPE_VIDEO_WITH_METADATA -> JSVideoUrlRangeSource(plugin, obj);
|
||||||
TYPE_HLS -> fromV8HLS(plugin, obj);
|
TYPE_HLS -> fromV8HLS(plugin, obj);
|
||||||
TYPE_DASH_WIDEVINE -> JSDashManifestWidevineSource(plugin, obj)
|
TYPE_DASH_WIDEVINE -> JSDashManifestWidevineSource(plugin, obj)
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
package com.futo.platformplayer.api.media.platforms.js.models.sources
|
||||||
|
|
||||||
|
import com.caoccao.javet.values.reference.V8ValueObject
|
||||||
|
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlWidevineSource
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.JSClient
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||||
|
import com.futo.platformplayer.engine.V8Plugin
|
||||||
|
import com.futo.platformplayer.getOrThrow
|
||||||
|
|
||||||
|
class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource {
|
||||||
|
override val licenseUri: String
|
||||||
|
override val hasLicenseExecutor: Boolean
|
||||||
|
|
||||||
|
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||||
|
constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) {
|
||||||
|
val contextName = "JSAudioUrlWidevineSource"
|
||||||
|
val config = plugin.config
|
||||||
|
|
||||||
|
licenseUri = _obj.getOrThrow(config, "licenseUri", contextName)
|
||||||
|
hasLicenseExecutor = obj.has("getLicenseExecutor")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLicenseExecutor(): JSRequestExecutor? {
|
||||||
|
if (!hasLicenseExecutor || _obj.isClosed)
|
||||||
|
return null
|
||||||
|
|
||||||
|
val result = V8Plugin.catchScriptErrors<Any>(_config, "[${_config.name}] JSDashManifestWidevineSource", "obj.getLicenseExecutor()") {
|
||||||
|
_obj.invoke("getLicenseExecutor", arrayOf<Any>())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result !is V8ValueObject)
|
||||||
|
return null
|
||||||
|
|
||||||
|
return JSRequestExecutor(_plugin, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
val url = getVideoUrl()
|
||||||
|
return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseExecutor=$hasLicenseExecutor, licenseUri=$licenseUri)"
|
||||||
|
}
|
||||||
|
}
|
@ -1245,7 +1245,7 @@ class StateCasting {
|
|||||||
|
|
||||||
val videoExecutor = _videoExecutor;
|
val videoExecutor = _videoExecutor;
|
||||||
if (videoExecutor != null) {
|
if (videoExecutor != null) {
|
||||||
val data = videoExecutor.executeRequest(originalUrl, httpContext.headers)
|
val data = videoExecutor.executeRequest("GET", originalUrl, null, httpContext.headers)
|
||||||
httpContext.respondBytes(200, HttpHeaders().apply {
|
httpContext.respondBytes(200, HttpHeaders().apply {
|
||||||
put("Content-Type", mediaType)
|
put("Content-Type", mediaType)
|
||||||
}, data);
|
}, data);
|
||||||
@ -1263,7 +1263,7 @@ class StateCasting {
|
|||||||
|
|
||||||
val audioExecutor = _audioExecutor;
|
val audioExecutor = _audioExecutor;
|
||||||
if (audioExecutor != null) {
|
if (audioExecutor != null) {
|
||||||
val data = audioExecutor.executeRequest(originalUrl, httpContext.headers)
|
val data = audioExecutor.executeRequest("GET", originalUrl, null, httpContext.headers)
|
||||||
httpContext.respondBytes(200, HttpHeaders().apply {
|
httpContext.respondBytes(200, HttpHeaders().apply {
|
||||||
put("Content-Type", mediaType)
|
put("Content-Type", mediaType)
|
||||||
}, data);
|
}, data);
|
||||||
|
@ -663,7 +663,7 @@ class VideoDownload {
|
|||||||
val url = foundTemplateUrl.replace("\$Number\$", indexCounter.toString());
|
val url = foundTemplateUrl.replace("\$Number\$", indexCounter.toString());
|
||||||
|
|
||||||
val data = if(executor != null)
|
val data = if(executor != null)
|
||||||
executor.executeRequest(url, mapOf());
|
executor.executeRequest("GET", url, null, mapOf());
|
||||||
else {
|
else {
|
||||||
val resp = client.get(url, mutableMapOf());
|
val resp = client.get(url, mutableMapOf());
|
||||||
if(!resp.isOk)
|
if(!resp.isOk)
|
||||||
|
@ -40,6 +40,7 @@ import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudi
|
|||||||
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestSource
|
||||||
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.models.streams.sources.IVideoUrlSource
|
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource
|
||||||
|
import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlWidevineSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
|
import com.futo.platformplayer.api.media.models.streams.sources.LocalAudioSource
|
||||||
import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
|
import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource
|
||||||
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
|
import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
|
||||||
@ -56,7 +57,7 @@ import com.futo.platformplayer.helpers.VideoHelper
|
|||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.states.StateApp
|
import com.futo.platformplayer.states.StateApp
|
||||||
import com.futo.platformplayer.video.PlayerManager
|
import com.futo.platformplayer.video.PlayerManager
|
||||||
import com.futo.platformplayer.views.video.datasources.Base64MediaDrmCallback
|
import com.futo.platformplayer.views.video.datasources.PluginMediaDrmCallback
|
||||||
import com.futo.platformplayer.views.video.datasources.JSHttpDataSource
|
import com.futo.platformplayer.views.video.datasources.JSHttpDataSource
|
||||||
import getHttpDataSourceFactory
|
import getHttpDataSourceFactory
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
@ -415,6 +416,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||||||
is IDashManifestSource -> { swapVideoSourceDash(videoSource); true;}
|
is IDashManifestSource -> { swapVideoSourceDash(videoSource); true;}
|
||||||
is JSDashManifestRawSource -> swapVideoSourceDashRaw(videoSource, play, resume);
|
is JSDashManifestRawSource -> swapVideoSourceDashRaw(videoSource, play, resume);
|
||||||
is IHLSManifestSource -> { swapVideoSourceHLS(videoSource); true; }
|
is IHLSManifestSource -> { swapVideoSourceHLS(videoSource); true; }
|
||||||
|
is IVideoUrlWidevineSource -> { swapVideoSourceUrlWidevine(videoSource); true; }
|
||||||
is IVideoUrlSource -> { swapVideoSourceUrl(videoSource); true; }
|
is IVideoUrlSource -> { swapVideoSourceUrl(videoSource); true; }
|
||||||
null -> { _lastVideoMediaSource = null; true;}
|
null -> { _lastVideoMediaSource = null; true;}
|
||||||
else -> throw IllegalArgumentException("Unsupported video source [${videoSource.javaClass.simpleName}]");
|
else -> throw IllegalArgumentException("Unsupported video source [${videoSource.javaClass.simpleName}]");
|
||||||
@ -479,6 +481,32 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||||||
.createMediaSource(MediaItem.fromUri(videoSource.getVideoUrl()));
|
.createMediaSource(MediaItem.fromUri(videoSource.getVideoUrl()));
|
||||||
}
|
}
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
|
private fun swapVideoSourceUrlWidevine(videoSource: IVideoUrlWidevineSource) {
|
||||||
|
Logger.i(TAG, "Loading VideoSource [UrlWidevine]");
|
||||||
|
val dataSource = if(videoSource is JSSource && videoSource.requiresCustomDatasource)
|
||||||
|
videoSource.getHttpDataSourceFactory()
|
||||||
|
else
|
||||||
|
DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT)
|
||||||
|
|
||||||
|
val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource)
|
||||||
|
|
||||||
|
val callback = if (videoSource.hasLicenseExecutor) {
|
||||||
|
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseExecutor()!!, videoSource.licenseUri)
|
||||||
|
} else {
|
||||||
|
baseCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
_lastVideoMediaSource = ProgressiveMediaSource.Factory(dataSource)
|
||||||
|
.setDrmSessionManagerProvider {
|
||||||
|
DefaultDrmSessionManager.Builder()
|
||||||
|
.setMultiSession(true)
|
||||||
|
.build(callback)
|
||||||
|
}
|
||||||
|
.createMediaSource(
|
||||||
|
MediaItem.fromUri(videoSource.getVideoUrl())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
private fun swapVideoSourceDash(videoSource: IDashManifestSource) {
|
private fun swapVideoSourceDash(videoSource: IDashManifestSource) {
|
||||||
Logger.i(TAG, "Loading VideoSource [Dash]");
|
Logger.i(TAG, "Loading VideoSource [Dash]");
|
||||||
val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource))
|
val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource))
|
||||||
@ -497,12 +525,8 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||||||
|
|
||||||
val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource)
|
val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource)
|
||||||
|
|
||||||
videoSource.licenseHeaders?.forEach { (key, value) ->
|
val callback = if (videoSource.hasLicenseExecutor) {
|
||||||
baseCallback.setKeyRequestProperty(key, value)
|
PluginMediaDrmCallback(baseCallback, videoSource.getLicenseExecutor()!!, videoSource.licenseUri)
|
||||||
}
|
|
||||||
|
|
||||||
val callback = if (videoSource.decodeLicenseResponse) {
|
|
||||||
Base64MediaDrmCallback(baseCallback)
|
|
||||||
} else {
|
} else {
|
||||||
baseCallback
|
baseCallback
|
||||||
}
|
}
|
||||||
@ -668,13 +692,9 @@ abstract class FutoVideoPlayerBase : RelativeLayout {
|
|||||||
|
|
||||||
val baseCallback = HttpMediaDrmCallback(audioSource.licenseUri, dataSource)
|
val baseCallback = HttpMediaDrmCallback(audioSource.licenseUri, dataSource)
|
||||||
|
|
||||||
audioSource.licenseHeaders?.forEach { (key, value) ->
|
val callback = if (audioSource.hasLicenseExecutor) {
|
||||||
baseCallback.setKeyRequestProperty(key, value)
|
PluginMediaDrmCallback(baseCallback, audioSource.getLicenseExecutor()!!, audioSource.licenseUri)
|
||||||
}
|
} else {
|
||||||
|
|
||||||
val callback = if(audioSource.decodeLicenseResponse){
|
|
||||||
Base64MediaDrmCallback(baseCallback)
|
|
||||||
}else{
|
|
||||||
baseCallback
|
baseCallback
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +360,7 @@ public class JSHttpDataSource extends BaseDataSource implements HttpDataSource {
|
|||||||
if(executor != null) {
|
if(executor != null) {
|
||||||
try {
|
try {
|
||||||
Logger.Companion.i(TAG, "Executor for " + dataSpec.uri.toString(), null);
|
Logger.Companion.i(TAG, "Executor for " + dataSpec.uri.toString(), null);
|
||||||
byte[] data = executor.executeRequest(dataSpec.uri.toString(), dataSpec.httpRequestHeaders);
|
byte[] data = executor.executeRequest("GET", dataSpec.uri.toString(), null, dataSpec.httpRequestHeaders);
|
||||||
Logger.Companion.i(TAG, "Executor result for " + dataSpec.uri.toString() + " : " + data.length, null);
|
Logger.Companion.i(TAG, "Executor result for " + dataSpec.uri.toString() + " : " + data.length, null);
|
||||||
if (data == null)
|
if (data == null)
|
||||||
throw new HttpDataSourceException(
|
throw new HttpDataSourceException(
|
||||||
|
@ -3,20 +3,21 @@ package com.futo.platformplayer.views.video.datasources
|
|||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import androidx.media3.exoplayer.drm.ExoMediaDrm
|
import androidx.media3.exoplayer.drm.ExoMediaDrm
|
||||||
import androidx.media3.exoplayer.drm.MediaDrmCallback
|
import androidx.media3.exoplayer.drm.MediaDrmCallback
|
||||||
|
import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import kotlin.io.encoding.Base64
|
|
||||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||||
|
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
class Base64MediaDrmCallback(
|
class PluginMediaDrmCallback(
|
||||||
private val delegate: MediaDrmCallback,
|
private val delegate: MediaDrmCallback,
|
||||||
|
private val requestExecutor: JSRequestExecutor,
|
||||||
|
private val licenseUrl: String
|
||||||
) : MediaDrmCallback by delegate {
|
) : MediaDrmCallback by delegate {
|
||||||
|
|
||||||
@ExperimentalEncodingApi
|
@ExperimentalEncodingApi
|
||||||
override fun executeKeyRequest(uuid: UUID, request: ExoMediaDrm.KeyRequest): ByteArray {
|
override fun executeKeyRequest(uuid: UUID, request: ExoMediaDrm.KeyRequest): ByteArray {
|
||||||
val originalResponse = delegate.executeKeyRequest(uuid, request)
|
val pluginResponse = requestExecutor.executeRequest("POST", licenseUrl, request.data, mapOf())
|
||||||
val decodedData: ByteArray = Base64.decode(originalResponse)
|
|
||||||
|
|
||||||
return decodedData
|
return pluginResponse
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user