Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import com.nuvio.app.features.downloads.DownloadItem
import com.nuvio.app.features.downloads.DownloadsRepository
import com.nuvio.app.features.p2p.P2pSettingsRepository
import com.nuvio.app.features.p2p.P2pStreamingEngine
import com.nuvio.app.features.player.skip.NextEpisodeInfo
import com.nuvio.app.features.player.skip.PlayerNextEpisodeRules
import com.nuvio.app.features.streams.StreamItem
import com.nuvio.app.features.streams.StreamLinkCacheRepository
import com.nuvio.app.features.watchprogress.WatchProgressRepository
Expand Down Expand Up @@ -402,6 +404,50 @@ internal fun PlayerScreenRuntime.playNextEpisode() {
}
}

/**
* Plays an episode selected outside the player UI through the same download,
* source resolution, and autoplay policy as next-episode playback.
*/
internal fun PlayerScreenRuntime.playEpisodeAtIndex(index: Int) {
val targetEpisode = PlayerNextEpisodeRules.resolvePlayableEpisodeAtIndex(playerMetaVideos, index) ?: return
scope.launchPlayerNextEpisodeAutoPlay(
previousJob = nextEpisodeAutoPlayJob,
nextEpisodeInfo = NextEpisodeInfo(
videoId = targetEpisode.id,
season = targetEpisode.season ?: return,
episode = targetEpisode.episode ?: return,
title = targetEpisode.title,
thumbnail = targetEpisode.thumbnail,
overview = targetEpisode.overview,
released = targetEpisode.released,
hasAired = true,
isWatched = false,
unairedMessage = null,
),
allEpisodes = playerMetaVideos,
parentMetaId = parentMetaId,
parentMetaType = parentMetaType,
contentType = contentType,
settings = playerSettingsUiState,
currentStreamBingeGroup = currentStreamBingeGroup,
onDownloadedEpisodeSelected = { item, episode -> switchToDownloadedEpisode(item, episode) },
onEpisodeStreamSelected = { stream, episode -> switchToEpisodeStream(stream, episode) },
onManualSelectionRequired = { episode ->
episodeStreamsPanelState = EpisodeStreamsPanelState(
showStreams = true,
selectedEpisode = episode,
)
showEpisodesPanel = true
},
onSearchingChanged = { nextEpisodeAutoPlaySearching = it },
onSourceNameChanged = { nextEpisodeAutoPlaySourceName = it },
onCountdownChanged = { nextEpisodeAutoPlayCountdown = it },
onNextEpisodeCardVisibleChanged = { showNextEpisodeCard = it },
)?.let { job ->
nextEpisodeAutoPlayJob = job
}
}

internal fun PlayerScreenRuntime.openSourcesPanel() {
val vid = activeVideoId ?: return
PlayerStreamsRepository.loadSources(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ import com.nuvio.app.features.details.MetaVideo

object PlayerNextEpisodeRules {

fun resolvePlayableEpisodeAtIndex(videos: List<MetaVideo>, index: Int): MetaVideo? =
videos.getOrNull(index)?.takeIf { hasEpisodeAired(it.released) }

fun resolveNextEpisode(
videos: List<MetaVideo>,
currentSeason: Int?,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.nuvio.app.features.player.skip

import com.nuvio.app.features.details.MetaVideo
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull

class PlayerNextEpisodeRulesTest {
@Test
fun resolvesAiredEpisodeAtItsOriginalIndex() {
val episodes = listOf(
MetaVideo(id = "s1e2", title = "Episode 2", released = "2020-01-02"),
MetaVideo(id = "s1e1", title = "Episode 1", released = "2020-01-01"),
)

assertEquals("s1e1", PlayerNextEpisodeRules.resolvePlayableEpisodeAtIndex(episodes, 1)?.id)
}

@Test
fun rejectsInvalidAndUnairedEpisodeIndices() {
val episodes = listOf(
MetaVideo(id = "future", title = "Future", released = "2999-01-01"),
)

assertNull(PlayerNextEpisodeRules.resolvePlayableEpisodeAtIndex(episodes, -1))
assertNull(PlayerNextEpisodeRules.resolvePlayableEpisodeAtIndex(episodes, 1))
assertNull(PlayerNextEpisodeRules.resolvePlayableEpisodeAtIndex(episodes, 0))
}
}