Fix combining continue/next-up for new episode premieres (#381)

Better handling for combining continue/next-up by considering the
premiere date of the episode. So episodes will use the previously
watched one's last played date or the episode's premiere date, whichever
is newer.

This means when a new season comes out or the show returns from a break,
the new episodes will show earlier in the list like the next up rows
shows when not combined.

Fixes #377
This commit is contained in:
damontecres 2025-12-06 15:35:29 -05:00 committed by GitHub
parent 793f9802e4
commit e669f3ad59
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -8,7 +8,6 @@ import com.github.damontecres.wholphin.preferences.AppPreference
import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope
import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler import com.github.damontecres.wholphin.util.GetEpisodesRequestHandler
import com.google.common.cache.CacheBuilder import com.google.common.cache.CacheBuilder
import com.google.common.cache.CacheLoader
import dagger.hilt.android.qualifiers.ActivityContext import dagger.hilt.android.qualifiers.ActivityContext
import dagger.hilt.android.scopes.ActivityScoped import dagger.hilt.android.scopes.ActivityScoped
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -40,20 +39,20 @@ class DatePlayedService
.newBuilder() .newBuilder()
.maximumSize(AppPreference.HomePageItems.max) .maximumSize(AppPreference.HomePageItems.max)
.expireAfterWrite(2, TimeUnit.HOURS) .expireAfterWrite(2, TimeUnit.HOURS)
.build<SeriesItemId, Deferred<LocalDateTime>>( .build<SeriesItemId, Deferred<LocalDateTime>>()
object : CacheLoader<SeriesItemId, Deferred<LocalDateTime>>() {
override fun load(key: SeriesItemId): Deferred<LocalDateTime> = getLastPlayed(key)
},
)
private fun getLastPlayed(key: SeriesItemId): Deferred<LocalDateTime> { private fun getLastPlayed(
seriesId: UUID,
item: BaseItem,
): Deferred<LocalDateTime> {
val request = val request =
GetEpisodesRequest( GetEpisodesRequest(
seriesId = key.seriesId, seriesId = seriesId,
adjacentTo = key.itemId, adjacentTo = item.id,
limit = 1, limit = 1,
) )
return scope.async(Dispatchers.IO) { return scope.async(Dispatchers.IO) {
val premiereDate = item.data.premiereDate
try { try {
val result = val result =
GetEpisodesRequestHandler GetEpisodesRequestHandler
@ -61,10 +60,22 @@ class DatePlayedService
api, api,
request, request,
).content.items ).content.items
result.firstOrNull()?.userData?.lastPlayedDate ?: LocalDateTime.MIN .firstOrNull()
?.userData
?.lastPlayedDate
if (premiereDate != null && premiereDate.isAfter(result)) {
premiereDate
} else {
result
} ?: LocalDateTime.MIN
} catch (ex: InvalidStatusException) { } catch (ex: InvalidStatusException) {
Timber.w("Error fetching %s: %s", key, ex.localizedMessage) Timber.w(
LocalDateTime.MIN "Error fetching series=%s, item=%s: %s",
seriesId,
item.id,
ex.localizedMessage,
)
LocalDateTime.MIN.coerceAtLeast(premiereDate ?: LocalDateTime.MIN)
} }
} }
} }
@ -73,7 +84,10 @@ class DatePlayedService
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val seriesId = item.data.seriesId val seriesId = item.data.seriesId
return@withContext if (seriesId != null) { return@withContext if (seriesId != null) {
datePlayedCache.get(SeriesItemId(seriesId, item.id)).await() datePlayedCache
.get(SeriesItemId(seriesId, item.id)) {
getLastPlayed(seriesId, item)
}.await()
} else { } else {
null null
} }