From 6f9721f30920b9da339442f516f59964a2331784 Mon Sep 17 00:00:00 2001 From: Uwe Trottmann Date: Thu, 29 Aug 2024 11:14:40 +0200 Subject: [PATCH] Support notes (VIP only) --- CHANGELOG.md | 2 + .../java/com/uwetrottmann/trakt5/TraktV2.java | 5 ++ .../trakt5/entities/AddNoteRequest.java | 59 ++++++++++++++ .../uwetrottmann/trakt5/entities/Note.java | 32 ++++++++ .../trakt5/entities/NoteAttachedTo.java | 33 ++++++++ .../trakt5/entities/NoteResponse.java | 30 +++++++ .../trakt5/entities/UpdateNoteRequest.java | 42 ++++++++++ .../uwetrottmann/trakt5/enums/NoteType.java | 40 ++++++++++ .../uwetrottmann/trakt5/enums/Privacy.java | 31 +++++++ .../uwetrottmann/trakt5/services/Notes.java | 80 +++++++++++++++++++ .../uwetrottmann/trakt5/services/Users.java | 18 +++++ .../trakt5/services/NotesTest.java | 64 +++++++++++++++ .../trakt5/services/UsersTest.java | 27 +++++++ 13 files changed, 463 insertions(+) create mode 100644 src/main/java/com/uwetrottmann/trakt5/entities/AddNoteRequest.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/entities/Note.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/entities/NoteAttachedTo.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/entities/NoteResponse.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/entities/UpdateNoteRequest.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/enums/NoteType.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/enums/Privacy.java create mode 100644 src/main/java/com/uwetrottmann/trakt5/services/Notes.java create mode 100644 src/test/java/com/uwetrottmann/trakt5/services/NotesTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 07a6cf20..e74f417c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ Change Log ## next +* `TraktV2.notes()`: support to add, get, update and delete a note. +* `TraktV2.users().notes(...)`: Support to get all notes for a user. * Add `Sync.removePlayback(id)`. ## 6.14.0 diff --git a/src/main/java/com/uwetrottmann/trakt5/TraktV2.java b/src/main/java/com/uwetrottmann/trakt5/TraktV2.java index eabb85cd..5812b8b2 100644 --- a/src/main/java/com/uwetrottmann/trakt5/TraktV2.java +++ b/src/main/java/com/uwetrottmann/trakt5/TraktV2.java @@ -32,6 +32,7 @@ import com.uwetrottmann.trakt5.services.Episodes; import com.uwetrottmann.trakt5.services.Genres; import com.uwetrottmann.trakt5.services.Movies; +import com.uwetrottmann.trakt5.services.Notes; import com.uwetrottmann.trakt5.services.People; import com.uwetrottmann.trakt5.services.Recommendations; import com.uwetrottmann.trakt5.services.Scrobble; @@ -448,6 +449,10 @@ public Movies movies() { return retrofit().create(Movies.class); } + public Notes notes() { + return retrofit().create(Notes.class); + } + public People people() { return retrofit().create(People.class); } diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/AddNoteRequest.java b/src/main/java/com/uwetrottmann/trakt5/entities/AddNoteRequest.java new file mode 100644 index 00000000..01cb6eb3 --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/entities/AddNoteRequest.java @@ -0,0 +1,59 @@ +/* + * Copyright 2024 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.entities; + +import javax.annotation.Nonnull; + +public class AddNoteRequest extends UpdateNoteRequest { + + public NoteAttachedTo attached_to; + public Movie movie; + public Show show; + public Season season; + public Episode episode; + public Person person; + + public AddNoteRequest(@Nonnull Movie movie, @Nonnull String notes) { + super(notes); + this.movie = movie; + } + + public AddNoteRequest(@Nonnull Show show, @Nonnull String notes) { + super(notes); + this.show = show; + } + + public AddNoteRequest(@Nonnull Season season, @Nonnull String notes) { + super(notes); + this.season = season; + } + + public AddNoteRequest(@Nonnull Episode episode, @Nonnull String notes) { + super(notes); + this.episode = episode; + } + + public AddNoteRequest(@Nonnull Person person, @Nonnull String notes) { + super(notes); + this.person = person; + } + + public AddNoteRequest setAttachedTo(NoteAttachedTo attachedTo) { + this.attached_to = attachedTo; + return this; + } +} diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/Note.java b/src/main/java/com/uwetrottmann/trakt5/entities/Note.java new file mode 100644 index 00000000..9dec0f73 --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/entities/Note.java @@ -0,0 +1,32 @@ +/* + * Copyright 2024 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.entities; + +import com.uwetrottmann.trakt5.enums.Privacy; +import org.threeten.bp.OffsetDateTime; + +public class Note { + + public long id; + public String notes; + public Privacy privacy; + public boolean spoiler; + public OffsetDateTime created_at; + public OffsetDateTime updated_at; + public User user; + +} diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/NoteAttachedTo.java b/src/main/java/com/uwetrottmann/trakt5/entities/NoteAttachedTo.java new file mode 100644 index 00000000..834b5a2d --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/entities/NoteAttachedTo.java @@ -0,0 +1,33 @@ +/* + * Copyright 2024 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.entities; + +import com.uwetrottmann.trakt5.enums.NoteType; + +public class NoteAttachedTo { + public NoteType type; + public Long id; + + public NoteAttachedTo(NoteType type) { + this.type = type; + } + + public NoteAttachedTo(long id) { + this.type = NoteType.HISTORY; + this.id = id; + } +} diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/NoteResponse.java b/src/main/java/com/uwetrottmann/trakt5/entities/NoteResponse.java new file mode 100644 index 00000000..76ff8755 --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/entities/NoteResponse.java @@ -0,0 +1,30 @@ +/* + * Copyright 2024 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.entities; + +public class NoteResponse { + + public NoteAttachedTo attached_to; + public String type; + public Movie movie; + public Show show; + public Season season; + public Episode episode; + public Person person; + public Note note; + +} diff --git a/src/main/java/com/uwetrottmann/trakt5/entities/UpdateNoteRequest.java b/src/main/java/com/uwetrottmann/trakt5/entities/UpdateNoteRequest.java new file mode 100644 index 00000000..18c22b4c --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/entities/UpdateNoteRequest.java @@ -0,0 +1,42 @@ +/* + * Copyright 2024 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.entities; + +import com.uwetrottmann.trakt5.enums.Privacy; + +import javax.annotation.Nonnull; + +public class UpdateNoteRequest { + + String notes; + Boolean spoiler; + Privacy privacy; + + public UpdateNoteRequest(@Nonnull String notes) { + this.notes = notes; + } + + public UpdateNoteRequest setSpoiler(boolean spoiler) { + this.spoiler = spoiler; + return this; + } + + public UpdateNoteRequest setPrivacy(@Nonnull Privacy privacy) { + this.privacy = privacy; + return this; + } +} diff --git a/src/main/java/com/uwetrottmann/trakt5/enums/NoteType.java b/src/main/java/com/uwetrottmann/trakt5/enums/NoteType.java new file mode 100644 index 00000000..b968a829 --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/enums/NoteType.java @@ -0,0 +1,40 @@ +/* + * Copyright 2024 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; + +import com.google.gson.annotations.SerializedName; + +public enum NoteType { + + @SerializedName("movie") + MOVIE, + @SerializedName("show") + SHOW, + @SerializedName("season") + SEASON, + @SerializedName("episode") + EPISODE, + @SerializedName("person") + PERSON, + @SerializedName("history") + HISTORY, + @SerializedName("collection") + COLLECTION, + @SerializedName("rating") + RATING + +} diff --git a/src/main/java/com/uwetrottmann/trakt5/enums/Privacy.java b/src/main/java/com/uwetrottmann/trakt5/enums/Privacy.java new file mode 100644 index 00000000..cdac2dde --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/enums/Privacy.java @@ -0,0 +1,31 @@ +/* + * Copyright 2024 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; + +import com.google.gson.annotations.SerializedName; + +public enum Privacy { + + @SerializedName("private") + PRIVATE, + + @SerializedName("friends") + FRIENDS, + + @SerializedName("public") + PUBLIC +} diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Notes.java b/src/main/java/com/uwetrottmann/trakt5/services/Notes.java new file mode 100644 index 00000000..fc9135e9 --- /dev/null +++ b/src/main/java/com/uwetrottmann/trakt5/services/Notes.java @@ -0,0 +1,80 @@ +/* + * Copyright 2024 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.AddNoteRequest; +import com.uwetrottmann.trakt5.entities.Note; +import com.uwetrottmann.trakt5.entities.UpdateNoteRequest; +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.DELETE; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.PUT; +import retrofit2.http.Path; + +public interface Notes { + + /** + * VIP Only, OAuth Required + *

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

+ * Online documentation + */ + @POST("notes") + Call addNote( + @Body AddNoteRequest request + ); + + /** + * VIP Only, OAuth Required + *

+ * Get a note. + *

+ * Online documentation + */ + @GET("notes/{id}") + Call getNote( + @Path("id") long id + ); + + /** + * VIP Only, OAuth Required + *

+ * Update a note (maximum 500 characters). + *

+ * Online documentation + */ + @PUT("notes/{id}") + Call updateNote( + @Path("id") long id, + @Body UpdateNoteRequest request + ); + + /** + * VIP Only, OAuth Required + *

+ * Delete a note. + *

+ * Online documentation + */ + @DELETE("notes/{id}") + Call deleteNote( + @Path("id") long id + ); +} diff --git a/src/main/java/com/uwetrottmann/trakt5/services/Users.java b/src/main/java/com/uwetrottmann/trakt5/services/Users.java index d8cdb7d3..8eaf9995 100644 --- a/src/main/java/com/uwetrottmann/trakt5/services/Users.java +++ b/src/main/java/com/uwetrottmann/trakt5/services/Users.java @@ -25,6 +25,7 @@ import com.uwetrottmann.trakt5.entities.ListEntry; import com.uwetrottmann.trakt5.entities.ListItemRank; import com.uwetrottmann.trakt5.entities.ListReorderResponse; +import com.uwetrottmann.trakt5.entities.NoteResponse; import com.uwetrottmann.trakt5.entities.RatedEpisode; import com.uwetrottmann.trakt5.entities.RatedMovie; import com.uwetrottmann.trakt5.entities.RatedSeason; @@ -39,6 +40,7 @@ import com.uwetrottmann.trakt5.entities.WatchlistedSeason; import com.uwetrottmann.trakt5.enums.Extended; import com.uwetrottmann.trakt5.enums.HistoryType; +import com.uwetrottmann.trakt5.enums.NoteType; import com.uwetrottmann.trakt5.enums.RatingsFilter; import org.threeten.bp.OffsetDateTime; import retrofit2.Call; @@ -105,6 +107,22 @@ Call> collectionShows( @Query(value = "extended", encoded = true) Extended extended ); + /** + * VIP Only, OAuth Optional + *

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

+ * Online documentation + */ + @GET("users/{username}/notes/{type}") + Call> notes( + @Path("username") UserSlug userSlug, + @Path("type") String type, + @Query("page") Integer page, + @Query("limit") Integer limit, + @Query(value = "extended", encoded = true) Extended extended + ); + /** * OAuth Optional * diff --git a/src/test/java/com/uwetrottmann/trakt5/services/NotesTest.java b/src/test/java/com/uwetrottmann/trakt5/services/NotesTest.java new file mode 100644 index 00000000..aa6a876b --- /dev/null +++ b/src/test/java/com/uwetrottmann/trakt5/services/NotesTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2024 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.BaseTestCase; +import com.uwetrottmann.trakt5.TestData; +import com.uwetrottmann.trakt5.entities.AddNoteRequest; +import com.uwetrottmann.trakt5.entities.Note; +import com.uwetrottmann.trakt5.entities.Show; +import com.uwetrottmann.trakt5.entities.ShowIds; +import com.uwetrottmann.trakt5.entities.UpdateNoteRequest; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +public class NotesTest extends BaseTestCase { + + @Test + public void note_addGetUpdateDelete() throws Exception { + Notes notes = getTrakt().notes(); + + // Add note + // Note: an existing note is overwritten, so no need to delete before this test + Show show = new Show(); + show.ids = ShowIds.trakt(TestData.SHOW_TRAKT_ID); + Note note = executeCall(notes.addNote(new AddNoteRequest(show, "A very good show! ❤"))); + assertThat(note.id).isPositive(); + // Note: Trakt replaces emoji with shortcodes :( + // https://trakt.docs.apiary.io/#introduction/emojis + assertThat(note.notes).isEqualTo("A very good show! :heart:"); + + Thread.sleep(500); // Give server time to update state + + // Get note + Note readNote = executeCall(notes.getNote(note.id)); + assertThat(readNote.id).isEqualTo(note.id); + + // Update note + String updatedText = "This note was updated!"; + Note updatedNote = executeCall(notes.updateNote(readNote.id, new UpdateNoteRequest(updatedText))); + assertThat(updatedNote.id).isEqualTo(readNote.id); + assertThat(updatedNote.notes).isEqualTo(updatedText); + + Thread.sleep(500); // Give server time to update state + + // Delete note + executeVoidCall(notes.deleteNote(updatedNote.id)); + } + +} diff --git a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java index e8576d73..1e590c03 100644 --- a/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java +++ b/src/test/java/com/uwetrottmann/trakt5/services/UsersTest.java @@ -28,6 +28,8 @@ import com.uwetrottmann.trakt5.entities.ListItemRank; import com.uwetrottmann.trakt5.entities.ListReorderResponse; import com.uwetrottmann.trakt5.entities.MovieIds; +import com.uwetrottmann.trakt5.entities.Note; +import com.uwetrottmann.trakt5.entities.NoteResponse; import com.uwetrottmann.trakt5.entities.PersonIds; import com.uwetrottmann.trakt5.entities.RatedEpisode; import com.uwetrottmann.trakt5.entities.RatedMovie; @@ -48,6 +50,7 @@ import com.uwetrottmann.trakt5.enums.Extended; import com.uwetrottmann.trakt5.enums.HistoryType; import com.uwetrottmann.trakt5.enums.ListPrivacy; +import com.uwetrottmann.trakt5.enums.NoteType; import com.uwetrottmann.trakt5.enums.Rating; import com.uwetrottmann.trakt5.enums.RatingsFilter; import com.uwetrottmann.trakt5.enums.SortBy; @@ -109,6 +112,30 @@ public void test_collectionShows() throws IOException { assertSyncShows(shows, "collection"); } + @Test + public void test_notes() throws IOException { + List allNotes = executeCall( + getTrakt().users().notes(UserSlug.ME, "all", null, null, Extended.FULL)); + assertThat(allNotes).isNotEmpty(); + for (NoteResponse noteResponse : allNotes) { + assertThat(noteResponse.attached_to).isNotNull(); + assertThat(noteResponse.attached_to.type).isNotNull(); + assertThat(noteResponse.note).isNotNull(); + assertThat(noteResponse.note.id).isPositive(); + assertThat(noteResponse.note.privacy).isNotNull(); + assertThat(noteResponse.note.notes).isNotEmpty(); + assertThat(noteResponse.note.user).isNotNull(); + } + + List showNotes = executeCall( + getTrakt().users().notes(UserSlug.ME, "shows", null, null, null)); + assertThat(showNotes).isNotEmpty(); + for (NoteResponse noteResponse : showNotes) { + assertThat(noteResponse.attached_to).isNotNull(); + assertThat(noteResponse.attached_to.type).isEqualTo(NoteType.SHOW); + } + } + @Test public void test_lists() throws IOException { List lists = executeCall(getTrakt().users().lists(UserSlug.ME));