Skip to content

Commit e6bc8a0

Browse files
committed
Merge branch 'trakt-movie-collection-pagination' into dev
2 parents dc1a5d9 + 8e29d64 commit e6bc8a0

File tree

2 files changed

+84
-100
lines changed

2 files changed

+84
-100
lines changed

app/src/main/java/com/battlelancer/seriesguide/sync/TraktMovieSync.kt

Lines changed: 25 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: Apache-2.0
2-
// Copyright 2017-2024 Uwe Trottmann
2+
// SPDX-FileCopyrightText: Copyright © 2017 Uwe Trottmann <uwe@uwetrottmann.com>
33

44
package com.battlelancer.seriesguide.sync
55

@@ -9,20 +9,20 @@ import com.battlelancer.seriesguide.movies.database.SgMovieFlags
99
import com.battlelancer.seriesguide.movies.tools.MovieTools
1010
import com.battlelancer.seriesguide.provider.SeriesGuideContract.Movies
1111
import com.battlelancer.seriesguide.provider.SgRoomDatabase
12-
import com.battlelancer.seriesguide.traktapi.SgTrakt
1312
import com.battlelancer.seriesguide.traktapi.TraktSettings
13+
import com.battlelancer.seriesguide.traktapi.TraktTools4
14+
import com.battlelancer.seriesguide.traktapi.TraktTools4.TraktNonNullResponse.Success
1415
import com.battlelancer.seriesguide.util.DBUtils
1516
import com.battlelancer.seriesguide.util.Errors
16-
import com.uwetrottmann.trakt5.entities.BaseMovie
1717
import com.uwetrottmann.trakt5.entities.LastActivityMore
1818
import com.uwetrottmann.trakt5.entities.MovieIds
1919
import com.uwetrottmann.trakt5.entities.SyncItems
2020
import com.uwetrottmann.trakt5.entities.SyncMovie
2121
import com.uwetrottmann.trakt5.entities.SyncResponse
22+
import kotlinx.coroutines.Dispatchers
2223
import kotlinx.coroutines.runBlocking
2324
import retrofit2.Response
2425
import timber.log.Timber
25-
import kotlin.collections.set
2626

