Play or shuffle series, season, collections, & playlists from context menu (#1544)

## Description
Adds options to the context menu to play or shuffle items in a series,
season, collection, or playlist. So you can long click a TV show and
play it directly.

Playing a TV show will play the next up episode (same as the play button
on the series detail page).

Playing a season, collection, or playlist will start from the beginning.

Also, removes the green play arrows and uses the same neutral color as
other icons.

### Related issues
Closes #1451
Closes #1507

### Testing
Emulator from library pages & series detail pages

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Damontecres 2026-06-10 19:30:07 -04:00 • committed by GitHub
parent f7f0ea9cca
commit 38b4a8c4de
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 107 additions and 233 deletions

View file

@ -23,6 +23,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineScope
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.playlistsApi
import org.jellyfin.sdk.api.client.extensions.tvShowsApi
import org.jellyfin.sdk.api.client.extensions.videosApi
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.BaseItemKind
@ -202,28 +203,72 @@ class PlaylistCreator
BaseItemKind.SEASON -> {
val seriesId = item.seriesId
if (seriesId != null) {
PlaylistCreationResult.Success(
createFromEpisode(
seriesId = seriesId,
seasonId = item.id,
episodeId = null,
shuffled = shuffled,
),
)
if (shuffled) {
api.tvShowsApi
.getEpisodes(
seriesId = seriesId,
seasonId = item.id,
limit = Playlist.MAX_SIZE,
sortBy = ItemSortBy.RANDOM,
fields = DefaultItemFields,
).content.items
.convertAndAddParts()
.let {
PlaylistCreationResult.Success(Playlist(it))
}
} else {
PlaylistCreationResult.Success(
createFromEpisode(
seriesId = seriesId,
seasonId = item.id,
episodeId = null,
shuffled = shuffled,
),
)
}
} else {
PlaylistCreationResult.Error(null, "Episode has no seriesId")
}
}
BaseItemKind.SERIES -> {
PlaylistCreationResult.Success(
createFromEpisode(
seriesId = item.id,
seasonId = null,
episodeId = null,
shuffled = shuffled,
),
)
if (shuffled) {
api.tvShowsApi
.getEpisodes(
seriesId = item.id,
limit = Playlist.MAX_SIZE,
sortBy = ItemSortBy.RANDOM,
fields = DefaultItemFields,
).content.items
.convertAndAddParts()
.let {
PlaylistCreationResult.Success(Playlist(it))
}
} else {
val result by api.tvShowsApi.getNextUp(seriesId = item.id)
val nextUp =
result.items.firstOrNull() ?: api.tvShowsApi
.getEpisodes(
item.id,
limit = 1,
).content.items
.firstOrNull()
if (nextUp != null) {
PlaylistCreationResult.Success(
createFromEpisode(
seriesId = item.id,
seasonId = null,
episodeId = nextUp.id,
shuffled = shuffled,
),
)
} else {
PlaylistCreationResult.Error(
null,
"Could not determine next up episode for series: " + item.id,
)
}
}
}
BaseItemKind.PLAYLIST -> {