mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-05 07:41:23 +00:00
Added support for chapter skip in casting.
This commit is contained in:
parent
d63627bd61
commit
ef72561768
3 changed files with 66 additions and 9 deletions
|
@ -50,6 +50,7 @@ import com.futo.platformplayer.api.media.exceptions.ContentNotAvailableYetExcept
|
||||||
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
|
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
|
||||||
import com.futo.platformplayer.api.media.models.PlatformAuthorMembershipLink
|
import com.futo.platformplayer.api.media.models.PlatformAuthorMembershipLink
|
||||||
import com.futo.platformplayer.api.media.models.chapters.ChapterType
|
import com.futo.platformplayer.api.media.models.chapters.ChapterType
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||||
import com.futo.platformplayer.api.media.models.live.ILiveChatWindowDescriptor
|
import com.futo.platformplayer.api.media.models.live.ILiveChatWindowDescriptor
|
||||||
import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
|
import com.futo.platformplayer.api.media.models.live.IPlatformLiveEvent
|
||||||
|
@ -459,20 +460,29 @@ class VideoDetailView : ConstraintLayout {
|
||||||
_cast.onSettingsClick.subscribe { showVideoSettings() };
|
_cast.onSettingsClick.subscribe { showVideoSettings() };
|
||||||
_player.onVideoSettings.subscribe { showVideoSettings() };
|
_player.onVideoSettings.subscribe { showVideoSettings() };
|
||||||
_player.onToggleFullScreen.subscribe(::handleFullScreen);
|
_player.onToggleFullScreen.subscribe(::handleFullScreen);
|
||||||
_player.onChapterChanged.subscribe { chapter, isScrub ->
|
|
||||||
|
val onChapterChanged = { chapter: IChapter?, isScrub: Boolean ->
|
||||||
if(_layoutSkip.visibility == VISIBLE && chapter?.type != ChapterType.SKIPPABLE)
|
if(_layoutSkip.visibility == VISIBLE && chapter?.type != ChapterType.SKIPPABLE)
|
||||||
_layoutSkip.visibility = GONE;
|
_layoutSkip.visibility = GONE;
|
||||||
|
|
||||||
if(!isScrub) {
|
if(!isScrub) {
|
||||||
if(chapter?.type == ChapterType.SKIPPABLE) {
|
if(chapter?.type == ChapterType.SKIPPABLE) {
|
||||||
_layoutSkip.visibility = VISIBLE;
|
_layoutSkip.visibility = VISIBLE;
|
||||||
}
|
} else if(chapter?.type == ChapterType.SKIP) {
|
||||||
else if(chapter?.type == ChapterType.SKIP) {
|
val ad = StateCasting.instance.activeDevice
|
||||||
|
if (ad != null) {
|
||||||
|
ad.seekVideo(chapter.timeEnd)
|
||||||
|
} else {
|
||||||
_player.seekTo((chapter.timeEnd * 1000).toLong());
|
_player.seekTo((chapter.timeEnd * 1000).toLong());
|
||||||
|
}
|
||||||
|
|
||||||
UIDialogs.toast(context, "Skipped chapter [${chapter.name}]", false);
|
UIDialogs.toast(context, "Skipped chapter [${chapter.name}]", false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
_player.onChapterChanged.subscribe(onChapterChanged);
|
||||||
|
_cast.onChapterChanged.subscribe(onChapterChanged);
|
||||||
|
|
||||||
_cast.onMinimizeClick.subscribe {
|
_cast.onMinimizeClick.subscribe {
|
||||||
_player.setFullScreen(false);
|
_player.setFullScreen(false);
|
||||||
|
@ -667,12 +677,20 @@ class VideoDetailView : ConstraintLayout {
|
||||||
};
|
};
|
||||||
|
|
||||||
_layoutSkip.setOnClickListener {
|
_layoutSkip.setOnClickListener {
|
||||||
|
val ad = StateCasting.instance.activeDevice;
|
||||||
|
if (ad != null) {
|
||||||
|
val currentChapter = _cast.getCurrentChapter((ad.time * 1000).toLong());
|
||||||
|
if(currentChapter?.type == ChapterType.SKIPPABLE) {
|
||||||
|
ad.seekVideo(currentChapter.timeEnd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
val currentChapter = _player.getCurrentChapter(_player.position);
|
val currentChapter = _player.getCurrentChapter(_player.position);
|
||||||
if(currentChapter?.type == ChapterType.SKIPPABLE) {
|
if(currentChapter?.type == ChapterType.SKIPPABLE) {
|
||||||
_player.seekTo((currentChapter.timeEnd * 1000).toLong());
|
_player.seekTo((currentChapter.timeEnd * 1000).toLong());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val _trackingUpdateTimeLock = Object();
|
val _trackingUpdateTimeLock = Object();
|
||||||
val _trackingUpdateInterval = 2500;
|
val _trackingUpdateInterval = 2500;
|
||||||
|
@ -1145,10 +1163,12 @@ class VideoDetailView : ConstraintLayout {
|
||||||
//TODO: Implement video.getContentChapters()
|
//TODO: Implement video.getContentChapters()
|
||||||
val chapters = null ?: StatePlatform.instance.getContentChapters(video.url);
|
val chapters = null ?: StatePlatform.instance.getContentChapters(video.url);
|
||||||
_player.setChapters(chapters);
|
_player.setChapters(chapters);
|
||||||
|
_cast.setChapters(chapters);
|
||||||
}
|
}
|
||||||
catch(ex: Throwable) {
|
catch(ex: Throwable) {
|
||||||
Logger.e(TAG, "Failed to get chapters", ex);
|
Logger.e(TAG, "Failed to get chapters", ex);
|
||||||
_player.setChapters(null);
|
_player.setChapters(null);
|
||||||
|
_cast.setChapters(null);
|
||||||
|
|
||||||
/*withContext(Dispatchers.Main) {
|
/*withContext(Dispatchers.Main) {
|
||||||
UIDialogs.toast(context, "Failed to get chapters\n" + ex.message);
|
UIDialogs.toast(context, "Failed to get chapters\n" + ex.message);
|
||||||
|
|
|
@ -18,10 +18,12 @@ import androidx.media3.ui.DefaultTimeBar
|
||||||
import androidx.media3.ui.TimeBar
|
import androidx.media3.ui.TimeBar
|
||||||
import com.bumptech.glide.Glide
|
import com.bumptech.glide.Glide
|
||||||
import com.futo.platformplayer.R
|
import com.futo.platformplayer.R
|
||||||
|
import com.futo.platformplayer.api.media.models.chapters.IChapter
|
||||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||||
import com.futo.platformplayer.casting.AirPlayCastingDevice
|
import com.futo.platformplayer.casting.AirPlayCastingDevice
|
||||||
import com.futo.platformplayer.casting.StateCasting
|
import com.futo.platformplayer.casting.StateCasting
|
||||||
import com.futo.platformplayer.constructs.Event0
|
import com.futo.platformplayer.constructs.Event0
|
||||||
|
import com.futo.platformplayer.constructs.Event2
|
||||||
import com.futo.platformplayer.states.StatePlayer
|
import com.futo.platformplayer.states.StatePlayer
|
||||||
import com.futo.platformplayer.toHumanTime
|
import com.futo.platformplayer.toHumanTime
|
||||||
import com.futo.platformplayer.views.behavior.GestureControlView
|
import com.futo.platformplayer.views.behavior.GestureControlView
|
||||||
|
@ -51,7 +53,10 @@ class CastView : ConstraintLayout {
|
||||||
private var _scope: CoroutineScope = CoroutineScope(Dispatchers.Main);
|
private var _scope: CoroutineScope = CoroutineScope(Dispatchers.Main);
|
||||||
private var _updateTimeJob: Job? = null;
|
private var _updateTimeJob: Job? = null;
|
||||||
private var _inPictureInPicture: Boolean = false;
|
private var _inPictureInPicture: Boolean = false;
|
||||||
|
private var _chapters: List<IChapter>? = null;
|
||||||
|
private var _currentChapter: IChapter? = null;
|
||||||
|
|
||||||
|
val onChapterChanged = Event2<IChapter?, Boolean>();
|
||||||
val onMinimizeClick = Event0();
|
val onMinimizeClick = Event0();
|
||||||
val onSettingsClick = Event0();
|
val onSettingsClick = Event0();
|
||||||
val onPrevious = Event0();
|
val onPrevious = Event0();
|
||||||
|
@ -129,6 +134,36 @@ class CastView : ConstraintLayout {
|
||||||
_buttonNext.setOnClickListener { onNext.emit() };
|
_buttonNext.setOnClickListener { onNext.emit() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateCurrentChapter(chaptPos: Long, isScrub: Boolean = false): Boolean {
|
||||||
|
val currentChapter = getCurrentChapter(chaptPos);
|
||||||
|
if(_currentChapter != currentChapter) {
|
||||||
|
_currentChapter = currentChapter;
|
||||||
|
/*runBlocking(Dispatchers.Main) {
|
||||||
|
if (currentChapter != null) {
|
||||||
|
//TODO: Add chapter controls
|
||||||
|
//_control_chapter.text = " • " + currentChapter.name;
|
||||||
|
//_control_chapter_fullscreen.text = " • " + currentChapter.name;
|
||||||
|
} else {
|
||||||
|
//TODO: Add chapter controls
|
||||||
|
//_control_chapter.text = "";
|
||||||
|
//_control_chapter_fullscreen.text = "";
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
onChapterChanged.emit(currentChapter, isScrub);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setChapters(chapters: List<IChapter>?) {
|
||||||
|
_chapters = chapters;
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getCurrentChapter(pos: Long): IChapter? {
|
||||||
|
return _chapters?.let { chaps -> chaps.find { pos.toDouble() / 1000 > it.timeStart && pos.toDouble() / 1000 < it.timeEnd } };
|
||||||
|
}
|
||||||
|
|
||||||
private fun updateNextPrevious() {
|
private fun updateNextPrevious() {
|
||||||
val vidPrev = StatePlayer.instance.getPrevQueueItem(true);
|
val vidPrev = StatePlayer.instance.getPrevQueueItem(true);
|
||||||
val vidNext = StatePlayer.instance.getNextQueueItem(true);
|
val vidNext = StatePlayer.instance.getNextQueueItem(true);
|
||||||
|
@ -225,6 +260,7 @@ class CastView : ConstraintLayout {
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
fun setTime(ms: Long) {
|
fun setTime(ms: Long) {
|
||||||
|
updateCurrentChapter(ms);
|
||||||
_textPosition.text = ms.toHumanTime(true);
|
_textPosition.text = ms.toHumanTime(true);
|
||||||
_timeBar.setPosition(ms / 1000);
|
_timeBar.setPosition(ms / 1000);
|
||||||
StatePlayer.instance.updateMediaSessionPlaybackState(getPlaybackStateCompat(), ms);
|
StatePlayer.instance.updateMediaSessionPlaybackState(getPlaybackStateCompat(), ms);
|
||||||
|
|
|
@ -458,7 +458,8 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
val currentChapter = getCurrentChapter(chaptPos);
|
val currentChapter = getCurrentChapter(chaptPos);
|
||||||
if(_currentChapter != currentChapter) {
|
if(_currentChapter != currentChapter) {
|
||||||
_currentChapter = currentChapter;
|
_currentChapter = currentChapter;
|
||||||
runBlocking(Dispatchers.Main) {
|
|
||||||
|
StateApp.instance.scopeOrNull?.launch(Dispatchers.Main) {
|
||||||
if (currentChapter != null) {
|
if (currentChapter != null) {
|
||||||
_control_chapter.text = " • " + currentChapter.name;
|
_control_chapter.text = " • " + currentChapter.name;
|
||||||
_control_chapter_fullscreen.text = " • " + currentChapter.name;
|
_control_chapter_fullscreen.text = " • " + currentChapter.name;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue