diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js index 4156abca..821fa656 100644 --- a/app/src/main/assets/scripts/source.js +++ b/app/src/main/assets/scripts/source.js @@ -67,6 +67,7 @@ class ScriptException extends Error { super(arguments[0]); this.plugin_type = "ScriptException"; this.message = arguments[0]; + this.msg = arguments[0]; } else { super(msg); diff --git a/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt b/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt index fc1f5cf3..e08cb7e9 100644 --- a/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt +++ b/app/src/main/java/com/futo/platformplayer/Extensions_V8.kt @@ -194,7 +194,6 @@ fun V8ObjectToHashMap(obj: V8ValueObject?): HashMap { return map; } - fun V8ValuePromise.toV8ValueBlocking(plugin: V8Plugin): T { val latch = CountDownLatch(1); var promiseResult: T? = null; @@ -204,16 +203,19 @@ fun V8ValuePromise.toV8ValueBlocking(plugin: V8Plugin): T { override fun onFulfilled(p0: V8Value?) { if(p0 is V8ValueError) promiseException = ScriptExecutionException(plugin.config, p0.message); - else + else { + if(p0 is V8ValueObject) + p0.setWeak(); promiseResult = p0 as T; + } latch.countDown(); } override fun onRejected(p0: V8Value?) { - promiseException = (NotImplementedError("onRejected promise not implemented..")); + promiseException = p0?.toException(plugin.config); latch.countDown(); } override fun onCatch(p0: V8Value?) { - promiseException = (NotImplementedError("onCatch promise not implemented..")); + promiseException = p0?.toException(plugin.config); latch.countDown(); } }); @@ -223,8 +225,25 @@ fun V8ValuePromise.toV8ValueBlocking(plugin: V8Plugin): T { promiseException = CancellationException("Cancelled by system"); latch.countDown(); } - plugin.unbusy { - latch.await(); + //Logger.i("V8", "V8ValueBlocking started (Busy) [" + blockCount + "]" + Thread.currentThread().stackTrace.drop(3)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(4)?.firstOrNull()?.toString()+ ", " + Thread.currentThread().stackTrace.drop(5)?.firstOrNull()?.toString()); + + + if(!promise.isPending) { + try { + Logger.i("V8", "V8Promise resolved synchronously"); + if(promise.isFulfilled) + promiseResult = promise.getResult(); + else + promiseException = promise.getResult().toException(plugin.config); + } + catch(ex: Throwable) { + promiseException = ex; + } + } + else { + plugin.unbusy { + latch.await(); + } } if(promiseException != null) throw promiseException!!; @@ -250,11 +269,11 @@ fun V8ValuePromise.toV8ValueAsync(plugin: V8Plugin): V8Deferred } override fun onRejected(p0: V8Value?) { plugin.resolvePromise(promise); - underlyingDef.completeExceptionally(NotImplementedError("onRejected promise not implemented..")); + underlyingDef.completeExceptionally(p0?.toException(plugin.config) ?: NotImplementedError("onRejected promise not implemented..")); } override fun onCatch(p0: V8Value?) { plugin.resolvePromise(promise); - underlyingDef.completeExceptionally(NotImplementedError("onCatch promise not implemented..")); + underlyingDef.completeExceptionally(p0?.toException(plugin.config) ?: NotImplementedError("onCatch promise not implemented..")); } }); } @@ -265,6 +284,20 @@ fun V8ValuePromise.toV8ValueAsync(plugin: V8Plugin): V8Deferred return def; } +fun V8Value.toException(config: IV8PluginConfig): Throwable { + val p0 = this; + if(p0 is V8ValueObject) { + val pluginType = p0.getOrDefault(config, "plugin_type", "Promise Exception", "")?.let { if(!it.isNullOrBlank()) it + "" else "" } + val msg = p0.getOrDefault(config, "msg", "Promise Exception", null) + ?: p0.getOrDefault(config, "message", "Promise Exception", ""); + return Exception("Promise Failed: " + pluginType + msg); + } + else if(p0 is V8ValueString) + return Exception("Promise Failed:" + p0.value); + else + return NotImplementedError("onCatch promise not implemented.."); +} + class V8Deferred(val deferred: Deferred, val estDuration: Int = -1): Deferred by deferred { fun convert(conversion: (result: T)->R): V8Deferred{ diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt index 5e4e1e42..d824d18c 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt @@ -39,6 +39,7 @@ import com.futo.platformplayer.R import com.futo.platformplayer.Settings import com.futo.platformplayer.UIDialogs import com.futo.platformplayer.api.http.ManagedHttpClient +import com.futo.platformplayer.api.media.models.video.LocalVideoDetails import com.futo.platformplayer.casting.StateCasting import com.futo.platformplayer.constructs.Event1 import com.futo.platformplayer.dp @@ -768,7 +769,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { if (targetData != null) { lifecycleScope.launch(Dispatchers.Main) { try { - handleUrlAll(targetData) + handleUrlAll(targetData, intent) } catch (e: Throwable) { Logger.e(TAG, "Unhandled exception in handleUrlAll", e) } @@ -779,8 +780,9 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { } } - suspend fun handleUrlAll(url: String) { + suspend fun handleUrlAll(url: String, openIntent: Intent? = null) { val uri = Uri.parse(url) + val intent = openIntent ?: this.intent; when (uri.scheme) { "grayjay" -> { if (url.startsWith("grayjay://license/")) { @@ -807,11 +809,11 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { } "content" -> { - if (!handleContent(url, intent.type)) { + if (!handleContent(url, intent?.type)) { UIDialogs.showSingleButtonDialog( this, R.drawable.ic_play, - getString(R.string.unknown_content_format) + " [${url}]\n[${intent.type}]", + getString(R.string.unknown_content_format) + " [${url}]\n[${intent?.type}]", "Ok", { }); } @@ -932,6 +934,12 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { } else if (file.lowercase().endsWith(".txt") || mime == "text/plain") { return handleUnknownText(String(data)); } + else if (mime?.let { it.startsWith("video/") || it.startsWith("audio/") } ?: false) { + val mediaItem = LocalVideoDetails.fromContent(file, mime); + navigateWhenReady(_fragVideoDetail, mediaItem); + return true; + } + return false; } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/LocalVideoUnMuxedSourceDescriptor.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/LocalVideoUnMuxedSourceDescriptor.kt index b5d28c6f..9d923d60 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/LocalVideoUnMuxedSourceDescriptor.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/LocalVideoUnMuxedSourceDescriptor.kt @@ -2,10 +2,24 @@ package com.futo.platformplayer.api.media.models.streams import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalAudioContentSource import com.futo.platformplayer.downloads.VideoLocal -class LocalVideoUnMuxedSourceDescriptor(private val video: VideoLocal) : VideoUnMuxedSourceDescriptor() { - override val videoSources: Array get() = video.videoSource.toTypedArray(); - override val audioSources: Array get() = video.audioSource.toTypedArray(); +class LocalVideoUnMuxedSourceDescriptor : VideoUnMuxedSourceDescriptor { + override val videoSources: Array; + override val audioSources: Array; + + constructor(video: VideoLocal) { + videoSources = video.videoSource.toTypedArray(); + audioSources = video.audioSource.toTypedArray(); + } + constructor(audio: LocalAudioContentSource) { + videoSources = arrayOf() + audioSources = arrayOf(audio); + } + constructor(videoSources: Array, audioSources: Array) { + this.videoSources = videoSources; + this.audioSources = audioSources; + } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/AudioUrlSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/AudioUrlSource.kt index a4d2cb55..9c5075b4 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/AudioUrlSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/AudioUrlSource.kt @@ -14,7 +14,8 @@ class AudioUrlSource( override val language: String = Language.UNKNOWN, override val duration: Long? = null, override var priority: Boolean = false, - override var original: Boolean = false + override var original: Boolean = false, + var isLocal: Boolean = false ) : IAudioUrlSource, IStreamMetaDataSource{ override var streamMetaData: StreamMetaData? = null; diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/VideoUrlSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/VideoUrlSource.kt index 490b8d4c..ebc112ec 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/VideoUrlSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/streams/sources/VideoUrlSource.kt @@ -14,7 +14,8 @@ open class VideoUrlSource( override val codec : String = "", override val bitrate : Int? = 0, - override var priority: Boolean = false + override var priority: Boolean = false, + var isLocal: Boolean = false ) : IVideoUrlSource, IStreamMetaDataSource { override var streamMetaData: StreamMetaData? = null; diff --git a/app/src/main/java/com/futo/platformplayer/api/media/models/video/LocalPlatformVideoDetails.kt b/app/src/main/java/com/futo/platformplayer/api/media/models/video/LocalPlatformVideoDetails.kt new file mode 100644 index 00000000..52659b46 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/models/video/LocalPlatformVideoDetails.kt @@ -0,0 +1,122 @@ +package com.futo.platformplayer.api.media.models.video + +import android.annotation.SuppressLint +import android.net.Uri +import android.provider.MediaStore +import android.provider.OpenableColumns +import androidx.core.net.toUri +import com.futo.platformplayer.api.media.IPlatformClient +import com.futo.platformplayer.api.media.PlatformID +import com.futo.platformplayer.api.media.Serializer +import com.futo.platformplayer.api.media.models.PlatformAuthorLink +import com.futo.platformplayer.api.media.models.Thumbnails +import com.futo.platformplayer.api.media.models.comments.IPlatformComment +import com.futo.platformplayer.api.media.models.contents.ContentType +import com.futo.platformplayer.api.media.models.contents.IPlatformContent +import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker +import com.futo.platformplayer.api.media.models.ratings.IRating +import com.futo.platformplayer.api.media.models.ratings.RatingLikes +import com.futo.platformplayer.api.media.models.streams.IVideoSourceDescriptor +import com.futo.platformplayer.api.media.models.streams.LocalVideoUnMuxedSourceDescriptor +import com.futo.platformplayer.api.media.models.streams.VideoMuxedSourceDescriptor +import com.futo.platformplayer.api.media.models.streams.VideoUnMuxedSourceDescriptor +import com.futo.platformplayer.api.media.models.streams.sources.AudioUrlSource +import com.futo.platformplayer.api.media.models.streams.sources.IDashManifestSource +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.LocalAudioSource +import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource +import com.futo.platformplayer.api.media.models.streams.sources.SubtitleRawSource +import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource +import com.futo.platformplayer.api.media.platforms.local.models.LocalVideoMuxedSourceDescriptor +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalAudioContentSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalVideoContentSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalVideoFileSource +import com.futo.platformplayer.api.media.structures.IPager +import com.futo.platformplayer.others.Language +import com.futo.platformplayer.serializers.OffsetDateTimeNullableSerializer +import com.futo.platformplayer.states.StateApp +import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json +import java.time.OffsetDateTime + +@kotlinx.serialization.Serializable +open class LocalVideoDetails( + override val id: PlatformID, + override val name: String, + override val thumbnails: Thumbnails, + override val author: PlatformAuthorLink, + override val url: String, + override val duration: Long, + + val mimeType: String? = null, + @kotlinx.serialization.Serializable(with = OffsetDateTimeNullableSerializer::class) + override val datetime: OffsetDateTime? +) : IPlatformVideo, IPlatformVideoDetails { + final override val contentType: ContentType get() = ContentType.MEDIA; + + override var playbackTime: Long = -1; + @kotlinx.serialization.Serializable(with = OffsetDateTimeNullableSerializer::class) + override var playbackDate: OffsetDateTime? = null; + + override val isLive: Boolean get() = false; + + override val dash: IDashManifestSource? get() = null; + override val hls: IHLSManifestSource? get() = null; + override val live: IVideoSource? get() = null; + + + override val shareUrl: String = "" + override val viewCount: Long = -1 + override val rating: IRating = RatingLikes(0) + override val description: String = ""; + override val video: IVideoSourceDescriptor = (if(mimeType?.startsWith("audio/") ?: false) + (LocalVideoUnMuxedSourceDescriptor( + arrayOf(), + arrayOf(LocalAudioContentSource(url, mimeType ?: "", name)) + )) + else (LocalVideoMuxedSourceDescriptor( + LocalVideoContentSource(url, mimeType ?: "", name) + )) + ); + override val preview: ISerializedVideoSourceDescriptor? = null; + + override val subtitles: List = listOf() + override val isShort: Boolean = false + + fun toJson() : String { + return Json.encodeToString(this); + } + fun fromJson(str : String) : SerializedPlatformVideoDetails { + return Serializer.json.decodeFromString(str); + } + + override fun getComments(client: IPlatformClient): IPager? = null; + override fun getPlaybackTracker(): IPlaybackTracker? = null; + override fun getContentRecommendations(client: IPlatformClient): IPager? = null; + + companion object { + fun fromFile(name: String, filePath: String, mimeType: String? = null) : LocalVideoDetails { + if(filePath.startsWith("content://")) + return fromContent(filePath, mimeType); + + return LocalVideoDetails(PlatformID("FILE", filePath, null, 0, -1), + name, Thumbnails(), PlatformAuthorLink.UNKNOWN, filePath, -1, mimeType, null); + } + fun fromContent(contentUrl: String, mimeType: String? = null) : LocalVideoDetails { + var nameToUse = getFileNameFromContentUrl(contentUrl) ?: "File"; + + return LocalVideoDetails(PlatformID("FILE", contentUrl, null, 0, -1), + nameToUse, Thumbnails(), PlatformAuthorLink.UNKNOWN, contentUrl, -1, mimeType, null); + } + + @SuppressLint("Range") + private fun getFileNameFromContentUrl(url: String): String? { + val cursor = StateApp.instance.context.contentResolver.query(url.toUri(), null, null, null, null); + cursor?.moveToFirst(); + val fileName = cursor?.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)); + cursor?.close(); + return fileName; + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/LocalVideoMuxedSourceDescriptor.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/LocalVideoMuxedSourceDescriptor.kt index da8ae431..0170f2fa 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/LocalVideoMuxedSourceDescriptor.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/LocalVideoMuxedSourceDescriptor.kt @@ -1,13 +1,23 @@ package com.futo.platformplayer.api.media.platforms.local.models 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.IVideoSource import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalVideoContentSource import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalVideoFileSource import com.futo.platformplayer.downloads.VideoLocal -class LocalVideoMuxedSourceDescriptor( - private val video: LocalVideoFileSource -) : VideoMuxedSourceDescriptor() { - override val videoSources: Array get() = arrayOf(video); +class LocalVideoMuxedSourceDescriptor: VideoMuxedSourceDescriptor { + override val videoSources: Array; + + constructor(video: LocalVideoFileSource) { + videoSources = arrayOf(video); + } + constructor(video: LocalVideoContentSource) { + videoSources = arrayOf(video); + } + constructor(videoSources: Array) { + this.videoSources = videoSources; + } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalAudioContentSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalAudioContentSource.kt new file mode 100644 index 00000000..06f1c50c --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalAudioContentSource.kt @@ -0,0 +1,33 @@ +package com.futo.platformplayer.api.media.platforms.local.models.sources + +import android.content.Context +import android.provider.MediaStore +import android.provider.MediaStore.Video +import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource +import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource +import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource +import com.futo.platformplayer.helpers.VideoHelper +import com.futo.platformplayer.others.Language +import java.io.File + +class LocalAudioContentSource : IAudioSource { + + override val name: String; + override val container: String; + override val codec: String = "" + override val bitrate: Int = 0 + override val duration: Long; + override val priority: Boolean = false; + override val language: String = Language.UNKNOWN + override val original: Boolean = false; + + var contentUrl: String; + + constructor(contentUrl: String, mime: String, name: String? = null) { + this.name = name ?: "File"; + container = mime; + duration = 0; + + this.contentUrl = contentUrl; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalAudioFileSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalAudioFileSource.kt new file mode 100644 index 00000000..ae822837 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalAudioFileSource.kt @@ -0,0 +1,34 @@ +package com.futo.platformplayer.api.media.platforms.local.models.sources + +import android.content.Context +import android.provider.MediaStore +import android.provider.MediaStore.Video +import com.futo.platformplayer.api.media.models.streams.sources.IAudioSource +import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource +import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource +import com.futo.platformplayer.helpers.VideoHelper +import com.futo.platformplayer.others.Language +import java.io.File + +class LocalAudioFileSource: IAudioSource { + + + override val name: String; + override val container: String; + override val codec: String = "" + override val bitrate: Int = 0 + override val duration: Long; + override val priority: Boolean = false; + override val language: String = Language.UNKNOWN; + override val original: Boolean = false; + + var file: File; + + constructor(file: File) { + this.file = file; + name = file.name; + container = VideoHelper.videoExtensionToMimetype(file.extension) ?: ""; + duration = 0; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoContentSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoContentSource.kt new file mode 100644 index 00000000..d8507fab --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoContentSource.kt @@ -0,0 +1,33 @@ +package com.futo.platformplayer.api.media.platforms.local.models.sources + +import android.content.Context +import android.provider.MediaStore +import android.provider.MediaStore.Video +import com.futo.platformplayer.api.media.models.streams.sources.IVideoSource +import com.futo.platformplayer.api.media.models.streams.sources.VideoUrlSource +import com.futo.platformplayer.helpers.VideoHelper +import java.io.File + +class LocalVideoContentSource: IVideoSource { + + + override val name: String; + override val width: Int; + override val height: Int; + override val container: String; + override val codec: String = "" + override val bitrate: Int = 0 + override val duration: Long; + override val priority: Boolean = false; + + var contentUrl: String; + + constructor(contentUrl: String, mime: String, name: String? = null) { + this.name = name ?: "File"; + width = 0; + height = 0; + container = mime; + duration = 0; + this.contentUrl = contentUrl; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoFileSource.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoFileSource.kt index 9e2f7792..4b4ff583 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoFileSource.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/local/models/sources/LocalVideoFileSource.kt @@ -20,7 +20,10 @@ class LocalVideoFileSource: IVideoSource { override val duration: Long; override val priority: Boolean = false; + var file: File; + constructor(file: File) { + this.file = file; name = file.name; width = 0; height = 0; diff --git a/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt b/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt index 9b888bff..9b350458 100644 --- a/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt +++ b/app/src/main/java/com/futo/platformplayer/engine/V8Plugin.kt @@ -242,10 +242,12 @@ class V8Plugin { } fun busy(handle: ()->T): T { _busyLock.lock(); + //Logger.i(TAG, "Busy Enter [" + _busyLock.holdCount + "]" + Thread.currentThread().stackTrace.drop(3)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(4)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(5)?.firstOrNull()?.toString()) try { return handle(); } finally { + //Logger.i(TAG, "Busy Leave [" + _busyLock.holdCount + "]" + Thread.currentThread().stackTrace.drop(3)?.firstOrNull()?.toString() + ", " + Thread.currentThread().stackTrace.drop(4)?.firstOrNull()?.toString()+ ", " + Thread.currentThread().stackTrace.drop(5)?.firstOrNull()?.toString()) _busyLock.unlock(); } /* 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 ff147b65..37cbe052 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 @@ -64,6 +64,10 @@ import com.futo.platformplayer.api.media.platforms.js.models.sources.JSDashManif import com.futo.platformplayer.api.media.platforms.js.models.sources.JSHLSManifestAudioSource 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.api.media.platforms.local.models.sources.LocalAudioContentSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalAudioFileSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalVideoContentSource +import com.futo.platformplayer.api.media.platforms.local.models.sources.LocalVideoFileSource import com.futo.platformplayer.api.media.structures.IPager import com.futo.platformplayer.constructs.Event0 import com.futo.platformplayer.constructs.Event1 @@ -480,6 +484,8 @@ abstract class FutoVideoPlayerBase : RelativeLayout { is IHLSManifestSource -> { swapVideoSourceHLS(videoSource); true; } is IVideoUrlWidevineSource -> { swapVideoSourceUrlWidevine(videoSource); true; } is IVideoUrlSource -> { swapVideoSourceUrl(videoSource); true; } + is LocalVideoFileSource -> { swapVideoSourceLocalFile(videoSource); true; } + is LocalVideoContentSource -> { swapVideoSourceLocalContent(videoSource); true; } null -> { _lastVideoMediaSource = null; true;} else -> throw IllegalArgumentException("Unsupported video source [${videoSource.javaClass.simpleName}]"); } @@ -496,6 +502,8 @@ abstract class FutoVideoPlayerBase : RelativeLayout { is JSDashManifestRawAudioSource -> swapAudioSourceDashRaw(audioSource, play, resume, swapId); is IAudioUrlWidevineSource -> { swapAudioSourceUrlWidevine(audioSource); true; } is IAudioUrlSource -> { swapAudioSourceUrl(audioSource); true; } + is LocalAudioFileSource -> { swapAudioSourceLocalFile(audioSource); true; } + is LocalAudioContentSource -> { swapAudioSourceLocalContent(audioSource); true; } null -> { _lastAudioMediaSource = null; true; } else -> throw IllegalArgumentException("Unsupported video source [${audioSource.javaClass.simpleName}]"); } @@ -514,6 +522,23 @@ abstract class FutoVideoPlayerBase : RelativeLayout { .createMediaSource(MediaItem.fromUri(Uri.fromFile(file))); } @OptIn(UnstableApi::class) + private fun swapVideoSourceLocalFile(videoSource: LocalVideoFileSource) { + Logger.i(TAG, "Loading VideoSource [Local]"); + val file = videoSource.file; + if(!file.exists()) + throw IllegalArgumentException("File for this video does not exist"); + _lastVideoMediaSource = ProgressiveMediaSource.Factory(DefaultDataSource.Factory(context)) + .createMediaSource(MediaItem.fromUri(Uri.fromFile(file))); + } + @OptIn(UnstableApi::class) + private fun swapVideoSourceLocalContent(videoSource: LocalVideoContentSource) { + Logger.i(TAG, "Loading VideoSource [Local]"); + if(!videoSource.contentUrl.startsWith("content://")) + throw IllegalArgumentException("Not a content uri"); + _lastVideoMediaSource = ProgressiveMediaSource.Factory(DefaultDataSource.Factory(context)) + .createMediaSource(MediaItem.fromUri(videoSource.contentUrl)); + } + @OptIn(UnstableApi::class) private fun swapVideoSourceUrlRange(videoSource: JSVideoUrlRangeSource) { Logger.i(TAG, "Loading JSVideoUrlRangeSource"); if(videoSource.hasItag) { @@ -707,6 +732,23 @@ abstract class FutoVideoPlayerBase : RelativeLayout { .createMediaSource(MediaItem.fromUri(Uri.fromFile(file))); } @OptIn(UnstableApi::class) + private fun swapAudioSourceLocalFile(audioSource: LocalAudioFileSource) { + Logger.i(TAG, "Loading VideoSource [Local]"); + val file = audioSource.file; + if(!file.exists()) + throw IllegalArgumentException("File for this video does not exist"); + _lastAudioMediaSource = ProgressiveMediaSource.Factory(DefaultDataSource.Factory(context)) + .createMediaSource(MediaItem.fromUri(Uri.fromFile(file))); + } + @OptIn(UnstableApi::class) + private fun swapAudioSourceLocalContent(audioSource: LocalAudioContentSource) { + Logger.i(TAG, "Loading VideoSource [Local]"); + if(!audioSource.contentUrl.startsWith("content://")) + throw IllegalArgumentException("Not a content uri"); + _lastAudioMediaSource = ProgressiveMediaSource.Factory(DefaultDataSource.Factory(context)) + .createMediaSource(MediaItem.fromUri(audioSource.contentUrl)); + } + @OptIn(UnstableApi::class) private fun swapAudioSourceUrlRange(audioSource: JSAudioUrlRangeSource) { Logger.i(TAG, "Loading JSAudioUrlRangeSource"); if(audioSource.hasItag) { diff --git a/app/src/stable/assets/sources/odysee b/app/src/stable/assets/sources/odysee index 736c6b95..89ad7e9a 160000 --- a/app/src/stable/assets/sources/odysee +++ b/app/src/stable/assets/sources/odysee @@ -1 +1 @@ -Subproject commit 736c6b953a4613145e32010ff5ee5b08be1baac6 +Subproject commit 89ad7e9a4bae727164099fbd853f031c4902b674 diff --git a/app/src/stable/assets/sources/rumble b/app/src/stable/assets/sources/rumble index 3368dfaa..3a7087cc 160000 --- a/app/src/stable/assets/sources/rumble +++ b/app/src/stable/assets/sources/rumble @@ -1 +1 @@ -Subproject commit 3368dfaa2ccaaa060cbbc0e91c86200e4d927b6e +Subproject commit 3a7087ccb0a8626e354e80673fb1e73d1527175b diff --git a/app/src/stable/assets/sources/soundcloud b/app/src/stable/assets/sources/soundcloud index 048acef1..49db9e3e 160000 --- a/app/src/stable/assets/sources/soundcloud +++ b/app/src/stable/assets/sources/soundcloud @@ -1 +1 @@ -Subproject commit 048acef152823d2621da177d3b4e1535cf4ca8ac +Subproject commit 49db9e3e15725c2e58c1fca565922aea738230d1 diff --git a/app/src/stable/assets/sources/youtube b/app/src/stable/assets/sources/youtube index f1465628..72c0cf18 160000 --- a/app/src/stable/assets/sources/youtube +++ b/app/src/stable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit f1465628ecb67c9bceb96aed667355e6ddbb49d3 +Subproject commit 72c0cf181dede3e41846c8f017ce061ff1fcd231 diff --git a/app/src/unstable/AndroidManifest.xml b/app/src/unstable/AndroidManifest.xml index ba96bb29..dae2026f 100644 --- a/app/src/unstable/AndroidManifest.xml +++ b/app/src/unstable/AndroidManifest.xml @@ -8,6 +8,16 @@ + + + + + + + + + + diff --git a/app/src/unstable/assets/sources/odysee b/app/src/unstable/assets/sources/odysee index 736c6b95..89ad7e9a 160000 --- a/app/src/unstable/assets/sources/odysee +++ b/app/src/unstable/assets/sources/odysee @@ -1 +1 @@ -Subproject commit 736c6b953a4613145e32010ff5ee5b08be1baac6 +Subproject commit 89ad7e9a4bae727164099fbd853f031c4902b674 diff --git a/app/src/unstable/assets/sources/rumble b/app/src/unstable/assets/sources/rumble index 3368dfaa..3a7087cc 160000 --- a/app/src/unstable/assets/sources/rumble +++ b/app/src/unstable/assets/sources/rumble @@ -1 +1 @@ -Subproject commit 3368dfaa2ccaaa060cbbc0e91c86200e4d927b6e +Subproject commit 3a7087ccb0a8626e354e80673fb1e73d1527175b diff --git a/app/src/unstable/assets/sources/soundcloud b/app/src/unstable/assets/sources/soundcloud index 048acef1..49db9e3e 160000 --- a/app/src/unstable/assets/sources/soundcloud +++ b/app/src/unstable/assets/sources/soundcloud @@ -1 +1 @@ -Subproject commit 048acef152823d2621da177d3b4e1535cf4ca8ac +Subproject commit 49db9e3e15725c2e58c1fca565922aea738230d1 diff --git a/app/src/unstable/assets/sources/youtube b/app/src/unstable/assets/sources/youtube index f1465628..72c0cf18 160000 --- a/app/src/unstable/assets/sources/youtube +++ b/app/src/unstable/assets/sources/youtube @@ -1 +1 @@ -Subproject commit f1465628ecb67c9bceb96aed667355e6ddbb49d3 +Subproject commit 72c0cf181dede3e41846c8f017ce061ff1fcd231