1066 lines
21 KiB
Go
1066 lines
21 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
)
|
|
|
|
func AniListQuery(body interface{}, login bool) (json.RawMessage, string) {
|
|
reader, _ := json.Marshal(body)
|
|
response, err := http.NewRequest("POST", "https://graphql.anilist.co", bytes.NewBuffer(reader))
|
|
if err != nil {
|
|
log.Printf("Failed at response, %s\n", err)
|
|
}
|
|
if login && (AniListJWT{}) != aniListJwt {
|
|
response.Header.Add("Authorization", "Bearer "+aniListJwt.AccessToken)
|
|
} else if login {
|
|
return nil, "Please login to AniList to make this request"
|
|
}
|
|
response.Header.Add("Content-Type", "application/json")
|
|
response.Header.Add("Accept", "application/json")
|
|
|
|
client := &http.Client{}
|
|
res, resErr := client.Do(response)
|
|
if resErr != nil {
|
|
log.Printf("Failed at res, %s\n", err)
|
|
}
|
|
|
|
defer res.Body.Close()
|
|
|
|
returnedBody, err := io.ReadAll(res.Body)
|
|
if err != nil {
|
|
return nil, "Could not read the returned body."
|
|
}
|
|
|
|
return returnedBody, res.Status
|
|
}
|
|
|
|
func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
|
|
user := a.GetAniListLoggedInUser()
|
|
|
|
var neededVariables interface{}
|
|
|
|
if login {
|
|
neededVariables = struct {
|
|
MediaId int `json:"mediaId"`
|
|
UserId int `json:"userId"`
|
|
ListType string `json:"listType"`
|
|
}{
|
|
MediaId: aniId,
|
|
UserId: user.Data.Viewer.ID,
|
|
ListType: "ANIME",
|
|
}
|
|
} else {
|
|
neededVariables = struct {
|
|
MediaId int `json:"mediaId"`
|
|
ListType string `json:"listType"`
|
|
}{
|
|
MediaId: aniId,
|
|
ListType: "ANIME",
|
|
}
|
|
}
|
|
body := struct {
|
|
Query string `json:"query"`
|
|
Variables interface{} `json:"variables"`
|
|
}{
|
|
Query: `
|
|
query($userId: Int, $mediaId: Int, $listType: MediaType) {
|
|
MediaList(mediaId: $mediaId, userId: $userId, type: $listType) {
|
|
id
|
|
mediaId
|
|
userId
|
|
media {
|
|
id
|
|
idMal
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
description
|
|
coverImage {
|
|
extraLarge
|
|
large
|
|
medium
|
|
color
|
|
}
|
|
startDate {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
endDate {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
bannerImage
|
|
format
|
|
season
|
|
seasonYear
|
|
status
|
|
episodes
|
|
duration
|
|
countryOfOrigin
|
|
source
|
|
synonyms
|
|
averageScore
|
|
meanScore
|
|
popularity
|
|
trending
|
|
favourites
|
|
isFavourite
|
|
relations {
|
|
nodes {
|
|
id
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
}
|
|
}
|
|
nextAiringEpisode {
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
}
|
|
airingSchedule {
|
|
nodes {
|
|
id
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
mediaId
|
|
}
|
|
}
|
|
genres
|
|
tags {
|
|
id
|
|
name
|
|
description
|
|
rank
|
|
isMediaSpoiler
|
|
isAdult
|
|
}
|
|
isAdult
|
|
}
|
|
status
|
|
startedAt{
|
|
year
|
|
month
|
|
day
|
|
}
|
|
completedAt{
|
|
year
|
|
month
|
|
day
|
|
}
|
|
notes
|
|
progress
|
|
score
|
|
repeat
|
|
user {
|
|
id
|
|
name
|
|
avatar {
|
|
large
|
|
medium
|
|
}
|
|
statistics {
|
|
anime {
|
|
count
|
|
statuses {
|
|
status
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
Variables: neededVariables,
|
|
}
|
|
|
|
returnedBody, status := AniListQuery(body, login)
|
|
var post AniListGetSingleAnime
|
|
|
|
if status == "404 Not Found" && !login {
|
|
return post
|
|
}
|
|
|
|
if status == "404 Not Found" {
|
|
post = a.GetAniListItem(aniId, false)
|
|
}
|
|
|
|
err := json.Unmarshal(returnedBody, &post)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
}
|
|
|
|
if !login {
|
|
post.Data.MediaList.UserID = user.Data.Viewer.ID
|
|
post.Data.MediaList.Status = ""
|
|
post.Data.MediaList.StartedAt.Year = 0
|
|
post.Data.MediaList.StartedAt.Month = 0
|
|
post.Data.MediaList.StartedAt.Day = 0
|
|
post.Data.MediaList.CompletedAt.Year = 0
|
|
post.Data.MediaList.CompletedAt.Month = 0
|
|
post.Data.MediaList.CompletedAt.Day = 0
|
|
post.Data.MediaList.Notes = ""
|
|
post.Data.MediaList.Progress = 0
|
|
post.Data.MediaList.Score = 0
|
|
post.Data.MediaList.Repeat = 0
|
|
post.Data.MediaList.User.ID = user.Data.Viewer.ID
|
|
post.Data.MediaList.User.Name = user.Data.Viewer.Name
|
|
post.Data.MediaList.User.Avatar.Large = user.Data.Viewer.Avatar.Large
|
|
post.Data.MediaList.User.Avatar.Medium = user.Data.Viewer.Avatar.Medium
|
|
post.Data.MediaList.User.Statistics.Anime.Count = 0
|
|
// This provides an empty array and frees up the memory from the garbage collector
|
|
post.Data.MediaList.User.Statistics.Anime.Statuses = nil
|
|
}
|
|
|
|
return post
|
|
}
|
|
|
|
func (a *App) AniListSearch(query string) (interface{}, error) {
|
|
type Variables struct {
|
|
Search string `json:"search"`
|
|
ListType string `json:"listType"`
|
|
}
|
|
body := struct {
|
|
Query string `json:"query"`
|
|
Variables Variables `json:"variables"`
|
|
}{
|
|
Query: `
|
|
query ($search: String!, $listType: MediaType) {
|
|
Page (page: 1, perPage: 100) {
|
|
pageInfo {
|
|
total
|
|
currentPage
|
|
lastPage
|
|
hasNextPage
|
|
perPage
|
|
}
|
|
media (search: $search, type: $listType) {
|
|
id
|
|
idMal
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
description
|
|
coverImage {
|
|
extraLarge
|
|
large
|
|
medium
|
|
color
|
|
}
|
|
bannerImage
|
|
format
|
|
season
|
|
seasonYear
|
|
status
|
|
episodes
|
|
duration
|
|
countryOfOrigin
|
|
source
|
|
synonyms
|
|
averageScore
|
|
meanScore
|
|
popularity
|
|
trending
|
|
favourites
|
|
isFavourite
|
|
relations{
|
|
nodes{
|
|
id
|
|
title{
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
}
|
|
}
|
|
startDate{
|
|
year
|
|
month
|
|
day
|
|
}
|
|
endDate{
|
|
year
|
|
month
|
|
day
|
|
}
|
|
nextAiringEpisode{
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
}
|
|
airingSchedule{
|
|
nodes{
|
|
id
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
mediaId
|
|
}
|
|
}
|
|
genres
|
|
tags{
|
|
id
|
|
name
|
|
description
|
|
rank
|
|
isMediaSpoiler
|
|
isAdult
|
|
}
|
|
isAdult
|
|
}
|
|
|
|
}
|
|
}
|
|
`,
|
|
Variables: Variables{
|
|
Search: query,
|
|
ListType: "ANIME",
|
|
},
|
|
}
|
|
returnedBody, status := AniListQuery(body, false)
|
|
if status != "200 OK" {
|
|
return nil, fmt.Errorf("API search failed with status: %s", status)
|
|
}
|
|
var post interface{}
|
|
err := json.Unmarshal(returnedBody, &post)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
return nil, fmt.Errorf("Failed to parse search results")
|
|
}
|
|
return post, nil
|
|
}
|
|
|
|
func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) (AniListCurrentUserWatchList, error) {
|
|
user := a.GetAniListLoggedInUser()
|
|
type Variables struct {
|
|
Page int `json:"page"`
|
|
PerPage int `json:"perPage"`
|
|
UserId int `json:"userId"`
|
|
ListType string `json:"listType"`
|
|
Status string `json:"status"`
|
|
Sort string `json:"sort"`
|
|
}
|
|
body := struct {
|
|
Query string `json:"query"`
|
|
Variables Variables `json:"variables"`
|
|
}{
|
|
Query: `
|
|
query (
|
|
$page: Int
|
|
$perPage: Int
|
|
$userId: Int
|
|
$listType: MediaType
|
|
$status: MediaListStatus
|
|
$sort: [MediaListSort]
|
|
) {
|
|
Page(page: $page, perPage: $perPage) {
|
|
pageInfo {
|
|
total
|
|
perPage
|
|
currentPage
|
|
lastPage
|
|
hasNextPage
|
|
}
|
|
mediaList(userId: $userId, type: $listType, status: $status, sort: $sort) {
|
|
id
|
|
mediaId
|
|
userId
|
|
media {
|
|
id
|
|
idMal
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
description
|
|
coverImage {
|
|
extraLarge
|
|
large
|
|
medium
|
|
color
|
|
}
|
|
bannerImage
|
|
format
|
|
season
|
|
seasonYear
|
|
status
|
|
episodes
|
|
duration
|
|
countryOfOrigin
|
|
source
|
|
synonyms
|
|
averageScore
|
|
meanScore
|
|
popularity
|
|
trending
|
|
favourites
|
|
isFavourite
|
|
relations{
|
|
nodes{
|
|
id
|
|
title{
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
}
|
|
}
|
|
startDate{
|
|
year
|
|
month
|
|
day
|
|
}
|
|
endDate{
|
|
year
|
|
month
|
|
day
|
|
}
|
|
nextAiringEpisode{
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
}
|
|
airingSchedule{
|
|
nodes{
|
|
id
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
mediaId
|
|
}
|
|
}
|
|
genres
|
|
tags{
|
|
id
|
|
name
|
|
description
|
|
rank
|
|
isMediaSpoiler
|
|
isAdult
|
|
}
|
|
isAdult
|
|
}
|
|
|
|
status
|
|
startedAt {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
completedAt {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
notes
|
|
progress
|
|
score
|
|
repeat
|
|
user {
|
|
id
|
|
name
|
|
avatar {
|
|
large
|
|
medium
|
|
}
|
|
statistics {
|
|
anime {
|
|
count
|
|
statuses {
|
|
status
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
Variables: Variables{
|
|
Page: page,
|
|
PerPage: perPage,
|
|
UserId: user.Data.Viewer.ID,
|
|
ListType: "ANIME",
|
|
Status: "CURRENT",
|
|
Sort: sort,
|
|
},
|
|
}
|
|
|
|
returnedBody, status := AniListQuery(body, true)
|
|
|
|
var badPost struct {
|
|
Errors []struct {
|
|
Message string `json:"message"`
|
|
Status int `json:"status"`
|
|
Locations []struct {
|
|
Line int `json:"line"`
|
|
Column int `json:"column"`
|
|
} `json:"locations"`
|
|
} `json:"errors"`
|
|
Data any `json:"data"`
|
|
}
|
|
var post AniListCurrentUserWatchList
|
|
if status == "200 OK" {
|
|
err := json.Unmarshal(returnedBody, &post)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
}
|
|
// Getting the real total, finding the real last page and storing that in the Page info
|
|
statuses := post.Data.Page.MediaList[0].User.Statistics.Anime.Statuses
|
|
var total int
|
|
for _, status := range statuses {
|
|
if status.Status == "CURRENT" {
|
|
total = status.Count
|
|
}
|
|
}
|
|
|
|
lastPage := total / perPage
|
|
|
|
post.Data.Page.PageInfo.Total = total
|
|
post.Data.Page.PageInfo.LastPage = lastPage
|
|
}
|
|
|
|
if status == "403 Forbidden" {
|
|
err := json.Unmarshal(returnedBody, &badPost)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
return post, fmt.Errorf("API authentication error")
|
|
}
|
|
return post, fmt.Errorf("AniList API error: %s", badPost.Errors[0].Message)
|
|
}
|
|
if status != "200 OK" {
|
|
return post, fmt.Errorf("API request failed with status: %s", status)
|
|
}
|
|
|
|
return post, nil
|
|
}
|
|
|
|
func (a *App) AniListUpdateEntry(updateBody AniListUpdateVariables) AniListGetSingleAnime {
|
|
body := struct {
|
|
Query string `json:"query"`
|
|
Variables AniListUpdateVariables `json:"variables"`
|
|
}{
|
|
Query: `
|
|
mutation (
|
|
$mediaId: Int
|
|
$progress: Int
|
|
$status: MediaListStatus
|
|
$score: Float
|
|
$repeat: Int
|
|
$notes: String
|
|
$startedAt: FuzzyDateInput
|
|
$completedAt: FuzzyDateInput
|
|
) {
|
|
SaveMediaListEntry(
|
|
mediaId: $mediaId
|
|
progress: $progress
|
|
status: $status
|
|
score: $score
|
|
repeat: $repeat
|
|
notes: $notes
|
|
startedAt: $startedAt
|
|
completedAt: $completedAt
|
|
) {
|
|
id
|
|
idMal
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
description
|
|
coverImage {
|
|
extraLarge
|
|
large
|
|
medium
|
|
color
|
|
}
|
|
bannerImage
|
|
format
|
|
season
|
|
seasonYear
|
|
status
|
|
episodes
|
|
duration
|
|
countryOfOrigin
|
|
source
|
|
synonyms
|
|
averageScore
|
|
meanScore
|
|
popularity
|
|
trending
|
|
favourites
|
|
isFavourite
|
|
relations {
|
|
nodes {
|
|
id
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
}
|
|
}
|
|
startDate {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
endDate {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
nextAiringEpisode {
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
}
|
|
airingSchedule {
|
|
nodes {
|
|
id
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
mediaId
|
|
}
|
|
}
|
|
genres
|
|
tags {
|
|
id
|
|
name
|
|
description
|
|
rank
|
|
isMediaSpoiler
|
|
isAdult
|
|
}
|
|
isAdult
|
|
}
|
|
|
|
status
|
|
startedAt {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
completedAt {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
notes
|
|
progress
|
|
score
|
|
repeat
|
|
user {
|
|
id
|
|
name
|
|
avatar {
|
|
large
|
|
medium
|
|
}
|
|
statistics {
|
|
anime {
|
|
count
|
|
statuses {
|
|
status
|
|
count
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
`,
|
|
Variables: updateBody,
|
|
}
|
|
|
|
returnedBody, _ := AniListQuery(body, true)
|
|
|
|
var returnedJson AniListUpdateReturn
|
|
err := json.Unmarshal(returnedBody, &returnedJson)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
}
|
|
|
|
var post AniListGetSingleAnime
|
|
|
|
post.Data.MediaList = returnedJson.Data.SaveMediaListEntry
|
|
|
|
return post
|
|
}
|
|
|
|
func (a *App) AniListDeleteEntry(mediaListId int) DeleteAniListReturn {
|
|
type Variables = struct {
|
|
Id int `json:"id"`
|
|
}
|
|
|
|
body := struct {
|
|
Query string `json:"query"`
|
|
Variables Variables `json:"variables"`
|
|
}{
|
|
Query: `
|
|
mutation(
|
|
$id:Int,
|
|
){
|
|
DeleteMediaListEntry(
|
|
id:$id,
|
|
){
|
|
deleted
|
|
}
|
|
}
|
|
`,
|
|
Variables: Variables{
|
|
Id: mediaListId,
|
|
},
|
|
}
|
|
|
|
returnedBody, _ := AniListQuery(body, true)
|
|
|
|
var post DeleteAniListReturn
|
|
err := json.Unmarshal(returnedBody, &post)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
}
|
|
|
|
return post
|
|
}
|
|
|
|
func (a *App) AniListBrowse(
|
|
page int,
|
|
perPage int,
|
|
id int,
|
|
isAdult bool,
|
|
search string,
|
|
format []string,
|
|
status string,
|
|
countryOfOrigin string,
|
|
source string,
|
|
season string,
|
|
seasonYear int,
|
|
year string,
|
|
onList bool,
|
|
yearLesser int,
|
|
yearGreater int,
|
|
episodeLesser int,
|
|
episodeGreater int,
|
|
durationLesser int,
|
|
durationGreater int,
|
|
chapterLesser int,
|
|
chapterGreater int,
|
|
volumeLesser int,
|
|
volumeGreater int,
|
|
licensedBy []int,
|
|
isLicensed bool,
|
|
genres []string,
|
|
excludedGenres []string,
|
|
tags []string,
|
|
excludedTags []string,
|
|
minimumTagRank int,
|
|
sort []string) (AniListCurrentUserWatchList, error) {
|
|
// user := a.GetAniListLoggedInUser()
|
|
type Variables struct {
|
|
Page int `json:"page"`
|
|
PerPage int `json:"perPage"`
|
|
Id int `json:"id"`
|
|
IsAdult bool `json:"isAdult"`
|
|
Search string `json:"search"`
|
|
Format []string `json:"format"`
|
|
Status string `json:"status"`
|
|
CountryOfOrigin string `json:"countryOfOrigin"`
|
|
Source string `json:"source"`
|
|
Season string `json:"season"`
|
|
SeasonYear int `json:"seasonYear"`
|
|
Year string `json:"year"`
|
|
OnList bool `json:"onList"`
|
|
YearLesser int `json:"yearLesser"`
|
|
YearGreater int `json:"yearGreater"`
|
|
EpisodeLesser int `json:"episodeLesser"`
|
|
EpisodeGreater int `json:"episodeGreater"`
|
|
DurationLesser int `json:"durationLesser"`
|
|
DurationGreater int `json:"durationGreater"`
|
|
ChapterLesser int `json:"chapterLesser"`
|
|
ChapterGreater int `json:"chapterGreater"`
|
|
VolumeLesser int `json:"volumeLesser"`
|
|
VolumeGreater int `json:"volumeGreater"`
|
|
LicensedBy []int `json:"licensedBy"`
|
|
IsLicensed bool `json:"isLicensed"`
|
|
Genres []string `json:"genres"`
|
|
ExcludedGenres []string `json:"excludedGenres"`
|
|
Tags []string `json:"tags"`
|
|
ExcludedTags []string `json:"excludedTags"`
|
|
MinimumTagRank int `json:"minimumTagRank"`
|
|
Sort []string `json:"sort"`
|
|
}
|
|
body := struct {
|
|
Query string `json:"query"`
|
|
Variables Variables `json:"variables"`
|
|
}{
|
|
Query: `
|
|
query (
|
|
$page: Int = 1
|
|
$perPage: Int = 20
|
|
$id: Int
|
|
$isAdult: Boolean = false
|
|
$search: String
|
|
$format: [MediaFormat]
|
|
$status: MediaStatus
|
|
$countryOfOrigin: CountryCode
|
|
$source: MediaSource
|
|
$season: MediaSeason
|
|
$seasonYear: Int
|
|
$year: String
|
|
$onList: Boolean
|
|
$yearLesser: FuzzyDateInt
|
|
$yearGreater: FuzzyDateInt
|
|
$episodeLesser: Int
|
|
$episodeGreater: Int
|
|
$durationLesser: Int
|
|
$durationGreater: Int
|
|
$chapterLesser: Int
|
|
$chapterGreater: Int
|
|
$volumeLesser: Int
|
|
$volumeGreater: Int
|
|
$licensedBy: [Int]
|
|
$isLicensed: Boolean
|
|
$genres: [String]
|
|
$excludedGenres: [String]
|
|
$tags: [String]
|
|
$excludedTags: [String]
|
|
$minimumTagRank: Int
|
|
$sort: [MediaSort] = [POPULARITY_DESC, SCORE_DESC]
|
|
) {
|
|
Page(page: $page, perPage: $perPage) {
|
|
pageInfo {
|
|
total
|
|
perPage
|
|
currentPage
|
|
lastPage
|
|
hasNextPage
|
|
}
|
|
media(
|
|
id: $id
|
|
type: ANIME
|
|
season: $season
|
|
format_in: $format
|
|
status: $status
|
|
countryOfOrigin: $countryOfOrigin
|
|
source: $source
|
|
search: $search
|
|
onList: $onList
|
|
seasonYear: $seasonYear
|
|
startDate_like: $year
|
|
startDate_lesser: $yearLesser
|
|
startDate_greater: $yearGreater
|
|
episodes_lesser: $episodeLesser
|
|
episodes_greater: $episodeGreater
|
|
duration_lesser: $durationLesser
|
|
duration_greater: $durationGreater
|
|
chapters_lesser: $chapterLesser
|
|
chapters_greater: $chapterGreater
|
|
volumes_lesser: $volumeLesser
|
|
volumes_greater: $volumeGreater
|
|
licensedById_in: $licensedBy
|
|
isLicensed: $isLicensed
|
|
genre_in: $genres
|
|
genre_not_in: $excludedGenres
|
|
tag_in: $tags
|
|
tag_not_in: $excludedTags
|
|
minimumTagRank: $minimumTagRank
|
|
sort: $sort
|
|
isAdult: $isAdult
|
|
) {
|
|
id
|
|
mediaId
|
|
userId
|
|
media {
|
|
id
|
|
idMal
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
description
|
|
coverImage {
|
|
extraLarge
|
|
large
|
|
medium
|
|
color
|
|
}
|
|
bannerImage
|
|
format
|
|
season
|
|
seasonYear
|
|
status
|
|
episodes
|
|
duration
|
|
countryOfOrigin
|
|
source
|
|
synonyms
|
|
averageScore
|
|
meanScore
|
|
popularity
|
|
trending
|
|
favourites
|
|
isFavourite
|
|
relations {
|
|
nodes {
|
|
id
|
|
title {
|
|
userPreferred
|
|
romaji
|
|
english
|
|
native
|
|
}
|
|
}
|
|
}
|
|
startDate {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
endDate {
|
|
year
|
|
month
|
|
day
|
|
}
|
|
nextAiringEpisode {
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
}
|
|
airingSchedule {
|
|
nodes {
|
|
id
|
|
airingAt
|
|
timeUntilAiring
|
|
episode
|
|
mediaId
|
|
}
|
|
}
|
|
genres
|
|
tags {
|
|
id
|
|
name
|
|
description
|
|
rank
|
|
isMediaSpoiler
|
|
isAdult
|
|
}
|
|
isAdult
|
|
}
|
|
|
|
}
|
|
}
|
|
`,
|
|
Variables: Variables{
|
|
Page: page,
|
|
PerPage: perPage,
|
|
Id: id,
|
|
IsAdult: isAdult,
|
|
Search: search,
|
|
Format: format,
|
|
Status: status,
|
|
CountryOfOrigin: countryOfOrigin,
|
|
Source: source,
|
|
Season: season,
|
|
SeasonYear: seasonYear,
|
|
Year: year,
|
|
OnList: onList,
|
|
YearLesser: yearLesser,
|
|
YearGreater: yearGreater,
|
|
EpisodeLesser: episodeLesser,
|
|
EpisodeGreater: episodeGreater,
|
|
DurationLesser: durationLesser,
|
|
DurationGreater: durationGreater,
|
|
ChapterLesser: chapterLesser,
|
|
ChapterGreater: chapterGreater,
|
|
VolumeLesser: volumeLesser,
|
|
VolumeGreater: volumeGreater,
|
|
LicensedBy: licensedBy,
|
|
IsLicensed: isLicensed,
|
|
Genres: genres,
|
|
ExcludedGenres: excludedGenres,
|
|
Tags: tags,
|
|
ExcludedTags: excludedTags,
|
|
MinimumTagRank: minimumTagRank,
|
|
Sort: sort,
|
|
},
|
|
}
|
|
|
|
returnedBody, status := AniListQuery(body, true)
|
|
|
|
var badPost struct {
|
|
Errors []struct {
|
|
Message string `json:"message"`
|
|
Status int `json:"status"`
|
|
Locations []struct {
|
|
Line int `json:"line"`
|
|
Column int `json:"column"`
|
|
} `json:"locations"`
|
|
} `json:"errors"`
|
|
Data any `json:"data"`
|
|
}
|
|
var post AniListCurrentUserWatchList
|
|
if status == "200 OK" {
|
|
err := json.Unmarshal(returnedBody, &post)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
}
|
|
// Getting the real total, finding the real last page and storing that in the Page info
|
|
statuses := post.Data.Page.MediaList[0].User.Statistics.Anime.Statuses
|
|
var total int
|
|
for _, status := range statuses {
|
|
if status.Status == "CURRENT" {
|
|
total = status.Count
|
|
}
|
|
}
|
|
|
|
lastPage := total / perPage
|
|
|
|
post.Data.Page.PageInfo.Total = total
|
|
post.Data.Page.PageInfo.LastPage = lastPage
|
|
}
|
|
|
|
if status == "403 Forbidden" {
|
|
err := json.Unmarshal(returnedBody, &badPost)
|
|
if err != nil {
|
|
log.Printf("Failed at unmarshal, %s\n", err)
|
|
return post, fmt.Errorf("API authentication error")
|
|
}
|
|
return post, fmt.Errorf("AniList API error: %s", badPost.Errors[0].Message)
|
|
}
|
|
if status != "200 OK" {
|
|
return post, fmt.Errorf("API request failed with status: %s", status)
|
|
}
|
|
|
|
return post, nil
|
|
}
|