Tolerate unknown RT labels, expire cached ratings, avoid duplicate collectors and Jellyfin flash
All checks were successful
review/code-claude Reviewed c54acc9c (PASS); review-fix delta re-checked by firstmate

This commit is contained in:
justinzeus 2026-10-29 20:28:51 +01:00
parent c54acc9c1d
commit 04d659b115
5 changed files with 89 additions and 38 deletions

View file

@ -4,6 +4,7 @@ import com.github.damontecres.wholphin.api.seerr.MoviesApi
import com.github.damontecres.wholphin.api.seerr.SeerrApiClient
import com.github.damontecres.wholphin.api.seerr.TvApi
import com.github.damontecres.wholphin.api.seerr.infrastructure.ClientException
import com.github.damontecres.wholphin.api.seerr.infrastructure.Serializer
import com.github.damontecres.wholphin.api.seerr.model.MovieDetails
import com.github.damontecres.wholphin.api.seerr.model.MovieMovieIdRatingsGet200Response
import com.github.damontecres.wholphin.api.seerr.model.MovieMovieIdRatingscombinedGet200Response
@ -67,9 +68,9 @@ class SeerrRatingsServiceTest {
rt =
MovieMovieIdRatingsGet200Response(
criticsScore = 96,
criticsRating = MovieMovieIdRatingsGet200Response.CriticsRating.CERTIFIED_FRESH,
criticsRating = "Certified Fresh",
audienceScore = 90,
audienceRating = MovieMovieIdRatingsGet200Response.AudienceRating.UPRIGHT,
audienceRating = "Upright",
),
imdb = MovieMovieIdRatingscombinedGet200ResponseImdb(criticsScore = 8.8.toBigDecimal(), criticsScoreCount = 2_500_000),
)
@ -89,15 +90,42 @@ class SeerrRatingsServiceTest {
coVerify(exactly = 0) { moviesApi.movieMovieIdGet(any()) }
}
@Test
fun unknownRtLabelsDoNotDropTheResponse() =
runTest {
val json = Serializer.kotlinxSerializationJson
// Labels Seerr might add later must not fail parsing; the scores still show
coEvery { moviesApi.movieMovieIdRatingscombinedGet(movieId = 30) } returns
json.decodeFromString<MovieMovieIdRatingscombinedGet200Response>(
"""{"rt":{"criticsScore":92,"criticsRating":"Mystery","audienceScore":80,"audienceRating":"Whatever"},""" +
""""imdb":{"criticsScore":8.8,"criticsScoreCount":2500000}}""",
)
coEvery { tvApi.tvTvIdRatingsGet(tvId = 31) } returns
json.decodeFromString<TvTvIdRatingsGet200Response>(
"""{"criticsScore":70,"criticsRating":"Brand New","audienceScore":60,"audienceRating":"Other"}""",
)
val movie = service.get(SeerrItemType.MOVIE, 30)!!
assertEquals(92, movie.rtCritics?.percent)
assertEquals(RtMark.UNKNOWN, movie.rtCritics?.mark)
assertEquals(RtMark.UPRIGHT, movie.rtAudience?.mark)
assertEquals(8.8, movie.imdb!!, 0.0)
val tv = service.get(SeerrItemType.TV, 31)!!
assertEquals(70, tv.rtCritics?.percent)
assertEquals(RtMark.UNKNOWN, tv.rtCritics?.mark)
assertEquals(60, tv.rtAudience?.percent)
}
@Test
fun seriesUsesTvRatingsIncludingAudienceAndHasNoImdb() =
runTest {
coEvery { tvApi.tvTvIdRatingsGet(tvId = 20) } returns
TvTvIdRatingsGet200Response(
criticsScore = 70,
criticsRating = TvTvIdRatingsGet200Response.CriticsRating.FRESH,
criticsRating = "Fresh",
audienceScore = 30,
audienceRating = TvTvIdRatingsGet200Response.AudienceRating.SPILLED,
audienceRating = "Spilled",
)
val ratings = service.get(SeerrItemType.TV, 20)!!
@ -137,7 +165,7 @@ class SeerrRatingsServiceTest {
runTest {
coEvery { moviesApi.movieMovieIdRatingscombinedGet(movieId = 603) } returns fullMovieRatings
coEvery { tvApi.tvTvIdRatingsGet(tvId = 603) } returns
TvTvIdRatingsGet200Response(criticsScore = 12, criticsRating = TvTvIdRatingsGet200Response.CriticsRating.ROTTEN)
TvTvIdRatingsGet200Response(criticsScore = 12, criticsRating = "Rotten")
val movie = service.get(SeerrItemType.MOVIE, 603)!!
val tv = service.get(SeerrItemType.TV, 603)!!
@ -205,9 +233,15 @@ class SeerrRatingsServiceTest {
runTest {
coEvery { moviesApi.movieMovieIdRatingscombinedGet(movieId = 42) } returns fullMovieRatings
val ratings = service.forItem(jellyfinItem(BaseItemKind.MOVIE, mapOf("Tmdb" to "42"))).first()
val item = jellyfinItem(BaseItemKind.MOVIE, mapOf("Tmdb" to "42"))
assertNull(service.cachedFor(item))
val ratings = service.forItem(item).first()
assertEquals(96, ratings?.rtCritics?.percent)
// a later screen can start from the cached value instead of the Jellyfin values
assertEquals(ratings, service.cachedFor(item))
assertNull(service.cachedFor(jellyfinItem(BaseItemKind.SERIES, mapOf("Tmdb" to "42"))))
}
@Test