mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Fix possible TV guide crash & update Play All libraries (#315)
- Fixes a possible crash if the server has Live TV enabled, but no channels - Disable Play All/Shuffle for Collections "library"
This commit is contained in:
parent
6004687deb
commit
7be4fb5fdf
7 changed files with 156 additions and 131 deletions
|
|
@ -52,9 +52,18 @@ data class GetItemsFilter(
|
||||||
return newFilter
|
return newFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
fun applyTo(req: GetItemsRequest) =
|
/**
|
||||||
req.copy(
|
* Add the filtering from this into the [GetItemsRequest], overwriting the fields
|
||||||
includeItemTypes = includeItemTypes,
|
*
|
||||||
|
* @param req the [GetItemsRequest]
|
||||||
|
* @param overwriteIncludeTypes whether the includeItemTypes field should be overwritten (used from this) or used as-is from the [GetItemsRequest]
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
fun applyTo(
|
||||||
|
req: GetItemsRequest,
|
||||||
|
overwriteIncludeTypes: Boolean = true,
|
||||||
|
) = req.copy(
|
||||||
|
includeItemTypes = if (overwriteIncludeTypes) includeItemTypes else req.includeItemTypes,
|
||||||
isFavorite = favorite,
|
isFavorite = favorite,
|
||||||
genreIds = genres,
|
genreIds = genres,
|
||||||
minCommunityRating = minCommunityRating,
|
minCommunityRating = minCommunityRating,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.github.damontecres.wholphin.ui.DefaultItemFields
|
||||||
import com.github.damontecres.wholphin.ui.components.baseItemKinds
|
import com.github.damontecres.wholphin.ui.components.baseItemKinds
|
||||||
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
||||||
import com.github.damontecres.wholphin.ui.indexOfFirstOrNull
|
import com.github.damontecres.wholphin.ui.indexOfFirstOrNull
|
||||||
|
import com.github.damontecres.wholphin.ui.playback.playable
|
||||||
import com.github.damontecres.wholphin.ui.toServerString
|
import com.github.damontecres.wholphin.ui.toServerString
|
||||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||||
import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler
|
import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler
|
||||||
|
|
@ -93,14 +94,18 @@ class PlaylistCreator
|
||||||
item: BaseItemDto,
|
item: BaseItemDto,
|
||||||
startIndex: Int = 0,
|
startIndex: Int = 0,
|
||||||
sortAndDirection: SortAndDirection?,
|
sortAndDirection: SortAndDirection?,
|
||||||
recursive: Boolean,
|
|
||||||
filter: GetItemsFilter,
|
filter: GetItemsFilter,
|
||||||
): Playlist {
|
): Playlist {
|
||||||
val includeItemTypes =
|
val includeItemTypes =
|
||||||
item.collectionType?.baseItemKinds?.takeIf { it.isNotEmpty() }
|
item.collectionType
|
||||||
?: listOf(BaseItemKind.MOVIE, BaseItemKind.EPISODE, BaseItemKind.VIDEO)
|
?.baseItemKinds
|
||||||
|
?.filter { it.playable }
|
||||||
|
?.takeIf { it.isNotEmpty() }
|
||||||
|
?: BaseItemKind.entries.filter { it.playable }
|
||||||
val request =
|
val request =
|
||||||
filter.applyTo(
|
filter.applyTo(
|
||||||
|
overwriteIncludeTypes = false,
|
||||||
|
req =
|
||||||
GetItemsRequest(
|
GetItemsRequest(
|
||||||
parentId = item.id,
|
parentId = item.id,
|
||||||
enableImageTypes = listOf(ImageType.PRIMARY, ImageType.THUMB),
|
enableImageTypes = listOf(ImageType.PRIMARY, ImageType.THUMB),
|
||||||
|
|
@ -144,7 +149,6 @@ class PlaylistCreator
|
||||||
} else {
|
} else {
|
||||||
sortAndDirection
|
sortAndDirection
|
||||||
},
|
},
|
||||||
recursive = recursive,
|
|
||||||
filter = filter,
|
filter = filter,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -211,7 +215,7 @@ class PlaylistCreator
|
||||||
else -> PlaylistCreationResult.Error(null, "Unsupported type: ${item.type}")
|
else -> PlaylistCreationResult.Error(null, "Unsupported type: ${item.type}")
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getPlaylists(
|
suspend fun getServerPlaylists(
|
||||||
mediaType: MediaType?,
|
mediaType: MediaType?,
|
||||||
scope: CoroutineScope,
|
scope: CoroutineScope,
|
||||||
): List<PlaylistInfo?> {
|
): List<PlaylistInfo?> {
|
||||||
|
|
@ -234,7 +238,7 @@ class PlaylistCreator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun createPlaylist(
|
suspend fun createServerPlaylist(
|
||||||
name: String,
|
name: String,
|
||||||
initialItems: List<UUID>,
|
initialItems: List<UUID>,
|
||||||
): UUID? =
|
): UUID? =
|
||||||
|
|
@ -251,14 +255,14 @@ class PlaylistCreator
|
||||||
.toUUIDOrNull()
|
.toUUIDOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun addToPlaylist(
|
suspend fun addToServerPlaylist(
|
||||||
playlistId: UUID,
|
playlistId: UUID,
|
||||||
itemId: UUID,
|
itemId: UUID,
|
||||||
) {
|
) {
|
||||||
api.playlistsApi.addItemToPlaylist(playlistId, listOf(itemId))
|
api.playlistsApi.addItemToPlaylist(playlistId, listOf(itemId))
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun removeFromPlaylist(
|
suspend fun removeFromServerPlaylist(
|
||||||
playlistId: UUID,
|
playlistId: UUID,
|
||||||
itemId: UUID,
|
itemId: UUID,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ class AddPlaylistViewModel
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
this@AddPlaylistViewModel.playlistState.setValueOnMain(PlaylistLoadingState.Loading)
|
this@AddPlaylistViewModel.playlistState.setValueOnMain(PlaylistLoadingState.Loading)
|
||||||
try {
|
try {
|
||||||
val playlists = playlistCreator.getPlaylists(mediaType, viewModelScope)
|
val playlists = playlistCreator.getServerPlaylists(mediaType, viewModelScope)
|
||||||
this@AddPlaylistViewModel.playlistState.setValueOnMain(PlaylistLoadingState.Success(playlists))
|
this@AddPlaylistViewModel.playlistState.setValueOnMain(PlaylistLoadingState.Success(playlists))
|
||||||
} catch (ex: Exception) {
|
} catch (ex: Exception) {
|
||||||
playlistState.setValueOnMain(PlaylistLoadingState.Error(ex))
|
playlistState.setValueOnMain(PlaylistLoadingState.Error(ex))
|
||||||
|
|
@ -43,7 +43,7 @@ class AddPlaylistViewModel
|
||||||
itemId: UUID,
|
itemId: UUID,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
|
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
|
||||||
playlistCreator.addToPlaylist(playlistId, itemId)
|
playlistCreator.addToServerPlaylist(playlistId, itemId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -52,7 +52,7 @@ class AddPlaylistViewModel
|
||||||
itemId: UUID,
|
itemId: UUID,
|
||||||
) {
|
) {
|
||||||
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
|
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
|
||||||
val playlistId = playlistCreator.createPlaylist(playlistName, listOf(itemId))
|
val playlistId = playlistCreator.createServerPlaylist(playlistName, listOf(itemId))
|
||||||
if (playlistId == null) {
|
if (playlistId == null) {
|
||||||
showToast(context, "Error creating playlist", Toast.LENGTH_LONG)
|
showToast(context, "Error creating playlist", Toast.LENGTH_LONG)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ fun CollectionFolderBoxSet(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
filter: GetItemsFilter = GetItemsFilter(),
|
filter: GetItemsFilter = GetItemsFilter(),
|
||||||
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
|
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
|
||||||
|
playEnabled: Boolean = false,
|
||||||
) {
|
) {
|
||||||
var showHeader by remember { mutableStateOf(true) }
|
var showHeader by remember { mutableStateOf(true) }
|
||||||
CollectionFolderGrid(
|
CollectionFolderGrid(
|
||||||
|
|
@ -44,6 +45,6 @@ fun CollectionFolderBoxSet(
|
||||||
showHeader = position < columns
|
showHeader = position < columns
|
||||||
},
|
},
|
||||||
params = CollectionFolderGridParameters.POSTER,
|
params = CollectionFolderGridParameters.POSTER,
|
||||||
playEnabled = true,
|
playEnabled = playEnabled,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -95,6 +95,9 @@ fun TvGuideGrid(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Column(modifier = modifier) {
|
Column(modifier = modifier) {
|
||||||
|
if (channels.isEmpty()) {
|
||||||
|
ErrorMessage("Live TV is enabled, but no channels were found.", null)
|
||||||
|
} else {
|
||||||
TvGuideGridContent(
|
TvGuideGridContent(
|
||||||
loading = state is LoadingState.Loading,
|
loading = state is LoadingState.Loading,
|
||||||
channels = channels,
|
channels = channels,
|
||||||
|
|
@ -125,8 +128,11 @@ fun TvGuideGrid(
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Toast
|
Toast
|
||||||
.makeText(context, "No guide data found!", Toast.LENGTH_SHORT)
|
.makeText(
|
||||||
.show()
|
context,
|
||||||
|
"No guide data found!",
|
||||||
|
Toast.LENGTH_SHORT,
|
||||||
|
).show()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
viewModel.getItem(program.id)
|
viewModel.getItem(program.id)
|
||||||
|
|
@ -140,6 +146,7 @@ fun TvGuideGrid(
|
||||||
.focusRequester(focusRequester),
|
.focusRequester(focusRequester),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (showItemDialog != null) {
|
if (showItemDialog != null) {
|
||||||
val onDismissRequest = { showItemDialog = null }
|
val onDismissRequest = { showItemDialog = null }
|
||||||
ProgramDialog(
|
ProgramDialog(
|
||||||
|
|
|
||||||
|
|
@ -103,11 +103,12 @@ fun DestinationContent(
|
||||||
|
|
||||||
BaseItemKind.BOX_SET ->
|
BaseItemKind.BOX_SET ->
|
||||||
CollectionFolderBoxSet(
|
CollectionFolderBoxSet(
|
||||||
preferences,
|
preferences = preferences,
|
||||||
destination.itemId,
|
itemId = destination.itemId,
|
||||||
destination.item,
|
item = destination.item,
|
||||||
false,
|
recursive = false,
|
||||||
modifier,
|
playEnabled = true,
|
||||||
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
|
|
||||||
BaseItemKind.PLAYLIST ->
|
BaseItemKind.PLAYLIST ->
|
||||||
|
|
|
||||||
|
|
@ -37,21 +37,24 @@ val PrefContentScale.scale: ContentScale
|
||||||
val BaseItemKind.playable: Boolean
|
val BaseItemKind.playable: Boolean
|
||||||
get() =
|
get() =
|
||||||
when (this) {
|
when (this) {
|
||||||
|
BaseItemKind.EPISODE,
|
||||||
|
BaseItemKind.MOVIE,
|
||||||
|
BaseItemKind.MUSIC_VIDEO,
|
||||||
|
BaseItemKind.TRAILER,
|
||||||
|
BaseItemKind.VIDEO,
|
||||||
|
-> true
|
||||||
|
|
||||||
|
// TODO add support for these eventually
|
||||||
|
BaseItemKind.LIVE_TV_CHANNEL,
|
||||||
|
BaseItemKind.LIVE_TV_PROGRAM,
|
||||||
|
BaseItemKind.PROGRAM,
|
||||||
|
BaseItemKind.RECORDING,
|
||||||
|
BaseItemKind.TV_CHANNEL,
|
||||||
|
BaseItemKind.TV_PROGRAM,
|
||||||
BaseItemKind.AUDIO_BOOK,
|
BaseItemKind.AUDIO_BOOK,
|
||||||
BaseItemKind.AUDIO,
|
BaseItemKind.AUDIO,
|
||||||
BaseItemKind.CHANNEL,
|
BaseItemKind.CHANNEL,
|
||||||
BaseItemKind.EPISODE,
|
-> false
|
||||||
BaseItemKind.MOVIE,
|
|
||||||
BaseItemKind.LIVE_TV_CHANNEL,
|
|
||||||
BaseItemKind.LIVE_TV_PROGRAM,
|
|
||||||
BaseItemKind.MUSIC_VIDEO,
|
|
||||||
BaseItemKind.PROGRAM,
|
|
||||||
BaseItemKind.RECORDING,
|
|
||||||
BaseItemKind.TRAILER,
|
|
||||||
BaseItemKind.TV_CHANNEL,
|
|
||||||
BaseItemKind.TV_PROGRAM,
|
|
||||||
BaseItemKind.VIDEO,
|
|
||||||
-> true
|
|
||||||
|
|
||||||
BaseItemKind.AGGREGATE_FOLDER,
|
BaseItemKind.AGGREGATE_FOLDER,
|
||||||
BaseItemKind.BASE_PLUGIN_FOLDER,
|
BaseItemKind.BASE_PLUGIN_FOLDER,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue