Fix some bugs on discover pages (#1832)
## Description Fix some bugs on discover pages: - UI fixes for available seasons - Fix toggle not updating when removing a season from a pending request - Don't request images if the path is null - Better error handling when fetching ratings ### Related issues Follow up to #1816 ### Testing Emulator ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
ba52915cf0
commit
2110d846c1
7 changed files with 112 additions and 49 deletions
|
|
@ -184,21 +184,23 @@ class SeerrService
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val current = seerrServerRepository.current.firstOrNull() ?: return null
|
return path?.takeIf { it.isNotNullOrBlank() }?.let {
|
||||||
val cacheImages = current.serverConfig.cacheImages == true
|
val current = seerrServerRepository.current.firstOrNull() ?: return null
|
||||||
val base =
|
val cacheImages = current.serverConfig.cacheImages == true
|
||||||
if (cacheImages) {
|
val base =
|
||||||
current.server.url.removeSuffix("/") + "/imageproxy/tmdb"
|
if (cacheImages) {
|
||||||
} else {
|
current.server.url.removeSuffix("/") + "/imageproxy/tmdb"
|
||||||
"https://image.tmdb.org"
|
} else {
|
||||||
}
|
"https://image.tmdb.org"
|
||||||
val prefix =
|
}
|
||||||
when (imageType) {
|
val prefix =
|
||||||
ImageType.PRIMARY -> "/t/p/w500"
|
when (imageType) {
|
||||||
ImageType.BACKDROP -> "/t/p/w${backdropWidth}_and_h${backdropHeight}_multi_faces"
|
ImageType.PRIMARY -> "/t/p/w500"
|
||||||
else -> throw IllegalArgumentException("Image type not supported: $imageType")
|
ImageType.BACKDROP -> "/t/p/w${backdropWidth}_and_h${backdropHeight}_multi_faces"
|
||||||
}
|
else -> throw IllegalArgumentException("Image type not supported: $imageType")
|
||||||
return "${base}${prefix}$path"
|
}
|
||||||
|
return "${base}${prefix}$path"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getProfilesAndFolders(type: SeerrItemType): SeerrRequestData {
|
suspend fun getProfilesAndFolders(type: SeerrItemType): SeerrRequestData {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.github.damontecres.wholphin.data.ServerRepository
|
||||||
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
||||||
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
||||||
import com.github.damontecres.wholphin.data.model.RemoteTrailer
|
import com.github.damontecres.wholphin.data.model.RemoteTrailer
|
||||||
|
import com.github.damontecres.wholphin.data.model.RequestStatus
|
||||||
import com.github.damontecres.wholphin.data.model.SeerrItemType
|
import com.github.damontecres.wholphin.data.model.SeerrItemType
|
||||||
import com.github.damontecres.wholphin.data.model.SeerrPermission
|
import com.github.damontecres.wholphin.data.model.SeerrPermission
|
||||||
import com.github.damontecres.wholphin.data.model.Trailer
|
import com.github.damontecres.wholphin.data.model.Trailer
|
||||||
|
|
@ -20,6 +21,7 @@ import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.services.SeerrServerRepository
|
import com.github.damontecres.wholphin.services.SeerrServerRepository
|
||||||
import com.github.damontecres.wholphin.services.SeerrService
|
import com.github.damontecres.wholphin.services.SeerrService
|
||||||
import com.github.damontecres.wholphin.services.SeerrUserConfig
|
import com.github.damontecres.wholphin.services.SeerrUserConfig
|
||||||
|
import com.github.damontecres.wholphin.ui.equalsNotNull
|
||||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
|
|
@ -100,9 +102,13 @@ class DiscoverMovieViewModel
|
||||||
updateCanCancel()
|
updateCanCancel()
|
||||||
|
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
val result =
|
val rating =
|
||||||
seerrService.api.moviesApi.movieMovieIdRatingsGet(movieId = item.id)
|
getDiscoverRating(item.id) {
|
||||||
_state.update { it.copy(rating = DiscoverRating(result)) }
|
DiscoverRating(
|
||||||
|
seerrService.api.moviesApi.movieMovieIdRatingsGet(movieId = item.id),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_state.update { it.copy(rating = rating) }
|
||||||
}
|
}
|
||||||
if (state.value.similar.isEmpty()) {
|
if (state.value.similar.isEmpty()) {
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
|
|
@ -248,7 +254,12 @@ fun canUserCancelRequest(
|
||||||
(
|
(
|
||||||
// User requested this
|
// User requested this
|
||||||
user.hasPermission(SeerrPermission.REQUEST) &&
|
user.hasPermission(SeerrPermission.REQUEST) &&
|
||||||
requests?.any { it.requestedBy?.id == user?.id } == true
|
requests
|
||||||
|
.orEmpty()
|
||||||
|
.any {
|
||||||
|
equalsNotNull(it.requestedBy?.id, user?.id) &&
|
||||||
|
RequestStatus.from(it.status) < RequestStatus.APPROVED
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
data class DiscoverMovieState(
|
data class DiscoverMovieState(
|
||||||
|
|
|
||||||
|
|
@ -105,8 +105,11 @@ class DiscoverSeriesViewModel
|
||||||
updateCanCancel()
|
updateCanCancel()
|
||||||
|
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
val result = seerrService.api.tvApi.tvTvIdRatingsGet(tvId = item.id)
|
val rating =
|
||||||
_state.update { it.copy(rating = DiscoverRating(result)) }
|
getDiscoverRating(item.id) {
|
||||||
|
DiscoverRating(seerrService.api.tvApi.tvTvIdRatingsGet(tvId = item.id))
|
||||||
|
}
|
||||||
|
_state.update { it.copy(rating = rating) }
|
||||||
}
|
}
|
||||||
if (state.value.similar.isEmpty()) {
|
if (state.value.similar.isEmpty()) {
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
|
|
@ -183,6 +186,18 @@ class DiscoverSeriesViewModel
|
||||||
seasonAvailability[seasonNumber] = availability
|
seasonAvailability[seasonNumber] = availability
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
tv.mediaInfo?.seasons?.forEach {
|
||||||
|
it.seasonNumber?.let { seasonNumber ->
|
||||||
|
val status = if (is4k) it.status4k else it.status
|
||||||
|
val availability =
|
||||||
|
SeerrAvailability.from(status) ?: SeerrAvailability.UNKNOWN
|
||||||
|
val current =
|
||||||
|
seasonAvailability.getOrDefault(seasonNumber, SeerrAvailability.UNKNOWN)
|
||||||
|
if (availability > current) {
|
||||||
|
seasonAvailability[seasonNumber] = availability
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tv.mediaInfo
|
tv.mediaInfo
|
||||||
?.requests
|
?.requests
|
||||||
|
|
@ -209,10 +224,6 @@ class DiscoverSeriesViewModel
|
||||||
tv.seasons?.firstOrNull { it.seasonNumber == seasonNumber }?.let {
|
tv.seasons?.firstOrNull { it.seasonNumber == seasonNumber }?.let {
|
||||||
val availability =
|
val availability =
|
||||||
when (status) {
|
when (status) {
|
||||||
RequestStatus.UNKNOWN -> {
|
|
||||||
SeerrAvailability.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestStatus.PENDING -> {
|
RequestStatus.PENDING -> {
|
||||||
SeerrAvailability.PENDING
|
SeerrAvailability.PENDING
|
||||||
}
|
}
|
||||||
|
|
@ -229,22 +240,39 @@ class DiscoverSeriesViewModel
|
||||||
SeerrAvailability.UNKNOWN
|
SeerrAvailability.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestStatus.COMPLETED -> {
|
RequestStatus.UNKNOWN,
|
||||||
|
RequestStatus.COMPLETED,
|
||||||
|
-> {
|
||||||
seasonAvailability.getOrDefault(
|
seasonAvailability.getOrDefault(
|
||||||
seasonNumber,
|
seasonNumber,
|
||||||
SeerrAvailability.UNKNOWN,
|
SeerrAvailability.UNKNOWN,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
val defaultEditable =
|
||||||
|
availability != SeerrAvailability.AVAILABLE &&
|
||||||
|
availability != SeerrAvailability.PARTIALLY_AVAILABLE &&
|
||||||
|
availability != SeerrAvailability.PROCESSING &&
|
||||||
|
availability != SeerrAvailability.BLOCKLISTED
|
||||||
RequestSeason(
|
RequestSeason(
|
||||||
season = it,
|
season = it,
|
||||||
status = status,
|
status = status,
|
||||||
availability = availability,
|
availability = availability,
|
||||||
editable = editable.getOrDefault(seasonNumber, true),
|
editable = editable.getOrDefault(seasonNumber, defaultEditable),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Timber.v("Got %s seasons, is4k=%s", requestSeasons.size, is4k)
|
Timber.v("Got %s seasons, is4k=%s", requestSeasons.size, is4k)
|
||||||
|
// requestSeasons.forEach {
|
||||||
|
// Timber.v(
|
||||||
|
// "is4k=%s, season %s: availability=%s, status=%s, editable=%s",
|
||||||
|
// is4k,
|
||||||
|
// it.season.seasonNumber,
|
||||||
|
// it.availability,
|
||||||
|
// it.status,
|
||||||
|
// it.editable,
|
||||||
|
// )
|
||||||
|
// }
|
||||||
_state.update {
|
_state.update {
|
||||||
if (is4k) {
|
if (is4k) {
|
||||||
it.copy(seasons4k = requestSeasons)
|
it.copy(seasons4k = requestSeasons)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
package com.github.damontecres.wholphin.ui.detail.discover
|
||||||
|
|
||||||
|
import com.github.damontecres.wholphin.api.seerr.infrastructure.ClientException
|
||||||
|
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
||||||
|
import kotlinx.coroutines.CancellationException
|
||||||
|
import timber.log.Timber
|
||||||
|
|
||||||
|
suspend fun getDiscoverRating(
|
||||||
|
id: Int,
|
||||||
|
func: suspend () -> DiscoverRating,
|
||||||
|
): DiscoverRating? =
|
||||||
|
try {
|
||||||
|
func.invoke()
|
||||||
|
} catch (ex: CancellationException) {
|
||||||
|
throw ex
|
||||||
|
} catch (ex: ClientException) {
|
||||||
|
if (ex.statusCode == 404) {
|
||||||
|
Timber.w("No rating for %s", id)
|
||||||
|
} else {
|
||||||
|
Timber.e(ex, "Error fetching rating for %s", id)
|
||||||
|
}
|
||||||
|
null
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Error fetching rating for %s", id)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
@ -83,11 +83,13 @@ fun RequestSeasons(
|
||||||
mutableStateSetOf(
|
mutableStateSetOf(
|
||||||
*seasons
|
*seasons
|
||||||
.filter { season ->
|
.filter { season ->
|
||||||
season.status == RequestStatus.PENDING ||
|
!season.editable && (
|
||||||
season.status == RequestStatus.APPROVED ||
|
season.status == RequestStatus.PENDING ||
|
||||||
season.status == RequestStatus.COMPLETED ||
|
season.status == RequestStatus.APPROVED ||
|
||||||
season.availability == SeerrAvailability.PARTIALLY_AVAILABLE ||
|
season.status == RequestStatus.COMPLETED ||
|
||||||
season.availability == SeerrAvailability.AVAILABLE
|
season.availability == SeerrAvailability.PARTIALLY_AVAILABLE ||
|
||||||
|
season.availability == SeerrAvailability.AVAILABLE
|
||||||
|
)
|
||||||
}.mapNotNull { season -> season.season.seasonNumber }
|
}.mapNotNull { season -> season.season.seasonNumber }
|
||||||
.toTypedArray(),
|
.toTypedArray(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.github.damontecres.wholphin.R
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.api.seerr.infrastructure.ClientException
|
|
||||||
import com.github.damontecres.wholphin.data.filter.DiscoverFilter
|
import com.github.damontecres.wholphin.data.filter.DiscoverFilter
|
||||||
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
import com.github.damontecres.wholphin.data.model.DiscoverItem
|
||||||
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
import com.github.damontecres.wholphin.data.model.DiscoverRating
|
||||||
|
|
@ -42,6 +41,7 @@ import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.services.SeerrService
|
import com.github.damontecres.wholphin.services.SeerrService
|
||||||
import com.github.damontecres.wholphin.ui.components.Genre
|
import com.github.damontecres.wholphin.ui.components.Genre
|
||||||
import com.github.damontecres.wholphin.ui.data.RowColumn
|
import com.github.damontecres.wholphin.ui.data.RowColumn
|
||||||
|
import com.github.damontecres.wholphin.ui.detail.discover.getDiscoverRating
|
||||||
import com.github.damontecres.wholphin.ui.launchIO
|
import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.listToDotString
|
import com.github.damontecres.wholphin.ui.listToDotString
|
||||||
import com.github.damontecres.wholphin.ui.main.HomePageHeader
|
import com.github.damontecres.wholphin.ui.main.HomePageHeader
|
||||||
|
|
@ -262,13 +262,11 @@ class SeerrDiscoverViewModel
|
||||||
return@launchIO
|
return@launchIO
|
||||||
}
|
}
|
||||||
val result =
|
val result =
|
||||||
try {
|
getDiscoverRating(id) {
|
||||||
when (type) {
|
when (type) {
|
||||||
SeerrItemType.MOVIE -> {
|
SeerrItemType.MOVIE -> {
|
||||||
DiscoverRating(
|
DiscoverRating(
|
||||||
seerrService.api.moviesApi.movieMovieIdRatingsGet(
|
seerrService.api.moviesApi.movieMovieIdRatingsGet(movieId = id),
|
||||||
movieId = id,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -284,18 +282,8 @@ class SeerrDiscoverViewModel
|
||||||
DiscoverRating(null, null)
|
DiscoverRating(null, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (ex: ClientException) {
|
} ?: DiscoverRating(null, null)
|
||||||
if (ex.statusCode == 404) {
|
|
||||||
Timber.w("No rating found for %s", id)
|
|
||||||
DiscoverRating(null, null)
|
|
||||||
} else {
|
|
||||||
Timber.e(ex, "Error getting rating for %s", id)
|
|
||||||
return@launchIO
|
|
||||||
}
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
Timber.e(ex, "Error getting rating for %s", id)
|
|
||||||
return@launchIO
|
|
||||||
}
|
|
||||||
ratingCache.put(id, result)
|
ratingCache.put(id, result)
|
||||||
rating.update {
|
rating.update {
|
||||||
ratingCache.asMap().toMap()
|
ratingCache.asMap().toMap()
|
||||||
|
|
|
||||||
|
|
@ -1304,6 +1304,12 @@ components:
|
||||||
type: integer
|
type: integer
|
||||||
example: 0
|
example: 0
|
||||||
description: Availability of the media. 1 = `UNKNOWN`, 2 = `PENDING`, 3 = `PROCESSING`, 4 = `PARTIALLY_AVAILABLE`, 5 = `AVAILABLE`, 6 = `DELETED`
|
description: Availability of the media. 1 = `UNKNOWN`, 2 = `PENDING`, 3 = `PROCESSING`, 4 = `PARTIALLY_AVAILABLE`, 5 = `AVAILABLE`, 6 = `DELETED`
|
||||||
|
seasons:
|
||||||
|
type: array
|
||||||
|
readOnly: true
|
||||||
|
nullable: true
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Season'
|
||||||
requests:
|
requests:
|
||||||
type: array
|
type: array
|
||||||
readOnly: true
|
readOnly: true
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue