From a51919e02612317c2efa09e210b734e81bac3621 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Wed, 28 Jan 2026 15:59:43 +0100 Subject: [PATCH 01/20] Sync/Users: add paginated collection methods, deprecate old ones https://github.com/trakt/trakt-api/discussions/681 --- CHANGELOG.md | 4 ++ .../uwetrottmann/trakt5/services/Sync.java | 38 ++++++++++++++++++ .../uwetrottmann/trakt5/services/Users.java | 40 +++++++++++++++++++ .../trakt5/services/SyncTest.java | 4 +- .../trakt5/services/UsersTest.java | 4 +- 5 files changed, 86 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 181ceaa8..6c8690ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Next release +* Add paginated variants of `Sync.collectionMovies()`, `Sync.collectionShows()`, `Users.collectionMovies()` + and `Users.collectionShows()` with required `page` and `limit` parameters. The original methods without pagination + parameters are deprecated. + ## 6.16.0 - 2024-11-07 * `TraktV2`: add `isUnauthorized(response)`, `isAccountLocked(response)` and `isNotVip(response)` helper methods. diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index c4088ac3..4f98afe9 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -57,9 +57,28 @@ public interface Sync { *

* Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on * physical media. + * + * @deprecated Use {@link #collectionMovies(int, int, Extended)} instead. + */ + @Deprecated + @GET("sync/collection/movies") + Call> collectionMovies( + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * OAuth Required + *

+ * Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on + * physical media. + * + * @param page Number of page of results to be returned. + * @param limit Number of results to return per page. */ @GET("sync/collection/movies") Call> collectionMovies( + @Query("page") int page, + @Query("limit") int limit, @Query(value = "extended", encoded = true) Extended extended ); @@ -68,9 +87,28 @@ Call> collectionMovies( *

* Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on * physical media. + * + * @deprecated Use {@link #collectionShows(int, int, Extended)} instead. + */ + @Deprecated + @GET("sync/collection/shows") + Call> collectionShows( + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * OAuth Required + *

+ * Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on + * physical media. + * + * @param page Number of page of results to be returned. + * @param limit Number of results to return per page. */ @GET("sync/collection/shows") Call> collectionShows( + @Query("page") int page, + @Query("limit") int limit, @Query(value = "extended", encoded = true) Extended extended ); diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 93ba1153..86db00a0 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -84,13 +84,49 @@ Call profile( * physical media. * * @param userSlug Example: "sean". + * @deprecated Use {@link #collectionMovies(UserSlug, int, int, Extended)} instead. */ + @Deprecated @GET("users/{username}/collection/movies") Call> collectionMovies( @Path("username") UserSlug userSlug, @Query(value = "extended", encoded = true) Extended extended ); + /** + * OAuth Optional + *

+ * Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on + * physical media. + * + * @param userSlug Example: "sean". + * @param page Number of page of results to be returned. + * @param limit Number of results to return per page. + */ + @GET("users/{username}/collection/movies") + Call> collectionMovies( + @Path("username") UserSlug userSlug, + @Query("page") int page, + @Query("limit") int limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * OAuth Optional + *

+ * Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on + * physical media. + * + * @param userSlug Example: "sean". + * @deprecated Use {@link #collectionShows(UserSlug, int, int, Extended)} instead. + */ + @Deprecated + @GET("users/{username}/collection/shows") + Call> collectionShows( + @Path("username") UserSlug userSlug, + @Query(value = "extended", encoded = true) Extended extended + ); + /** * OAuth Optional *

@@ -98,10 +134,14 @@ Call> collectionMovies( * physical media. * * @param userSlug Example: "sean". + * @param page Number of page of results to be returned. + * @param limit Number of results to return per page. */ @GET("users/{username}/collection/shows") Call> collectionShows( @Path("username") UserSlug userSlug, + @Query("page") int page, + @Query("limit") int limit, @Query(value = "extended", encoded = true) Extended extended ); diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index d1c657eb..96d6c126 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -180,13 +180,13 @@ private void assertLastActivityUpdated(LastActivityUpdated activity) { @Test public void test_collectionMovies() throws IOException { - List movies = executeCall(getTrakt().sync().collectionMovies(null)); + List movies = executeCall(getTrakt().sync().collectionMovies(1, 1000, null)); assertSyncMovies(movies, "collection"); } @Test public void test_collectionShows() throws IOException { - List shows = executeCall(getTrakt().sync().collectionShows(null)); + List shows = executeCall(getTrakt().sync().collectionShows(1, 1000, null)); assertSyncShows(shows, "collection"); } diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index e63a4d1d..3bea7eed 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -102,13 +102,13 @@ public void test_profile() throws IOException { @Test public void test_collectionMovies() throws IOException { List movies = executeCall( - getTrakt().users().collectionMovies(TestData.USER_SLUG, null)); + getTrakt().users().collectionMovies(TestData.USER_SLUG, 1, 1000, null)); assertSyncMovies(movies, "collection"); } @Test public void test_collectionShows() throws IOException { - List shows = executeCall(getTrakt().users().collectionShows(TestData.USER_SLUG, null)); + List shows = executeCall(getTrakt().users().collectionShows(TestData.USER_SLUG, 1, 1000, null)); assertSyncShows(shows, "collection"); } From 0a7eeca6a5a0f711f9db45bd1181152ec1f4c790 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 10:08:07 +0100 Subject: [PATCH 02/20] MoviesTest: handle translation returning country variants --- src/test/java/com/uwetrottmann/trakt5/services/MoviesTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/uwetrottmann/trakt5/services/MoviesTest.java b/src/test/java/com/uwetrottmann/trakt5/services/MoviesTest.java index 85416462..049f1eaf 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/MoviesTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/MoviesTest.java @@ -104,7 +104,7 @@ public void test_translation() throws IOException { "de")); assertThat(translations).isNotNull(); // we know that Batman Begins has a German translation, otherwise this test would fail - assertThat(translations).hasSize(1); + assertThat(translations).isNotEmpty(); assertThat(translations.get(0).language).isEqualTo("de"); } From 5caca6fb670f86c25c2b968c7c79e3efc859ce74 Mon Sep 17 00:00:00 2001 From: defhead Date: Fri, 26 Mar 2021 23:25:52 +0100 Subject: [PATCH 03/20] Add missing sync history methods --- .../uwetrottmann/trakt5/services/Sync.java | 64 +++++++ .../trakt5/services/SyncTest.java | 165 ++++++++++++++++++ 2 files changed, 229 insertions(+) diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index 4f98afe9..1d13673f 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -18,6 +18,7 @@ import com.uwetrottmann.trakt5.entities.BaseMovie; import com.uwetrottmann.trakt5.entities.BaseShow; +import com.uwetrottmann.trakt5.entities.HistoryEntry; import com.uwetrottmann.trakt5.entities.LastActivities; import com.uwetrottmann.trakt5.entities.PlaybackResponse; import com.uwetrottmann.trakt5.entities.RatedEpisode; @@ -29,7 +30,9 @@ import com.uwetrottmann.trakt5.entities.WatchlistedEpisode; import com.uwetrottmann.trakt5.entities.WatchlistedSeason; import com.uwetrottmann.trakt5.enums.Extended; +import com.uwetrottmann.trakt5.enums.HistoryType; import com.uwetrottmann.trakt5.enums.RatingsFilter; +import org.threeten.bp.OffsetDateTime; import retrofit2.Call; import retrofit2.http.Body; import retrofit2.http.DELETE; @@ -199,6 +202,67 @@ Call> watchedShows( @Query(value = "extended", encoded = true) Extended extended ); + /** + * OAuth Required + * + *

Returns movies and episodes that the a user has watched, sorted by most recent. + * + *

The {@code id} uniquely identifies each history event and can be used to remove events individually using the + * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or {@code + * watch}. + */ + @GET("sync/history") + Call> getHistory( + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended, + @Query("start_at") OffsetDateTime startAt, + @Query("end_at") OffsetDateTime endAt + ); + + /** + * OAuth Required + * + *

Returns movies or episodes (depending on the type) that the a user has watched, + * sorted by most recent. + * + *

The {@code id} uniquely identifies each history event and can be used to remove events individually using the + * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or {@code + * watch}. + */ + @GET("sync/history/{type}") + Call> getHistory( + @Path("type") HistoryType type, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended, + @Query("start_at") OffsetDateTime startAt, + @Query("end_at") OffsetDateTime endAt + ); + + /** + * OAuth Required + * + *

Returns the history for just the specified item. For example, {@code /sync/history/movies/12601} would return + * all watches for TRON: Legacy and {@code /sync/history/shows/1388} would return all watched episodes + * for Breaking Bad. If an invalid {@code id} is sent, a 404 error will be returned. If the {@code id} is valid, + * but there is no history, an empty array will be returned. + * + *

The {@code id} uniquely identifies each history event and can be used to remove events individually using the + * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or {@code + * watch}. + */ + @GET("sync/history/{type}/{id}") + Call> getHistory( + @Path("type") HistoryType type, + @Path("id") int id, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended, + @Query("start_at") OffsetDateTime startAt, + @Query("end_at") OffsetDateTime endAt + ); + /** * OAuth Required *

diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index 96d6c126..f0871deb 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -21,6 +21,7 @@ import com.uwetrottmann.trakt5.entities.BaseMovie; import com.uwetrottmann.trakt5.entities.BaseShow; import com.uwetrottmann.trakt5.entities.EpisodeIds; +import com.uwetrottmann.trakt5.entities.HistoryEntry; import com.uwetrottmann.trakt5.entities.LastActivities; import com.uwetrottmann.trakt5.entities.LastActivity; import com.uwetrottmann.trakt5.entities.LastActivityAccount; @@ -44,6 +45,7 @@ import com.uwetrottmann.trakt5.entities.SyncShow; import com.uwetrottmann.trakt5.entities.WatchlistedEpisode; import com.uwetrottmann.trakt5.entities.WatchlistedSeason; +import com.uwetrottmann.trakt5.enums.HistoryType; import com.uwetrottmann.trakt5.enums.Rating; import com.uwetrottmann.trakt5.enums.RatingsFilter; import org.junit.Test; @@ -615,6 +617,169 @@ public void test_deleteItemsFromWatchlist() throws IOException { assertSyncResponseDelete(requestResponse); } + @Test + public void test_getHistory() throws IOException { + Call> call = getTrakt().sync().getHistory(null, null, null, null, null); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + + for (HistoryEntry entry : body) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + if ("episode".equals(entry.type)) { + assertThat(entry.episode).isNotNull(); + assertThat(entry.show).isNotNull(); + } else if ("movie".equals(entry.type)) { + assertThat(entry.movie).isNotNull(); + } + } + } + + @Test + public void test_getHistory_with_pagination() throws IOException { + Call> call = getTrakt().sync().getHistory(1, 5, null, null, null); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + + for (HistoryEntry entry : body) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + if ("episode".equals(entry.type)) { + assertThat(entry.episode).isNotNull(); + assertThat(entry.show).isNotNull(); + } else if ("movie".equals(entry.type)) { + assertThat(entry.movie).isNotNull(); + } + } + } + + @Test + public void test_getHistory_movies() throws IOException { + Call> call = getTrakt().sync().getHistory(HistoryType.MOVIES, null, null, null, null, null); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + + for (HistoryEntry entry : body) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + assertThat(entry.movie).isNotNull(); + } + } + + @Test + public void test_getHistory_movies_with_pagination() throws IOException { + Call> call = getTrakt().sync().getHistory(HistoryType.MOVIES, 1, 5, null, null, null); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + + for (HistoryEntry entry : body) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + assertThat(entry.movie).isNotNull(); + } + } + + @Test + public void test_getHistory_episodes() throws IOException { + Call> call = getTrakt().sync().getHistory(HistoryType.EPISODES, null, null, null, null, + null); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + + for (HistoryEntry entry : body) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + assertThat(entry.episode).isNotNull(); + assertThat(entry.show).isNotNull(); + } + } + + @Test + public void test_getHistory_episodes_with_pagination() throws IOException { + Call> call = getTrakt().sync().getHistory(HistoryType.EPISODES, 1, 5, null, null, null); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + + for (HistoryEntry entry : body) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + assertThat(entry.episode).isNotNull(); + assertThat(entry.show).isNotNull(); + } + } + + @Test + public void test_getHistory_item() throws IOException { + Call> call = getTrakt().sync().getHistory(HistoryType.MOVIES, + TestData.MOVIE_WATCHED_TRAKT_ID, null, null, null, + OffsetDateTime.of(2016, 8, 3, 9, 0, 0, 0, ZoneOffset.UTC), + OffsetDateTime.of(2016, 8, 3, 10, 0, 0, 0, ZoneOffset.UTC)); + Response> response = executeCallWithoutReadingBody(call); + assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); + List body = response.body(); + if (body == null) { + throw new IllegalStateException("Body should not be null for successful response"); + } + assertThat(body.size()).isGreaterThan(0); + + for (HistoryEntry entry : body) { + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isEqualTo("movie"); + assertThat(entry.movie).isNotNull(); + } + } + private MovieIds buildMovieIds() { return MovieIds.tmdb(TestData.MOVIE_TMDB_ID); From 71522b0831b676711c0072d592807868419ee2e4 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 10:37:50 +0100 Subject: [PATCH 04/20] Sync: simplify history tests, deduplicate assertions, add changelog entry --- CHANGELOG.md | 1 + .../uwetrottmann/trakt5/services/Sync.java | 38 ++-- .../uwetrottmann/trakt5/services/Users.java | 10 +- .../trakt5/services/HistoryAssertions.java | 65 +++++++ .../trakt5/services/SyncTest.java | 164 ++++-------------- .../trakt5/services/UsersTest.java | 59 ++----- 6 files changed, 134 insertions(+), 203 deletions(-) create mode 100644 src/test/java/com/uwetrottmann/trakt5/services/HistoryAssertions.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c8690ff..3fc6e7a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ * Add paginated variants of `Sync.collectionMovies()`, `Sync.collectionShows()`, `Users.collectionMovies()` and `Users.collectionShows()` with required `page` and `limit` parameters. The original methods without pagination parameters are deprecated. +* Add history endpoints to `Sync`. Thanks @defhead! [#125](https://github.com/UweTrottmann/trakt-java/pull/125) ## 6.16.0 - 2024-11-07 diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index 1d13673f..a2e3d49d 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -27,6 +27,7 @@ import com.uwetrottmann.trakt5.entities.RatedShow; import com.uwetrottmann.trakt5.entities.SyncItems; import com.uwetrottmann.trakt5.entities.SyncResponse; +import com.uwetrottmann.trakt5.entities.UserSlug; import com.uwetrottmann.trakt5.entities.WatchlistedEpisode; import com.uwetrottmann.trakt5.entities.WatchlistedSeason; import com.uwetrottmann.trakt5.enums.Extended; @@ -204,15 +205,13 @@ Call> watchedShows( /** * OAuth Required + *

+ * Like {@link Users#history(UserSlug, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}. * - *

Returns movies and episodes that the a user has watched, sorted by most recent. - * - *

The {@code id} uniquely identifies each history event and can be used to remove events individually using the - * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or {@code - * watch}. + * @see Sync#history(HistoryType, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime) */ @GET("sync/history") - Call> getHistory( + Call> history( @Query("page") Integer page, @Query("limit") Integer limit, @Query(value = "extended", encoded = true) Extended extended, @@ -222,16 +221,15 @@ Call> getHistory( /** * OAuth Required + *

+ * Like {@link #history(Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}, but allows to set a type to + * only return movies or episodes. * - *

Returns movies or episodes (depending on the type) that the a user has watched, - * sorted by most recent. - * - *

The {@code id} uniquely identifies each history event and can be used to remove events individually using the - * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or {@code - * watch}. + * @see Users#history(UserSlug, HistoryType, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime) + * @see Sync#history(Integer, Integer, Extended, OffsetDateTime, OffsetDateTime) */ @GET("sync/history/{type}") - Call> getHistory( + Call> history( @Path("type") HistoryType type, @Query("page") Integer page, @Query("limit") Integer limit, @@ -242,18 +240,12 @@ Call> getHistory( /** * OAuth Required - * - *

Returns the history for just the specified item. For example, {@code /sync/history/movies/12601} would return - * all watches for TRON: Legacy and {@code /sync/history/shows/1388} would return all watched episodes - * for Breaking Bad. If an invalid {@code id} is sent, a 404 error will be returned. If the {@code id} is valid, - * but there is no history, an empty array will be returned. - * - *

The {@code id} uniquely identifies each history event and can be used to remove events individually using the - * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or {@code - * watch}. + *

+ * Like + * {@link Users#history(UserSlug, HistoryType, int, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}. */ @GET("sync/history/{type}/{id}") - Call> getHistory( + Call> history( @Path("type") HistoryType type, @Path("id") int id, @Query("page") Integer page, diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 86db00a0..4759fb57 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -332,6 +332,7 @@ Call> friends( * {@code watch}. * * @param userSlug Example: "sean". + * @see Sync#history(Integer, Integer, Extended, OffsetDateTime, OffsetDateTime) */ @GET("users/{username}/history") Call> history( @@ -346,13 +347,11 @@ Call> history( /** * OAuth Optional *

- * Returns movies or episodes that a user has watched, sorted by most recent. - *

- * The {@code id} uniquely identifies each history event and can be used to remove events individually using the - * {@code POST /sync/history/remove method}. The action will be set to {@code scrobble}, {@code checkin}, or - * {@code watch}. + * Like {@link #history(UserSlug, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}, but allows to set a + * type to only return movies or episodes. * * @param userSlug Example: "sean". + * @see Sync#history(HistoryType, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime) */ @GET("users/{username}/history/{type}") Call> history( @@ -378,6 +377,7 @@ Call> history( * {@code watch}. * * @param userSlug Example: "sean". + * @see Sync#history(HistoryType, int, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime) */ @GET("users/{username}/history/{type}/{id}") Call> history( diff --git a/src/test/java/com/uwetrottmann/trakt5/services/HistoryAssertions.java b/src/test/java/com/uwetrottmann/trakt5/services/HistoryAssertions.java new file mode 100644 index 00000000..98414343 --- /dev/null +++ b/src/test/java/com/uwetrottmann/trakt5/services/HistoryAssertions.java @@ -0,0 +1,65 @@ +/* + * Copyright © 2026 Uwe Trottmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.uwetrottmann.trakt5.services; + + +import com.uwetrottmann.trakt5.entities.HistoryEntry; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class HistoryAssertions { + + public static void assertHistory(List history) { + for (HistoryEntry entry : history) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isNotEmpty(); + if ("episode".equals(entry.type)) { + assertThat(entry.episode).isNotNull(); + assertThat(entry.show).isNotNull(); + } else if ("movie".equals(entry.type)) { + assertThat(entry.movie).isNotNull(); + } + } + } + + public static void assertEpisodeHistory(List history) { + for (HistoryEntry entry : history) { + assertThat(entry.id).isGreaterThan(0); + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isEqualTo("episode"); + assertThat(entry.episode).isNotNull(); + assertThat(entry.show).isNotNull(); +// System.out.println( +// "Episode watched at date: " + entry.watched_at + entry.watched_at.toInstant().toEpochMilli()); + } + } + + public static void assertMovieHistory(List history) { + for (HistoryEntry entry : history) { + assertThat(entry.watched_at).isNotNull(); + assertThat(entry.action).isNotEmpty(); + assertThat(entry.type).isEqualTo("movie"); + assertThat(entry.movie).isNotNull(); + } + } + +} diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index f0871deb..8c564327 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -59,6 +59,9 @@ import java.util.ArrayList; import java.util.List; +import static com.uwetrottmann.trakt5.services.HistoryAssertions.assertEpisodeHistory; +import static com.uwetrottmann.trakt5.services.HistoryAssertions.assertHistory; +import static com.uwetrottmann.trakt5.services.HistoryAssertions.assertMovieHistory; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; @@ -618,82 +621,18 @@ public void test_deleteItemsFromWatchlist() throws IOException { } @Test - public void test_getHistory() throws IOException { - Call> call = getTrakt().sync().getHistory(null, null, null, null, null); - Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); - List body = response.body(); - if (body == null) { - throw new IllegalStateException("Body should not be null for successful response"); - } - - for (HistoryEntry entry : body) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - if ("episode".equals(entry.type)) { - assertThat(entry.episode).isNotNull(); - assertThat(entry.show).isNotNull(); - } else if ("movie".equals(entry.type)) { - assertThat(entry.movie).isNotNull(); - } - } + public void test_history() throws IOException { + List history = executeCall( + getTrakt().sync().history(null, null, null, null, null) + ); + assertHistory(history); } @Test - public void test_getHistory_with_pagination() throws IOException { - Call> call = getTrakt().sync().getHistory(1, 5, null, null, null); + public void test_history_withPagination() throws IOException { + Call> call = getTrakt().sync().history(1, 5, null, null, null); Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); - List body = response.body(); - if (body == null) { - throw new IllegalStateException("Body should not be null for successful response"); - } - - for (HistoryEntry entry : body) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - if ("episode".equals(entry.type)) { - assertThat(entry.episode).isNotNull(); - assertThat(entry.show).isNotNull(); - } else if ("movie".equals(entry.type)) { - assertThat(entry.movie).isNotNull(); - } - } - } - @Test - public void test_getHistory_movies() throws IOException { - Call> call = getTrakt().sync().getHistory(HistoryType.MOVIES, null, null, null, null, null); - Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); - List body = response.body(); - if (body == null) { - throw new IllegalStateException("Body should not be null for successful response"); - } - - for (HistoryEntry entry : body) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - assertThat(entry.movie).isNotNull(); - } - } - - @Test - public void test_getHistory_movies_with_pagination() throws IOException { - Call> call = getTrakt().sync().getHistory(HistoryType.MOVIES, 1, 5, null, null, null); - Response> response = executeCallWithoutReadingBody(call); assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); @@ -702,82 +641,37 @@ public void test_getHistory_movies_with_pagination() throws IOException { throw new IllegalStateException("Body should not be null for successful response"); } - for (HistoryEntry entry : body) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - assertThat(entry.movie).isNotNull(); - } + assertHistory(body); } @Test - public void test_getHistory_episodes() throws IOException { - Call> call = getTrakt().sync().getHistory(HistoryType.EPISODES, null, null, null, null, - null); - Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); - List body = response.body(); - if (body == null) { - throw new IllegalStateException("Body should not be null for successful response"); - } + public void test_history_episodes() throws IOException { + List history = executeCall( + getTrakt().sync().history(HistoryType.EPISODES, null, null, null, null, null) + ); - for (HistoryEntry entry : body) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - assertThat(entry.episode).isNotNull(); - assertThat(entry.show).isNotNull(); - } + assertEpisodeHistory(history); } @Test - public void test_getHistory_episodes_with_pagination() throws IOException { - Call> call = getTrakt().sync().getHistory(HistoryType.EPISODES, 1, 5, null, null, null); - Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); - List body = response.body(); - if (body == null) { - throw new IllegalStateException("Body should not be null for successful response"); - } + public void test_history_movies() throws IOException { + List history = executeCall( + getTrakt().sync().history(HistoryType.MOVIES, null, null, null, null, null)); - for (HistoryEntry entry : body) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - assertThat(entry.episode).isNotNull(); - assertThat(entry.show).isNotNull(); - } + assertMovieHistory(history); } @Test - public void test_getHistory_item() throws IOException { - Call> call = getTrakt().sync().getHistory(HistoryType.MOVIES, - TestData.MOVIE_WATCHED_TRAKT_ID, null, null, null, - OffsetDateTime.of(2016, 8, 3, 9, 0, 0, 0, ZoneOffset.UTC), - OffsetDateTime.of(2016, 8, 3, 10, 0, 0, 0, ZoneOffset.UTC)); - Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("10"); - List body = response.body(); - if (body == null) { - throw new IllegalStateException("Body should not be null for successful response"); - } - assertThat(body.size()).isGreaterThan(0); + public void test_history_item() throws IOException { + List history = executeCall( + getTrakt().sync().history(HistoryType.MOVIES, + TestData.MOVIE_WATCHED_TRAKT_ID, null, null, null, + OffsetDateTime.of(2016, 8, 3, 9, 0, 0, 0, ZoneOffset.UTC), + OffsetDateTime.of(2016, 8, 3, 10, 0, 0, 0, ZoneOffset.UTC)) + ); - for (HistoryEntry entry : body) { - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isEqualTo("movie"); - assertThat(entry.movie).isNotNull(); - } + assertThat(history.size()).isGreaterThan(0); + assertMovieHistory(history); } diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index 3bea7eed..87254dc2 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -67,6 +67,9 @@ import java.util.ArrayList; import java.util.List; +import static com.uwetrottmann.trakt5.services.HistoryAssertions.assertEpisodeHistory; +import static com.uwetrottmann.trakt5.services.HistoryAssertions.assertHistory; +import static com.uwetrottmann.trakt5.services.HistoryAssertions.assertMovieHistory; import static org.assertj.core.api.Assertions.assertThat; public class UsersTest extends BaseTestCase { @@ -333,72 +336,48 @@ public void test_friends() throws IOException { } @Test - public void test_historyEpisodesAndMovies() throws IOException { + public void test_history() throws IOException { List history = executeCall( getTrakt().users().history(TestData.USER_SLUG, 1, DEFAULT_PAGE_SIZE, null, null, null)); - for (HistoryEntry entry : history) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isNotEmpty(); - if ("episode".equals(entry.type)) { - assertThat(entry.episode).isNotNull(); - assertThat(entry.show).isNotNull(); - } else if ("movie".equals(entry.type)) { - assertThat(entry.movie).isNotNull(); - } - } + assertHistory(history); } @Test - public void test_historyEpisodes() throws IOException { + public void test_history_episodes() throws IOException { List history = executeCall( getTrakt().users().history(TestData.USER_SLUG, HistoryType.EPISODES, 1, DEFAULT_PAGE_SIZE, null, null, null)); - for (HistoryEntry entry : history) { - assertThat(entry.id).isGreaterThan(0); - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isEqualTo("episode"); - assertThat(entry.episode).isNotNull(); - assertThat(entry.show).isNotNull(); - System.out.println( - "Episode watched at date: " + entry.watched_at + entry.watched_at.toInstant().toEpochMilli()); - } + + assertEpisodeHistory(history); } @Test - public void test_historyMovies() throws IOException { + public void test_history_movies() throws IOException { List history = executeCall( getTrakt().users().history(UserSlug.ME, HistoryType.MOVIES, 1, DEFAULT_PAGE_SIZE, null, null, null)); + assertMovieHistory(history); } @Test - public void test_historyItem() throws IOException { - List history = executeCall(getTrakt().users().history(UserSlug.ME, HistoryType.MOVIES, - TestData.MOVIE_WATCHED_TRAKT_ID, 1, - DEFAULT_PAGE_SIZE, null, - OffsetDateTime.of(2016, 8, 3, 9, 0, 0, 0, ZoneOffset.UTC), - OffsetDateTime.of(2016, 8, 3, 10, 0, 0, 0, ZoneOffset.UTC))); + public void test_history_item() throws IOException { + List history = executeCall( + getTrakt().users().history(UserSlug.ME, HistoryType.MOVIES, + TestData.MOVIE_WATCHED_TRAKT_ID, 1, + DEFAULT_PAGE_SIZE, null, + OffsetDateTime.of(2016, 8, 3, 9, 0, 0, 0, ZoneOffset.UTC), + OffsetDateTime.of(2016, 8, 3, 10, 0, 0, 0, ZoneOffset.UTC)) + ); + assertThat(history.size()).isGreaterThan(0); assertMovieHistory(history); } - private void assertMovieHistory(List history) { - for (HistoryEntry entry : history) { - assertThat(entry.watched_at).isNotNull(); - assertThat(entry.action).isNotEmpty(); - assertThat(entry.type).isEqualTo("movie"); - assertThat(entry.movie).isNotNull(); - } - } - @Test public void test_ratingsMovies() throws IOException { List ratedMovies = executeCall( From e9e20ec0e84601e9686fb1d6704406feabbc3deb Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 10:58:22 +0100 Subject: [PATCH 05/20] Sync: add playback methods that accept start/end and pagination #161 --- CHANGELOG.md | 2 + .../trakt5/enums/PlaybackType.java | 35 +++++++++++++ .../uwetrottmann/trakt5/services/Sync.java | 52 +++++++++++++++++++ .../trakt5/services/SyncTest.java | 2 +- 4 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/uwetrottmann/trakt5/enums/PlaybackType.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fc6e7a9..d39c4855 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and `Users.collectionShows()` with required `page` and `limit` parameters. The original methods without pagination parameters are deprecated. * Add history endpoints to `Sync`. Thanks @defhead! [#125](https://github.com/UweTrottmann/trakt-java/pull/125) +* Add `Sync.playback()` that also accepts start and end times and supports pagination. The existing `getPlayback()` + methods are deprecated. ## 6.16.0 - 2024-11-07 diff --git a/src/main/java/com/uwetrottmann/trakt5/enums/PlaybackType.java b/src/main/java/com/uwetrottmann/trakt5/enums/PlaybackType.java new file mode 100644 index 00000000..bea16af4 --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/enums/PlaybackType.java @@ -0,0 +1,35 @@ +/* + * Copyright © 2026 Uwe Trottmann + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.uwetrottmann.trakt5.enums; + +public enum PlaybackType implements TraktEnum { + + MOVIES("movies"), + EPISODES("episodes"); + + private final String value; + + PlaybackType(String value) { + this.value = value; + } + + @Override + public String toString() { + return value; + } + +} diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index a2e3d49d..a1942059 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -32,6 +32,7 @@ import com.uwetrottmann.trakt5.entities.WatchlistedSeason; import com.uwetrottmann.trakt5.enums.Extended; import com.uwetrottmann.trakt5.enums.HistoryType; +import com.uwetrottmann.trakt5.enums.PlaybackType; import com.uwetrottmann.trakt5.enums.RatingsFilter; import org.threeten.bp.OffsetDateTime; import retrofit2.Call; @@ -150,11 +151,56 @@ Call> watchedMovies( @Query(value = "extended", encoded = true) Extended extended ); + /** + * OAuth Required + *

+ * Whenever a scrobble is paused, the playback progress is saved. Use this progress to sync up playback across + * different media centers or apps. For example, you can start watching a movie in a media center, stop it, then + * resume on your tablet from the same spot. Each item will have the progress percentage between 0 and 100. + *

+ * Use {@link #playback(PlaybackType, OffsetDateTime, OffsetDateTime, Integer, Integer)} to specify a type to only + * get movies or episodes. + *

+ * By default, all results will be returned. Pagination is optional and can be used for something like an "on deck" + * feature, or if you only need a limited data set. + *

+ * Note: Trakt only saves playback progress for the last 6 months. + * + * @see #playback(PlaybackType, OffsetDateTime, OffsetDateTime, Integer, Integer) + */ + @GET("sync/playback") + Call> playback( + @Query("start_at") OffsetDateTime startAt, + @Query("end_at") OffsetDateTime endAt, + @Query("page") Integer page, + @Query("limit") Integer limit + ); + + /** + * OAuth Required + *

+ * Like {@link #playback(OffsetDateTime, OffsetDateTime, Integer, Integer)}, but allows to specify a type to only + * get movies or episodes. + * + * @see #playback(OffsetDateTime, OffsetDateTime, Integer, Integer) + */ + @GET("sync/playback/{type}") + Call> playback( + @Path("type") PlaybackType type, + @Query("start_at") OffsetDateTime startAt, + @Query("end_at") OffsetDateTime endAt, + @Query("page") Integer page, + @Query("limit") Integer limit + ); + /** * OAuth Required *

* Returns all playbacks; + * + * @deprecated Use {@link #playback(OffsetDateTime, OffsetDateTime, Integer, Integer)} instead. */ + @Deprecated @GET("sync/playback") Call> getPlayback( @Query("limit") Integer limit @@ -164,7 +210,10 @@ Call> getPlayback( * OAuth Required *

* Returns all playbacks; + * + * @deprecated Use {@link #playback(PlaybackType, OffsetDateTime, OffsetDateTime, Integer, Integer)} instead. */ + @Deprecated @GET("sync/playback/episodes") Call> getPlaybackEpisodes( @Query("limit") Integer limit @@ -174,7 +223,10 @@ Call> getPlaybackEpisodes( * OAuth Required *

* Returns all playbacks; + * + * @deprecated Use {@link #playback(PlaybackType, OffsetDateTime, OffsetDateTime, Integer, Integer)} instead. */ + @Deprecated @GET("sync/playback/movies") Call> getPlaybackMovies( @Query("limit") Integer limit diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index 8c564327..fea0d7c8 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -106,7 +106,7 @@ public void test_getPlayback() throws IOException, InterruptedException { // Give the server some time to process the request. Thread.sleep(1500); - List playbacks = executeCall(getTrakt().sync().getPlayback(10)); + List playbacks = executeCall(getTrakt().sync().playback(null, null, null, 10)); assertThat(playbacks).isNotNull(); boolean foundEpisode = false; boolean foundMovie = false; From d839be31ef523066fd7433d897d7b36343563545 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 11:10:09 +0100 Subject: [PATCH 06/20] Users: add listItems that requires pagination, supports type and ordering --- CHANGELOG.md | 2 + .../uwetrottmann/trakt5/services/Users.java | 92 +++++++++++++++++++ .../trakt5/services/UsersTest.java | 44 ++++++++- 3 files changed, 134 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d39c4855..8678682e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ * Add history endpoints to `Sync`. Thanks @defhead! [#125](https://github.com/UweTrottmann/trakt-java/pull/125) * Add `Sync.playback()` that also accepts start and end times and supports pagination. The existing `getPlayback()` methods are deprecated. +* Add `Users.listItems()` variants that requires pagination and support type and sort order parameters. The original + method is deprecated. ## 6.16.0 - 2024-11-07 diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 4759fb57..04597509 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -221,11 +221,103 @@ Call reorderLists( * OAuth Optional *

* Get all items on a custom list. Items can be movies, shows, seasons, episodes, or people. + * + * @deprecated Use {@link #listItems(UserSlug, String, int, int, Extended)} instead. + */ + @Deprecated + @GET("users/{username}/lists/{id}/items") + Call> listItems( + @Path("username") UserSlug userSlug, + @Path("id") String id, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * OAuth Optional + *

+ * Get all items on a personal list. Items can be a movie, show, season, episode, or person. Use + * {@link #listItems(UserSlug, String, String, int, int, Extended)} to specify the type parameter with a single + * value or comma-delimited string for multiple item types. + *

+ * Notes: Each list item contains a notes field with text entered by the user. + *

+ * Sorting: Default sorting is based on the list defaults and sent in the X-Sort-By and X-Sort-How headers. Use + * {@link #listItems(UserSlug, String, String, String, String, int, int, Extended)} to specify a custom sort order. */ @GET("users/{username}/lists/{id}/items") Call> listItems( @Path("username") UserSlug userSlug, @Path("id") String id, + @Query("page") int page, + @Query("limit") int limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #listItems(UserSlug, String, int, int, Extended)}, but you can specify a sort order. + *

+ * The specified order will be sent in the X-Applied-Sort-By and X-Applied-Sort-How headers. + *

+ * Some sort_by options are VIP Only including imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, + * votes, imdb_votes, and tmdb_votes. If sent for a non VIP, the items will fall back to rank. + * + * @param sortBy Sort by a specific property. Possible values: rank, added, title, released , runtime, popularity, + * random, percentage, imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, votes, + * imdb_votes, tmdb_votes, my_rating, watched, collected. + * @param sortHow Sort direction. Possible values: asc, desc. + */ + @GET("users/{username}/lists/{id}/items/{sort_by}/{sort_how}") + Call> listItems( + @Path("username") UserSlug userSlug, + @Path("id") String id, + @Path("sort_by") String sortBy, + @Path("sort_how") String sortHow, + @Query("page") int page, + @Query("limit") int limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #listItems(UserSlug, String, int, int, Extended)}, but you can specify the type parameter with a + * single value or comma-delimited string for multiple item types. + * + * @param type Filter for a specific item type. Example: {@code movie,show}. Possible values: movie, show, season, + * episode, person. + */ + @GET("users/{username}/lists/{id}/items/{type}") + Call> listItems( + @Path("username") UserSlug userSlug, + @Path("id") String id, + @Path("type") String type, + @Query("page") int page, + @Query("limit") int limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #listItems(UserSlug, String, String, int, int, Extended)}, but you can specify a sort order. + *

+ * The specified order will be sent in the X-Applied-Sort-By and X-Applied-Sort-How headers. + *

+ * Some sort_by options are VIP Only including imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, + * votes, imdb_votes, and tmdb_votes. If sent for a non VIP, the items will fall back to rank. + * + * @param type Filter for a specific item type. Example: {@code movie,show}. Possible values: movie, show, + * season, episode, person. + * @param sortBy Sort by a specific property. Possible values: rank, added, title, released, runtime, popularity, + * random, percentage, imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, votes, + * imdb_votes, tmdb_votes, my_rating, watched, collected. + * @param sortHow Sort direction. Possible values: asc, desc. + */ + @GET("users/{username}/lists/{id}/items/{type}/{sort_by}/{sort_how}") + Call> listItems( + @Path("username") UserSlug userSlug, + @Path("id") String id, + @Path("type") String type, + @Path("sort_by") String sortBy, + @Path("sort_how") String sortHow, + @Query("page") int page, + @Query("limit") int limit, @Query(value = "extended", encoded = true) Extended extended ); diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index 87254dc2..1c81e104 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -213,9 +213,45 @@ public void test_updateList() throws IOException { @Test public void test_listItems() throws IOException { - List entries = executeCall(getTrakt().users().listItems(UserSlug.ME, - String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), - null)); + List entries = executeCall( + getTrakt().users().listItems(UserSlug.ME, + String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), 1, 1000, null) + ); + assertListEntries(entries); + } + + @Test + public void test_listItems_sortOrder() throws IOException { + List entries = executeCall( + getTrakt().users().listItems(UserSlug.ME, + String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), + "title", "asc", 1, 1000, null) + ); + assertListEntries(entries); + } + + @Test + public void test_listItems_type() throws IOException { + List entries = executeCall( + getTrakt().users().listItems(UserSlug.ME, + String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), + "movie,show", 1, 1000, null) + ); + assertListEntries(entries); + } + + @Test + public void test_listItems_typeAndsortOrder() throws IOException { + List entries = executeCall( + getTrakt().users().listItems(UserSlug.ME, + String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), + "movie,show", "title", "asc", 1, 1000, null) + ); + assertListEntries(entries); + } + + private static void assertListEntries(List entries) { + assertThat(entries).isNotEmpty(); for (ListEntry entry : entries) { assertThat(entry.listed_at).isNotNull(); assertThat(entry.id).isNotNull(); @@ -257,7 +293,7 @@ public void test_addListItems() throws IOException { @Test public void test_reorderListItems() throws IOException { List entries = executeCall(getTrakt().users().listItems(UserSlug.ME, - String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), + String.valueOf(TEST_LIST_WITH_ITEMS_TRAKT_ID), 1, 1000, null)); // reverse order From 6fae87a2e28ebdacef4ff3de77b95f2096b7e8c0 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 14:32:10 +0100 Subject: [PATCH 07/20] Only send minute-precision watched_at timestamps, warn about them --- CHANGELOG.md | 2 ++ .../uwetrottmann/trakt5/entities/BaseCheckinResponse.java | 4 ++++ .../com/uwetrottmann/trakt5/entities/BaseEpisode.java | 4 ++++ .../java/com/uwetrottmann/trakt5/entities/BaseMovie.java | 4 ++++ .../java/com/uwetrottmann/trakt5/entities/BaseShow.java | 4 ++++ .../com/uwetrottmann/trakt5/entities/HistoryEntry.java | 4 ++++ .../com/uwetrottmann/trakt5/entities/SyncEpisode.java | 4 ++++ .../java/com/uwetrottmann/trakt5/entities/SyncMovie.java | 4 ++++ .../java/com/uwetrottmann/trakt5/entities/SyncSeason.java | 4 ++++ .../java/com/uwetrottmann/trakt5/entities/SyncShow.java | 4 ++++ .../java/com/uwetrottmann/trakt5/services/SyncTest.java | 8 +++++--- 11 files changed, 43 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8678682e..c9b867aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ methods are deprecated. * Add `Users.listItems()` variants that requires pagination and support type and sort order parameters. The original method is deprecated. +* Add warnings to `watched_at` fields + that [Trakt will only store and return minute-precision timestamps](https://github.com/trakt/trakt-api/discussions/694). ## 6.16.0 - 2024-11-07 diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/BaseCheckinResponse.java b/src/main/java/com/uwetrottmann/trakt5/entities/BaseCheckinResponse.java index ce105819..75bad584 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/BaseCheckinResponse.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/BaseCheckinResponse.java @@ -21,6 +21,10 @@ public abstract class BaseCheckinResponse { + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. + */ public OffsetDateTime watched_at; public ShareSettings sharing; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/BaseEpisode.java b/src/main/java/com/uwetrottmann/trakt5/entities/BaseEpisode.java index 68c03915..c7b2eb7e 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/BaseEpisode.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/BaseEpisode.java @@ -26,6 +26,10 @@ public class BaseEpisode { public OffsetDateTime collected_at; /** watched */ public Integer plays; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. + */ public OffsetDateTime last_watched_at; /** progress */ public Boolean completed; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/BaseMovie.java b/src/main/java/com/uwetrottmann/trakt5/entities/BaseMovie.java index beee97c5..121c74be 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/BaseMovie.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/BaseMovie.java @@ -23,6 +23,10 @@ public class BaseMovie { public Movie movie; public OffsetDateTime collected_at; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. + */ public OffsetDateTime last_watched_at; public OffsetDateTime last_updated_at; public OffsetDateTime listed_at; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/BaseShow.java b/src/main/java/com/uwetrottmann/trakt5/entities/BaseShow.java index ae344f88..3aa9fee1 100755 --- a/src/main/java/com/uwetrottmann/trakt5/entities/BaseShow.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/BaseShow.java @@ -33,6 +33,10 @@ public class BaseShow { public OffsetDateTime listed_at; /** watched */ public Integer plays; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. + */ public OffsetDateTime last_watched_at; public OffsetDateTime last_updated_at; public OffsetDateTime reset_at; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/HistoryEntry.java b/src/main/java/com/uwetrottmann/trakt5/entities/HistoryEntry.java index b4483046..fe50a5d9 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/HistoryEntry.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/HistoryEntry.java @@ -21,6 +21,10 @@ public class HistoryEntry { public Long id; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. + */ public OffsetDateTime watched_at; public String action; public String type; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/SyncEpisode.java b/src/main/java/com/uwetrottmann/trakt5/entities/SyncEpisode.java index 1716b6d9..a9e42bf2 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/SyncEpisode.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/SyncEpisode.java @@ -34,6 +34,10 @@ public class SyncEpisode { public EpisodeIds ids; public OffsetDateTime collected_at; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. Using {@code .truncatedTo(ChronoUnit.MINUTES)} can be helpful. + */ public OffsetDateTime watched_at; public OffsetDateTime rated_at; public Rating rating; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/SyncMovie.java b/src/main/java/com/uwetrottmann/trakt5/entities/SyncMovie.java index 5df2eff2..1937f4bd 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/SyncMovie.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/SyncMovie.java @@ -32,6 +32,10 @@ public class SyncMovie { public MovieIds ids; public OffsetDateTime collected_at; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. Using {@code .truncatedTo(ChronoUnit.MINUTES)} can be helpful. + */ public OffsetDateTime watched_at; public OffsetDateTime rated_at; public Rating rating; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/SyncSeason.java b/src/main/java/com/uwetrottmann/trakt5/entities/SyncSeason.java index f947d033..03fa69e7 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/SyncSeason.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/SyncSeason.java @@ -29,6 +29,10 @@ public class SyncSeason { public List episodes; public OffsetDateTime collected_at; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. Using {@code .truncatedTo(ChronoUnit.MINUTES)} can be helpful. + */ public OffsetDateTime watched_at; public OffsetDateTime rated_at; public Rating rating; diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/SyncShow.java b/src/main/java/com/uwetrottmann/trakt5/entities/SyncShow.java index 1ee82f09..a880d0fa 100644 --- a/src/main/java/com/uwetrottmann/trakt5/entities/SyncShow.java +++ b/src/main/java/com/uwetrottmann/trakt5/entities/SyncShow.java @@ -29,6 +29,10 @@ public class SyncShow { public List seasons; public OffsetDateTime collected_at; + /** + * Warning: Trakt is planning to only store and return minute-precision timestamps for watched_at. So seconds and + * nanoseconds will always be zero. Using {@code .truncatedTo(ChronoUnit.MINUTES)} can be helpful. + */ public OffsetDateTime watched_at; public OffsetDateTime rated_at; public Rating rating; diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index fea0d7c8..1c0de153 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -52,6 +52,7 @@ import org.threeten.bp.Instant; import org.threeten.bp.OffsetDateTime; import org.threeten.bp.ZoneOffset; +import org.threeten.bp.temporal.ChronoUnit; import retrofit2.Call; import retrofit2.Response; @@ -324,16 +325,17 @@ public void test_watchedShows() throws IOException { public void test_addItemsToWatchedHistory() throws IOException { // movie SyncMovie movie = new SyncMovie(); - movie.watched_at = OffsetDateTime.now().minusHours(1); + // Trakt only stores minute precision for watched_at + movie.watched_at = OffsetDateTime.now().truncatedTo(ChronoUnit.MINUTES).minusHours(1); movie.ids = buildMovieIds(); // episode SyncEpisode episode = new SyncEpisode(); episode.number = TestData.EPISODE_NUMBER; - episode.watched_at = OffsetDateTime.now().minusHours(1); + episode.watched_at = OffsetDateTime.now().truncatedTo(ChronoUnit.MINUTES).minusHours(1); SyncEpisode episode2 = new SyncEpisode(); episode2.number = 2; - episode2.watched_at = OffsetDateTime.now().minusMinutes(30); + episode2.watched_at = OffsetDateTime.now().truncatedTo(ChronoUnit.MINUTES).minusMinutes(30); // season SyncSeason season = new SyncSeason(); season.number = TestData.EPISODE_SEASON; From 7f926c940dea69ffb7984aee592e55a9d38f96fb Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 14:40:17 +0100 Subject: [PATCH 08/20] Changelog: group under and reference Trakt API change announcement --- CHANGELOG.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c9b867aa..8a0d3169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,14 +2,15 @@ ## Next release -* Add paginated variants of `Sync.collectionMovies()`, `Sync.collectionShows()`, `Users.collectionMovies()` - and `Users.collectionShows()` with required `page` and `limit` parameters. The original methods without pagination - parameters are deprecated. +* Address [Trakt requiring pagination](https://github.com/trakt/trakt-api/discussions/681) for lists and library + (formerly collection) endpoints: + * Add paginated variants of `Sync.collectionMovies()`, `Sync.collectionShows()`, `Users.collectionMovies()` + and `Users.collectionShows()` with required `page` and `limit` parameters. The original methods are deprecated. + * Add `Users.listItems()` variants that require pagination and support type and sort order parameters. The original + method is deprecated. * Add history endpoints to `Sync`. Thanks @defhead! [#125](https://github.com/UweTrottmann/trakt-java/pull/125) * Add `Sync.playback()` that also accepts start and end times and supports pagination. The existing `getPlayback()` methods are deprecated. -* Add `Users.listItems()` variants that requires pagination and support type and sort order parameters. The original - method is deprecated. * Add warnings to `watched_at` fields that [Trakt will only store and return minute-precision timestamps](https://github.com/trakt/trakt-api/discussions/694). From 3b71aef5789299ded7ec503523bc4cc251448a7b Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 15:34:44 +0100 Subject: [PATCH 09/20] Sync/Users: refer to collection as "library (formerly collection)" --- .../uwetrottmann/trakt5/services/Sync.java | 24 +++++++------------ .../uwetrottmann/trakt5/services/Users.java | 16 ++++++------- 2 files changed, 16 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index a1942059..e71dbc09 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -60,8 +60,8 @@ public interface Sync { /** * OAuth Required *

- * Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. + * Get all movies in a user's library (formerly collection). A collected item indicates availability to watch + * digitally or on physical media. * * @deprecated Use {@link #collectionMovies(int, int, Extended)} instead. */ @@ -74,11 +74,7 @@ Call> collectionMovies( /** * OAuth Required *

- * Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. - * - * @param page Number of page of results to be returned. - * @param limit Number of results to return per page. + * Like {@link Users#collectionMovies(UserSlug, int, int, Extended)}. */ @GET("sync/collection/movies") Call> collectionMovies( @@ -90,8 +86,8 @@ Call> collectionMovies( /** * OAuth Required *

- * Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. + * Get all shows in a user's library (formerly collection). A collected item indicates availability to watch + * digitally or on physical media. * * @deprecated Use {@link #collectionShows(int, int, Extended)} instead. */ @@ -104,11 +100,7 @@ Call> collectionShows( /** * OAuth Required *

- * Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. - * - * @param page Number of page of results to be returned. - * @param limit Number of results to return per page. + * Like {@link Users#collectionShows(UserSlug, int, int, Extended)}. */ @GET("sync/collection/shows") Call> collectionShows( @@ -120,7 +112,7 @@ Call> collectionShows( /** * OAuth Required *

- * Add one or more items to a user's collection including the format of the item. + * Add one or more items to a user's library (formerly collection) including the format of the item. * * @param items A list of movies, shows, seasons or episodes. */ @@ -132,7 +124,7 @@ Call addItemsToCollection( /** * OAuth Required *

- * Remove one or more items from a user's collection. + * Remove one or more items from a user's library (formerly collection). * * @param items A list of movies, shows, seasons or episodes. */ diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 04597509..4b7a9bca 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -80,8 +80,8 @@ Call profile( /** * OAuth Optional *

- * Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. + * Get all movies in a user's library (formerly collection). A collected item indicates availability to watch + * digitally or on physical media. * * @param userSlug Example: "sean". * @deprecated Use {@link #collectionMovies(UserSlug, int, int, Extended)} instead. @@ -96,12 +96,12 @@ Call> collectionMovies( /** * OAuth Optional *

- * Get all collected movies in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. + * Get all movies in a user's library (formerly collection). * * @param userSlug Example: "sean". * @param page Number of page of results to be returned. * @param limit Number of results to return per page. + * @see Sync#collectionMovies(int, int, Extended) */ @GET("users/{username}/collection/movies") Call> collectionMovies( @@ -114,8 +114,8 @@ Call> collectionMovies( /** * OAuth Optional *

- * Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. + * Get all shows in a user's library (formerly collection). A collected item indicates availability to watch + * digitally or on physical media. * * @param userSlug Example: "sean". * @deprecated Use {@link #collectionShows(UserSlug, int, int, Extended)} instead. @@ -130,12 +130,12 @@ Call> collectionShows( /** * OAuth Optional *

- * Get all collected shows in a user's collection. A collected item indicates availability to watch digitally or on - * physical media. + * Get all shows in a user's library (formerly collection). * * @param userSlug Example: "sean". * @param page Number of page of results to be returned. * @param limit Number of results to return per page. + * @see Sync#collectionShows(int, int, Extended) */ @GET("users/{username}/collection/shows") Call> collectionShows( From 6c927c158960ae931b7a0c030a751963f4600aaf Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Jan 2026 17:14:25 +0100 Subject: [PATCH 10/20] TraktV2: add isAccountLimitExceeded, isRateLimitExceeded and isServerError --- CHANGELOG.md | 2 ++ .../java/com/uwetrottmann/trakt5/TraktV2.java | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8a0d3169..e42dede0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ methods are deprecated. * Add warnings to `watched_at` fields that [Trakt will only store and return minute-precision timestamps](https://github.com/trakt/trakt-api/discussions/694). +* Add `TraktV2.isAccountLimitExceeded()`, `TraktV2.isRateLimitExceeded()` and `TraktV2.isServerError()` methods to help + inspect `Response` objects for more common Trakt HTTP status codes. ## 6.16.0 - 2024-11-07 diff --git a/src/main/java/com/uwetrottmann/trakt5/TraktV2.java b/src/main/java/com/uwetrottmann/trakt5/TraktV2.java index 0ab10660..113b923b 100644 --- a/src/main/java/com/uwetrottmann/trakt5/TraktV2.java +++ b/src/main/java/com/uwetrottmann/trakt5/TraktV2.java @@ -361,6 +361,14 @@ public static boolean isUnauthorized(Response response) { return response.code() == 401; } + /** + * Checks if the response code is 420, which indicates an account limit would be exceeded. These limits can be higher for VIP users. + */ + public static boolean isAccountLimitExceeded(Response response) { + return response.code() == 420; + } + /** * Checks if the response code is 423, which indicates the * Trakt account is locked. @@ -377,6 +385,21 @@ public static boolean isNotVip(Response response) { return response.code() == 426; } + /** + * Checks if the response code is 429, which indicates the rate limit was exceeded. + * Trakt rate limiting info + */ + public static boolean isRateLimitExceeded(Response response) { + return response.code() == 429; + } + + /** + * Checks if the response code is 500 or greater, which indicates a server error. + */ + public static boolean isServerError(Response response) { + return response.code() >= 500; + } + /** * If it exists, returns the value of the {@code X-Pagination-Page-Count} header from the response. */ From 55acbdabd1c590fd021fa1ac198f119a551f1062 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Fri, 30 Jan 2026 14:42:25 +0100 Subject: [PATCH 11/20] SyncTest: unify assertion of pagination --- .../com/uwetrottmann/trakt5/BaseTestCase.java | 11 +++++ .../trakt5/services/SyncTest.java | 42 +++++++++++-------- 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java b/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java index 3fcf6dcc..0aa7d905 100644 --- a/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java +++ b/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java @@ -308,6 +308,17 @@ public void assertCrewMembers(@Nullable List crew, Type type) { } } + /** + * Checks that the promised pagination headers are returned and that the supplied page and limit parameters were + * used. + */ + public static void assertPaginationHeaders(Response response, int expectedPage, int expectedLimit) { + assertThat(TraktV2.getPageCount(response)).isNotNull(); + assertThat(TraktV2.getItemCount(response)).isNotNull(); + assertThat(response.headers().get("X-Pagination-Page")).isEqualTo(String.valueOf(expectedPage)); + assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo(String.valueOf(expectedLimit)); + } + protected void assertAccessTokenResponse(Response response) { assertSuccessfulResponse(response); assertThat(response.body().access_token).isNotEmpty(); diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index 1c0de153..cdd15d83 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -391,10 +391,12 @@ public void test_ratingsMovies_filtered() throws IOException { @Test public void test_ratingsMovies_with_pagination() throws IOException { - Call> call = getTrakt().sync().ratingsMovies(RatingsFilter.ALL, null, 1, 2); + int page = 1; + int limit = 2; + Call> call = getTrakt().sync().ratingsMovies(RatingsFilter.ALL, null, page, limit); Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + + assertPaginationHeaders(response, page, limit); } @Test @@ -405,10 +407,12 @@ public void test_ratingsShows() throws IOException { @Test public void test_ratingsShows_with_pagination() throws IOException { - Call> call = getTrakt().sync().ratingsShows(RatingsFilter.ALL, null, 1, 2); + int page = 1; + int limit = 2; + Call> call = getTrakt().sync().ratingsShows(RatingsFilter.ALL, null, page, limit); Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + + assertPaginationHeaders(response, page, limit); } @Test @@ -420,10 +424,12 @@ public void test_ratingsSeasons() throws IOException { @Test public void test_ratingsSeasons_with_pagination() throws IOException { - Call> call = getTrakt().sync().ratingsSeasons(RatingsFilter.ALL, null, 1, 5); + int page = 1; + int limit = 5; + Call> call = getTrakt().sync().ratingsSeasons(RatingsFilter.ALL, null, page, limit); Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + + assertPaginationHeaders(response, page, limit); } @Test @@ -435,10 +441,12 @@ public void test_ratingsEpisodes() throws IOException { @Test public void test_ratingsEpisodes_with_pagination() throws IOException { - Call> call = getTrakt().sync().ratingsEpisodes(RatingsFilter.ALL, null, 1, 2); + int page = 1; + int limit = 2; + Call> call = getTrakt().sync().ratingsEpisodes(RatingsFilter.ALL, null, page, limit); Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); + + assertPaginationHeaders(response, page, limit); } @Test @@ -632,17 +640,17 @@ public void test_history() throws IOException { @Test public void test_history_withPagination() throws IOException { - Call> call = getTrakt().sync().history(1, 5, null, null, null); + int page = 1; + int limit = 5; + Call> call = getTrakt().sync().history(page, limit, null, null, null); Response> response = executeCallWithoutReadingBody(call); - assertThat(response.headers().get("X-Pagination-Page-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Item-Count")).isNotEmpty(); - assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo("5"); + assertPaginationHeaders(response, page, limit); + List body = response.body(); if (body == null) { throw new IllegalStateException("Body should not be null for successful response"); } - assertHistory(body); } From 0fe5da9c7fd50712a2d89f8db334436df528aba6 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Fri, 30 Jan 2026 14:47:54 +0100 Subject: [PATCH 12/20] Add generic type arguments in CommentsTest, UsersTest --- .../java/com/uwetrottmann/trakt5/services/CommentsTest.java | 6 +++--- .../java/com/uwetrottmann/trakt5/services/UsersTest.java | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/java/com/uwetrottmann/trakt5/services/CommentsTest.java b/src/test/java/com/uwetrottmann/trakt5/services/CommentsTest.java index 8ae87c28..c54ae0d5 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/CommentsTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/CommentsTest.java @@ -49,7 +49,7 @@ public void test_postAndUpdate() throws InterruptedException, IOException { Thread.sleep(3000); // delete the comment again - Response response = getTrakt().comments().delete(commentResponse.id).execute(); + Response response = getTrakt().comments().delete(commentResponse.id).execute(); assertSuccessfulResponse(response); assertThat(response.code()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); } @@ -64,7 +64,7 @@ public void test_delete() throws InterruptedException, IOException { Thread.sleep(3000); // delete the comment again - Response response = getTrakt().comments().delete(commentResponse.id).execute(); + Response response = getTrakt().comments().delete(commentResponse.id).execute(); assertSuccessfulResponse(response); assertThat(response.code()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); } @@ -95,7 +95,7 @@ public void test_replies() throws InterruptedException, IOException { } // delete the comment and replies (does this work?) - Response deleteResponse = getTrakt().comments().delete(response.id).execute(); + Response deleteResponse = getTrakt().comments().delete(response.id).execute(); assertSuccessfulResponse(deleteResponse); assertThat(deleteResponse.code()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); } diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index 1c81e104..ce924336 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -190,7 +190,7 @@ public void test_createList() throws IOException { assertThat(createdList.sort_how).isEqualTo(SortHow.DESC); // Note: created list is always desc, even on web. // ...and delete it again - Response deleteResponse = getTrakt().users().deleteList(UserSlug.ME, + Response deleteResponse = getTrakt().users().deleteList(UserSlug.ME, String.valueOf(createdList.ids.trakt)).execute(); assertSuccessfulResponse(deleteResponse); assertThat(deleteResponse.code()).isEqualTo(204); @@ -332,7 +332,7 @@ public void test_reorderLists() throws IOException { public void test_unfollowAndFollow() throws InterruptedException, IOException { // unfollow first UserSlug userToFollow = new UserSlug(TestData.USER_TO_FOLLOW); - Response response = getTrakt().users().unfollow(userToFollow).execute(); + Response response = getTrakt().users().unfollow(userToFollow).execute(); assertSuccessfulResponse(response); assertThat(response.code()).isEqualTo(HttpURLConnection.HTTP_NO_CONTENT); From 7aa494664ffa33b8d214c1ff9f0055c89992d48b Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Fri, 30 Jan 2026 14:51:28 +0100 Subject: [PATCH 13/20] Maven: ignore warnings for missing Javadoc comments --- pom.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pom.xml b/pom.xml index 11a4a2f2..2d4bf50e 100644 --- a/pom.xml +++ b/pom.xml @@ -205,6 +205,8 @@ 3.12.0 8 + + all,-missing From 1d3a6a262b7e5d64a331da29f03e7b189e151ebe Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Fri, 30 Jan 2026 14:53:15 +0100 Subject: [PATCH 14/20] Releasing: fix Maven command to install locally --- RELEASING.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/RELEASING.md b/RELEASING.md index 344b7aaa..f4412080 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -2,8 +2,14 @@ ## Local testing +Note: on Windows, avoid Git Bash. It uses its own `gpg`. + ```bash -./mwnw clean install -P release,heyuwe-sign +./mvnw clean install -P release,heyuwe-sign -DskipTests +``` + +```powershell +.\mvnw.cmd clean install -P release,heyuwe-sign -DskipTests ``` ## Preparing a release and deploying it to Maven Central From 9941176e55d0d4b17d1004417a808fcafede6af3 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 5 Feb 2026 13:35:33 +0100 Subject: [PATCH 15/20] Users: add watchlist variants that support pagination and ordering --- CHANGELOG.md | 1 + .../uwetrottmann/trakt5/services/Users.java | 197 ++++++++++++++++-- .../com/uwetrottmann/trakt5/BaseTestCase.java | 6 + .../trakt5/services/UsersTest.java | 67 +++++- 4 files changed, 253 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e42dede0..ac00a597 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ that [Trakt will only store and return minute-precision timestamps](https://github.com/trakt/trakt-api/discussions/694). * Add `TraktV2.isAccountLimitExceeded()`, `TraktV2.isRateLimitExceeded()` and `TraktV2.isServerError()` methods to help inspect `Response` objects for more common Trakt HTTP status codes. +* Add variants of the watchlist methods that support pagination and sort order parameters. ## 6.16.0 - 2024-11-07 diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 4b7a9bca..12eb645e 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -51,6 +51,7 @@ import retrofit2.http.Path; import retrofit2.http.Query; +import javax.annotation.Nonnull; import java.util.List; public interface Users { @@ -546,48 +547,220 @@ Call> ratingsEpisodes( /** * OAuth Optional *

- * Returns all items in a user's watchlist filtered by movies. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Returns all items in a user's watchlist filtered by movies. + *

+ * The watchlist should not be used as a list of what the user is actively watching. Use a combination of the + * /sync/watched and /shows/:id/progress methods to get what the user is actively watching. + *

+ * Auto Removal + *

+ * When an item is watched, it will be automatically removed from the watchlist. For shows and seasons, watching 1 + * episode will remove the entire show or season. + * + * @see #watchlistMovies(UserSlug, String, String, Integer, Integer, Extended) */ @GET("users/{username}/watchlist/movies") Call> watchlistMovies( - @Path("username") UserSlug userSlug, + @Nonnull @Path("username") UserSlug userSlug, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistMovies(UserSlug, Extended)}, but you can specify pagination parameters. + */ + @GET("users/{username}/watchlist/movies") + Call> watchlistMovies( + @Nonnull @Path("username") UserSlug userSlug, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistMovies(UserSlug, Extended)}, but you can specify pagination parameters and a sort order. + *

+ * The specified order will be sent in the X-Applied-Sort-By and X-Applied-Sort-How headers. + *

+ * Some sort_by options are VIP Only including imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, + * votes, imdb_votes, and tmdb_votes. If sent for a non VIP, the items will fall back to rank. + * + * @param sortBy Sort by a specific property. Possible values: rank, added, title, released , runtime, popularity, + * random, percentage, imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, votes, + * imdb_votes, tmdb_votes, my_rating, watched, collected. + * @param sortHow Sort direction. Possible values: asc, desc. + */ + @GET("users/{username}/watchlist/movies/{sort_by}/{sort_how}") + Call> watchlistMovies( + @Nonnull @Path("username") UserSlug userSlug, + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, @Query(value = "extended", encoded = true) Extended extended ); /** * OAuth Optional *

- * Returns all items in a user's watchlist filtered by shows. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Returns all items in a user's watchlist filtered by shows. + *

+ * The watchlist should not be used as a list of what the user is actively watching. Use a combination of the + * /sync/watched and /shows/:id/progress methods to get what the user is actively watching. + *

+ * Auto Removal + *

+ * When an item is watched, it will be automatically removed from the watchlist. For shows and seasons, watching 1 + * episode will remove the entire show or season. + * + * @see #watchlistShows(UserSlug, String, String, Integer, Integer, Extended) */ @GET("users/{username}/watchlist/shows") Call> watchlistShows( - @Path("username") UserSlug userSlug, + @Nonnull @Path("username") UserSlug userSlug, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistShows(UserSlug, Extended)}, but you can specify pagination parameters. + */ + @GET("users/{username}/watchlist/shows") + Call> watchlistShows( + @Nonnull @Path("username") UserSlug userSlug, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistShows(UserSlug, Extended)}, but you can specify pagination parameters and a sort order. + *

+ * The specified order will be sent in the X-Applied-Sort-By and X-Applied-Sort-How headers. + *

+ * Some sort_by options are VIP Only including imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, + * votes, imdb_votes, and tmdb_votes. If sent for a non VIP, the items will fall back to rank. + * + * @param sortBy Sort by a specific property. Possible values: rank, added, title, released , runtime, popularity, + * random, percentage, imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, votes, + * imdb_votes, tmdb_votes, my_rating, watched, collected. + * @param sortHow Sort direction. Possible values: asc, desc. + */ + @GET("users/{username}/watchlist/shows/{sort_by}/{sort_how}") + Call> watchlistShows( + @Nonnull @Path("username") UserSlug userSlug, + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, @Query(value = "extended", encoded = true) Extended extended ); /** * OAuth Optional *

- * Returns all items in a user's watchlist filtered by seasons. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Returns all items in a user's watchlist filtered by seasons. + *

+ * The watchlist should not be used as a list of what the user is actively watching. Use a combination of the + * /sync/watched and /shows/:id/progress methods to get what the user is actively watching. + *

+ * Auto Removal + *

+ * When an item is watched, it will be automatically removed from the watchlist. For shows and seasons, watching 1 + * episode will remove the entire show or season. + * + * @see #watchlistSeasons(UserSlug, String, String, Integer, Integer, Extended) */ @GET("users/{username}/watchlist/seasons") Call> watchlistSeasons( - @Path("username") UserSlug userSlug, + @Nonnull @Path("username") UserSlug userSlug, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistSeasons(UserSlug, Extended)}, but you can specify pagination parameters. + */ + @GET("users/{username}/watchlist/seasons") + Call> watchlistSeasons( + @Nonnull @Path("username") UserSlug userSlug, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistSeasons(UserSlug, Extended)}, but you can specify pagination parameters and a sort order. + *

+ * The specified order will be sent in the X-Applied-Sort-By and X-Applied-Sort-How headers. + *

+ * Some sort_by options are VIP Only including imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, + * votes, imdb_votes, and tmdb_votes. If sent for a non VIP, the items will fall back to rank. + * + * @param sortBy Sort by a specific property. Possible values: rank, added, title, released , runtime, popularity, + * random, percentage, imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, votes, + * imdb_votes, tmdb_votes, my_rating, watched, collected. + * @param sortHow Sort direction. Possible values: asc, desc. + */ + @GET("users/{username}/watchlist/seasons/{sort_by}/{sort_how}") + Call> watchlistSeasons( + @Nonnull @Path("username") UserSlug userSlug, + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, @Query(value = "extended", encoded = true) Extended extended ); /** * OAuth Optional *

- * Returns all items in a user's watchlist filtered by episodes. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Returns all items in a user's watchlist filtered by episodes. + *

+ * The watchlist should not be used as a list of what the user is actively watching. Use a combination of the + * /sync/watched and /shows/:id/progress methods to get what the user is actively watching. + *

+ * Auto Removal + *

+ * When an item is watched, it will be automatically removed from the watchlist. For shows and seasons, watching 1 + * episode will remove the entire show or season. + * + * @see #watchlistEpisodes(UserSlug, String, String, Integer, Integer, Extended) */ @GET("users/{username}/watchlist/episodes") Call> watchlistEpisodes( - @Path("username") UserSlug userSlug, + @Nonnull @Path("username") UserSlug userSlug, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistEpisodes(UserSlug, Extended)}, but you can specify pagination parameters. + */ + @GET("users/{username}/watchlist/episodes") + Call> watchlistEpisodes( + @Nonnull @Path("username") UserSlug userSlug, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link #watchlistEpisodes(UserSlug, Extended)}, but you can specify pagination parameters and a sort order. + *

+ * The specified order will be sent in the X-Applied-Sort-By and X-Applied-Sort-How headers. + *

+ * Some sort_by options are VIP Only including imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, + * votes, imdb_votes, and tmdb_votes. If sent for a non VIP, the items will fall back to rank. + * + * @param sortBy Sort by a specific property. Possible values: rank, added, title, released , runtime, popularity, + * random, percentage, imdb_rating, tmdb_rating, rt_tomatometer, rt_audience, metascore, votes, + * imdb_votes, tmdb_votes, my_rating, watched, collected. + * @param sortHow Sort direction. Possible values: asc, desc. + */ + @GET("users/{username}/watchlist/episodes/{sort_by}/{sort_how}") + Call> watchlistEpisodes( + @Nonnull @Path("username") UserSlug userSlug, + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, @Query(value = "extended", encoded = true) Extended extended ); diff --git a/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java b/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java index 0aa7d905..13247b67 100644 --- a/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java +++ b/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java @@ -210,6 +210,7 @@ public void assertShowStats(Stats stats) { } protected static void assertSyncMovies(List movies, String type) { + assertThat(movies).isNotEmpty(); for (BaseMovie movie : movies) { assertThat(movie.movie).isNotNull(); switch (type) { @@ -319,6 +320,11 @@ public static void assertPaginationHeaders(Response response, int expectedPag assertThat(response.headers().get("X-Pagination-Limit")).isEqualTo(String.valueOf(expectedLimit)); } + public static void assertSortOrderHeaders(Response response, String expectedSortBy, String expectedSortHow) { + assertThat(response.headers().get("x-applied-sort-by")).isEqualTo(expectedSortBy); + assertThat(response.headers().get("x-applied-sort-how")).isEqualTo(expectedSortHow); + } + protected void assertAccessTokenResponse(Response response) { assertSuccessfulResponse(response); assertThat(response.body().access_token).isNotEmpty(); diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index ce924336..94522cca 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -464,20 +464,48 @@ public void test_watchlistMovies() throws IOException { assertSyncMovies(movies, "watchlist"); } + @Test + public void test_watchlistMovies_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistMovies(UserSlug.ME, 1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistMovies_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistMovies(UserSlug.ME, "title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_watchlistShows() throws IOException { - List shows = executeCall(getTrakt().users().watchlistShows(UserSlug.ME, - null)); + List shows = executeCall(getTrakt().users().watchlistShows(UserSlug.ME, null)); + assertThat(shows).isNotEmpty(); for (BaseShow show : shows) { assertThat(show.show).isNotNull(); assertThat(show.listed_at).isNotNull(); } } + @Test + public void test_watchlistShows_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistShows(UserSlug.ME, 1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistShows_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistShows(UserSlug.ME, "title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_watchlistSeasons() throws IOException { - List seasons = executeCall(getTrakt().users().watchlistSeasons(UserSlug.ME, - null)); + List seasons = executeCall(getTrakt().users().watchlistSeasons(UserSlug.ME, null)); + assertThat(seasons).isNotEmpty(); for (WatchlistedSeason season : seasons) { assertThat(season.season).isNotNull(); assertThat(season.show).isNotNull(); @@ -485,10 +513,24 @@ public void test_watchlistSeasons() throws IOException { } } + @Test + public void test_watchlistSeasons_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistSeasons(UserSlug.ME, 1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistSeasons_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistSeasons(UserSlug.ME, "title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_watchlistEpisodes() throws IOException { - List episodes = executeCall(getTrakt().users().watchlistEpisodes(UserSlug.ME, - null)); + List episodes = executeCall(getTrakt().users().watchlistEpisodes(UserSlug.ME, null)); + assertThat(episodes).isNotEmpty(); for (WatchlistedEpisode episode : episodes) { assertThat(episode.episode).isNotNull(); assertThat(episode.show).isNotNull(); @@ -496,6 +538,19 @@ public void test_watchlistEpisodes() throws IOException { } } + @Test + public void test_watchlistEpisodes_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistEpisodes(UserSlug.ME, 1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistEpisodes_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().users().watchlistEpisodes(UserSlug.ME, "title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } @Test public void test_watchedMovies() throws IOException { From 745359026b1da4e1344f8a940f627b7822908502 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 5 Feb 2026 14:13:14 +0100 Subject: [PATCH 16/20] Sync: add watchlist variants that support pagination and ordering --- .../uwetrottmann/trakt5/services/Sync.java | 101 ++++++++++++++++-- .../trakt5/services/SyncTest.java | 62 ++++++++++- 2 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index e71dbc09..1ba273a8 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -43,6 +43,7 @@ import retrofit2.http.Path; import retrofit2.http.Query; +import javax.annotation.Nonnull; import java.util.List; public interface Sync { @@ -431,47 +432,131 @@ Call deleteRatings( /** * OAuth Required *

- * Returns all items in a user's watchlist filtered by movies. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Like {@link Users#watchlistMovies(UserSlug, Extended)}. */ @GET("sync/watchlist/movies") Call> watchlistMovies( @Query(value = "extended", encoded = true) Extended extended ); + /** + * Like {@link Users#watchlistMovies(UserSlug, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/movies") + Call> watchlistMovies( + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link Users#watchlistMovies(UserSlug, String, String, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/movies/{sort_by}/{sort_how}") + Call> watchlistMovies( + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + /** * OAuth Required *

- * Returns all items in a user's watchlist filtered by shows. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Like {@link Users#watchlistShows(UserSlug, Extended)}. */ @GET("sync/watchlist/shows") Call> watchlistShows( @Query(value = "extended", encoded = true) Extended extended ); + /** + * Like {@link Users#watchlistShows(UserSlug, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/shows") + Call> watchlistShows( + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link Users#watchlistShows(UserSlug, String, String, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/shows/{sort_by}/{sort_how}") + Call> watchlistShows( + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + /** * OAuth Required *

- * Returns all items in a user's watchlist filtered by seasons. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Like {@link Users#watchlistSeasons(UserSlug, Extended)}. */ @GET("sync/watchlist/seasons") Call> watchlistSeasons( @Query(value = "extended", encoded = true) Extended extended ); + /** + * Like {@link Users#watchlistSeasons(UserSlug, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/seasons") + Call> watchlistSeasons( + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link Users#watchlistSeasons(UserSlug, String, String, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/seasons/{sort_by}/{sort_how}") + Call> watchlistSeasons( + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + /** * OAuth Required *

- * Returns all items in a user's watchlist filtered by episodes. When an item is watched, it will be automatically - * removed from the watchlist. To track what the user is actively watching, use the progress APIs. + * Like {@link Users#watchlistEpisodes(UserSlug, Extended)}. */ @GET("sync/watchlist/episodes") Call> watchlistEpisodes( @Query(value = "extended", encoded = true) Extended extended ); + /** + * Like {@link Users#watchlistEpisodes(UserSlug, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/episodes") + Call> watchlistEpisodes( + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + + /** + * Like {@link Users#watchlistEpisodes(UserSlug, String, String, Integer, Integer, Extended)}. + */ + @GET("sync/watchlist/episodes/{sort_by}/{sort_how}") + Call> watchlistEpisodes( + @Nonnull @Path("sort_by") String sortBy, + @Nonnull @Path("sort_how") String sortHow, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + /** * OAuth Required *

diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index cdd15d83..bb4f5778 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -529,20 +529,48 @@ public void test_watchlistMovies() throws IOException { assertSyncMovies(movies, "watchlist"); } + @Test + public void test_watchlistMovies_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistMovies(1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistMovies_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistMovies("title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_watchlistShows() throws IOException { List shows = executeCall(getTrakt().sync().watchlistShows(null)); - assertThat(shows).isNotNull(); + assertThat(shows).isNotEmpty(); for (BaseShow show : shows) { assertThat(show.show).isNotNull(); assertThat(show.listed_at).isNotNull(); } } + @Test + public void test_watchlistShows_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistShows(1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistShows_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistShows("title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_watchlistSeasons() throws IOException { List seasons = executeCall(getTrakt().sync().watchlistSeasons(null)); - assertThat(seasons).isNotNull(); + assertThat(seasons).isNotEmpty(); for (WatchlistedSeason season : seasons) { assertThat(season.season).isNotNull(); assertThat(season.show).isNotNull(); @@ -550,10 +578,24 @@ public void test_watchlistSeasons() throws IOException { } } + @Test + public void test_watchlistSeasons_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistSeasons(1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistSeasons_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistSeasons("title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_watchlistEpisodes() throws IOException { List episodes = executeCall(getTrakt().sync().watchlistEpisodes(null)); - assertThat(episodes).isNotNull(); + assertThat(episodes).isNotEmpty(); for (WatchlistedEpisode episode : episodes) { assertThat(episode.episode).isNotNull(); assertThat(episode.show).isNotNull(); @@ -561,6 +603,20 @@ public void test_watchlistEpisodes() throws IOException { } } + @Test + public void test_watchlistEpisodes_pagination() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistEpisodes(1, 10, null)); + assertPaginationHeaders(response, 1, 10); + } + + @Test + public void test_watchlistEpisodes_sortOrder() throws IOException { + Response> response = executeCallWithoutReadingBody( + getTrakt().sync().watchlistEpisodes("title", "asc", null, null, null)); + assertSortOrderHeaders(response, "title", "asc"); + } + @Test public void test_addItemsToWatchlist_movie() throws IOException { SyncMovie movie = new SyncMovie(); From 838608c183c02a9d4dbf5d299d512013bb924a60 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 5 Feb 2026 14:26:57 +0100 Subject: [PATCH 17/20] SyncTest and UserTest: re-use assertions for watchlist items --- .../com/uwetrottmann/trakt5/BaseTestCase.java | 28 +++++++++++++++++++ .../trakt5/services/SyncTest.java | 20 ++----------- .../trakt5/services/UsersTest.java | 20 ++----------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java b/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java index 13247b67..b1f48e8b 100644 --- a/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java +++ b/src/test/java/com/uwetrottmann/trakt5/BaseTestCase.java @@ -32,6 +32,8 @@ import com.uwetrottmann.trakt5.entities.Ratings; import com.uwetrottmann.trakt5.entities.Stats; import com.uwetrottmann.trakt5.entities.TraktError; +import com.uwetrottmann.trakt5.entities.WatchlistedEpisode; +import com.uwetrottmann.trakt5.entities.WatchlistedSeason; import com.uwetrottmann.trakt5.enums.Type; import okhttp3.OkHttpClient; import okhttp3.logging.HttpLoggingInterceptor; @@ -256,6 +258,32 @@ protected static void assertSyncShows(List shows, String type) { } } + public static void assertWatchlistShows(List shows) { + assertThat(shows).isNotEmpty(); + for (BaseShow show : shows) { + assertThat(show.show).isNotNull(); + assertThat(show.listed_at).isNotNull(); + } + } + + public static void assertWatchlistSeasons(List seasons) { + assertThat(seasons).isNotEmpty(); + for (WatchlistedSeason season : seasons) { + assertThat(season.season).isNotNull(); + assertThat(season.show).isNotNull(); + assertThat(season.listed_at).isNotNull(); + } + } + + public static void assertWatchlistEpisodes(List episodes) { + assertThat(episodes).isNotEmpty(); + for (WatchlistedEpisode episode : episodes) { + assertThat(episode.episode).isNotNull(); + assertThat(episode.show).isNotNull(); + assertThat(episode.listed_at).isNotNull(); + } + } + public void assertCast(Credits credits, Type type) { for (CastMember castMember : credits.cast) { assertThat(castMember.character).isNotNull(); diff --git a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java index bb4f5778..85a06f8d 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/SyncTest.java @@ -546,11 +546,7 @@ public void test_watchlistMovies_sortOrder() throws IOException { @Test public void test_watchlistShows() throws IOException { List shows = executeCall(getTrakt().sync().watchlistShows(null)); - assertThat(shows).isNotEmpty(); - for (BaseShow show : shows) { - assertThat(show.show).isNotNull(); - assertThat(show.listed_at).isNotNull(); - } + assertWatchlistShows(shows); } @Test @@ -570,12 +566,7 @@ public void test_watchlistShows_sortOrder() throws IOException { @Test public void test_watchlistSeasons() throws IOException { List seasons = executeCall(getTrakt().sync().watchlistSeasons(null)); - assertThat(seasons).isNotEmpty(); - for (WatchlistedSeason season : seasons) { - assertThat(season.season).isNotNull(); - assertThat(season.show).isNotNull(); - assertThat(season.listed_at).isNotNull(); - } + assertWatchlistSeasons(seasons); } @Test @@ -595,12 +586,7 @@ public void test_watchlistSeasons_sortOrder() throws IOException { @Test public void test_watchlistEpisodes() throws IOException { List episodes = executeCall(getTrakt().sync().watchlistEpisodes(null)); - assertThat(episodes).isNotEmpty(); - for (WatchlistedEpisode episode : episodes) { - assertThat(episode.episode).isNotNull(); - assertThat(episode.show).isNotNull(); - assertThat(episode.listed_at).isNotNull(); - } + assertWatchlistEpisodes(episodes); } @Test diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index 94522cca..97deb739 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -481,11 +481,7 @@ public void test_watchlistMovies_sortOrder() throws IOException { @Test public void test_watchlistShows() throws IOException { List shows = executeCall(getTrakt().users().watchlistShows(UserSlug.ME, null)); - assertThat(shows).isNotEmpty(); - for (BaseShow show : shows) { - assertThat(show.show).isNotNull(); - assertThat(show.listed_at).isNotNull(); - } + assertWatchlistShows(shows); } @Test @@ -505,12 +501,7 @@ public void test_watchlistShows_sortOrder() throws IOException { @Test public void test_watchlistSeasons() throws IOException { List seasons = executeCall(getTrakt().users().watchlistSeasons(UserSlug.ME, null)); - assertThat(seasons).isNotEmpty(); - for (WatchlistedSeason season : seasons) { - assertThat(season.season).isNotNull(); - assertThat(season.show).isNotNull(); - assertThat(season.listed_at).isNotNull(); - } + assertWatchlistSeasons(seasons); } @Test @@ -530,12 +521,7 @@ public void test_watchlistSeasons_sortOrder() throws IOException { @Test public void test_watchlistEpisodes() throws IOException { List episodes = executeCall(getTrakt().users().watchlistEpisodes(UserSlug.ME, null)); - assertThat(episodes).isNotEmpty(); - for (WatchlistedEpisode episode : episodes) { - assertThat(episode.episode).isNotNull(); - assertThat(episode.show).isNotNull(); - assertThat(episode.listed_at).isNotNull(); - } + assertWatchlistEpisodes(episodes); } @Test From 4d1144b6da6753015474ec0af3f7c8354ef894f7 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 5 Feb 2026 14:41:57 +0100 Subject: [PATCH 18/20] Maven: set release instead of source and target Fixes "bootstrap class path not set in conjunction with -source 8" warning. --- pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2d4bf50e..9e1dcee1 100644 --- a/pom.xml +++ b/pom.xml @@ -132,8 +132,7 @@ maven-compiler-plugin 3.14.1 - 1.8 - 1.8 + 8 From efc68215de34041e94362739785d7ad777797e6f Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 5 Feb 2026 14:52:49 +0100 Subject: [PATCH 19/20] Docs: be specific an access token is required/optional, link API to set --- .../trakt5/services/Calendars.java | 9 +-- .../uwetrottmann/trakt5/services/Checkin.java | 7 +- .../trakt5/services/Comments.java | 13 ++-- .../uwetrottmann/trakt5/services/Notes.java | 9 +-- .../trakt5/services/Recommendations.java | 9 +-- .../trakt5/services/Scrobble.java | 7 +- .../uwetrottmann/trakt5/services/Shows.java | 5 +- .../uwetrottmann/trakt5/services/Sync.java | 65 ++++++++--------- .../uwetrottmann/trakt5/services/Users.java | 71 ++++++++++--------- 9 files changed, 102 insertions(+), 93 deletions(-) diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Calendars.java b/src/main/java/com/uwetrottmann/trakt5/services/Calendars.java index 4caa17d3..f3892ef8 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Calendars.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Calendars.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.CalendarMovieEntry; import com.uwetrottmann.trakt5.entities.CalendarShowEntry; import retrofit2.Call; @@ -27,7 +28,7 @@ public interface Calendars { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required * * @see #shows(String, int) */ @@ -38,7 +39,7 @@ Call> myShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required * * @see #newShows(String, int) */ @@ -49,7 +50,7 @@ Call> myNewShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required * * @see #seasonPremieres(String, int) */ @@ -60,7 +61,7 @@ Call> mySeasonPremieres( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required * * @see #movies(String, int) */ diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Checkin.java b/src/main/java/com/uwetrottmann/trakt5/services/Checkin.java index bdec1cb5..05ef01d9 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Checkin.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Checkin.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.EpisodeCheckin; import com.uwetrottmann.trakt5.entities.EpisodeCheckinResponse; import com.uwetrottmann.trakt5.entities.MovieCheckin; @@ -28,7 +29,7 @@ public interface Checkin { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Check into an episode. This should be tied to a user action to manually indicate they are watching something. The * item will display as watching on the site, then automatically switch to watched status once the duration has @@ -40,7 +41,7 @@ Call checkin( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Check into a movie. This should be tied to a user action to manually indicate they are watching something. The * item will display as watching on the site, then automatically switch to watched status once the duration has @@ -52,7 +53,7 @@ Call checkin( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Removes any active checkins, no need to provide a specific item. */ diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Comments.java b/src/main/java/com/uwetrottmann/trakt5/services/Comments.java index 2d7681f0..e7d43090 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Comments.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Comments.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.Comment; import retrofit2.Call; import retrofit2.http.Body; @@ -30,7 +31,7 @@ public interface Comments { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add a new comment to a movie, show, episode, or list. If you add a review, it needs to be at least 200 words. * Also make sure to allow and encourage spoilers to be indicated in your app. @@ -44,7 +45,7 @@ Call post( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns a single comment and indicates how many replies it has. Use GET /comments/:id/replies to get the actual * replies. @@ -57,7 +58,7 @@ Call get( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Update a single comment created within the last hour. The OAuth user must match the author of the comment in * order to update it. @@ -72,7 +73,7 @@ Call update( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Delete a single comment created within the last hour. This also effectively removes any replies this comment has. * The OAuth user must match the author of the comment in order to delete it. @@ -85,7 +86,7 @@ Call delete( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns all replies for a comment. It is possible these replies could have replies themselves, so in that case * you would just call GET /comment/:id/replies again with the new comment_id. @@ -98,7 +99,7 @@ Call> replies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add a new reply to an existing comment. Also make sure to allow and encourage spoilers to be indicated in your * app. diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Notes.java b/src/main/java/com/uwetrottmann/trakt5/services/Notes.java index fc9135e9..c397d4d9 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Notes.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Notes.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.AddNoteRequest; import com.uwetrottmann.trakt5.entities.Note; import com.uwetrottmann.trakt5.entities.UpdateNoteRequest; @@ -30,7 +31,7 @@ public interface Notes { /** - * VIP Only, OAuth Required + * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required *

* Add a note (maximum 500 characters). Note: this also replaces an existing note. *

@@ -42,7 +43,7 @@ Call addNote( ); /** - * VIP Only, OAuth Required + * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required *

* Get a note. *

@@ -54,7 +55,7 @@ Call getNote( ); /** - * VIP Only, OAuth Required + * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required *

* Update a note (maximum 500 characters). *

@@ -67,7 +68,7 @@ Call updateNote( ); /** - * VIP Only, OAuth Required + * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required *

* Delete a note. *

diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Recommendations.java b/src/main/java/com/uwetrottmann/trakt5/services/Recommendations.java index d548b2e9..bdda1c41 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Recommendations.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Recommendations.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.Movie; import com.uwetrottmann.trakt5.entities.Show; import com.uwetrottmann.trakt5.enums.Extended; @@ -30,7 +31,7 @@ public interface Recommendations { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Personalized movie recommendations for a user. Results returned with the top recommendation first. * @@ -45,7 +46,7 @@ Call> movies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Dismiss a movie from getting recommended anymore. * @@ -57,7 +58,7 @@ Call dismissMovie( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Personalized show recommendations for a user. Results returned with the top recommendation first. * @@ -72,7 +73,7 @@ Call> shows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Dismiss a show from getting recommended anymore. * diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Scrobble.java b/src/main/java/com/uwetrottmann/trakt5/services/Scrobble.java index 440b09ca..e1afb0cd 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Scrobble.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Scrobble.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.PlaybackResponse; import com.uwetrottmann.trakt5.entities.ScrobbleProgress; import retrofit2.Call; @@ -24,7 +25,7 @@ public interface Scrobble { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* User starts a video */ @@ -34,7 +35,7 @@ Call startWatching( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* User pauses a video */ @@ -44,7 +45,7 @@ Call pauseWatching( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* User stops a video */ diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Shows.java b/src/main/java/com/uwetrottmann/trakt5/services/Shows.java index a3eb79d6..29d1f1a9 100755 --- a/src/main/java/com/uwetrottmann/trakt5/services/Shows.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Shows.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.BaseShow; import com.uwetrottmann.trakt5.entities.Comment; import com.uwetrottmann.trakt5.entities.Credits; @@ -123,7 +124,7 @@ Call> comments( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns collection progress for show including details on all seasons and episodes. The {@code next_episode} will * be the next episode the user should collect, if there are no upcoming episodes it will be set to {@code null}. @@ -162,7 +163,7 @@ Call collectedProgress( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns watched progress for show including details on all seasons and episodes. The {@code next_episode} will be * the next episode the user should watch, if there are no upcoming episodes it will be set to {@code null}. If not diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java index 1ba273a8..f5c902f0 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Sync.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Sync.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.BaseMovie; import com.uwetrottmann.trakt5.entities.BaseShow; import com.uwetrottmann.trakt5.entities.HistoryEntry; @@ -49,7 +50,7 @@ public interface Sync { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* This method is a useful first step in the syncing process. We recommended caching these dates locally, then you * can compare to know exactly what data has changed recently. This can greatly optimize your syncs so you don't @@ -59,7 +60,7 @@ public interface Sync { Call lastActivities(); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get all movies in a user's library (formerly collection). A collected item indicates availability to watch * digitally or on physical media. @@ -73,7 +74,7 @@ Call> collectionMovies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#collectionMovies(UserSlug, int, int, Extended)}. */ @@ -85,7 +86,7 @@ Call> collectionMovies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get all shows in a user's library (formerly collection). A collected item indicates availability to watch * digitally or on physical media. @@ -99,7 +100,7 @@ Call> collectionShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#collectionShows(UserSlug, int, int, Extended)}. */ @@ -111,7 +112,7 @@ Call> collectionShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add one or more items to a user's library (formerly collection) including the format of the item. * @@ -123,7 +124,7 @@ Call addItemsToCollection( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Remove one or more items from a user's library (formerly collection). * @@ -135,7 +136,7 @@ Call deleteItemsFromCollection( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns all movies a user has watched. */ @@ -145,7 +146,7 @@ Call> watchedMovies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Whenever a scrobble is paused, the playback progress is saved. Use this progress to sync up playback across * different media centers or apps. For example, you can start watching a movie in a media center, stop it, then @@ -170,7 +171,7 @@ Call> playback( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link #playback(OffsetDateTime, OffsetDateTime, Integer, Integer)}, but allows to specify a type to only * get movies or episodes. @@ -187,7 +188,7 @@ Call> playback( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns all playbacks; * @@ -200,7 +201,7 @@ Call> getPlayback( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns all playbacks; * @@ -213,7 +214,7 @@ Call> getPlaybackEpisodes( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns all playbacks; * @@ -226,7 +227,7 @@ Call> getPlaybackMovies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Remove a playback item from a user's playback progress list. A 404 will be returned if the id is invalid. *

@@ -239,7 +240,7 @@ Call removePlayback( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Returns all shows a user has watched. */ @@ -249,7 +250,7 @@ Call> watchedShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#history(UserSlug, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}. * @@ -265,7 +266,7 @@ Call> history( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link #history(Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}, but allows to set a type to * only return movies or episodes. @@ -284,7 +285,7 @@ Call> history( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like * {@link Users#history(UserSlug, HistoryType, int, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}. @@ -301,7 +302,7 @@ Call> history( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add items to a user's watch history. Accepts shows, seasons, episodes and movies. If only a show is passed, * assumes all seasons are to be marked watched. Same for seasons. Send a watched_at UTC datetime to @@ -315,7 +316,7 @@ Call addItemsToWatchedHistory( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Remove items from a user's watch history including all watches, scrobbles, and checkins. Accepts shows, seasons, * episodes and movies. If only a show is passed, assumes all seasons are to be removed from history. Same for @@ -329,7 +330,7 @@ Call deleteItemsFromWatchedHistory( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get a user's ratings filtered by movies. You can filter for a specific rating between 1 and 10. * @@ -348,7 +349,7 @@ Call> ratingsMovies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get a user's ratings filtered by shows. You can filter for a specific rating between 1 and 10. * @@ -367,7 +368,7 @@ Call> ratingsShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get a user's ratings filtered by seasons. You can filter for a specific rating between 1 and 10. * @@ -386,7 +387,7 @@ Call> ratingsSeasons( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get a user's ratings filtered by episodes. You can filter for a specific rating between 1 and 10. * @@ -405,7 +406,7 @@ Call> ratingsEpisodes( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Rate one or more items. * @@ -417,7 +418,7 @@ Call addRatings( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Delete ratings for one or more items. * @@ -430,7 +431,7 @@ Call deleteRatings( /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#watchlistMovies(UserSlug, Extended)}. */ @@ -462,7 +463,7 @@ Call> watchlistMovies( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#watchlistShows(UserSlug, Extended)}. */ @@ -494,7 +495,7 @@ Call> watchlistShows( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#watchlistSeasons(UserSlug, Extended)}. */ @@ -526,7 +527,7 @@ Call> watchlistSeasons( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Like {@link Users#watchlistEpisodes(UserSlug, Extended)}. */ @@ -558,7 +559,7 @@ Call> watchlistEpisodes( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add one of more items to a user's watchlist. * @@ -570,7 +571,7 @@ Call addItemsToWatchlist( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Delete one or more items from a user's watchlist. * diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 12eb645e..38543709 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -16,6 +16,7 @@ package com.uwetrottmann.trakt5.services; +import com.uwetrottmann.trakt5.TraktV2; import com.uwetrottmann.trakt5.entities.BaseMovie; import com.uwetrottmann.trakt5.entities.BaseShow; import com.uwetrottmann.trakt5.entities.Followed; @@ -57,7 +58,7 @@ public interface Users { /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get the user's settings so you can align your app's experience with what they're used to on the Trakt website. */ @@ -65,7 +66,7 @@ public interface Users { Call settings(); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get a user's profile information. If the user is private, info will only be returned if you send OAuth and are * either that user or an approved follower. @@ -79,7 +80,7 @@ Call profile( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get all movies in a user's library (formerly collection). A collected item indicates availability to watch * digitally or on physical media. @@ -95,7 +96,7 @@ Call> collectionMovies( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get all movies in a user's library (formerly collection). * @@ -113,7 +114,7 @@ Call> collectionMovies( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get all shows in a user's library (formerly collection). A collected item indicates availability to watch * digitally or on physical media. @@ -129,7 +130,7 @@ Call> collectionShows( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get all shows in a user's library (formerly collection). * @@ -147,7 +148,7 @@ Call> collectionShows( ); /** - * VIP Only, OAuth Optional + * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns the most recently added notes for the user. *

@@ -163,7 +164,7 @@ Call> notes( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all custom lists for a user. */ @@ -173,7 +174,7 @@ Call> lists( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Create a new custom list. The name is the only required field, but the other info is recommended to ask for. */ @@ -184,7 +185,7 @@ Call createList( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Update a custom list by sending 1 or more parameters. If you update the list name, the original slug will still * be retained so existing references to this list won't break. @@ -197,7 +198,7 @@ Call updateList( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Remove a custom list and all items it contains. */ @@ -208,7 +209,7 @@ Call deleteList( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Reorder all custom lists by sending the updated rank of list ids. */ @@ -219,7 +220,7 @@ Call reorderLists( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get all items on a custom list. Items can be movies, shows, seasons, episodes, or people. * @@ -234,7 +235,7 @@ Call> listItems( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get all items on a personal list. Items can be a movie, show, season, episode, or person. Use * {@link #listItems(UserSlug, String, String, int, int, Extended)} to specify the type parameter with a single @@ -323,7 +324,7 @@ Call> listItems( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add one or more items to a custom list. Items can be movies, shows, seasons, episodes, or people. */ @@ -335,7 +336,7 @@ Call addListItems( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Remove one or more items from a custom list. */ @@ -347,7 +348,7 @@ Call deleteListItems( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Reorder all items on a list by sending the updated rank of list item ids. */ @@ -359,7 +360,7 @@ Call reorderListItems( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* If the user has a private profile, the follow request will require approval (approved_at will be null). If a user * is public, they will be followed immediately (approved_at will have a date). @@ -372,7 +373,7 @@ Call follow( ); /** - * OAuth Required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Unfollow someone you already follow. */ @@ -382,7 +383,7 @@ Call unfollow( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all followers including when the relationship began. */ @@ -393,7 +394,7 @@ Call> followers( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all user's they follow including when the relationship began. */ @@ -404,7 +405,7 @@ Call> following( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all friends for a user including when the relationship began. Friendship is a 2 way relationship where * each user follows the other. @@ -416,7 +417,7 @@ Call> friends( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns movies and episodes that a user has watched, sorted by most recent. *

@@ -438,7 +439,7 @@ Call> history( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Like {@link #history(UserSlug, Integer, Integer, Extended, OffsetDateTime, OffsetDateTime)}, but allows to set a * type to only return movies or episodes. @@ -458,7 +459,7 @@ Call> history( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns the history for just the specified item. For example, {@code /history/movies/12601} would return all * watches for TRON: Legacy and {@code /history/shows/1388} would return all watched episodes for Breaking Bad. If @@ -485,7 +486,7 @@ Call> history( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get a user's ratings filtered by movies. You can filter for a specific rating between 1 and 10. * @@ -500,7 +501,7 @@ Call> ratingsMovies( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get a user's ratings filtered by shows. You can filter for a specific rating between 1 and 10. * @@ -515,7 +516,7 @@ Call> ratingsShows( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get a user's ratings filtered by seasons. You can filter for a specific rating between 1 and 10. * @@ -530,7 +531,7 @@ Call> ratingsSeasons( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Get a user's ratings filtered by episodes. You can filter for a specific rating between 1 and 10. * @@ -545,7 +546,7 @@ Call> ratingsEpisodes( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all items in a user's watchlist filtered by movies. *

@@ -600,7 +601,7 @@ Call> watchlistMovies( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all items in a user's watchlist filtered by shows. *

@@ -655,7 +656,7 @@ Call> watchlistShows( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all items in a user's watchlist filtered by seasons. *

@@ -710,7 +711,7 @@ Call> watchlistSeasons( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all items in a user's watchlist filtered by episodes. *

@@ -765,7 +766,7 @@ Call> watchlistEpisodes( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all movies or shows a user has watched sorted by most plays. * @@ -778,7 +779,7 @@ Call> watchedMovies( ); /** - * OAuth Optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns all movies or shows a user has watched sorted by most plays. * From a681bd6fe636bc61724afbd2097b01ea02626a9b Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 5 Feb 2026 14:55:47 +0100 Subject: [PATCH 20/20] Notes are no longer VIP only --- src/main/java/com/uwetrottmann/trakt5/services/Notes.java | 8 ++++---- src/main/java/com/uwetrottmann/trakt5/services/Users.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Notes.java b/src/main/java/com/uwetrottmann/trakt5/services/Notes.java index c397d4d9..5e544107 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Notes.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Notes.java @@ -31,7 +31,7 @@ public interface Notes { /** - * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Add a note (maximum 500 characters). Note: this also replaces an existing note. *

@@ -43,7 +43,7 @@ Call addNote( ); /** - * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Get a note. *

@@ -55,7 +55,7 @@ Call getNote( ); /** - * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Update a note (maximum 500 characters). *

@@ -68,7 +68,7 @@ Call updateNote( ); /** - * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} required + * OAuth {@link TraktV2#accessToken(String) access token} required *

* Delete a note. *

diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index 38543709..0edb0c1f 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -148,7 +148,7 @@ Call> collectionShows( ); /** - * VIP Only, OAuth {@link TraktV2#accessToken(String) access token} optional + * OAuth {@link TraktV2#accessToken(String) access token} optional *

* Returns the most recently added notes for the user. *