Show Seerr source ratings on Jellyfin movie and series details

This commit is contained in:
justinzeus 2026-10-29 20:00:31 +01:00
parent 15b082ccd8
commit 38db9e5127
5 changed files with 34 additions and 2 deletions

View file

@ -339,6 +339,7 @@ fun MovieDetailsContent(
chosenStreams = state.chosenStreams,
bringIntoViewRequester = bringIntoViewRequester,
overviewOnClick = overviewOnClick,
sourceRatings = state.sourceRatings,
modifier =
Modifier
.fillMaxWidth()

View file

@ -20,6 +20,8 @@ import androidx.tv.material3.Text
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ChosenStreams
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.SourceRatings
import com.github.damontecres.wholphin.data.model.withSourceRatings
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.ui.components.GenreText
import com.github.damontecres.wholphin.ui.components.HeaderUtils
@ -41,8 +43,10 @@ fun MovieDetailsHeader(
bringIntoViewRequester: BringIntoViewRequester,
overviewOnClick: () -> Unit,
modifier: Modifier = Modifier,
sourceRatings: SourceRatings? = null,
) {
val dto = movie.data
val quickDetails = remember(movie, sourceRatings) { movie.ui.quickDetails.withSourceRatings(sourceRatings) }
val context = LocalContext.current
val scope = rememberCoroutineScope()
Column(
@ -64,7 +68,7 @@ fun MovieDetailsHeader(
modifier = Modifier.fillMaxWidth(.60f),
) {
QuickDetails(
movie.ui.quickDetails,
quickDetails,
movie.timeRemainingOrRuntime,
Modifier.padding(start = HeaderUtils.startPadding),
)

View file

@ -12,6 +12,7 @@ import com.github.damontecres.wholphin.data.model.Chapter
import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.data.model.ItemPlayback
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.data.model.SourceRatings
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.ExtrasService
@ -19,6 +20,7 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.PeopleFavorites
import com.github.damontecres.wholphin.services.SeerrRatingsService
import com.github.damontecres.wholphin.services.SeerrService
import com.github.damontecres.wholphin.services.ServerReportService
import com.github.damontecres.wholphin.services.StreamChoiceService
@ -57,6 +59,7 @@ class MovieViewModel
constructor(
private val api: ApiClient,
private val seerrService: SeerrService,
private val ratingsService: SeerrRatingsService,
@param:ApplicationContext private val context: Context,
private val navigationManager: NavigationManager,
val serverRepository: ServerRepository,
@ -152,6 +155,11 @@ class MovieViewModel
)
}
}
viewModelScope.launchIO {
ratingsService.forItem(movie).collect { ratings ->
_state.update { it.copy(sourceRatings = ratings) }
}
}
viewModelScope.launchIO {
val results = seerrService.similar(movie).orEmpty()
_state.update {
@ -305,6 +313,8 @@ data class MovieState(
val extras: List<ExtrasItem> = emptyList(),
val similar: List<BaseItem> = emptyList(),
val discovered: List<DiscoverItem> = emptyList(),
/** Seerr ratings, null until they load or if unavailable */
val sourceRatings: SourceRatings? = null,
val chosenStreams: ChosenStreams? = null,
val canDelete: Boolean = false,
) {

View file

@ -44,8 +44,10 @@ import com.github.damontecres.wholphin.data.ExtrasItem
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.data.model.SourceRatings
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.data.model.studioNames
import com.github.damontecres.wholphin.data.model.withSourceRatings
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.TrailerService
import com.github.damontecres.wholphin.ui.Cards
@ -253,6 +255,7 @@ fun SeriesDetails(
}
},
discovered = state.discovered,
sourceRatings = state.sourceRatings,
onClickDiscover = { index, item ->
viewModel.navigateTo(item.destination)
},
@ -330,6 +333,7 @@ fun SeriesDetailsContent(
extras: List<ExtrasItem>,
people: List<Person>,
discovered: List<DiscoverItem>,
sourceRatings: SourceRatings?,
played: Boolean,
favorite: Boolean,
canDelete: Boolean,
@ -377,6 +381,7 @@ fun SeriesDetailsContent(
showLogo = preferences.appPreferences.interfacePreferences.showLogos,
overviewOnClick = overviewOnClick,
bringIntoViewRequester = bringIntoViewRequester,
sourceRatings = sourceRatings,
modifier =
Modifier
.fillMaxWidth()
@ -654,9 +659,11 @@ fun SeriesDetailsHeader(
overviewOnClick: () -> Unit,
bringIntoViewRequester: BringIntoViewRequester,
modifier: Modifier = Modifier,
sourceRatings: SourceRatings? = null,
) {
val scope = rememberCoroutineScope()
val dto = series.data
val quickDetails = remember(series, sourceRatings) { series.ui.quickDetails.withSourceRatings(sourceRatings) }
Column(
verticalArrangement = Arrangement.spacedBy(4.dp),
modifier = modifier,
@ -674,7 +681,7 @@ fun SeriesDetailsHeader(
modifier = Modifier.fillMaxWidth(.60f),
) {
QuickDetails(
series.ui.quickDetails,
quickDetails,
null,
Modifier.padding(start = HeaderUtils.startPadding),
)

View file

@ -12,6 +12,7 @@ import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.DiscoverItem
import com.github.damontecres.wholphin.data.model.ItemPlayback
import com.github.damontecres.wholphin.data.model.Person
import com.github.damontecres.wholphin.data.model.SourceRatings
import com.github.damontecres.wholphin.data.model.Trailer
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.services.BackdropService
@ -20,6 +21,7 @@ import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaManagementService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.PeopleFavorites
import com.github.damontecres.wholphin.services.SeerrRatingsService
import com.github.damontecres.wholphin.services.SeerrService
import com.github.damontecres.wholphin.services.ServerReportService
import com.github.damontecres.wholphin.services.StreamChoiceService
@ -100,6 +102,7 @@ class SeriesViewModel
private val userPreferencesService: UserPreferencesService,
private val backdropService: BackdropService,
private val seerrService: SeerrService,
private val ratingsService: SeerrRatingsService,
private val mediaManagementService: MediaManagementService,
@Assisted val seriesId: UUID,
@Assisted val seasonEpisodeIds: SeasonEpisodeIds?,
@ -251,6 +254,11 @@ class SeriesViewModel
_state.update { it.copy(similar = similar) }
}
}
viewModelScope.launchIO {
ratingsService.forItem(series).collect { ratings ->
_state.update { it.copy(sourceRatings = ratings) }
}
}
viewModelScope.launchIO {
val results = seerrService.similar(series).orEmpty()
_state.update { it.copy(discovered = results) }
@ -895,5 +903,7 @@ data class SeriesState(
val peopleInEpisode: PeopleInItem = PeopleInItem(),
val discovered: List<DiscoverItem> = emptyList(),
val discoverSeries: DiscoverItem? = null,
/** Seerr ratings, null until they load or if unavailable */
val sourceRatings: SourceRatings? = null,
val chosenStreams: ChosenStreams? = null,
)