mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-26 22:42:17 +00:00
feat(trakt): add pagination support for fetching watched movies
This commit is contained in:
parent
2c47fb333e
commit
8c6741f5cb
2 changed files with 97 additions and 23 deletions
|
|
@ -43,6 +43,9 @@ private const val TRAKT_COMPLETION_PERCENT_THRESHOLD = 90f
|
|||
private const val HISTORY_PAGE_LIMIT = 1000
|
||||
private const val HISTORY_MAX_PAGES = 5
|
||||
private const val HISTORY_MAX_PAGES_ALL = 20
|
||||
private const val WATCHED_PAGE_LIMIT = 250
|
||||
private const val WATCHED_MAX_PAGES = 1_000
|
||||
private const val WATCHED_SHOWS_EXTENDED = "progress"
|
||||
private const val MAX_RECENT_EPISODE_HISTORY_ENTRIES = 300
|
||||
private const val METADATA_FETCH_TIMEOUT_MS = 3_500L
|
||||
private const val METADATA_FETCH_CONCURRENCY = 5
|
||||
|
|
@ -688,11 +691,7 @@ object TraktProgressRepository {
|
|||
): List<WatchProgressEntry> = withContext(Dispatchers.Default) {
|
||||
ContinueWatchingPreferencesRepository.ensureLoaded()
|
||||
val useFurthestEpisode = ContinueWatchingPreferencesRepository.uiState.value.upNextFromFurthestEpisode
|
||||
val payload = httpGetTextWithHeaders(
|
||||
url = "$BASE_URL/sync/watched/shows",
|
||||
headers = headers,
|
||||
)
|
||||
val watchedShows = json.decodeFromString<List<TraktWatchedShowItem>>(payload)
|
||||
val watchedShows = fetchWatchedShowPages(headers)
|
||||
updateWatchedShowCaches(watchedShows)
|
||||
val mapped = fixAmbiguousWatchedShowSeeds(
|
||||
watchedShows.mapNotNull { item ->
|
||||
|
|
@ -706,6 +705,34 @@ object TraktProgressRepository {
|
|||
mapped
|
||||
}
|
||||
|
||||
private suspend fun fetchWatchedShowPages(
|
||||
headers: Map<String, String>,
|
||||
): List<TraktWatchedShowItem> {
|
||||
val items = mutableListOf<TraktWatchedShowItem>()
|
||||
var page = 1
|
||||
while (page <= WATCHED_MAX_PAGES) {
|
||||
val response = httpRequestRaw(
|
||||
method = "GET",
|
||||
url = "$BASE_URL/sync/watched/shows?page=$page&limit=$WATCHED_PAGE_LIMIT&extended=$WATCHED_SHOWS_EXTENDED",
|
||||
headers = headers,
|
||||
body = "",
|
||||
)
|
||||
if (response.status !in 200..299) {
|
||||
error("Trakt watched shows request failed: ${response.status}")
|
||||
}
|
||||
val pageItems = json.decodeFromString<List<TraktWatchedShowItem>>(response.body)
|
||||
if (pageItems.isEmpty()) break
|
||||
items.addAll(pageItems)
|
||||
val pageCount = response.headerInt("x-pagination-page-count")
|
||||
if (pageCount != null && page >= pageCount) break
|
||||
page += 1
|
||||
}
|
||||
if (page > WATCHED_MAX_PAGES) {
|
||||
error("Trakt watched shows exceeded max pages")
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
private fun updateWatchedShowCaches(items: List<TraktWatchedShowItem>) {
|
||||
val siblingsMap = mutableMapOf<String, MutableSet<String>>()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.nuvio.app.features.watching.sync
|
||||
|
||||
import co.touchlab.kermit.Logger
|
||||
import com.nuvio.app.features.addons.httpGetTextWithHeaders
|
||||
import com.nuvio.app.features.addons.RawHttpResponse
|
||||
import com.nuvio.app.features.addons.httpRequestRaw
|
||||
import com.nuvio.app.features.tmdb.TmdbService
|
||||
import com.nuvio.app.features.trakt.TraktAuthRepository
|
||||
|
|
@ -18,6 +18,9 @@ import kotlinx.serialization.encodeToString
|
|||
import kotlinx.serialization.json.Json
|
||||
|
||||
private const val BASE_URL = "https://api.trakt.tv"
|
||||
private const val WATCHED_PAGE_LIMIT = 250
|
||||
private const val WATCHED_MAX_PAGES = 1_000
|
||||
private const val WATCHED_SHOWS_EXTENDED = "progress"
|
||||
|
||||
|
||||
object TraktWatchedSyncAdapter : WatchedSyncAdapter {
|
||||
|
|
@ -35,30 +38,16 @@ object TraktWatchedSyncAdapter : WatchedSyncAdapter {
|
|||
): List<WatchedItem> {
|
||||
val headers = TraktAuthRepository.authorizedHeaders() ?: return emptyList()
|
||||
|
||||
val (moviesPayload, showsPayload) = coroutineScope {
|
||||
val (movieItems, showItems) = coroutineScope {
|
||||
val movies = async {
|
||||
httpGetTextWithHeaders(
|
||||
url = "$BASE_URL/sync/watched/movies",
|
||||
headers = headers,
|
||||
)
|
||||
fetchWatchedMoviePages(headers)
|
||||
}
|
||||
val shows = async {
|
||||
httpGetTextWithHeaders(
|
||||
url = "$BASE_URL/sync/watched/shows",
|
||||
headers = headers,
|
||||
)
|
||||
fetchWatchedShowPages(headers)
|
||||
}
|
||||
movies.await() to shows.await()
|
||||
}
|
||||
|
||||
val movieItems = runCatching {
|
||||
json.decodeFromString<List<TraktWatchedMovieDto>>(moviesPayload)
|
||||
}.getOrDefault(emptyList())
|
||||
|
||||
val showItems = runCatching {
|
||||
json.decodeFromString<List<TraktWatchedShowDto>>(showsPayload)
|
||||
}.getOrDefault(emptyList())
|
||||
|
||||
val result = mutableListOf<WatchedItem>()
|
||||
|
||||
movieItems.forEach { item ->
|
||||
|
|
@ -122,6 +111,64 @@ object TraktWatchedSyncAdapter : WatchedSyncAdapter {
|
|||
return remappedResult
|
||||
}
|
||||
|
||||
private suspend fun fetchWatchedMoviePages(headers: Map<String, String>): List<TraktWatchedMovieDto> {
|
||||
val items = mutableListOf<TraktWatchedMovieDto>()
|
||||
var page = 1
|
||||
while (page <= WATCHED_MAX_PAGES) {
|
||||
val response = httpRequestRaw(
|
||||
method = "GET",
|
||||
url = "$BASE_URL/sync/watched/movies?page=$page&limit=$WATCHED_PAGE_LIMIT",
|
||||
headers = headers,
|
||||
body = "",
|
||||
)
|
||||
if (response.status !in 200..299) {
|
||||
error("Trakt watched movies request failed: ${response.status}")
|
||||
}
|
||||
val pageItems = json.decodeFromString<List<TraktWatchedMovieDto>>(response.body)
|
||||
if (pageItems.isEmpty()) break
|
||||
items.addAll(pageItems)
|
||||
val pageCount = response.headerInt("x-pagination-page-count")
|
||||
if (pageCount != null && page >= pageCount) break
|
||||
page += 1
|
||||
}
|
||||
if (page > WATCHED_MAX_PAGES) {
|
||||
error("Trakt watched movies exceeded max pages")
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
private suspend fun fetchWatchedShowPages(headers: Map<String, String>): List<TraktWatchedShowDto> {
|
||||
val items = mutableListOf<TraktWatchedShowDto>()
|
||||
var page = 1
|
||||
while (page <= WATCHED_MAX_PAGES) {
|
||||
val response = httpRequestRaw(
|
||||
method = "GET",
|
||||
url = "$BASE_URL/sync/watched/shows?page=$page&limit=$WATCHED_PAGE_LIMIT&extended=$WATCHED_SHOWS_EXTENDED",
|
||||
headers = headers,
|
||||
body = "",
|
||||
)
|
||||
if (response.status !in 200..299) {
|
||||
error("Trakt watched shows request failed: ${response.status}")
|
||||
}
|
||||
val pageItems = json.decodeFromString<List<TraktWatchedShowDto>>(response.body)
|
||||
if (pageItems.isEmpty()) break
|
||||
items.addAll(pageItems)
|
||||
val pageCount = response.headerInt("x-pagination-page-count")
|
||||
if (pageCount != null && page >= pageCount) break
|
||||
page += 1
|
||||
}
|
||||
if (page > WATCHED_MAX_PAGES) {
|
||||
error("Trakt watched shows exceeded max pages")
|
||||
}
|
||||
return items
|
||||
}
|
||||
|
||||
private fun RawHttpResponse.headerInt(name: String): Int? =
|
||||
headers[name.lowercase()]
|
||||
?.substringBefore(",")
|
||||
?.trim()
|
||||
?.toIntOrNull()
|
||||
|
||||
// ── push (add to history) ───────────────────────────────────────────
|
||||
override suspend fun push(
|
||||
profileId: Int,
|
||||
|
|
|
|||
Loading…
Reference in a new issue