rewrote standard media call and added browse function

This commit is contained in:
2026-07-22 15:22:58 -04:00
parent d3bc93f6c9
commit 54c109ae3b
2 changed files with 804 additions and 237 deletions
+707 -202
View File
@@ -74,37 +74,83 @@ func (a *App) GetAniListItem(aniId int, login bool) AniListGetSingleAnime {
mediaId mediaId
userId userId
media { media {
id id
idMal idMal
title { title {
romaji userPreferred
english romaji
native english
} native
description }
coverImage { description
large coverImage {
} extraLarge
season large
seasonYear medium
status color
episodes }
nextAiringEpisode { startDate {
airingAt year
timeUntilAiring month
episode day
} }
genres endDate {
tags{ year
id month
name day
description }
rank bannerImage
isMediaSpoiler format
isAdult season
} seasonYear
isAdult 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 status
startedAt{ startedAt{
year year
@@ -204,37 +250,84 @@ func (a *App) AniListSearch(query string) (interface{}, error) {
perPage perPage
} }
media (search: $search, type: $listType) { media (search: $search, type: $listType) {
id id
idMal idMal
title { 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 romaji
english english
native native
} }
description }
coverImage {
large
}
season
seasonYear
status
episodes
nextAiringEpisode{
airingAt
timeUntilAiring
episode
}
genres
tags{
id
name
description
rank
isMediaSpoiler
isAdult
}
isAdult
} }
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
}
} }
} }
`, `,
@@ -271,93 +364,140 @@ func (a *App) GetAniListUserWatchingList(page int, perPage int, sort string) (An
Variables Variables `json:"variables"` Variables Variables `json:"variables"`
}{ }{
Query: ` Query: `
query( query (
$page: Int $page: Int
$perPage: Int $perPage: Int
$userId: Int $userId: Int
$listType: MediaType $listType: MediaType
$status: MediaListStatus $status: MediaListStatus
$sort:[MediaListSort] $sort: [MediaListSort]
) { ) {
Page(page: $page, perPage: $perPage) { Page(page: $page, perPage: $perPage) {
pageInfo { pageInfo {
total total
perPage perPage
currentPage currentPage
lastPage lastPage
hasNextPage hasNextPage
} }
mediaList(userId: $userId, type: $listType, status: $status, sort: $sort) { mediaList(userId: $userId, type: $listType, status: $status, sort: $sort) {
id id
mediaId mediaId
userId userId
media { media {
id id
idMal idMal
title { title {
userPreferred
romaji romaji
english english
native native
} }
description description
coverImage { coverImage {
extraLarge
large large
medium
color
} }
bannerImage
format
season season
seasonYear seasonYear
status status
episodes 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{ nextAiringEpisode{
airingAt airingAt
timeUntilAiring timeUntilAiring
episode episode
} }
genres airingSchedule{
tags{ nodes{
id id
name airingAt
description timeUntilAiring
rank episode
isMediaSpoiler mediaId
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
}
} }
} }
} 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{ Variables: Variables{
Page: page, Page: page,
@@ -424,86 +564,138 @@ func (a *App) AniListUpdateEntry(updateBody AniListUpdateVariables) AniListGetSi
Variables AniListUpdateVariables `json:"variables"` Variables AniListUpdateVariables `json:"variables"`
}{ }{
Query: ` Query: `
mutation( mutation (
$mediaId:Int, $mediaId: Int
$progress:Int, $progress: Int
$status:MediaListStatus, $status: MediaListStatus
$score:Float, $score: Float
$repeat:Int, $repeat: Int
$notes:String, $notes: String
$startedAt:FuzzyDateInput, $startedAt: FuzzyDateInput
$completedAt:FuzzyDateInput, $completedAt: FuzzyDateInput
){ ) {
SaveMediaListEntry( SaveMediaListEntry(
mediaId:$mediaId, mediaId: $mediaId
progress:$progress, progress: $progress
status:$status, status: $status
score:$score, score: $score
repeat:$repeat, repeat: $repeat
notes:$notes, notes: $notes
startedAt:$startedAt startedAt: $startedAt
completedAt:$completedAt completedAt: $completedAt
){ ) {
id id
mediaId idMal
userId title {
media { userPreferred
id romaji
idMal english
title { native
romaji }
english description
native coverImage {
} extraLarge
description large
coverImage { medium
large color
} }
season bannerImage
seasonYear format
status season
episodes seasonYear
nextAiringEpisode { status
airingAt episodes
timeUntilAiring duration
episode countryOfOrigin
} source
isAdult synonyms
} averageScore
status meanScore
startedAt{ popularity
year trending
month favourites
day isFavourite
} relations {
completedAt{ nodes {
year id
month title {
day userPreferred
} romaji
notes english
progress native
score }
repeat }
user { }
id startDate {
name year
avatar{ month
large day
medium }
} endDate {
statistics{ year
anime{ month
count day
statuses{ }
status nextAiringEpisode {
count 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, Variables: updateBody,
} }
@@ -558,3 +750,316 @@ func (a *App) AniListDeleteEntry(mediaListId int) DeleteAniListReturn {
return post 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
}
+97 -35
View File
@@ -37,6 +37,20 @@ type AniListCurrentUserWatchList struct {
} `json:"data"` } `json:"data"`
} }
type AniListBrowseList struct {
Data struct {
Page struct {
PageInfo struct {
Total int `json:"total"`
PerPage int `json:"perPage"`
CurrentPage int `json:"currentPage"`
LastPage int `json:"lastPage"`
HasNextPage bool `json:"hasNextPage"`
} `json:"pageInfo"`
Media []Media `json:"mediaList"`
} `json:"Page"`
} `json:"data"`
}
type AniListGetSingleAnime struct { type AniListGetSingleAnime struct {
Data struct { Data struct {
MediaList MediaList `json:"MediaList"` MediaList MediaList `json:"MediaList"`
@@ -49,43 +63,91 @@ type AniListUpdateReturn struct {
} }
} }
type Media struct {
ID int `json:"id"`
IDMal int `json:"idMal"`
Title struct {
UserPreferred string `json:"userPreferred"`
Romaji string `json:"romaji"`
English string `json:"english"`
Native string `json:"native"`
} `json:"title"`
Description string `json:"description"`
CoverImage struct {
ExtraLarge string
Large string `json:"large"`
Medium string
Color string
} `json:"coverImage"`
BannerImage string
Format string
Season string `json:"season"`
SeasonYear int `json:"seasonYear"`
Status string `json:"status"`
Episodes int `json:"episodes"`
Duration int
CountryOfOrigin string
Source string
Synonyms []string
AverageScore int
MeanScore int
Popularity int
Trending int
Favourites int
isFavourite bool
Relations struct {
nodes struct {
id int
Title struct {
UserPreferred string `json:"userPreferred"`
Romaji string `json:"romaji"`
English string `json:"english"`
Native string `json:"native"`
} `json:"title"`
}
}
StartDate struct {
Year int
Month int
Day int
}
EndDate struct {
Year int
Month int
Day int
}
NextAiringEpisode struct {
AiringAt int `json:"airingAt"`
TimeUntilAiring int `json:"timeUntilAiring"`
Episode int `json:"episode"`
} `json:"nextAiringEpisode"`
AiringSchedule struct {
Nodes struct {
Id int
AiringAt int
TimeUntilAiring int
Episode int
MediaId int
}
}
Genres []string `json:"genres"`
Tags []struct {
Id int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Rank int `json:"rank"`
IsMediaSpoiler bool `json:"isMediaSpoiler"`
IsAdult bool `json:"isAdult"`
} `json:"tags"`
IsAdult bool `json:"isAdult"`
}
type MediaList struct { type MediaList struct {
ID int `json:"id"` ID int `json:"id"`
MediaID int `json:"mediaId"` MediaID int `json:"mediaId"`
UserID int `json:"userId"` UserID int `json:"userId"`
Media struct {
ID int `json:"id"`
IDMal int `json:"idMal"`
Title struct {
Romaji string `json:"romaji"`
English string `json:"english"`
Native string `json:"native"`
} `json:"title"`
Description string `json:"description"`
CoverImage struct {
Large string `json:"large"`
} `json:"coverImage"`
Season string `json:"season"`
SeasonYear int `json:"seasonYear"`
Status string `json:"status"`
Episodes int `json:"episodes"`
NextAiringEpisode struct {
AiringAt int `json:"airingAt"`
TimeUntilAiring int `json:"timeUntilAiring"`
Episode int `json:"episode"`
} `json:"nextAiringEpisode"`
Genres []string `json:"genres"`
Tags []struct {
Id int `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Rank int `json:"rank"`
IsMediaSpoiler bool `json:"isMediaSpoiler"`
IsAdult bool `json:"isAdult"`
} `json:"tags"`
IsAdult bool `json:"isAdult"`
} `json:"media"`
Status string `json:"status"` Status string `json:"status"`
Media Media `json:"media"`
StartedAt struct { StartedAt struct {
Year int `json:"year"` Year int `json:"year"`
Month int `json:"month"` Month int `json:"month"`