diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackController.java b/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackController.java index 9f06406078..e2a0d9849a 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackController.java +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackController.java @@ -639,23 +639,27 @@ private void startItem(BaseItemDto item, long position, StreamInfo response) { mVideoManager.setVideoPath(response.getMediaUrl()); } - // Set video start delay - long videoStartDelay = userPreferences.getValue().get(UserPreferences.Companion.getVideoStartDelay()); - if (videoStartDelay > 0) { - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - if (mVideoManager != null) { - mVideoManager.start(); + PlaybackControllerHelperKt.applyMediaSegments(this, item, () -> { + // Set video start delay + long videoStartDelay = userPreferences.getValue().get(UserPreferences.Companion.getVideoStartDelay()); + if (videoStartDelay > 0) { + mHandler.postDelayed(new Runnable() { + @Override + public void run() { + if (mVideoManager != null) { + mVideoManager.start(); + } } - } - }, videoStartDelay); - } else { - mVideoManager.start(); - } + }, videoStartDelay); + } else { + mVideoManager.start(); + } + + dataRefreshService.getValue().setLastPlayedItem(item); + reportingHelper.getValue().reportStart(item, mbPos); - dataRefreshService.getValue().setLastPlayedItem(item); - reportingHelper.getValue().reportStart(item, mbPos); + return null; + }); } public void startSpinner() { diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackControllerHelper.kt b/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackControllerHelper.kt index cf9a650825..337170a127 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackControllerHelper.kt +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/PlaybackControllerHelper.kt @@ -1,11 +1,19 @@ package org.jellyfin.androidtv.ui.playback +import androidx.annotation.OptIn import androidx.lifecycle.lifecycleScope +import androidx.media3.common.util.UnstableApi +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.jellyfin.androidtv.ui.playback.segment.MediaSegmentAction +import org.jellyfin.androidtv.ui.playback.segment.MediaSegmentRepository import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.extensions.liveTvApi import org.jellyfin.sdk.model.api.BaseItemDto +import org.jellyfin.sdk.model.api.MediaSegmentDto +import org.jellyfin.sdk.model.extensions.ticks import org.koin.android.ext.android.inject +import timber.log.Timber import java.util.UUID fun PlaybackController.getLiveTvChannel( @@ -22,3 +30,47 @@ fun PlaybackController.getLiveTvChannel( } } } + +fun PlaybackController.applyMediaSegments( + item: BaseItemDto, + callback: () -> Unit, +) { + val mediaSegmentRepository by fragment.inject() + + fragment.lifecycleScope.launch { + val mediaSegments = runCatching { + mediaSegmentRepository.getSegmentsForItem(item) + }.getOrNull().orEmpty() + + Timber.i(mediaSegments.toString()) + + for (mediaSegment in mediaSegments) { + val action = mediaSegmentRepository.getMediaSegmentAction(mediaSegment) + + when (action) { + MediaSegmentAction.SKIP -> addSkipAction(mediaSegment) + MediaSegmentAction.NOTHING -> Unit + } + } + + callback() + } +} + +@OptIn(UnstableApi::class) +private fun PlaybackController.addSkipAction(mediaSegment: MediaSegmentDto) { + mVideoManager.mExoPlayer + .createMessage { messageType: Int, payload: Any? -> + // We can't seek directly on the ExoPlayer instance as not all media is seekable + // the seek function in the PlaybackController checks this and optionally starts a transcode + // at the requested position + fragment.lifecycleScope.launch(Dispatchers.Main) { + seek(mediaSegment.endTicks.ticks.inWholeMilliseconds) + } + } + // Segments at position 0 will never be hit by ExoPlayer so we need to add a minimum value + .setPosition(mediaSegment.startTicks.ticks.inWholeMilliseconds.coerceAtLeast(1)) + .setPayload(mediaSegment) + .setDeleteAfterDelivery(false) + .send() +} diff --git a/app/src/main/java/org/jellyfin/androidtv/ui/playback/VideoManager.java b/app/src/main/java/org/jellyfin/androidtv/ui/playback/VideoManager.java index 815053a2f9..c6f1540136 100644 --- a/app/src/main/java/org/jellyfin/androidtv/ui/playback/VideoManager.java +++ b/app/src/main/java/org/jellyfin/androidtv/ui/playback/VideoManager.java @@ -64,7 +64,7 @@ public class VideoManager { private Limiter mLimiter; private PlaybackControllerNotifiable mPlaybackControllerNotifiable; private PlaybackOverlayFragmentHelper _helper; - private ExoPlayer mExoPlayer; + public ExoPlayer mExoPlayer; private PlayerView mExoPlayerView; private Handler mHandler = new Handler();