From 6ec033274f7897234d19b8fa391b22b5c08e4584 Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 18 Dec 2024 14:12:38 -0600 Subject: [PATCH 1/6] add raw dash audio source widevine support --- app/src/main/assets/scripts/source.js | 11 +- .../models/streams/sources/IWidevineSource.kt | 2 +- .../sources/JSAudioUrlWidevineSource.kt | 6 +- .../sources/JSDashManifestRawAudioSource.kt | 30 ++++- .../sources/JSDashManifestWidevineSource.kt | 4 +- .../sources/JSVideoUrlWidevineSource.kt | 6 +- .../views/video/FutoVideoPlayerBase.kt | 107 +++++++++++++----- 7 files changed, 120 insertions(+), 46 deletions(-) diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js index 402d4aa0..5a530361 100644 --- a/app/src/main/assets/scripts/source.js +++ b/app/src/main/assets/scripts/source.js @@ -372,7 +372,7 @@ class VideoUrlWidevineSource extends VideoUrlSource { super(obj); this.plugin_type = "VideoUrlWidevineSource"; - this.licenseUri = obj.licenseUri; + this.widevineLicenseUri = obj.licenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } @@ -409,7 +409,7 @@ class AudioUrlWidevineSource extends AudioUrlSource { super(obj); this.plugin_type = "AudioUrlWidevineSource"; - this.licenseUri = obj.licenseUri; + this.widevineLicenseUri = obj.licenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; @@ -469,6 +469,8 @@ class DashSource { this.language = obj.language; if(obj.requestModifier) this.requestModifier = obj.requestModifier; + if(obj.getRequestExecutor) + this.getRequestExecutor = obj.getRequestExecutor; } } class DashWidevineSource extends DashSource { @@ -476,7 +478,7 @@ class DashWidevineSource extends DashSource { super(obj); this.plugin_type = "DashWidevineSource"; - this.licenseUri = obj.licenseUri; + this.widevineLicenseUri = obj.licenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } @@ -511,6 +513,9 @@ class DashManifestRawAudioSource { this.manifest = obj.manifest ?? null; if(obj.requestModifier) this.requestModifier = obj.requestModifier; + this.widevineLicenseUri = obj.widevineLicenseUri; + if(obj.getLicenseRequestExecutor) + this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt index b94cf12c..d48eeb28 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt @@ -3,7 +3,7 @@ package com.futo.platformplayer.api.media.models.streams.sources import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor interface IWidevineSource { - val licenseUri: String + val widevineLicenseUri: String? val hasLicenseRequestExecutor: Boolean fun getLicenseRequestExecutor(): JSRequestExecutor? } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt index 516e07ff..a83f8381 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt @@ -8,7 +8,7 @@ import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrThrow class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { - override val licenseUri: String + override val widevineLicenseUri: String override val hasLicenseRequestExecutor: Boolean @Suppress("ConvertSecondaryConstructorToPrimary") @@ -16,7 +16,7 @@ class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { val contextName = "JSAudioUrlWidevineSource" val config = plugin.config - licenseUri = _obj.getOrThrow(config, "licenseUri", contextName) + widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } @@ -36,6 +36,6 @@ class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { override fun toString(): String { val url = getAudioUrl() - return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, licenseUri=$licenseUri)" + return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, widevineLicenseUri=$widevineLicenseUri)" } } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt index 35435f95..10833f16 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt @@ -2,19 +2,17 @@ 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.IAudioSource -import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource -import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource +import com.futo.platformplayer.api.media.models.streams.sources.IWidevineSource import com.futo.platformplayer.api.media.platforms.js.DevJSClient import com.futo.platformplayer.api.media.platforms.js.JSClient -import com.futo.platformplayer.engine.IV8PluginConfig +import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrDefault -import com.futo.platformplayer.getOrNull import com.futo.platformplayer.getOrThrow import com.futo.platformplayer.others.Language import com.futo.platformplayer.states.StateDeveloper -class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawSource { +class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawSource, IWidevineSource { override val container : String = "application/dash+xml"; override val name : String; override val codec: String; @@ -29,6 +27,9 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS override val hasGenerate: Boolean; + override val widevineLicenseUri: String? + override val hasLicenseRequestExecutor: Boolean + constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH_RAW, plugin, obj) { val contextName = "DashRawSource"; val config = plugin.config; @@ -41,6 +42,23 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS priority = _obj.getOrDefault(config, "priority", contextName, false) ?: false; language = _obj.getOrDefault(config, "language", contextName, Language.UNKNOWN) ?: Language.UNKNOWN; hasGenerate = _obj.has("generate"); + + widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) + hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") + } + + override fun getLicenseRequestExecutor(): JSRequestExecutor? { + if (!hasLicenseRequestExecutor || _obj.isClosed) + return null + + val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSDashManifestRawAudioSource", "obj.getLicenseRequestExecutor()") { + _obj.invoke("getLicenseRequestExecutor", arrayOf()) + } + + if (result !is V8ValueObject) + return null + + return JSRequestExecutor(_plugin, result) } override fun generate(): String? { @@ -61,4 +79,4 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS _obj.invokeString("generate"); } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt index be72d3a0..e3996691 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt @@ -23,7 +23,7 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, override var priority: Boolean = false - override val licenseUri: String + override val widevineLicenseUri: String override val hasLicenseRequestExecutor: Boolean @Suppress("ConvertSecondaryConstructorToPrimary") @@ -36,7 +36,7 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, priority = obj.getOrNull(config, "priority", contextName) ?: false - licenseUri = _obj.getOrThrow(config, "licenseUri", contextName) + widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt index bcd6607d..c87b1c85 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt @@ -8,7 +8,7 @@ import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrThrow class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { - override val licenseUri: String + override val widevineLicenseUri: String override val hasLicenseRequestExecutor: Boolean @Suppress("ConvertSecondaryConstructorToPrimary") @@ -16,7 +16,7 @@ class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { val contextName = "JSAudioUrlWidevineSource" val config = plugin.config - licenseUri = _obj.getOrThrow(config, "licenseUri", contextName) + widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } @@ -36,6 +36,6 @@ class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { override fun toString(): String { val url = getVideoUrl() - return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, licenseUri=$licenseUri)" + return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, widevineLicenseUri=$widevineLicenseUri)" } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index 9ca559ca..2e6eff64 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -1,6 +1,7 @@ package com.futo.platformplayer.views.video import android.content.Context +import android.media.MediaDrm import android.net.Uri import android.util.AttributeSet import android.widget.RelativeLayout @@ -57,8 +58,8 @@ import com.futo.platformplayer.helpers.VideoHelper import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.states.StateApp import com.futo.platformplayer.video.PlayerManager -import com.futo.platformplayer.views.video.datasources.PluginMediaDrmCallback import com.futo.platformplayer.views.video.datasources.JSHttpDataSource +import com.futo.platformplayer.views.video.datasources.PluginMediaDrmCallback import getHttpDataSourceFactory import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -483,15 +484,20 @@ abstract class FutoVideoPlayerBase : RelativeLayout { @OptIn(UnstableApi::class) private fun swapVideoSourceUrlWidevine(videoSource: IVideoUrlWidevineSource) { Logger.i(TAG, "Loading VideoSource [UrlWidevine]"); + + if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { + throw IllegalArgumentException("Device does not support Widevine") + } + val dataSource = if(videoSource is JSSource && videoSource.requiresCustomDatasource) videoSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(videoSource.widevineLicenseUri, dataSource) val callback = if (videoSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.licenseUri) + PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.widevineLicenseUri!!) } else { baseCallback } @@ -519,14 +525,19 @@ abstract class FutoVideoPlayerBase : RelativeLayout { @OptIn(UnstableApi::class) private fun swapVideoSourceDashWidevine(videoSource: IDashManifestWidevineSource) { Logger.i(TAG, "Loading VideoSource [DashWidevine]") + + if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { + throw IllegalArgumentException("Device does not support Widevine") + } + val dataSource = if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(videoSource.licenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(videoSource.widevineLicenseUri, dataSource) val callback = if (videoSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.licenseUri) + PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.widevineLicenseUri!!) } else { baseCallback } @@ -651,49 +662,89 @@ abstract class FutoVideoPlayerBase : RelativeLayout { @OptIn(UnstableApi::class) private fun swapAudioSourceDashRaw(audioSource: JSDashManifestRawAudioSource, play: Boolean, resume: Boolean): Boolean { - Logger.i(TAG, "Loading AudioSource [DashRaw]"); - val dataSource = if(audioSource is JSSource && (audioSource.requiresCustomDatasource)) + Logger.i(TAG, "Loading AudioSource [DashRaw]") + val dataSource = if (audioSource.requiresCustomDatasource) audioSource.getHttpDataSourceFactory() else - DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); - if(audioSource.hasGenerate) { + DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) + + val baseCallback = HttpMediaDrmCallback(audioSource.widevineLicenseUri, dataSource) + + val callback = + if (audioSource.hasLicenseRequestExecutor && audioSource.widevineLicenseUri != null) { + PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.widevineLicenseUri) + } else { + baseCallback + } + + _lastVideoMediaSource = DashMediaSource.Factory(dataSource).setDrmSessionManagerProvider { + DefaultDrmSessionManager.Builder().setMultiSession(true).build(callback) + }.createMediaSource(MediaItem.fromUri(audioSource.url)) + + if (audioSource.hasGenerate) { findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) { - val generated = audioSource.generate(); - if(generated != null) { + val generated = audioSource.generate() + if (generated != null) { withContext(Dispatchers.Main) { - _lastVideoMediaSource = DashMediaSource.Factory(dataSource) - .createMediaSource(DashManifestParser().parse(Uri.parse(audioSource.url), - ByteArrayInputStream(generated?.toByteArray() ?: ByteArray(0)))); - loadSelectedSources(play, resume); + val factory = DashMediaSource.Factory(dataSource) + if (audioSource.widevineLicenseUri != null) { + if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { + throw IllegalArgumentException("Device does not support Widevine") + } + factory.setDrmSessionManagerProvider { + DefaultDrmSessionManager.Builder().setMultiSession(true) + .build(callback) + } + } + _lastVideoMediaSource = factory.createMediaSource( + DashManifestParser().parse( + Uri.parse(audioSource.url), + ByteArrayInputStream(generated.toByteArray() ?: ByteArray(0)) + ) + ) + loadSelectedSources(play, resume) } } } - return false; - } - else { - _lastVideoMediaSource = DashMediaSource.Factory(dataSource) - .createMediaSource( - DashManifestParser().parse( - Uri.parse(audioSource.url), - ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0)) - ) - ); - return true; + return false + } else { + val factory = DashMediaSource.Factory(dataSource) + if (audioSource.widevineLicenseUri != null) { + if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { + throw IllegalArgumentException("Device does not support Widevine") + } + factory.setDrmSessionManagerProvider { + DefaultDrmSessionManager.Builder().setMultiSession(true) + .build(callback) + } + } + _lastVideoMediaSource = factory.createMediaSource( + DashManifestParser().parse( + Uri.parse(audioSource.url), + ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0)) + ) + ) + return true } } @OptIn(UnstableApi::class) private fun swapAudioSourceUrlWidevine(audioSource: IAudioUrlWidevineSource) { Logger.i(TAG, "Loading AudioSource [UrlWidevine]") + + if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { + throw IllegalArgumentException("Device does not support Widevine") + } + val dataSource = if (audioSource is JSSource && audioSource.requiresCustomDatasource) audioSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(audioSource.licenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(audioSource.widevineLicenseUri, dataSource) val callback = if (audioSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.licenseUri) + PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.widevineLicenseUri!!) } else { baseCallback } From ce8ede5d4078856da9e3e677ccf496baf87e55d2 Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 7 Jan 2025 13:59:19 -0600 Subject: [PATCH 2/6] Add dialog when failing to play DRM content Changelog: added --- .../mainactivity/main/VideoDetailView.kt | 17 +++++++++++++++++ app/src/main/res/values/strings.xml | 3 +++ 2 files changed, 20 insertions(+) diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index 22f7ffa2..b7223d15 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -31,11 +31,13 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.TextView import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.content.ContextCompat.startActivity import androidx.lifecycle.lifecycleScope import androidx.media3.common.C import androidx.media3.common.Format import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.HttpDataSource +import androidx.media3.exoplayer.analytics.AnalyticsListener import androidx.media3.ui.PlayerControlView import androidx.media3.ui.TimeBar import com.bumptech.glide.Glide @@ -433,6 +435,21 @@ class VideoDetailView : ConstraintLayout { _player.attachPlayer(); + _player.exoPlayer?.player?.addAnalyticsListener(object : AnalyticsListener { + override fun onDrmSessionManagerError( + eventTime: AnalyticsListener.EventTime, error: Exception + ) { + super.onDrmSessionManagerError(eventTime, error) + UIDialogs.showDialog(context, R.drawable.ic_lock, context.getString(R.string.drm_not_supported), context.getString(R.string.open_and_play_in_mobile_browser), null, 1, UIDialogs.Action(context.getString(R.string.open_in_browser), { + val intent = Intent(Intent.ACTION_VIEW, Uri.parse(video?.url)) + val options = + android.app.ActivityOptions.makeCustomAnimation(context, android.R.anim.fade_in, android.R.anim.fade_out) + startActivity(context, intent, options.toBundle()) + }, UIDialogs.ActionStyle.NONE), UIDialogs.Action(context.getString(R.string.close), {}, UIDialogs.ActionStyle.PRIMARY) + ) + } + }) + _container_content_liveChat.onRaidNow.subscribe { StatePlayer.instance.clearQueue(); fragment.navigate(it.targetUrl); diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b55bfcd..cce19abe 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -34,6 +34,7 @@ Default quality for watching a video Update Close + Open In Browser Never Select any of the following available import options. There is an update available, do you wish to update? @@ -240,6 +241,8 @@ This content is locked Unknown Tap to open in browser + This device does not support the DRM required to play this content + Please try playing this content in a mobile browser on this device. If it plays open a bug report and share your device model and OS version. Missing Plugin Viewers are raiding Go now From 4e548d29a640b9db0894cafa68ddaace865b1a13 Mon Sep 17 00:00:00 2001 From: Kai Date: Tue, 14 Jan 2025 12:30:21 -0600 Subject: [PATCH 3/6] prevent download when using widevine Changelog: changed --- .../main/java/com/futo/platformplayer/helpers/VideoHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt index 8b4b5847..7ad5e703 100644 --- a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt +++ b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt @@ -48,7 +48,7 @@ class VideoHelper { } fun isDownloadable(source: IVideoSource) = source is IVideoUrlSource || source is IHLSManifestSource || source is JSDashManifestRawSource; - fun isDownloadable(source: IAudioSource) = (source is IAudioUrlSource || source is IHLSManifestAudioSource || source is JSDashManifestRawAudioSource) && source !is IAudioUrlWidevineSource + fun isDownloadable(source: IAudioSource) = (source is IAudioUrlSource || source is IHLSManifestAudioSource || source is JSDashManifestRawAudioSource) && source !is IAudioUrlWidevineSource && !(source is JSDashManifestRawAudioSource && source.widevineLicenseUri != null) fun selectBestVideoSource(desc: IVideoSourceDescriptor, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? = selectBestVideoSource(desc.videoSources.toList(), desiredPixelCount, prefContainers); fun selectBestVideoSource(sources: Iterable, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? { From 89beb8af43015c367a6e317e7abc0408c7a72910 Mon Sep 17 00:00:00 2001 From: Kai Date: Wed, 5 Feb 2025 15:13:48 -0600 Subject: [PATCH 4/6] rename widevineLicenseUri to drmLicenseUri Changelog: changed --- app/src/main/assets/scripts/source.js | 8 +++---- .../models/streams/sources/IWidevineSource.kt | 2 +- .../sources/JSAudioUrlWidevineSource.kt | 6 ++--- .../sources/JSDashManifestRawAudioSource.kt | 4 ++-- .../sources/JSDashManifestWidevineSource.kt | 4 ++-- .../sources/JSVideoUrlWidevineSource.kt | 6 ++--- .../platformplayer/helpers/VideoHelper.kt | 2 +- .../views/video/FutoVideoPlayerBase.kt | 22 +++++++++---------- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js index 5a530361..4e14fd27 100644 --- a/app/src/main/assets/scripts/source.js +++ b/app/src/main/assets/scripts/source.js @@ -372,7 +372,7 @@ class VideoUrlWidevineSource extends VideoUrlSource { super(obj); this.plugin_type = "VideoUrlWidevineSource"; - this.widevineLicenseUri = obj.licenseUri; + this.drmLicenseUri = obj.licenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } @@ -409,7 +409,7 @@ class AudioUrlWidevineSource extends AudioUrlSource { super(obj); this.plugin_type = "AudioUrlWidevineSource"; - this.widevineLicenseUri = obj.licenseUri; + this.drmLicenseUri = obj.licenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; @@ -478,7 +478,7 @@ class DashWidevineSource extends DashSource { super(obj); this.plugin_type = "DashWidevineSource"; - this.widevineLicenseUri = obj.licenseUri; + this.drmLicenseUri = obj.licenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } @@ -513,7 +513,7 @@ class DashManifestRawAudioSource { this.manifest = obj.manifest ?? null; if(obj.requestModifier) this.requestModifier = obj.requestModifier; - this.widevineLicenseUri = obj.widevineLicenseUri; + this.drmLicenseUri = obj.drmLicenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt index d48eeb28..05927e27 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt @@ -3,7 +3,7 @@ package com.futo.platformplayer.api.media.models.streams.sources import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor interface IWidevineSource { - val widevineLicenseUri: String? + val drmLicenseUri: String? val hasLicenseRequestExecutor: Boolean fun getLicenseRequestExecutor(): JSRequestExecutor? } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt index a83f8381..c83ec563 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt @@ -8,7 +8,7 @@ import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrThrow class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { - override val widevineLicenseUri: String + override val drmLicenseUri: String override val hasLicenseRequestExecutor: Boolean @Suppress("ConvertSecondaryConstructorToPrimary") @@ -16,7 +16,7 @@ class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { val contextName = "JSAudioUrlWidevineSource" val config = plugin.config - widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) + drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } @@ -36,6 +36,6 @@ class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { override fun toString(): String { val url = getAudioUrl() - return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, widevineLicenseUri=$widevineLicenseUri)" + return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, drmLicenseUri=$drmLicenseUri)" } } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt index 10833f16..e678b0b5 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt @@ -27,7 +27,7 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS override val hasGenerate: Boolean; - override val widevineLicenseUri: String? + override val drmLicenseUri: String? override val hasLicenseRequestExecutor: Boolean constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH_RAW, plugin, obj) { @@ -43,7 +43,7 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS language = _obj.getOrDefault(config, "language", contextName, Language.UNKNOWN) ?: Language.UNKNOWN; hasGenerate = _obj.has("generate"); - widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) + drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt index e3996691..e7b0dc21 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt @@ -23,7 +23,7 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, override var priority: Boolean = false - override val widevineLicenseUri: String + override val drmLicenseUri: String override val hasLicenseRequestExecutor: Boolean @Suppress("ConvertSecondaryConstructorToPrimary") @@ -36,7 +36,7 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, priority = obj.getOrNull(config, "priority", contextName) ?: false - widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) + drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt index c87b1c85..6f78c14d 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt @@ -8,7 +8,7 @@ import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrThrow class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { - override val widevineLicenseUri: String + override val drmLicenseUri: String override val hasLicenseRequestExecutor: Boolean @Suppress("ConvertSecondaryConstructorToPrimary") @@ -16,7 +16,7 @@ class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { val contextName = "JSAudioUrlWidevineSource" val config = plugin.config - widevineLicenseUri = _obj.getOrThrow(config, "widevineLicenseUri", contextName) + drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } @@ -36,6 +36,6 @@ class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { override fun toString(): String { val url = getVideoUrl() - return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, widevineLicenseUri=$widevineLicenseUri)" + return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, drmLicenseUri=$drmLicenseUri)" } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt index eedf25fb..58cb73c8 100644 --- a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt +++ b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt @@ -46,7 +46,7 @@ class VideoHelper { return false } fun isDownloadable(source: IVideoSource) = (source is IVideoUrlSource || source is IHLSManifestSource || source is JSDashManifestRawSource) && source !is IWidevineSource - fun isDownloadable(source: IAudioSource) = (source is IAudioUrlSource || source is IHLSManifestAudioSource || source is JSDashManifestRawAudioSource) && source !is IWidevineSource && !(source is JSDashManifestRawAudioSource && source.widevineLicenseUri != null) + fun isDownloadable(source: IAudioSource) = (source is IAudioUrlSource || source is IHLSManifestAudioSource || source is JSDashManifestRawAudioSource) && source !is IWidevineSource && !(source is JSDashManifestRawAudioSource && source.drmLicenseUri != null) fun selectBestVideoSource(desc: IVideoSourceDescriptor, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? = selectBestVideoSource(desc.videoSources.toList(), desiredPixelCount, prefContainers); fun selectBestVideoSource(sources: Iterable, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? { val targetVideo = if(desiredPixelCount > 0) { diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index 2e6eff64..9c9cd328 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -494,10 +494,10 @@ abstract class FutoVideoPlayerBase : RelativeLayout { else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(videoSource.widevineLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(videoSource.drmLicenseUri, dataSource) val callback = if (videoSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.widevineLicenseUri!!) + PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!) } else { baseCallback } @@ -534,10 +534,10 @@ abstract class FutoVideoPlayerBase : RelativeLayout { if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(videoSource.widevineLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(videoSource.drmLicenseUri, dataSource) val callback = if (videoSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.widevineLicenseUri!!) + PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!) } else { baseCallback } @@ -668,11 +668,11 @@ abstract class FutoVideoPlayerBase : RelativeLayout { else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(audioSource.widevineLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(audioSource.drmLicenseUri, dataSource) val callback = - if (audioSource.hasLicenseRequestExecutor && audioSource.widevineLicenseUri != null) { - PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.widevineLicenseUri) + if (audioSource.hasLicenseRequestExecutor && audioSource.drmLicenseUri != null) { + PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri) } else { baseCallback } @@ -687,7 +687,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { if (generated != null) { withContext(Dispatchers.Main) { val factory = DashMediaSource.Factory(dataSource) - if (audioSource.widevineLicenseUri != null) { + if (audioSource.drmLicenseUri != null) { if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { throw IllegalArgumentException("Device does not support Widevine") } @@ -709,7 +709,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { return false } else { val factory = DashMediaSource.Factory(dataSource) - if (audioSource.widevineLicenseUri != null) { + if (audioSource.drmLicenseUri != null) { if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { throw IllegalArgumentException("Device does not support Widevine") } @@ -741,10 +741,10 @@ abstract class FutoVideoPlayerBase : RelativeLayout { else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(audioSource.widevineLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback(audioSource.drmLicenseUri, dataSource) val callback = if (audioSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.widevineLicenseUri!!) + PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri!!) } else { baseCallback } From be6bcb37ae79bbd3175daae743aaf320cd6b1d24 Mon Sep 17 00:00:00 2001 From: Kai Date: Mon, 10 Feb 2025 13:54:04 -0600 Subject: [PATCH 5/6] move widevine code to JSSource Changelog: changed --- .../sources/IAudioUrlWidevineSource.kt | 2 +- .../sources/IDashManifestWidevineSource.kt | 2 +- .../sources/IVideoUrlWidevineSource.kt | 2 +- .../models/streams/sources/IWidevineSource.kt | 9 -------- .../sources/JSAudioUrlWidevineSource.kt | 20 ---------------- .../sources/JSDashManifestRawAudioSource.kt | 23 +------------------ .../sources/JSDashManifestWidevineSource.kt | 20 ---------------- .../platforms/js/models/sources/JSSource.kt | 23 ++++++++++++++++--- .../sources/JSVideoUrlWidevineSource.kt | 20 ---------------- .../platformplayer/helpers/VideoHelper.kt | 6 ++--- .../views/video/FutoVideoPlayerBase.kt | 7 +++--- 11 files changed, 30 insertions(+), 104 deletions(-) delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt index 33d4fa54..7e2908aa 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt @@ -1,3 +1,3 @@ package com.futo.platformplayer.api.media.models.streams.sources -interface IAudioUrlWidevineSource : IAudioUrlSource, IWidevineSource +interface IAudioUrlWidevineSource : IAudioUrlSource diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt index c1b5ea35..9b0e3f8f 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt @@ -1,5 +1,5 @@ package com.futo.platformplayer.api.media.models.streams.sources -interface IDashManifestWidevineSource : IWidevineSource { +interface IDashManifestWidevineSource { val url: String } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt index 073af50a..3ea27f5c 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt @@ -1,3 +1,3 @@ package com.futo.platformplayer.api.media.models.streams.sources -interface IVideoUrlWidevineSource : IVideoUrlSource, IWidevineSource +interface IVideoUrlWidevineSource : IVideoUrlSource diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt deleted file mode 100644 index 05927e27..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IWidevineSource.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.futo.platformplayer.api.media.models.streams.sources - -import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor - -interface IWidevineSource { - val drmLicenseUri: String? - val hasLicenseRequestExecutor: Boolean - fun getLicenseRequestExecutor(): JSRequestExecutor? -} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt index c83ec563..ad75125b 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt @@ -8,30 +8,10 @@ import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrThrow class JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { - override val drmLicenseUri: String - override val hasLicenseRequestExecutor: Boolean - @Suppress("ConvertSecondaryConstructorToPrimary") constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) { val contextName = "JSAudioUrlWidevineSource" val config = plugin.config - - drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) - hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") - } - - override fun getLicenseRequestExecutor(): JSRequestExecutor? { - if (!hasLicenseRequestExecutor || _obj.isClosed) - return null - - val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSAudioUrlWidevineSource", "obj.getLicenseRequestExecutor()") { - _obj.invoke("getLicenseRequestExecutor", arrayOf()) - } - - if (result !is V8ValueObject) - return null - - return JSRequestExecutor(_plugin, result) } override fun toString(): String { diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt index e678b0b5..048fee9a 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestRawAudioSource.kt @@ -2,7 +2,6 @@ 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.IAudioSource -import com.futo.platformplayer.api.media.models.streams.sources.IWidevineSource import com.futo.platformplayer.api.media.platforms.js.DevJSClient import com.futo.platformplayer.api.media.platforms.js.JSClient import com.futo.platformplayer.api.media.platforms.js.models.JSRequestExecutor @@ -12,7 +11,7 @@ import com.futo.platformplayer.getOrThrow import com.futo.platformplayer.others.Language import com.futo.platformplayer.states.StateDeveloper -class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawSource, IWidevineSource { +class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawSource { override val container : String = "application/dash+xml"; override val name : String; override val codec: String; @@ -27,9 +26,6 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS override val hasGenerate: Boolean; - override val drmLicenseUri: String? - override val hasLicenseRequestExecutor: Boolean - constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH_RAW, plugin, obj) { val contextName = "DashRawSource"; val config = plugin.config; @@ -42,23 +38,6 @@ class JSDashManifestRawAudioSource : JSSource, IAudioSource, IJSDashManifestRawS priority = _obj.getOrDefault(config, "priority", contextName, false) ?: false; language = _obj.getOrDefault(config, "language", contextName, Language.UNKNOWN) ?: Language.UNKNOWN; hasGenerate = _obj.has("generate"); - - drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) - hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") - } - - override fun getLicenseRequestExecutor(): JSRequestExecutor? { - if (!hasLicenseRequestExecutor || _obj.isClosed) - return null - - val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSDashManifestRawAudioSource", "obj.getLicenseRequestExecutor()") { - _obj.invoke("getLicenseRequestExecutor", arrayOf()) - } - - if (result !is V8ValueObject) - return null - - return JSRequestExecutor(_plugin, result) } override fun generate(): String? { diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt index e7b0dc21..b205d574 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt @@ -23,9 +23,6 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, override var priority: Boolean = false - override val drmLicenseUri: String - override val hasLicenseRequestExecutor: Boolean - @Suppress("ConvertSecondaryConstructorToPrimary") constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH, plugin, obj) { val contextName = "DashWidevineSource" @@ -35,23 +32,6 @@ class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, duration = _obj.getOrThrow(config, "duration", contextName) priority = obj.getOrNull(config, "priority", contextName) ?: false - - drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) - hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") - } - - override fun getLicenseRequestExecutor(): JSRequestExecutor? { - if (!hasLicenseRequestExecutor || _obj.isClosed) - return null - - val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSDashManifestWidevineSource", "obj.getLicenseRequestExecutor()") { - _obj.invoke("getLicenseRequestExecutor", arrayOf()) - } - - if (result !is V8ValueObject) - return null - - return JSRequestExecutor(_plugin, result) } override fun getVideoUrl(): String { 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 3c76e23d..830c6125 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,9 +13,9 @@ import com.futo.platformplayer.api.media.platforms.js.models.JSRequestModifier import com.futo.platformplayer.engine.IV8PluginConfig import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrDefault +import com.futo.platformplayer.getOrThrow import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.orNull -import com.futo.platformplayer.views.video.datasources.JSHttpDataSource abstract class JSSource { protected val _plugin: JSClient; @@ -30,6 +28,9 @@ abstract class JSSource { val hasRequestExecutor: Boolean; private val _requestExecutor: JSRequest?; + val drmLicenseUri: String? + val hasLicenseRequestExecutor: Boolean + val requiresCustomDatasource: Boolean get() { return hasRequestModifier || hasRequestExecutor; } @@ -51,6 +52,9 @@ abstract class JSSource { JSRequest(plugin, it, null, null, true); } hasRequestExecutor = _requestExecutor != null || obj.has("getRequestExecutor"); + + drmLicenseUri = _obj.getOrThrow(_config, "drmLicenseUri", "JSSource.drmLicenseUri") + hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } fun getRequestModifier(): IRequestModifier? { @@ -84,6 +88,19 @@ abstract class JSSource { return JSRequestExecutor(_plugin, result) } + fun getLicenseRequestExecutor(): JSRequestExecutor? { + if (!hasLicenseRequestExecutor || _obj.isClosed) + return null + + val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSSource", "obj.getLicenseRequestExecutor()") { + _obj.invoke("getLicenseRequestExecutor", arrayOf()) + } + + if (result !is V8ValueObject) + return null + + return JSRequestExecutor(_plugin, result) + } fun getUnderlyingPlugin(): JSClient? { return _plugin; diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt index 6f78c14d..9d374ee6 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt @@ -8,30 +8,10 @@ import com.futo.platformplayer.engine.V8Plugin import com.futo.platformplayer.getOrThrow class JSVideoUrlWidevineSource : JSVideoUrlSource, IVideoUrlWidevineSource { - override val drmLicenseUri: String - override val hasLicenseRequestExecutor: Boolean - @Suppress("ConvertSecondaryConstructorToPrimary") constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) { val contextName = "JSAudioUrlWidevineSource" val config = plugin.config - - drmLicenseUri = _obj.getOrThrow(config, "drmLicenseUri", contextName) - hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") - } - - override fun getLicenseRequestExecutor(): JSRequestExecutor? { - if (!hasLicenseRequestExecutor || _obj.isClosed) - return null - - val result = V8Plugin.catchScriptErrors(_config, "[${_config.name}] JSAudioUrlWidevineSource", "obj.getLicenseRequestExecutor()") { - _obj.invoke("getLicenseRequestExecutor", arrayOf()) - } - - if (result !is V8ValueObject) - return null - - return JSRequestExecutor(_plugin, result) } override fun toString(): String { diff --git a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt index 58cb73c8..eeda2e8f 100644 --- a/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt +++ b/app/src/main/java/com/futo/platformplayer/helpers/VideoHelper.kt @@ -17,11 +17,11 @@ 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.IVideoSource import com.futo.platformplayer.api.media.models.streams.sources.IVideoUrlSource -import com.futo.platformplayer.api.media.models.streams.sources.IWidevineSource import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails import com.futo.platformplayer.api.media.platforms.js.models.sources.JSAudioUrlRangeSource import com.futo.platformplayer.api.media.platforms.js.models.sources.JSDashManifestRawAudioSource import com.futo.platformplayer.api.media.platforms.js.models.sources.JSDashManifestRawSource +import com.futo.platformplayer.api.media.platforms.js.models.sources.JSSource import com.futo.platformplayer.api.media.platforms.js.models.sources.JSVideoUrlRangeSource import com.futo.platformplayer.logging.Logger import com.futo.platformplayer.others.Language @@ -45,8 +45,8 @@ class VideoHelper { return false } - fun isDownloadable(source: IVideoSource) = (source is IVideoUrlSource || source is IHLSManifestSource || source is JSDashManifestRawSource) && source !is IWidevineSource - fun isDownloadable(source: IAudioSource) = (source is IAudioUrlSource || source is IHLSManifestAudioSource || source is JSDashManifestRawAudioSource) && source !is IWidevineSource && !(source is JSDashManifestRawAudioSource && source.drmLicenseUri != null) + fun isDownloadable(source: IVideoSource) = (source is IVideoUrlSource || source is IHLSManifestSource || source is JSDashManifestRawSource) && !(source is JSSource && source.drmLicenseUri != null) + fun isDownloadable(source: IAudioSource) = (source is IAudioUrlSource || source is IHLSManifestAudioSource || source is JSDashManifestRawAudioSource) && !(source is JSSource && source.drmLicenseUri != null) fun selectBestVideoSource(desc: IVideoSourceDescriptor, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? = selectBestVideoSource(desc.videoSources.toList(), desiredPixelCount, prefContainers); fun selectBestVideoSource(sources: Iterable, desiredPixelCount : Int, prefContainers : Array) : IVideoSource? { val targetVideo = if(desiredPixelCount > 0) { diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index 9c9cd328..a6694394 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -494,7 +494,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(videoSource.drmLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback((videoSource as JSSource).drmLicenseUri, dataSource) val callback = if (videoSource.hasLicenseRequestExecutor) { PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!) @@ -534,7 +534,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(videoSource.drmLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback((videoSource as JSSource).drmLicenseUri, dataSource) val callback = if (videoSource.hasLicenseRequestExecutor) { PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!) @@ -741,7 +741,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - val baseCallback = HttpMediaDrmCallback(audioSource.drmLicenseUri, dataSource) + val baseCallback = HttpMediaDrmCallback((audioSource as JSSource).drmLicenseUri, dataSource) val callback = if (audioSource.hasLicenseRequestExecutor) { PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri!!) @@ -760,7 +760,6 @@ abstract class FutoVideoPlayerBase : RelativeLayout { ) } - //Prefered source selection fun getPreferredVideoSource(video: IPlatformVideoDetails, targetPixels: Int = -1): IVideoSource? { val usePreview = false; From d80cba383319c72a7fe6de59cd27c9bf6ccd541e Mon Sep 17 00:00:00 2001 From: Kai Date: Mon, 10 Feb 2025 15:30:39 -0600 Subject: [PATCH 6/6] remove widevine specific swap functions from video player base Changelog: changed --- app/src/main/assets/scripts/source.js | 55 +++-- .../sources/IAudioUrlWidevineSource.kt | 3 - .../sources/IDashManifestWidevineSource.kt | 5 - .../sources/IVideoUrlWidevineSource.kt | 3 - .../sources/JSAudioUrlWidevineSource.kt | 21 -- .../sources/JSDashManifestWidevineSource.kt | 40 ---- .../platforms/js/models/sources/JSSource.kt | 8 +- .../sources/JSVideoUrlWidevineSource.kt | 21 -- .../views/video/FutoVideoPlayerBase.kt | 213 +++++++----------- 9 files changed, 116 insertions(+), 253 deletions(-) delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js index 4e14fd27..ebf84b0c 100644 --- a/app/src/main/assets/scripts/source.js +++ b/app/src/main/assets/scripts/source.js @@ -365,16 +365,20 @@ class VideoUrlSource { this.url = obj.url; if(obj.requestModifier) this.requestModifier = obj.requestModifier; + + // deprecated api conversion + if(obj.licenseUri) + this.drmLicenseUri = obj.licenseUri; + + if(obj.drmLicenseUri) + this.drmLicenseUri = obj.drmLicenseUri; + if(obj.getLicenseRequestExecutor) + this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } } class VideoUrlWidevineSource extends VideoUrlSource { constructor(obj) { super(obj); - this.plugin_type = "VideoUrlWidevineSource"; - - this.drmLicenseUri = obj.licenseUri; - if(obj.getLicenseRequestExecutor) - this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } } class VideoUrlRangeSource extends VideoUrlSource { @@ -402,16 +406,6 @@ class AudioUrlSource { this.language = obj.language ?? Language.UNKNOWN; if(obj.requestModifier) this.requestModifier = obj.requestModifier; - } -} -class AudioUrlWidevineSource extends AudioUrlSource { - constructor(obj) { - super(obj); - this.plugin_type = "AudioUrlWidevineSource"; - - this.drmLicenseUri = obj.licenseUri; - if(obj.getLicenseRequestExecutor) - this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; // deprecated api conversion if(obj.bearerToken) { @@ -429,6 +423,19 @@ class AudioUrlWidevineSource extends AudioUrlSource { } } } + // deprecated api conversion + if(obj.licenseUri) + this.drmLicenseUri = obj.licenseUri; + + if(obj.drmLicenseUri) + this.drmLicenseUri = obj.drmLicenseUri; + if(obj.getLicenseRequestExecutor) + this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; + } +} +class AudioUrlWidevineSource extends AudioUrlSource { + constructor(obj) { + super(obj); } } class AudioUrlRangeSource extends AudioUrlSource { @@ -471,16 +478,20 @@ class DashSource { this.requestModifier = obj.requestModifier; if(obj.getRequestExecutor) this.getRequestExecutor = obj.getRequestExecutor; + + // deprecated api conversion + if(obj.licenseUri) + this.drmLicenseUri = obj.licenseUri; + + if(obj.drmLicenseUri) + this.drmLicenseUri = obj.drmLicenseUri; + if(obj.getLicenseRequestExecutor) + this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } } class DashWidevineSource extends DashSource { constructor(obj) { super(obj); - this.plugin_type = "DashWidevineSource"; - - this.drmLicenseUri = obj.licenseUri; - if(obj.getLicenseRequestExecutor) - this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } } class DashManifestRawSource { @@ -513,7 +524,9 @@ class DashManifestRawAudioSource { this.manifest = obj.manifest ?? null; if(obj.requestModifier) this.requestModifier = obj.requestModifier; - this.drmLicenseUri = obj.drmLicenseUri; + + if(obj.drmLicenseUri) + this.drmLicenseUri = obj.drmLicenseUri; if(obj.getLicenseRequestExecutor) this.getLicenseRequestExecutor = obj.getLicenseRequestExecutor; } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt deleted file mode 100644 index 7e2908aa..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IAudioUrlWidevineSource.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.futo.platformplayer.api.media.models.streams.sources - -interface IAudioUrlWidevineSource : IAudioUrlSource diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt deleted file mode 100644 index 9b0e3f8f..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IDashManifestWidevineSource.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.futo.platformplayer.api.media.models.streams.sources - -interface IDashManifestWidevineSource { - val url: String -} diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt deleted file mode 100644 index 3ea27f5c..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/IVideoUrlWidevineSource.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.futo.platformplayer.api.media.models.streams.sources - -interface IVideoUrlWidevineSource : IVideoUrlSource diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt deleted file mode 100644 index ad75125b..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSAudioUrlWidevineSource.kt +++ /dev/null @@ -1,21 +0,0 @@ -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.IAudioUrlWidevineSource -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 JSAudioUrlWidevineSource : JSAudioUrlSource, IAudioUrlWidevineSource { - @Suppress("ConvertSecondaryConstructorToPrimary") - constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) { - val contextName = "JSAudioUrlWidevineSource" - val config = plugin.config - } - - override fun toString(): String { - val url = getAudioUrl() - return "(name=$name, container=$container, bitrate=$bitrate, codec=$codec, url=$url, language=$language, duration=$duration, hasLicenseRequestExecutor=${hasLicenseRequestExecutor}, drmLicenseUri=$drmLicenseUri)" - } -} diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt deleted file mode 100644 index b205d574..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSDashManifestWidevineSource.kt +++ /dev/null @@ -1,40 +0,0 @@ -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.IDashManifestSource -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.platforms.js.JSClient -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.getOrThrow - -class JSDashManifestWidevineSource : IVideoUrlSource, IDashManifestSource, - IDashManifestWidevineSource, JSSource { - override val width: Int = 0 - override val height: Int = 0 - override val container: String = "application/dash+xml" - override val codec: String = "Dash" - override val name: String - override val bitrate: Int? = null - override val url: String - override val duration: Long - - override var priority: Boolean = false - - @Suppress("ConvertSecondaryConstructorToPrimary") - constructor(plugin: JSClient, obj: V8ValueObject) : super(TYPE_DASH, plugin, obj) { - val contextName = "DashWidevineSource" - val config = plugin.config - name = _obj.getOrThrow(config, "name", contextName) - url = _obj.getOrThrow(config, "url", contextName) - duration = _obj.getOrThrow(config, "duration", contextName) - - priority = obj.getOrNull(config, "priority", contextName) ?: false - } - - override fun getVideoUrl(): String { - return url - } -} \ 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 830c6125..c3d57707 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 @@ -53,7 +53,7 @@ abstract class JSSource { } hasRequestExecutor = _requestExecutor != null || obj.has("getRequestExecutor"); - drmLicenseUri = _obj.getOrThrow(_config, "drmLicenseUri", "JSSource.drmLicenseUri") + drmLicenseUri = _obj.getOrDefault(_config, "drmLicenseUri", "JSSource.drmLicenseUri", null) hasLicenseRequestExecutor = obj.has("getLicenseRequestExecutor") } @@ -115,22 +115,17 @@ abstract class JSSource { const val TYPE_AUDIO_WITH_METADATA = "AudioUrlRangeSource"; const val TYPE_VIDEO_WITH_METADATA = "VideoUrlRangeSource"; const val TYPE_DASH = "DashSource"; - const val TYPE_DASH_WIDEVINE = "DashWidevineSource"; const val TYPE_DASH_RAW = "DashRawSource"; const val TYPE_DASH_RAW_AUDIO = "DashRawAudioSource"; const val TYPE_HLS = "HLSSource"; - 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 fromV8Video(plugin: JSClient, obj: V8ValueObject) : IVideoSource? { val type = obj.getString("plugin_type"); return when(type) { TYPE_VIDEOURL -> JSVideoUrlSource(plugin, obj); - TYPE_VIDEOURL_WIDEVINE -> JSVideoUrlWidevineSource(plugin, obj); TYPE_VIDEO_WITH_METADATA -> JSVideoUrlRangeSource(plugin, obj); TYPE_HLS -> fromV8HLS(plugin, obj); - TYPE_DASH_WIDEVINE -> JSDashManifestWidevineSource(plugin, obj) TYPE_DASH -> fromV8Dash(plugin, obj); TYPE_DASH_RAW -> fromV8DashRaw(plugin, obj); else -> { @@ -152,7 +147,6 @@ abstract class JSSource { TYPE_HLS -> JSHLSManifestAudioSource.fromV8HLS(plugin, obj); TYPE_AUDIOURL -> JSAudioUrlSource(plugin, obj); TYPE_DASH_RAW_AUDIO -> fromV8DashRawAudio(plugin, obj); - TYPE_AUDIOURL_WIDEVINE -> JSAudioUrlWidevineSource(plugin, obj); TYPE_AUDIO_WITH_METADATA -> JSAudioUrlRangeSource(plugin, obj); else -> { Logger.w("JSSource", "Unknown audio type ${type}"); diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt deleted file mode 100644 index 9d374ee6..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/sources/JSVideoUrlWidevineSource.kt +++ /dev/null @@ -1,21 +0,0 @@ -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 { - @Suppress("ConvertSecondaryConstructorToPrimary") - constructor(plugin: JSClient, obj: V8ValueObject) : super(plugin, obj) { - val contextName = "JSAudioUrlWidevineSource" - val config = plugin.config - } - - override fun toString(): String { - val url = getVideoUrl() - return "(width=$width, height=$height, container=$container, codec=$codec, name=$name, bitrate=$bitrate, duration=$duration, url=$url, hasLicenseRequestExecutor=$hasLicenseRequestExecutor, drmLicenseUri=$drmLicenseUri)" - } -} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt index a6694394..975bd0c3 100644 --- a/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt +++ b/app/src/main/java/com/futo/platformplayer/views/video/FutoVideoPlayerBase.kt @@ -23,6 +23,7 @@ import androidx.media3.exoplayer.dash.DashMediaSource import androidx.media3.exoplayer.dash.manifest.DashManifestParser import androidx.media3.exoplayer.drm.DefaultDrmSessionManager import androidx.media3.exoplayer.drm.HttpMediaDrmCallback +import androidx.media3.exoplayer.drm.MediaDrmCallback import androidx.media3.exoplayer.hls.HlsMediaSource import androidx.media3.exoplayer.source.MediaSource import androidx.media3.exoplayer.source.MergingMediaSource @@ -34,14 +35,11 @@ import com.futo.platformplayer.api.media.models.chapters.IChapter import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlSource -import com.futo.platformplayer.api.media.models.streams.sources.IAudioUrlWidevineSource import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource -import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestWidevineSource import com.futo.platformplayer.api.media.models.streams.sources.IHLSManifestAudioSource 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.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.LocalVideoSource import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource @@ -413,11 +411,9 @@ abstract class FutoVideoPlayerBase : RelativeLayout { val didSet = when(videoSource) { is LocalVideoSource -> { swapVideoSourceLocal(videoSource); true; } is JSVideoUrlRangeSource -> { swapVideoSourceUrlRange(videoSource); true; } - is IDashManifestWidevineSource -> { swapVideoSourceDashWidevine(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 IVideoUrlWidevineSource -> { swapVideoSourceUrlWidevine(videoSource); true; } is IVideoUrlSource -> { swapVideoSourceUrl(videoSource); true; } null -> { _lastVideoMediaSource = null; true;} else -> throw IllegalArgumentException("Unsupported video source [${videoSource.javaClass.simpleName}]"); @@ -430,8 +426,7 @@ abstract class FutoVideoPlayerBase : RelativeLayout { is LocalAudioSource -> {swapAudioSourceLocal(audioSource); true; } is JSAudioUrlRangeSource -> { swapAudioSourceUrlRange(audioSource); true; } is JSHLSManifestAudioSource -> { swapAudioSourceHLS(audioSource); true; } - is JSDashManifestRawAudioSource -> swapAudioSourceDashRaw(audioSource, play, resume); - is IAudioUrlWidevineSource -> { swapAudioSourceUrlWidevine(audioSource); true; } + is JSDashManifestRawAudioSource -> swapAudioSourceDashRaw(audioSource, play, resume) is IAudioUrlSource -> { swapAudioSourceUrl(audioSource); true; } null -> { _lastAudioMediaSource = null; true; } else -> throw IllegalArgumentException("Unsupported video source [${audioSource.javaClass.simpleName}]"); @@ -471,80 +466,50 @@ abstract class FutoVideoPlayerBase : RelativeLayout { } else throw IllegalArgumentException("source without itag data..."); } + @OptIn(UnstableApi::class) private fun swapVideoSourceUrl(videoSource: IVideoUrlSource) { Logger.i(TAG, "Loading VideoSource [Url]"); - val dataSource = if(videoSource is JSSource && videoSource.requiresCustomDatasource) + val dataSource = if (videoSource is JSSource && videoSource.requiresCustomDatasource) videoSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); - _lastVideoMediaSource = ProgressiveMediaSource.Factory(dataSource) - .createMediaSource(MediaItem.fromUri(videoSource.getVideoUrl())); - } - @OptIn(UnstableApi::class) - private fun swapVideoSourceUrlWidevine(videoSource: IVideoUrlWidevineSource) { - Logger.i(TAG, "Loading VideoSource [UrlWidevine]"); - if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { - throw IllegalArgumentException("Device does not support Widevine") - } + val drmCallback = if (videoSource is JSSource) getDrmCallback(videoSource, dataSource) else null - val dataSource = if(videoSource is JSSource && videoSource.requiresCustomDatasource) - videoSource.getHttpDataSourceFactory() - else - DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - - val baseCallback = HttpMediaDrmCallback((videoSource as JSSource).drmLicenseUri, dataSource) - - val callback = if (videoSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!) - } else { - baseCallback - } - - _lastVideoMediaSource = ProgressiveMediaSource.Factory(dataSource) - .setDrmSessionManagerProvider { + val factory = ProgressiveMediaSource.Factory(dataSource) + if (drmCallback != null) { + factory.setDrmSessionManagerProvider { DefaultDrmSessionManager.Builder() .setMultiSession(true) - .build(callback) + .build(drmCallback) } - .createMediaSource( - MediaItem.fromUri(videoSource.getVideoUrl()) - ) + } + + _lastVideoMediaSource = factory + .createMediaSource(MediaItem.fromUri(videoSource.getVideoUrl())); } + @OptIn(UnstableApi::class) private fun swapVideoSourceDash(videoSource: IDashManifestSource) { Logger.i(TAG, "Loading VideoSource [Dash]"); - val dataSource = if(videoSource is JSSource && (videoSource.requiresCustomDatasource)) + val dataSource = if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); - _lastVideoMediaSource = DashMediaSource.Factory(dataSource) - .createMediaSource(MediaItem.fromUri(videoSource.url)) - } - @OptIn(UnstableApi::class) - private fun swapVideoSourceDashWidevine(videoSource: IDashManifestWidevineSource) { - Logger.i(TAG, "Loading VideoSource [DashWidevine]") - if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { - throw IllegalArgumentException("Device does not support Widevine") + val drmCallback = + if (videoSource is JSSource) getDrmCallback(videoSource, dataSource) else null + + val factory = DashMediaSource.Factory(dataSource) + if (drmCallback != null) { + factory.setDrmSessionManagerProvider { + DefaultDrmSessionManager.Builder().setMultiSession(true).build(drmCallback) + } } - val dataSource = - if (videoSource is JSSource && (videoSource.requiresCustomDatasource)) videoSource.getHttpDataSourceFactory() - else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - - val baseCallback = HttpMediaDrmCallback((videoSource as JSSource).drmLicenseUri, dataSource) - - val callback = if (videoSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, videoSource.getLicenseRequestExecutor()!!, videoSource.drmLicenseUri!!) - } else { - baseCallback - } - - _lastVideoMediaSource = DashMediaSource.Factory(dataSource).setDrmSessionManagerProvider { - DefaultDrmSessionManager.Builder().setMultiSession(true).build(callback) - }.createMediaSource(MediaItem.fromUri(videoSource.url)) + _lastVideoMediaSource = + factory.createMediaSource(MediaItem.fromUri(videoSource.url)) } @OptIn(UnstableApi::class) private fun swapVideoSourceDashRaw(videoSource: JSDashManifestRawSource, play: Boolean, resume: Boolean): Boolean { @@ -639,15 +604,28 @@ abstract class FutoVideoPlayerBase : RelativeLayout { } else throw IllegalArgumentException("source without itag data...") } + @OptIn(UnstableApi::class) private fun swapAudioSourceUrl(audioSource: IAudioUrlSource) { Logger.i(TAG, "Loading AudioSource [Url]"); - val dataSource = if(audioSource is JSSource && audioSource.requiresCustomDatasource) + val dataSource = if (audioSource is JSSource && audioSource.requiresCustomDatasource) audioSource.getHttpDataSourceFactory() else DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); - _lastAudioMediaSource = ProgressiveMediaSource.Factory(dataSource) - .createMediaSource(MediaItem.fromUri(audioSource.getAudioUrl())); + + val drmCallback = + if (audioSource is JSSource) getDrmCallback(audioSource, dataSource) else null + + val factory = ProgressiveMediaSource.Factory(dataSource) + if (drmCallback != null) { + factory.setDrmSessionManagerProvider { + DefaultDrmSessionManager.Builder() + .setMultiSession(true) + .build(drmCallback) + } + } + _lastAudioMediaSource = + factory.createMediaSource(MediaItem.fromUri(audioSource.getAudioUrl())); } @OptIn(UnstableApi::class) private fun swapAudioSourceHLS(audioSource: IHLSManifestAudioSource) { @@ -662,102 +640,73 @@ abstract class FutoVideoPlayerBase : RelativeLayout { @OptIn(UnstableApi::class) private fun swapAudioSourceDashRaw(audioSource: JSDashManifestRawAudioSource, play: Boolean, resume: Boolean): Boolean { - Logger.i(TAG, "Loading AudioSource [DashRaw]") + Logger.i(TAG, "Loading AudioSource [DashRaw]"); val dataSource = if (audioSource.requiresCustomDatasource) audioSource.getHttpDataSourceFactory() else - DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) + DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT); - val baseCallback = HttpMediaDrmCallback(audioSource.drmLicenseUri, dataSource) - - val callback = - if (audioSource.hasLicenseRequestExecutor && audioSource.drmLicenseUri != null) { - PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri) - } else { - baseCallback - } - - _lastVideoMediaSource = DashMediaSource.Factory(dataSource).setDrmSessionManagerProvider { - DefaultDrmSessionManager.Builder().setMultiSession(true).build(callback) - }.createMediaSource(MediaItem.fromUri(audioSource.url)) + val drmCallback = getDrmCallback(audioSource, dataSource) if (audioSource.hasGenerate) { findViewTreeLifecycleOwner()?.lifecycle?.coroutineScope?.launch(Dispatchers.IO) { - val generated = audioSource.generate() + val generated = audioSource.generate(); if (generated != null) { withContext(Dispatchers.Main) { val factory = DashMediaSource.Factory(dataSource) - if (audioSource.drmLicenseUri != null) { - if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { - throw IllegalArgumentException("Device does not support Widevine") - } + if (drmCallback != null) { factory.setDrmSessionManagerProvider { DefaultDrmSessionManager.Builder().setMultiSession(true) - .build(callback) + .build(drmCallback) } } - _lastVideoMediaSource = factory.createMediaSource( - DashManifestParser().parse( - Uri.parse(audioSource.url), - ByteArrayInputStream(generated.toByteArray() ?: ByteArray(0)) - ) - ) - loadSelectedSources(play, resume) + _lastVideoMediaSource = factory + .createMediaSource( + DashManifestParser().parse( + Uri.parse(audioSource.url), + ByteArrayInputStream(generated.toByteArray() ?: ByteArray(0)) + ) + ); + loadSelectedSources(play, resume); } } } - return false + return false; } else { val factory = DashMediaSource.Factory(dataSource) - if (audioSource.drmLicenseUri != null) { - if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { - throw IllegalArgumentException("Device does not support Widevine") - } + if (drmCallback != null) { factory.setDrmSessionManagerProvider { DefaultDrmSessionManager.Builder().setMultiSession(true) - .build(callback) + .build(drmCallback) } } - _lastVideoMediaSource = factory.createMediaSource( - DashManifestParser().parse( - Uri.parse(audioSource.url), - ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0)) - ) - ) - return true + _lastVideoMediaSource = factory + .createMediaSource( + DashManifestParser().parse( + Uri.parse(audioSource.url), + ByteArrayInputStream(audioSource.manifest?.toByteArray() ?: ByteArray(0)) + ) + ); + return true; } } @OptIn(UnstableApi::class) - private fun swapAudioSourceUrlWidevine(audioSource: IAudioUrlWidevineSource) { - Logger.i(TAG, "Loading AudioSource [UrlWidevine]") - - if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { - throw IllegalArgumentException("Device does not support Widevine") - } - - val dataSource = if (audioSource is JSSource && audioSource.requiresCustomDatasource) - audioSource.getHttpDataSourceFactory() - else - DefaultHttpDataSource.Factory().setUserAgent(DEFAULT_USER_AGENT) - - val baseCallback = HttpMediaDrmCallback((audioSource as JSSource).drmLicenseUri, dataSource) - - val callback = if (audioSource.hasLicenseRequestExecutor) { - PluginMediaDrmCallback(baseCallback, audioSource.getLicenseRequestExecutor()!!, audioSource.drmLicenseUri!!) - } else { - baseCallback - } - - _lastAudioMediaSource = ProgressiveMediaSource.Factory(dataSource) - .setDrmSessionManagerProvider { - DefaultDrmSessionManager.Builder() - .setMultiSession(true) - .build(callback) + private fun getDrmCallback(source: JSSource, dataSource: HttpDataSource.Factory): MediaDrmCallback? { + return if (source.drmLicenseUri != null) { + if (!MediaDrm.isCryptoSchemeSupported(C.WIDEVINE_UUID)) { + throw IllegalArgumentException("Device does not support Widevine") } - .createMediaSource( - MediaItem.fromUri(audioSource.getAudioUrl()) - ) + + val delegateCallback = + HttpMediaDrmCallback(source.drmLicenseUri, dataSource) + + if (source.hasLicenseRequestExecutor) { + PluginMediaDrmCallback(delegateCallback, source.getLicenseRequestExecutor()!!, source.drmLicenseUri) + } else { + delegateCallback + } + } else null } //Prefered source selection