2727
/**
2828
* Syncs movie collection and watchlist and watched movies with the connected Trakt profile.
@@ -74,9 +74,15 @@ class TraktMovieSync(
7474
}
7575

7676
// Download Trakt state.
77-
val collection = downloadCollection() ?: return false
78-
val watchlist = downloadWatchlist() ?: return false
79-
val watchedWithPlays = downloadWatched() ?: return false
77+
val collection = runBlocking(Dispatchers.Default) {
78+
downloadCollection()
79+
} ?: return false
80+
val watchlist = runBlocking(Dispatchers.Default) {
81+
downloadWatchlist()
82+
} ?: return false
83+
val watchedWithPlays = runBlocking(Dispatchers.Default) {
84+
downloadWatched()
85+
} ?: return false
8086

8187
// Loop through local movies to build updates.
8288
val localMovies: List<SgMovieFlags> = try {
@@ -214,100 +220,27 @@ class TraktMovieSync(
214220
return addingSuccessful
215221
}
216222

217-
private fun downloadCollection(): MutableSet<Int>? {
218-
return try {
219-
val response = traktSync.sync
220-
.collectionMovies(null)
221-
.execute()
222-
val collection = verifyListResponse(
223-
response,
224-
"null collection response", ACTION_GET_COLLECTION
225-
)
226-
toTmdbIdSet(collection)
227-
} catch (e: Exception) {
228-
Errors.logAndReport(ACTION_GET_COLLECTION, e)
229-
null
223+
private suspend fun downloadCollection(): MutableSet<Int>? {
224+
return when (val response = TraktTools4.getCollectedMoviesByTmdbId(traktSync.sync)) {
225+
is Success -> response.data
226+
else -> null
230227
}
231228
}
232229

233-
private fun downloadWatchlist(): MutableSet<Int>? {
234-
return try {
235-
val response = traktSync.sync
236-
.watchlistMovies(null)
237-
.execute()
238-
val watchlist = verifyListResponse(
239-
response,
240-
"null watchlist response", ACTION_GET_WATCHLIST
241-
)
242-
toTmdbIdSet(watchlist)
243-
} catch (e: Exception) {
244-
Errors.logAndReport(ACTION_GET_WATCHLIST, e)
245-
null
230+
private suspend fun downloadWatchlist(): MutableSet<Int>? {
231+
return when (val response = TraktTools4.getMoviesOnWatchlistByTmdbId(traktSync.sync)) {
232+
is Success -> response.data
233+
else -> null
246234
}
247235
}
248236

249-
private fun downloadWatched(): MutableMap<Int, Int>? {
250-
return try {
251-
val response = traktSync.sync
252-
.watchedMovies(null)
253-
.execute()
254-
val watched = verifyListResponse(
255-
response,
256-
"null watched response", ACTION_GET_WATCHED
257-
)
258-
mapTmdbIdToPlays(watched)
259-
} catch (e: Exception) {
260-
Errors.logAndReport(ACTION_GET_WATCHED, e)
261-
null
262-
}
263-
}
264-
265-
private fun verifyListResponse(
266-
response: Response<List<BaseMovie>>,
267-
nullResponse: String,
268-
action: String
269-
): List<BaseMovie>? {
270-
return if (response.isSuccessful) {
271-
val movies = response.body()
272-
if (movies == null) {
273-
Timber.e(nullResponse)
274-
}
275-
movies
276-
} else {
277-
if (SgTrakt.isUnauthorized(context, response)) {
278-
return null
279-
}
280-
Errors.logAndReport(action, response)
281-
null
237+
private suspend fun downloadWatched(): MutableMap<Int, Int>? {
238+
return when (val response = TraktTools4.getWatchedMoviesByTmdbId(traktSync.sync)) {
239+
is Success -> response.data
240+
else -> null
282241
}
283242
}
284243

285-
private fun toTmdbIdSet(movies: List<BaseMovie>?): MutableSet<Int>? {
286-
if (movies == null) {
287-
return null
288-
}
289-
val tmdbIdSet: MutableSet<Int> = HashSet()
290-
for (movie in movies) {
291-
val tmdbId = movie.movie?.ids?.tmdb
292-
?: continue // skip invalid values
293-
tmdbIdSet.add(tmdbId)
294-
}
295-
return tmdbIdSet
296-
}
297-
298-
private fun mapTmdbIdToPlays(movies: List<BaseMovie>?): MutableMap<Int, Int>? {
299-
if (movies == null) {
300-
return null
301-
}
302-
val map: MutableMap<Int, Int> = HashMap()
303-
for (movie in movies) {
304-
val tmdbId = movie.movie?.ids?.tmdb
305-
?: continue // skip invalid values
306-
map[tmdbId] = movie.plays
307-
}
308-
return map
309-
}
310-
311244
/**
312245
* Uploads the given movies to the appropriate list(s)/history on Trakt.
313246
*/
@@ -368,10 +301,4 @@ class TraktMovieSync(
368301

369302
private fun convertToSyncMovieList(movieTmdbIds: Set<Int>): List<SyncMovie> =
370303
movieTmdbIds.map { SyncMovie().id(MovieIds.tmdb(it)) }
371-
372-
companion object {
373-
private const val ACTION_GET_COLLECTION = "get movie collection"
374-
private const val ACTION_GET_WATCHLIST = "get movie watchlist"
375-
private const val ACTION_GET_WATCHED = "get watched movies"
376-
}
377304
}

