mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-09-17 15:02:34 +00:00
Attempt to fetch live videos for offline videos
This commit is contained in:
parent
2530c6eb58
commit
c529446219
1 changed files with 63 additions and 25 deletions
|
@ -124,6 +124,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
private var _searchVideo: IPlatformVideo? = null;
|
private var _searchVideo: IPlatformVideo? = null;
|
||||||
var video: IPlatformVideoDetails? = null
|
var video: IPlatformVideoDetails? = null
|
||||||
private set;
|
private set;
|
||||||
|
var videoLocal: VideoLocal? = null;
|
||||||
private var _playbackTracker: IPlaybackTracker? = null;
|
private var _playbackTracker: IPlaybackTracker? = null;
|
||||||
|
|
||||||
val currentUrl get() = video?.url ?: _searchVideo?.url ?: _url;
|
val currentUrl get() = video?.url ?: _searchVideo?.url ?: _url;
|
||||||
|
@ -1044,10 +1045,32 @@ class VideoDetailView : ConstraintLayout {
|
||||||
_player.setPlaybackRate(Settings.instance.playback.getDefaultPlaybackSpeed());
|
_player.setPlaybackRate(Settings.instance.playback.getDefaultPlaybackSpeed());
|
||||||
}
|
}
|
||||||
|
|
||||||
val video = if(videoDetail is VideoLocal)
|
var videoLocal: VideoLocal? = null;
|
||||||
videoDetail;
|
var video: IPlatformVideoDetails? = null;
|
||||||
else //TODO: Update cached video if it exists with video
|
|
||||||
StateDownloads.instance.getCachedVideo(videoDetail.id) ?: videoDetail;
|
if(videoDetail is VideoLocal) {
|
||||||
|
videoLocal = videoDetail;
|
||||||
|
video = videoDetail;
|
||||||
|
val videoTask = StatePlatform.instance.getContentDetails(videoDetail.url);
|
||||||
|
videoTask.invokeOnCompletion { ex ->
|
||||||
|
if(ex != null) {
|
||||||
|
Logger.e(TAG, "Failed to fetch live video for offline video", ex);
|
||||||
|
return@invokeOnCompletion;
|
||||||
|
}
|
||||||
|
val result = videoTask.getCompleted();
|
||||||
|
if(this.video == videoDetail && result != null && result is IPlatformVideoDetails) {
|
||||||
|
this.video = result;
|
||||||
|
fragment.lifecycleScope.launch(Dispatchers.Main) {
|
||||||
|
updateQualitySourcesOverlay(result, videoLocal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else { //TODO: Update cached video if it exists with video
|
||||||
|
videoLocal = StateDownloads.instance.getCachedVideo(videoDetail.id);
|
||||||
|
video = videoDetail;
|
||||||
|
}
|
||||||
|
this.videoLocal = videoLocal;
|
||||||
this.video = video;
|
this.video = video;
|
||||||
this._playbackTracker = null;
|
this._playbackTracker = null;
|
||||||
|
|
||||||
|
@ -1082,9 +1105,13 @@ class VideoDetailView : ConstraintLayout {
|
||||||
me._playbackTracker = tracker;
|
me._playbackTracker = tracker;
|
||||||
}
|
}
|
||||||
catch(ex: Throwable) {
|
catch(ex: Throwable) {
|
||||||
withContext(Dispatchers.Main) {
|
Logger.e(TAG, "Playback tracker failed", ex);
|
||||||
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_get_playback_tracker), ex);
|
if(me.video?.isLive == true) withContext(Dispatchers.Main) {
|
||||||
|
UIDialogs.toast(context, context.getString(R.string.failed_to_get_playback_tracker));
|
||||||
};
|
};
|
||||||
|
else withContext(Dispatchers.Main) {
|
||||||
|
UIDialogs.showGeneralErrorDialog(context, context.getString(R.string.failed_to_get_playback_tracker), ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1235,7 +1262,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
|
|
||||||
//Overlay
|
//Overlay
|
||||||
updateQualitySourcesOverlay(video);
|
updateQualitySourcesOverlay(video, videoLocal);
|
||||||
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
|
|
||||||
|
@ -1514,9 +1541,9 @@ class VideoDetailView : ConstraintLayout {
|
||||||
//Quality Selector data
|
//Quality Selector data
|
||||||
private fun updateQualityFormatsOverlay(liveStreamVideoFormats : List<Format>?, liveStreamAudioFormats : List<Format>?) {
|
private fun updateQualityFormatsOverlay(liveStreamVideoFormats : List<Format>?, liveStreamAudioFormats : List<Format>?) {
|
||||||
val v = video ?: return;
|
val v = video ?: return;
|
||||||
updateQualitySourcesOverlay(v, liveStreamVideoFormats, liveStreamAudioFormats);
|
updateQualitySourcesOverlay(v, videoLocal, liveStreamVideoFormats, liveStreamAudioFormats);
|
||||||
}
|
}
|
||||||
private fun updateQualitySourcesOverlay(videoDetails: IPlatformVideoDetails?, liveStreamVideoFormats: List<Format>? = null, liveStreamAudioFormats: List<Format>? = null) {
|
private fun updateQualitySourcesOverlay(videoDetails: IPlatformVideoDetails?, videoLocal: VideoLocal? = null, liveStreamVideoFormats: List<Format>? = null, liveStreamAudioFormats: List<Format>? = null) {
|
||||||
Logger.i(TAG, "updateQualitySourcesOverlay");
|
Logger.i(TAG, "updateQualitySourcesOverlay");
|
||||||
|
|
||||||
val video: IPlatformVideoDetails?;
|
val video: IPlatformVideoDetails?;
|
||||||
|
@ -1524,24 +1551,35 @@ class VideoDetailView : ConstraintLayout {
|
||||||
val localAudioSource: List<LocalAudioSource>?;
|
val localAudioSource: List<LocalAudioSource>?;
|
||||||
val localSubtitleSources: List<LocalSubtitleSource>?;
|
val localSubtitleSources: List<LocalSubtitleSource>?;
|
||||||
|
|
||||||
|
val videoSources: List<IVideoSource>?;
|
||||||
|
val audioSources: List<IAudioSource>?;
|
||||||
|
|
||||||
if(videoDetails is VideoLocal) {
|
if(videoDetails is VideoLocal) {
|
||||||
video = videoDetails.videoSerialized;
|
video = videoLocal?.videoSerialized;
|
||||||
localVideoSources = videoDetails.videoSource.toList();
|
localVideoSources = videoDetails.videoSource.toList();
|
||||||
localAudioSource = videoDetails.audioSource.toList();
|
localAudioSource = videoDetails.audioSource.toList();
|
||||||
localSubtitleSources = videoDetails.subtitlesSources.toList();
|
localSubtitleSources = videoDetails.subtitlesSources.toList();
|
||||||
|
videoSources = null
|
||||||
|
audioSources = null;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
video = videoDetails;
|
video = videoDetails;
|
||||||
localVideoSources = null;
|
videoSources = video?.video?.videoSources?.toList();
|
||||||
localAudioSource = null;
|
audioSources = if(video?.video?.isUnMuxed == true)
|
||||||
localSubtitleSources = null;
|
(video.video as VideoUnMuxedSourceDescriptor).audioSources.toList()
|
||||||
|
else null
|
||||||
|
if(videoLocal != null) {
|
||||||
|
localVideoSources = videoLocal.videoSource.toList();
|
||||||
|
localAudioSource = videoLocal.audioSource.toList();
|
||||||
|
localSubtitleSources = videoLocal.subtitlesSources.toList();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
localVideoSources = null;
|
||||||
|
localAudioSource = null;
|
||||||
|
localSubtitleSources = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val videoSources = video?.video?.videoSources?.toList();
|
|
||||||
val audioSources = if(video?.video?.isUnMuxed == true)
|
|
||||||
(video.video as VideoUnMuxedSourceDescriptor).audioSources.toList()
|
|
||||||
else null
|
|
||||||
|
|
||||||
val bestVideoSources = videoSources?.map { it.height * it.width }
|
val bestVideoSources = videoSources?.map { it.height * it.width }
|
||||||
?.distinct()
|
?.distinct()
|
||||||
?.map { x -> VideoHelper.selectBestVideoSource(videoSources.filter { x == it.height * it.width }, -1, FutoVideoPlayerBase.PREFERED_VIDEO_CONTAINERS) }
|
?.map { x -> VideoHelper.selectBestVideoSource(videoSources.filter { x == it.height * it.width }, -1, FutoVideoPlayerBase.PREFERED_VIDEO_CONTAINERS) }
|
||||||
|
@ -1569,7 +1607,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
if(localVideoSources?.isNotEmpty() == true)
|
if(localVideoSources?.isNotEmpty() == true)
|
||||||
SlideUpMenuGroup(this.context, context.getString(R.string.offline_video), "video",
|
SlideUpMenuGroup(this.context, context.getString(R.string.offline_video), "video",
|
||||||
*localVideoSources.stream()
|
*localVideoSources
|
||||||
.map {
|
.map {
|
||||||
SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, "${it.width}x${it.height}", it,
|
SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, "${it.width}x${it.height}", it,
|
||||||
{ handleSelectVideoTrack(it) });
|
{ handleSelectVideoTrack(it) });
|
||||||
|
@ -1577,7 +1615,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
else null,
|
else null,
|
||||||
if(localAudioSource?.isNotEmpty() == true)
|
if(localAudioSource?.isNotEmpty() == true)
|
||||||
SlideUpMenuGroup(this.context, context.getString(R.string.offline_audio), "audio",
|
SlideUpMenuGroup(this.context, context.getString(R.string.offline_audio), "audio",
|
||||||
*localAudioSource.stream()
|
*localAudioSource
|
||||||
.map {
|
.map {
|
||||||
SlideUpMenuItem(this.context, R.drawable.ic_music, it.name, it.bitrate.toHumanBitrate(), it,
|
SlideUpMenuItem(this.context, R.drawable.ic_music, it.name, it.bitrate.toHumanBitrate(), it,
|
||||||
{ handleSelectAudioTrack(it) });
|
{ handleSelectAudioTrack(it) });
|
||||||
|
@ -1593,7 +1631,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
else null,
|
else null,
|
||||||
if(liveStreamVideoFormats?.isEmpty() == false)
|
if(liveStreamVideoFormats?.isEmpty() == false)
|
||||||
SlideUpMenuGroup(this.context, context.getString(R.string.stream_video), "video",
|
SlideUpMenuGroup(this.context, context.getString(R.string.stream_video), "video",
|
||||||
*liveStreamVideoFormats.stream()
|
*liveStreamVideoFormats
|
||||||
.map {
|
.map {
|
||||||
SlideUpMenuItem(this.context, R.drawable.ic_movie, it?.label ?: it.containerMimeType ?: it.bitrate.toString(), "${it.width}x${it.height}", it,
|
SlideUpMenuItem(this.context, R.drawable.ic_movie, it?.label ?: it.containerMimeType ?: it.bitrate.toString(), "${it.width}x${it.height}", it,
|
||||||
{ _player.selectVideoTrack(it.height) });
|
{ _player.selectVideoTrack(it.height) });
|
||||||
|
@ -1601,7 +1639,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
else null,
|
else null,
|
||||||
if(liveStreamAudioFormats?.isEmpty() == false)
|
if(liveStreamAudioFormats?.isEmpty() == false)
|
||||||
SlideUpMenuGroup(this.context, context.getString(R.string.stream_audio), "audio",
|
SlideUpMenuGroup(this.context, context.getString(R.string.stream_audio), "audio",
|
||||||
*liveStreamAudioFormats.stream()
|
*liveStreamAudioFormats
|
||||||
.map {
|
.map {
|
||||||
SlideUpMenuItem(this.context, R.drawable.ic_music, "${it?.label ?: it.containerMimeType} ${it.bitrate}", "", it,
|
SlideUpMenuItem(this.context, R.drawable.ic_music, "${it?.label ?: it.containerMimeType} ${it.bitrate}", "", it,
|
||||||
{ _player.selectAudioTrack(it.bitrate) });
|
{ _player.selectAudioTrack(it.bitrate) });
|
||||||
|
@ -1610,7 +1648,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
|
|
||||||
if(bestVideoSources.isNotEmpty())
|
if(bestVideoSources.isNotEmpty())
|
||||||
SlideUpMenuGroup(this.context, context.getString(R.string.video), "video",
|
SlideUpMenuGroup(this.context, context.getString(R.string.video), "video",
|
||||||
*bestVideoSources.stream()
|
*bestVideoSources
|
||||||
.map {
|
.map {
|
||||||
SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, if (it.width > 0 && it.height > 0) "${it.width}x${it.height}" else "", it,
|
SlideUpMenuItem(this.context, R.drawable.ic_movie, it!!.name, if (it.width > 0 && it.height > 0) "${it.width}x${it.height}" else "", it,
|
||||||
{ handleSelectVideoTrack(it) });
|
{ handleSelectVideoTrack(it) });
|
||||||
|
@ -1618,7 +1656,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
else null,
|
else null,
|
||||||
if(bestAudioSources.isNotEmpty())
|
if(bestAudioSources.isNotEmpty())
|
||||||
SlideUpMenuGroup(this.context, context.getString(R.string.audio), "audio",
|
SlideUpMenuGroup(this.context, context.getString(R.string.audio), "audio",
|
||||||
*bestAudioSources.stream()
|
*bestAudioSources
|
||||||
.map {
|
.map {
|
||||||
SlideUpMenuItem(this.context, R.drawable.ic_music, it.name, it.bitrate.toHumanBitrate(), it,
|
SlideUpMenuItem(this.context, R.drawable.ic_music, it.name, it.bitrate.toHumanBitrate(), it,
|
||||||
{ handleSelectAudioTrack(it) });
|
{ handleSelectAudioTrack(it) });
|
||||||
|
@ -1841,7 +1879,7 @@ class VideoDetailView : ConstraintLayout {
|
||||||
private fun setCastEnabled(isCasting: Boolean) {
|
private fun setCastEnabled(isCasting: Boolean) {
|
||||||
Logger.i(TAG, "setCastEnabled(isCasting=$isCasting)")
|
Logger.i(TAG, "setCastEnabled(isCasting=$isCasting)")
|
||||||
|
|
||||||
video?.let { updateQualitySourcesOverlay(it); };
|
video?.let { updateQualitySourcesOverlay(it, videoLocal); };
|
||||||
|
|
||||||
_isCasting = isCasting;
|
_isCasting = isCasting;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue