aboutsummaryrefslogtreecommitdiff
path: root/user/manga
diff options
context:
space:
mode:
Diffstat (limited to 'user/manga')
-rw-r--r--user/manga/README.md19
-rw-r--r--user/manga/client.go23
-rw-r--r--user/manga/mangalist.go113
-rw-r--r--user/manga/mangalist.structs.go51
-rw-r--r--user/manga/request_handler.go96
-rw-r--r--user/manga/update_mangalist.go203
6 files changed, 505 insertions, 0 deletions
diff --git a/user/manga/README.md b/user/manga/README.md
new file mode 100644
index 0000000..1a6c636
--- /dev/null
+++ b/user/manga/README.md
@@ -0,0 +1,19 @@
+# MAL2Go/user
+MAL2Go `user/anime` package has functionality related to updating the user's anime list.
+
+## Usage
+Firstly, import this package and instanciate the client.
+``` go
+import (
+ "github.com/MikunoNaka/MAL2Go/user/anime"
+)
+```
+
+Now instanciate with
+``` go
+myClient := anime.Client {
+ AuthToken: "Bearer " + yourTokenHere,
+}
+```
+
+**More to be added later**
diff --git a/user/manga/client.go b/user/manga/client.go
new file mode 100644
index 0000000..272bfff
--- /dev/null
+++ b/user/manga/client.go
@@ -0,0 +1,23 @@
+/* MAL2Go - MyAnimeList V2 API wrapper for Go
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@protonmail.ch>
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+package manga
+
+import (
+ "github.com/MikunoNaka/MAL2Go/util"
+)
+
+type Client util.DefaultClient
diff --git a/user/manga/mangalist.go b/user/manga/mangalist.go
new file mode 100644
index 0000000..009a65c
--- /dev/null
+++ b/user/manga/mangalist.go
@@ -0,0 +1,113 @@
+/* MAL2Go - MyAnimeList V2 API wrapper for Go
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@protonmail.ch>
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+package manga
+
+import (
+ "encoding/json"
+ "strconv"
+ "fmt"
+ "errors"
+ e "github.com/MikunoNaka/MAL2Go/errhandlers"
+ u "github.com/MikunoNaka/MAL2Go/util"
+)
+
+const BASE_URL string = "https://api.myanimelist.net/v2"
+const maxListLimit int = 1000
+
+// Delete a manga from user's manga list
+func (c Client)DeleteManga(id int) string {
+ endpoint := fmt.Sprintf("%s/manga/%d/my_list_status", BASE_URL, id)
+ /* Returns 200 if manga successfully deleted
+ * Alternatively returns 404 if manga not in user's manga list */
+ return c.requestHandler(endpoint, "DELETE")
+}
+
+// Get authenticated user's manga list
+func (c Client) GetMangaList(user, status, sort string, limit, offset int, fields []string) (MangaList, error){
+ var userMangaList MangaList
+ // error handling for limit
+ limitErr := e.LimitErrHandler(limit, maxListLimit)
+ if limitErr != nil {
+ return userMangaList, limitErr
+ }
+
+ // handle all the errors for the fields
+ fields, err := e.FieldsErrHandler(fields)
+ if err != nil {
+ return userMangaList, err
+ }
+
+ // append "list_status" field only used by this func.
+ fields = append(fields, "list_status")
+
+ // checks if valid sort is specified
+ if !e.IsValidMangaListSort(sort) {
+ return userMangaList, errors.New(fmt.Sprintf("GetMangaList: Invalid sort specified: \"%s\"", sort))
+ }
+
+ // checks if valid status is specified
+ if status != "" && !e.IsValidMangaListStatus(status) {
+ return userMangaList, errors.New(fmt.Sprintf("GetMangaList: Invalid status specified: \"%s\"", status))
+ }
+
+ // get own list if user not specified
+ if user == "" {
+ user = "@me"
+ }
+
+ var endpoint string
+ // if status is "" it returns all anime
+ if status == "" {
+ endpoint, _ = u.UrlGenerator(
+ BASE_URL + "/users/" + user + "/mangalist",
+ []string{"sort", "limit", "offset", "fields"},
+ [][]string{{sort}, {strconv.Itoa(limit)}, {strconv.Itoa(offset)}, fields},
+ true,
+ )
+ } else {
+ // status gets included if specified
+ endpoint, _ = u.UrlGenerator(
+ BASE_URL + "/users/" + user + "/mangalist",
+ []string{"status", "sort", "limit", "offset", "fields"},
+ [][]string{{status}, {sort}, {strconv.Itoa(limit)}, {strconv.Itoa(offset)}, fields},
+ true,
+ )
+ }
+
+ // get data from API
+ var mangaListData MangaListRaw
+ data := c.requestHandler(endpoint, "GET")
+ json.Unmarshal([]byte(data), &mangaListData)
+
+ // set MyListStatus for each element and add it to array
+ var mangas []Manga
+ for _, element := range mangaListData.Data {
+ a := element.Manga
+ a.ListStatus = element.ListStatus
+
+ mangas = append(mangas, a)
+ }
+
+ // finally create AnimeList
+ userMangaList = MangaList {
+ Mangas: mangas,
+ Paging: mangaListData.Paging,
+ }
+
+ return userMangaList, nil
+}
+
diff --git a/user/manga/mangalist.structs.go b/user/manga/mangalist.structs.go
new file mode 100644
index 0000000..0ea7d70
--- /dev/null
+++ b/user/manga/mangalist.structs.go
@@ -0,0 +1,51 @@
+/* MAL2Go - MyAnimeList V2 API wrapper for Go
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@protonmail.ch>
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+package manga
+
+import (
+ "github.com/MikunoNaka/MAL2Go/util"
+ "github.com/MikunoNaka/MAL2Go/manga"
+)
+
+type Manga manga.Manga
+
+type MangaListRaw struct {
+ Data []struct {
+ Manga Manga `json:"node"`
+ ListStatus manga.ListStatus `json:"list_status"`
+ } `json:"data"`
+ Paging util.ListPaging `json:"paging"`
+}
+
+type MangaList struct {
+ Mangas []Manga
+ Paging util.ListPaging
+}
+
+type UpdateMangaData struct {
+ Status string
+ IsRereading bool
+ Score int
+ VolumesRead int
+ ChaptersRead int
+ Priority int
+ TimesReread int
+ // NOTE: idk what RereadValue is
+ RereadValue int
+ Tags string
+ Comments string
+}
diff --git a/user/manga/request_handler.go b/user/manga/request_handler.go
new file mode 100644
index 0000000..ff2b0df
--- /dev/null
+++ b/user/manga/request_handler.go
@@ -0,0 +1,96 @@
+/* MAL2Go - MyAnimeList V2 API wrapper for Go
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@protonmail.ch>
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+package manga
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "net/url"
+ "strconv"
+ "strings"
+)
+
+type serverResponse struct {
+ Message string
+ Error string
+}
+
+// Handles HTTP request with your OAuth token as a Header
+func (c Client) requestHandler(endpoint, method string) string {
+ // generate request
+ req, err := http.NewRequest(method, endpoint, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+ req.Header.Add("Authorization", c.AuthToken)
+
+ // do request
+ res, err := c.HttpClient.Do(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer res.Body.Close()
+
+ // read body
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // for DeleteAnime, its endpoint returns null data
+ if method == "DELETE" {
+ return strconv.Itoa(res.StatusCode)
+ }
+
+ return string(body)
+}
+
+// for PUT requests (used for updating anime)
+func (c Client) putRequestHandler(endpoint string, params url.Values) serverResponse {
+ paramsEncoded := params.Encode()
+
+ // generate request
+ req, err := http.NewRequest(http.MethodPut, endpoint, strings.NewReader(paramsEncoded))
+ if err != nil {
+ log.Fatal(err)
+ }
+ req.Header.Add("Authorization", c.AuthToken)
+ // this makes the sending-data-to-server magic work
+ req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
+ req.Header.Add("Content-Length", strconv.Itoa(len(paramsEncoded)))
+
+ // do request
+ res, err := c.HttpClient.Do(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer res.Body.Close()
+
+ // read body
+ body, err := ioutil.ReadAll(res.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // TODO: there are other serverResponses. Add them
+ // server response, ie message / error
+ var resp serverResponse
+ json.Unmarshal(body, &resp)
+
+ return resp
+}
diff --git a/user/manga/update_mangalist.go b/user/manga/update_mangalist.go
new file mode 100644
index 0000000..cac27e8
--- /dev/null
+++ b/user/manga/update_mangalist.go
@@ -0,0 +1,203 @@
+/* MAL2Go - MyAnimeList V2 API wrapper for Go
+ * Copyright (C) 2022 Vidhu Kant Sharma <vidhukant@protonmail.ch>
+
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+package manga
+
+import (
+ e "github.com/MikunoNaka/MAL2Go/errhandlers"
+ "errors"
+ "fmt"
+ "net/url"
+ "strconv"
+)
+
+// generate the endpoint url with the manga id
+func endpointGenerator(id int) string {
+ return fmt.Sprintf(BASE_URL + "/manga/%d/my_list_status", id)
+}
+
+// update just an manga's status
+func (c Client)SetStatus(id int, status string) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // checks if specified list status is valid
+ if !e.IsValidMangaListStatus(status) {
+ return serverResponse{}, errors.New(fmt.Sprintf("SetStatus: Invalid list status: \"%s\"", status))
+ }
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("status", status)
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's num of chapters read
+func (c Client)SetChaptersRead(id int, chapters int) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("num_chapters_read", strconv.Itoa(chapters))
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's rereading status
+func (c Client)SetIsRereading(id int, isRereading bool) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("is_rereading", strconv.FormatBool(isRereading))
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just the manga's score
+func (c Client)SetScore(id int, score int) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // checks if specified score is valid
+ if !e.IsValidScore(score) {
+ return serverResponse{}, errors.New(fmt.Sprintf("SetScore: Invalid score: %d doesn't lie within 0-10", score))
+ }
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("score", strconv.Itoa(score))
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's priority
+func (c Client)SetPriority(id int, priority int) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // checks if specified priority is valid
+ if !e.IsValidPriority(priority) {
+ return serverResponse{}, errors.New(fmt.Sprintf("SetPriority: Invalid priority: %d doesn't lie within 0-2", priority))
+ }
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("priority", strconv.Itoa(priority))
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's reread value
+func (c Client)SetRereadValue(id int, rereadValue int) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // checks if specified reread value is valid
+ if !e.IsValidRewatchValue(rereadValue) {
+ return serverResponse{}, errors.New(fmt.Sprintf("SetRereadValue: Invalid rewatch value: %d doesn't lie within 0-5", rereadValue))
+ }
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("reread_value", strconv.Itoa(rereadValue))
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's reread count
+func (c Client)SetRereadCount(id int, rereadCount int) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("num_times_reread", strconv.Itoa(rereadCount))
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's tags
+func (c Client)UpdateTags(id int, tags string) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("tags", tags)
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+// update just a manga's comments
+func (c Client)UpdateComments(id int, comments string) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // data to be sent to the server
+ params := url.Values{}
+ params.Set("comments", comments)
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+
+/* NOTE: This will overwrite everything
+ * i won't use it.. but it's pretty flexible
+ * so this will stay here */
+// Update/Add a manga to user's manga list
+func (c Client)UpdateManga(id int, data UpdateMangaData) (serverResponse, error) {
+ endpoint := endpointGenerator(id)
+
+ // checks if specified list status is valid
+ if !e.IsValidMangaListStatus(data.Status) {
+ return serverResponse{}, errors.New(fmt.Sprintf("UpdateManga: Invalid list status: \"%s\"", data.Status))
+ }
+
+ // checks if specified score is valid
+ if !e.IsValidScore(data.Score) {
+ return serverResponse{}, errors.New(fmt.Sprintf("UpdateManga: Invalid score: %d doesn't lie within 0-10", data.Score))
+ }
+
+ // checks if specified priority is valid
+ if !e.IsValidPriority(data.Priority) {
+ return serverResponse{}, errors.New(fmt.Sprintf("UpdateManga: Invalid priority: %d doesn't lie within 0-2", data.Priority))
+ }
+
+ // checks if specified rewatch value is valid
+ if !e.IsValidRewatchValue(data.RereadValue) {
+ return serverResponse{}, errors.New(fmt.Sprintf("UpdateManga: Invalid reread value: %d doesn't lie within 0-5", data.RereadValue))
+ }
+
+ params := url.Values{}
+
+ /* NOTE: THIS WILL OVERWRITE ANY DATA THAT
+ * IS NOT SPECIFIED AND SET IT TO NULL */
+ params.Set("status", data.Status)
+ params.Set("is_rereading", strconv.FormatBool(data.IsRereading))
+ params.Set("score", strconv.Itoa(data.Score))
+ params.Set("num_chapters_read", strconv.Itoa(data.ChaptersRead))
+ params.Set("priority", strconv.Itoa(data.Priority))
+ params.Set("num_times_reread", strconv.Itoa(data.TimesReread))
+ params.Set("reread_value", strconv.Itoa(data.RereadValue))
+ params.Set("tags", data.Tags)
+ params.Set("comments", data.Comments)
+
+ // make API request
+ return c.putRequestHandler(endpoint, params), nil
+}
+