app/src/main/java/com/battlelancer/seriesguide/traktapi/TraktTools4.kt

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import com.battlelancer.seriesguide.traktapi.TraktTools4.awaitTraktCall
77
import com.battlelancer.seriesguide.util.Errors
88
import com.uwetrottmann.trakt5.TraktV2
99
import com.uwetrottmann.trakt5.entities.AddNoteRequest
10+
import com.uwetrottmann.trakt5.entities.BaseMovie
1011
import com.uwetrottmann.trakt5.entities.BaseShow
1112
import com.uwetrottmann.trakt5.entities.Note
1213
import com.uwetrottmann.trakt5.entities.Show
@@ -26,6 +27,9 @@ import timber.log.Timber
2627
*/
2728
object TraktTools4 {
2829

30+
// 1000 is the maximum limit according to https://github.com/trakt/trakt-api/discussions/681
31+
private const val COLLECTION_MAX_LIMIT = 1000
32+
2933
sealed interface TraktResponse<T> {
3034
data class Success<T>(
3135
/**
@@ -81,8 +85,7 @@ object TraktTools4 {
8185
action = "get collected shows",
8286
reportIsNotVip = true // Should work even if not VIP
8387
) { page ->
84-
// 1000 is the maximum limit according to https://github.com/trakt/trakt-api/discussions/681
85-
traktSync.collectionShows(page, 1000, null)
88+
traktSync.collectionShows(page, COLLECTION_MAX_LIMIT, null)
8689
}
8790
}
8891

@@ -160,6 +163,60 @@ object TraktTools4 {
160163
)
161164
}
162165

166+
suspend fun getWatchedMoviesByTmdbId(
167+
traktSync: Sync
168+
): TraktNonNullResponse<MutableMap<Int, Int>> {
169+
val response = awaitTraktCallNonNull(
170+
traktSync.watchedMovies(null),
171+
"get watched movies",
172+
reportIsNotVip = true // Should work even if not VIP
173+
)
174+
return mapResponseData(response) { mapMoviesToTmdbIdWithPlays(it) }
175+
}
176+
177+
private fun mapMoviesToTmdbIdWithPlays(traktMovies: List<BaseMovie>): MutableMap<Int, Int> {
178+
val map: MutableMap<Int, Int> = HashMap(traktMovies.size)
179+
for (movie in traktMovies) {
180+
val tmdbId = movie.movie?.ids?.tmdb
181+
?: continue // skip invalid values
182+
map[tmdbId] = movie.plays
183+
}
184+
return map
185+
}
186+
187+
suspend fun getCollectedMoviesByTmdbId(
188+
traktSync: Sync
189+
): TraktNonNullResponse<MutableSet<Int>> {
190+
val response = fetchAllPages(
191+
action = "get collected movies",
192+
reportIsNotVip = true // Should work even if not VIP
193+
) { page ->
194+
traktSync.collectionMovies(page, COLLECTION_MAX_LIMIT, null)
195+
}
196+
return mapResponseData(response) { mapMoviesToTmdbIdSet(it) }
197+
}
198+
199+
suspend fun getMoviesOnWatchlistByTmdbId(
200+
traktSync: Sync
201+
): TraktNonNullResponse<MutableSet<Int>> {
202+
val response = awaitTraktCallNonNull(
203+
traktSync.watchlistMovies(null),
204+
"get movie watchlist",
205+
reportIsNotVip = true // Should work even if not VIP
206+
)
207+
return mapResponseData(response) { mapMoviesToTmdbIdSet(it) }
208+
}
209+
210+
private fun mapMoviesToTmdbIdSet(traktMovies: List<BaseMovie>): MutableSet<Int> {
211+
val tmdbIdSet: MutableSet<Int> = HashSet(traktMovies.size)
212+
for (movie in traktMovies) {
213+
val tmdbId = movie.movie?.ids?.tmdb
214+
?: continue // skip invalid values
215+
tmdbIdSet.add(tmdbId)
216+
}
217+
return tmdbIdSet
218+
}
219+
163220
/**
164221
* Adds or updates the note for the given show.
165222
*

0 commit comments

Comments
 (0)