initial commit
This commit is contained in:
commit
c8669da106
53
airingschedule.go
Normal file
53
airingschedule.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
func (api *Api) GetAiringSchedule(vars AiringScheduleQuery, onError func(error)) <-chan *AiringSchedule {
|
||||||
|
resp := responseObj[*page[AiringSchedule]]{}
|
||||||
|
return requestPaged(api, getAiringScheduleQuery, vars.toMap(), &resp, onError)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
getAiringScheduleQuery = `query (
|
||||||
|
$id: Int,
|
||||||
|
$mediaId: Int,
|
||||||
|
$episode: Int,
|
||||||
|
$airingAt: Int,
|
||||||
|
$notYetAired: Boolean,
|
||||||
|
$id_in: [Int],
|
||||||
|
$id_not_in: [Int],
|
||||||
|
$mediaId_in: [Int],
|
||||||
|
$mediaId_not_in: [Int],
|
||||||
|
$episode_in: [Int],
|
||||||
|
$episode_not_in: [Int],
|
||||||
|
$episode_greater: Int,
|
||||||
|
$episode_lesser: Int,
|
||||||
|
$airingAt_greater: Int,
|
||||||
|
$airingAt_lesser: Int,
|
||||||
|
$sort: [AiringSort],
|
||||||
|
$page: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
Page (page: $page) {
|
||||||
|
pageInfo ` + subSelectionPageInfo + `
|
||||||
|
|
||||||
|
airingSchedules (
|
||||||
|
id: $id,
|
||||||
|
mediaId: $mediaId,
|
||||||
|
episode: $episode,
|
||||||
|
airingAt: $airingAt,
|
||||||
|
notYetAired: $notYetAired,
|
||||||
|
id_in: $id_in,
|
||||||
|
id_not_in: $id_not_in,
|
||||||
|
mediaId_in: $mediaId_in,
|
||||||
|
mediaId_not_in: $mediaId_not_in,
|
||||||
|
episode_in: $episode_in,
|
||||||
|
episode_not_in: $episode_not_in,
|
||||||
|
episode_greater: $episode_greater,
|
||||||
|
episode_lesser: $episode_lesser,
|
||||||
|
airingAt_greater: $airingAt_greater,
|
||||||
|
airingAt_lesser: $airingAt_lesser,
|
||||||
|
sort: $sort,
|
||||||
|
) ` + subSelectionAiringSchedule + `
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
100
api.go
Normal file
100
api.go
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Api struct {
|
||||||
|
AccessToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewApi(accessToken string) *Api {
|
||||||
|
return &Api{AccessToken: accessToken}
|
||||||
|
}
|
||||||
|
|
||||||
|
type queryObj struct {
|
||||||
|
Query string `json:"query"`
|
||||||
|
Vars interface{} `json:"variables"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type responseObj[T any] struct {
|
||||||
|
Data T `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func request[T any](api *Api, query string, vars map[string]interface{}, respObj *responseObj[T]) error {
|
||||||
|
q := &queryObj{
|
||||||
|
Query: query,
|
||||||
|
Vars: vars,
|
||||||
|
}
|
||||||
|
|
||||||
|
queryData, err := json.Marshal(q)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", "https://graphql.anilist.co/", bytes.NewReader(queryData))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Add("Content-Type", "application/json")
|
||||||
|
req.Header.Add("Authorization", "Bearer "+api.AccessToken)
|
||||||
|
|
||||||
|
resp, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
//data, _ := ioutil.ReadAll(resp.Body)
|
||||||
|
//fmt.Println(string(data))
|
||||||
|
|
||||||
|
dec := json.NewDecoder(resp.Body)
|
||||||
|
err = dec.Decode(respObj)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestPaged[R any](api *Api, query string, vars map[string]interface{}, respObj *responseObj[*page[R]], onError func(error)) <-chan *R {
|
||||||
|
resp := responseObj[struct {
|
||||||
|
Page *page[R] `json:"Page"`
|
||||||
|
}]{}
|
||||||
|
|
||||||
|
out := make(chan *R, 50)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer close(out)
|
||||||
|
|
||||||
|
vars["page"] = 0
|
||||||
|
|
||||||
|
for {
|
||||||
|
if p, ok := vars["page"].(int); ok {
|
||||||
|
vars["page"] = p + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
err := request(api, query, vars, &resp)
|
||||||
|
if err != nil {
|
||||||
|
if onError != nil {
|
||||||
|
onError(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, value := range resp.Data.Page.Data() {
|
||||||
|
value := value
|
||||||
|
out <- &value
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.Data.Page.PageInfo.CurrentPage == resp.Data.Page.PageInfo.LastPage {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
98
media.go
Normal file
98
media.go
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
func (api *Api) GetMedia(vars MediaQuery, onError func(error)) <-chan *Media {
|
||||||
|
resp := responseObj[*page[Media]]{}
|
||||||
|
return requestPaged(api, getMediaQuery, vars.toMap(), &resp, onError)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
getMediaQuery = `query (
|
||||||
|
$id: Int,
|
||||||
|
$startDate: FuzzyDateInt,
|
||||||
|
$endDate: FuzzyDateInt,
|
||||||
|
$season: MediaSeason,
|
||||||
|
$seasonYear: Int,
|
||||||
|
$type: MediaType,
|
||||||
|
$format: MediaFormat,
|
||||||
|
$status: MediaStatus,
|
||||||
|
$episodes: Int,
|
||||||
|
$duration: Int,
|
||||||
|
$chapters: Int,
|
||||||
|
$volumes: Int,
|
||||||
|
$isAdult: Boolean,
|
||||||
|
$genre: String,
|
||||||
|
$tag: String,
|
||||||
|
$source: MediaSource,
|
||||||
|
$search: String,
|
||||||
|
$id_in: [Int],
|
||||||
|
$id_not_in: [Int],
|
||||||
|
$startDate_greater: FuzzyDateInt,
|
||||||
|
$startDate_lesser: FuzzyDateInt,
|
||||||
|
$endDate_greater: FuzzyDateInt,
|
||||||
|
$endDate_lesser: FuzzyDateInt,
|
||||||
|
$format_in: [MediaFormat],
|
||||||
|
$format_not_in: [MediaFormat],
|
||||||
|
$status_in: [MediaStatus],
|
||||||
|
$status_not_in: [MediaStatus],
|
||||||
|
$episodes_greater: Int,
|
||||||
|
$episodes_lesser: Int,
|
||||||
|
$duration_greater: Int,
|
||||||
|
$duration_lesser: Int,
|
||||||
|
$volumes_greater: Int,
|
||||||
|
$volumes_lesser: Int,
|
||||||
|
$genre_in: [String],
|
||||||
|
$genre_not_in: [String],
|
||||||
|
$tag_in: [String],
|
||||||
|
$tag_not_in: [String],
|
||||||
|
$source_in: [MediaSource],
|
||||||
|
$sort:[MediaSort],
|
||||||
|
$page: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
Page (page: $page) {
|
||||||
|
pageInfo ` + subSelectionPageInfo + `
|
||||||
|
media (
|
||||||
|
id: $id,
|
||||||
|
startDate: $startDate,
|
||||||
|
endDate: $endDate,
|
||||||
|
season: $season,
|
||||||
|
seasonYear: $seasonYear,
|
||||||
|
type: $type,
|
||||||
|
format: $format,
|
||||||
|
status: $status,
|
||||||
|
episodes: $episodes,
|
||||||
|
duration: $duration,
|
||||||
|
chapters: $chapters,
|
||||||
|
volumes: $volumes,
|
||||||
|
isAdult: $isAdult,
|
||||||
|
genre: $genre,
|
||||||
|
tag: $tag,
|
||||||
|
source: $source,
|
||||||
|
search: $search,
|
||||||
|
id_in: $id_in,
|
||||||
|
id_not_in: $id_not_in,
|
||||||
|
startDate_greater: $startDate_greater,
|
||||||
|
startDate_lesser: $startDate_lesser,
|
||||||
|
endDate_greater: $endDate_greater,
|
||||||
|
endDate_lesser: $endDate_lesser,
|
||||||
|
format_in: $format_in,
|
||||||
|
format_not_in: $format_not_in,
|
||||||
|
status_in: $status_in,
|
||||||
|
status_not_in: $status_not_in,
|
||||||
|
episodes_greater: $episodes_greater,
|
||||||
|
episodes_lesser: $episodes_lesser,
|
||||||
|
duration_greater: $duration_greater,
|
||||||
|
duration_lesser: $duration_lesser,
|
||||||
|
volumes_greater: $volumes_greater,
|
||||||
|
volumes_lesser: $volumes_lesser,
|
||||||
|
genre_in: $genre_in,
|
||||||
|
genre_not_in: $genre_not_in,
|
||||||
|
tag_in: $tag_in,
|
||||||
|
tag_not_in: $tag_not_in,
|
||||||
|
source_in: $source_in,
|
||||||
|
sort: $sort
|
||||||
|
) ` + subSelectionMedia + `
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
51
medialist.go
Normal file
51
medialist.go
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
func (api *Api) GetMediaList(vars MediaListQuery, onError func(error)) <-chan *MediaList {
|
||||||
|
resp := responseObj[*page[MediaList]]{}
|
||||||
|
return requestPaged(api, getMediaListQuery, vars.toMap(), &resp, onError)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
getMediaListQuery = `query (
|
||||||
|
$id: Int,
|
||||||
|
$userId: Int,
|
||||||
|
$userName: String,
|
||||||
|
$type: MediaType,
|
||||||
|
$status: MediaListStatus,
|
||||||
|
$mediaId: Int,
|
||||||
|
$isFollowing: Boolean,
|
||||||
|
$notes: String,
|
||||||
|
$userId_in: [Int],
|
||||||
|
$status_in: [MediaListStatus],
|
||||||
|
$status_not_in: [MediaListStatus],
|
||||||
|
$status_not: MediaListStatus,
|
||||||
|
$mediaId_in: [Int],
|
||||||
|
$mediaId_not_in: [Int],
|
||||||
|
$sort: [MediaListSort],
|
||||||
|
$page: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
{
|
||||||
|
Page (page: $page) {
|
||||||
|
pageInfo ` + subSelectionPageInfo + `
|
||||||
|
|
||||||
|
mediaList (
|
||||||
|
id: $id,
|
||||||
|
userId: $userId,
|
||||||
|
userName: $userName,
|
||||||
|
type: $type,
|
||||||
|
status: $status,
|
||||||
|
mediaId: $mediaId,
|
||||||
|
isFollowing: $isFollowing,
|
||||||
|
notes: $notes,
|
||||||
|
userId_in: $userId_in,
|
||||||
|
status_in: $status_in,
|
||||||
|
status_not_in: $status_not_in,
|
||||||
|
status_not: $status_not,
|
||||||
|
mediaId_in: $mediaId_in,
|
||||||
|
mediaId_not_in: $mediaId_not_in,
|
||||||
|
sort: $sort
|
||||||
|
) ` + subSelectionMediaList + `
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
45
page.go
Normal file
45
page.go
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type page[T any] struct {
|
||||||
|
PageInfo *pageInfo `json:"pageInfo"`
|
||||||
|
Media []Media `json:"media"`
|
||||||
|
MediaList []MediaList `json:"mediaList"`
|
||||||
|
Users []User `json:"users"`
|
||||||
|
AiringSchedules []AiringSchedule `json:"airingSchedules"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *page[T]) Data() []T {
|
||||||
|
if reflect.TypeOf(new(T)).Elem() == reflect.TypeOf(new(User)).Elem() {
|
||||||
|
var data interface{} = p.Users
|
||||||
|
return data.([]T)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.TypeOf(new(T)).Elem() == reflect.TypeOf(new(Media)).Elem() {
|
||||||
|
var data interface{} = p.Media
|
||||||
|
return data.([]T)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.TypeOf(new(T)).Elem() == reflect.TypeOf(new(MediaList)).Elem() {
|
||||||
|
var data interface{} = p.MediaList
|
||||||
|
return data.([]T)
|
||||||
|
}
|
||||||
|
|
||||||
|
if reflect.TypeOf(new(T)).Elem() == reflect.TypeOf(new(AiringSchedule)).Elem() {
|
||||||
|
var data interface{} = p.AiringSchedules
|
||||||
|
return data.([]T)
|
||||||
|
}
|
||||||
|
|
||||||
|
panic("generic type not implemented: " + reflect.TypeOf(new(T)).Elem().Name())
|
||||||
|
}
|
||||||
|
|
||||||
|
type pageInfo struct {
|
||||||
|
Total int `json:"total"`
|
||||||
|
CurrentPage int `json:"currentPage"`
|
||||||
|
LastPage int `json:"lastPage"`
|
||||||
|
HasNextPage bool `json:"hasNextPage"`
|
||||||
|
PerPage int `json:"perPage"`
|
||||||
|
}
|
257
queries.go
Normal file
257
queries.go
Normal file
@ -0,0 +1,257 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type MediaListQuery struct {
|
||||||
|
ID int
|
||||||
|
UserID int
|
||||||
|
UserName string
|
||||||
|
Type MediaType
|
||||||
|
Status MediaListStatus
|
||||||
|
MediaID int
|
||||||
|
Following bool
|
||||||
|
Notes string
|
||||||
|
UserIdIn []int
|
||||||
|
StatusIn []MediaListStatus
|
||||||
|
StatusNotIn []MediaListStatus
|
||||||
|
StatusNot MediaListStatus
|
||||||
|
MediaIdIn []int
|
||||||
|
MediaIdNotIn []int
|
||||||
|
Sort []MediaListSort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *MediaListQuery) toMap() map[string]interface{} {
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
addValue2InterfaceMap(m, "id", q.ID)
|
||||||
|
addValue2InterfaceMap(m, "userId", q.UserID)
|
||||||
|
addValue2InterfaceMap(m, "userName", q.UserName)
|
||||||
|
addValue2InterfaceMap(m, "type", q.Type)
|
||||||
|
addValue2InterfaceMap(m, "status", q.Status)
|
||||||
|
addValue2InterfaceMap(m, "mediaId", q.MediaID)
|
||||||
|
addValue2InterfaceMap(m, "isFollowing", q.Following)
|
||||||
|
addValue2InterfaceMap(m, "notes", q.Notes)
|
||||||
|
addSlice2InterfaceMap(m, "userId_in", q.UserIdIn)
|
||||||
|
addSlice2InterfaceMap(m, "status_in", q.StatusIn)
|
||||||
|
addSlice2InterfaceMap(m, "status_not_in", q.StatusNotIn)
|
||||||
|
addValue2InterfaceMap(m, "status_not", q.StatusNot)
|
||||||
|
addSlice2InterfaceMap(m, "mediaId_in", q.MediaIdIn)
|
||||||
|
addSlice2InterfaceMap(m, "mediaId_not_in", q.MediaIdNotIn)
|
||||||
|
addSlice2InterfaceMap(m, "sort", q.Sort)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaListSort string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaListSortMediaId MediaListSort = "MEDIA_ID"
|
||||||
|
MediaListSortMediaIdDesc MediaListSort = "MEDIA_ID_DESC"
|
||||||
|
MediaListSortScore MediaListSort = "SCORE"
|
||||||
|
MediaListSortScoreDesc MediaListSort = "SCORE_DESC"
|
||||||
|
MediaListSortStatus MediaListSort = "STATUS"
|
||||||
|
MediaListSortStatusDesc MediaListSort = "STATUS_DESC"
|
||||||
|
MediaListSortProgress MediaListSort = "PROGRESS"
|
||||||
|
MediaListSortProgressDesc MediaListSort = "PROGRESS_DESC"
|
||||||
|
MediaListSortProgressVolumes MediaListSort = "PROGRESS_VOLUMES"
|
||||||
|
MediaListSortProgressVolumesDesc MediaListSort = "PROGRESS_VOLUMES_DESC"
|
||||||
|
MediaListSortRepeat MediaListSort = "REPEAT"
|
||||||
|
MediaListSortRepeatDesc MediaListSort = "REPEAT_DESC"
|
||||||
|
MediaListSortPriority MediaListSort = "PRIORITY"
|
||||||
|
MediaListSortPriorityDesc MediaListSort = "PRIORITY_DESC"
|
||||||
|
MediaListSortStartedOn MediaListSort = "STARTED_ON"
|
||||||
|
MediaListSortStartedOnDesc MediaListSort = "STARTED_ON_DESC"
|
||||||
|
MediaListSortFinishedOn MediaListSort = "FINISHED_ON"
|
||||||
|
MediaListSortFinishedOnDesc MediaListSort = "FINISHED_ON_DESC"
|
||||||
|
MediaListSortAddedTime MediaListSort = "ADDED_TIME"
|
||||||
|
MediaListSortAddedTimeDesc MediaListSort = "ADDED_TIME_DESC"
|
||||||
|
MediaListSortUpdatedTime MediaListSort = "UPDATED_TIME"
|
||||||
|
MediaListSortUpdatedTimeDesc MediaListSort = "UPDATED_TIME_DESC"
|
||||||
|
MediaListSortMediaTitleRomaji MediaListSort = "MEDIA_TITLE_ROMAJI"
|
||||||
|
MediaListSortMediaTitleRomajiDesc MediaListSort = "MEDIA_TITLE_ROMAJI_DESC"
|
||||||
|
MediaListSortMediaTitleEnglish MediaListSort = "MEDIA_TITLE_ENGLISH"
|
||||||
|
MediaListSortMediaTitleEnglishDesc MediaListSort = "MEDIA_TITLE_ENGLISH_DESC"
|
||||||
|
MediaListSortMediaTitleNative MediaListSort = "MEDIA_TITLE_NATIVE"
|
||||||
|
MediaListSortMediaTitleNativeDesc MediaListSort = "MEDIA_TITLE_NATIVE_DESC"
|
||||||
|
MediaListSortMediaPopularity MediaListSort = "MEDIA_POPULARITY"
|
||||||
|
MediaListSortMediaPopularityDesc MediaListSort = "MEDIA_POPULARITY_DESC"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AiringScheduleQuery struct {
|
||||||
|
ID int
|
||||||
|
MediaID int
|
||||||
|
Episode int
|
||||||
|
AiringAt time.Time
|
||||||
|
NotYetAired bool
|
||||||
|
IdIn []int
|
||||||
|
IdNotIn []int
|
||||||
|
MediaIdIn []int
|
||||||
|
MediaIdNotIn []int
|
||||||
|
EpisodeIn []int
|
||||||
|
EpisodeNotIn []int
|
||||||
|
EpisodeGreater int
|
||||||
|
EpisodeLesser int
|
||||||
|
AiringAtGreater time.Time
|
||||||
|
AiringAtLesser time.Time
|
||||||
|
Sort []AiringSort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *AiringScheduleQuery) toMap() map[string]interface{} {
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
addValue2InterfaceMap(m, "id", q.ID)
|
||||||
|
addValue2InterfaceMap(m, "mediaId", q.MediaID)
|
||||||
|
addValue2InterfaceMap(m, "episode", q.Episode)
|
||||||
|
addValue2InterfaceMap(m, "airingAt", q.AiringAt)
|
||||||
|
addValue2InterfaceMap(m, "notYetAired", q.NotYetAired)
|
||||||
|
addSlice2InterfaceMap(m, "id_in", q.IdIn)
|
||||||
|
addSlice2InterfaceMap(m, "id_not_in", q.IdNotIn)
|
||||||
|
addSlice2InterfaceMap(m, "mediaId_in", q.MediaIdIn)
|
||||||
|
addSlice2InterfaceMap(m, "mediaId_not_in", q.MediaIdNotIn)
|
||||||
|
addSlice2InterfaceMap(m, "episode_in", q.EpisodeIn)
|
||||||
|
addSlice2InterfaceMap(m, "episode_not_in", q.EpisodeNotIn)
|
||||||
|
addValue2InterfaceMap(m, "episode_greater", q.EpisodeGreater)
|
||||||
|
addValue2InterfaceMap(m, "episode_lesser", q.EpisodeLesser)
|
||||||
|
addValue2InterfaceMap(m, "airingAt_greater", q.AiringAtGreater)
|
||||||
|
addValue2InterfaceMap(m, "airingAt_lesser", q.AiringAtLesser)
|
||||||
|
addSlice2InterfaceMap(m, "sort", q.Sort)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
type AiringSort string
|
||||||
|
|
||||||
|
const (
|
||||||
|
AiringSortId AiringSort = "ID"
|
||||||
|
AiringSortIdDesc AiringSort = "ID_DESC"
|
||||||
|
AiringSortMediaId AiringSort = "MEDIA_ID"
|
||||||
|
AiringSortMediaIdDesc AiringSort = "MEDIA_ID_DESC"
|
||||||
|
AiringSortTime AiringSort = "TIME"
|
||||||
|
AiringSortTimeDesc AiringSort = "TIME_DESC"
|
||||||
|
AiringSortEpisode AiringSort = "EPISODE"
|
||||||
|
AiringSortEpisodeDesc AiringSort = "EPISODE_DESC"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaQuery struct {
|
||||||
|
ID int
|
||||||
|
StartDate time.Time
|
||||||
|
EndDate time.Time
|
||||||
|
Season MediaSeason
|
||||||
|
SeasonYear int
|
||||||
|
Type MediaType
|
||||||
|
Format MediaFormat
|
||||||
|
Status MediaStatus
|
||||||
|
Episodes int
|
||||||
|
Duration time.Duration
|
||||||
|
Chapters int
|
||||||
|
Volumes int
|
||||||
|
IsAdult bool
|
||||||
|
Genre string
|
||||||
|
Tag string
|
||||||
|
Source MediaSource
|
||||||
|
Search string
|
||||||
|
IdIn []int
|
||||||
|
IdNotIn []int
|
||||||
|
StartDateGreater time.Time
|
||||||
|
StartDateLesser time.Time
|
||||||
|
EndDateGreater time.Time
|
||||||
|
EndDateLesser time.Time
|
||||||
|
FormatIn []MediaFormat
|
||||||
|
FormatNotIn []MediaFormat
|
||||||
|
StatusIn []MediaStatus
|
||||||
|
StatusNotIn []MediaStatus
|
||||||
|
EpisodesGreater int
|
||||||
|
EpisodesLesser int
|
||||||
|
DurationGreater time.Duration
|
||||||
|
DurationLesser time.Duration
|
||||||
|
VolumesGreater int
|
||||||
|
VolumesLesser int
|
||||||
|
GenreIn []string
|
||||||
|
GenreNotIn []string
|
||||||
|
TagIn []string
|
||||||
|
TagNotIn []string
|
||||||
|
SourceIn []MediaSource
|
||||||
|
Sort []MediaSort
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *MediaQuery) toMap() map[string]interface{} {
|
||||||
|
m := map[string]interface{}{}
|
||||||
|
addValue2InterfaceMap(m, "id", q.ID)
|
||||||
|
addValue2InterfaceMap(m, "startDate", q.StartDate)
|
||||||
|
addValue2InterfaceMap(m, "endDate", q.EndDate)
|
||||||
|
addValue2InterfaceMap(m, "season", q.Season)
|
||||||
|
addValue2InterfaceMap(m, "seasonYear", q.SeasonYear)
|
||||||
|
addValue2InterfaceMap(m, "type", q.Type)
|
||||||
|
addValue2InterfaceMap(m, "format", q.Format)
|
||||||
|
addValue2InterfaceMap(m, "status", q.Status)
|
||||||
|
addValue2InterfaceMap(m, "episodes", q.Episodes)
|
||||||
|
addValue2InterfaceMap(m, "duration", q.Duration.Minutes())
|
||||||
|
addValue2InterfaceMap(m, "chapters", q.Chapters)
|
||||||
|
addValue2InterfaceMap(m, "volumes", q.Volumes)
|
||||||
|
addValue2InterfaceMap(m, "isAdult", q.IsAdult)
|
||||||
|
addValue2InterfaceMap(m, "genre", q.Genre)
|
||||||
|
addValue2InterfaceMap(m, "tag", q.Tag)
|
||||||
|
addValue2InterfaceMap(m, "source", q.Source)
|
||||||
|
addValue2InterfaceMap(m, "search", q.Search)
|
||||||
|
addSlice2InterfaceMap(m, "id_in", q.IdIn)
|
||||||
|
addSlice2InterfaceMap(m, "id_not_in", q.IdNotIn)
|
||||||
|
addValue2InterfaceMap(m, "startDateGreater", q.StartDateGreater)
|
||||||
|
addValue2InterfaceMap(m, "startDateLesser", q.StartDateLesser)
|
||||||
|
addValue2InterfaceMap(m, "endDateGreater", q.EndDateGreater)
|
||||||
|
addValue2InterfaceMap(m, "endDateLesser", q.EndDateLesser)
|
||||||
|
addSlice2InterfaceMap(m, "format_in", q.FormatIn)
|
||||||
|
addSlice2InterfaceMap(m, "format_not_in", q.FormatNotIn)
|
||||||
|
addSlice2InterfaceMap(m, "status_in", q.StatusIn)
|
||||||
|
addSlice2InterfaceMap(m, "status_not_in", q.StatusNotIn)
|
||||||
|
addValue2InterfaceMap(m, "episodesGreater", q.EpisodesGreater)
|
||||||
|
addValue2InterfaceMap(m, "episodesLesser", q.EpisodesLesser)
|
||||||
|
addValue2InterfaceMap(m, "durationGreater", q.DurationGreater.Minutes())
|
||||||
|
addValue2InterfaceMap(m, "durationLesser", q.DurationLesser.Minutes())
|
||||||
|
addValue2InterfaceMap(m, "volumesGreater", q.VolumesGreater)
|
||||||
|
addValue2InterfaceMap(m, "volumesLesser", q.VolumesLesser)
|
||||||
|
addSlice2InterfaceMap(m, "genre_in", q.GenreIn)
|
||||||
|
addSlice2InterfaceMap(m, "genre_not_in", q.GenreNotIn)
|
||||||
|
addSlice2InterfaceMap(m, "tag_in", q.TagIn)
|
||||||
|
addSlice2InterfaceMap(m, "tag_not_in", q.TagNotIn)
|
||||||
|
addSlice2InterfaceMap(m, "source_in", q.SourceIn)
|
||||||
|
addSlice2InterfaceMap(m, "sort", q.Sort)
|
||||||
|
return m
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaSort string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaSortId MediaSort = "ID"
|
||||||
|
MediaSortIdDesc MediaSort = "ID_DESC"
|
||||||
|
MediaSortTitleRomaji MediaSort = "TITLE_ROMAJI"
|
||||||
|
MediaSortTitleRomajiDesc MediaSort = "TITLE_ROMAJI_DESC"
|
||||||
|
MediaSortTitleEnglish MediaSort = "TITLE_ENGLISH"
|
||||||
|
MediaSortTitleEnglishDesc MediaSort = "TITLE_ENGLISH_DESC"
|
||||||
|
MediaSortTitleNative MediaSort = "TITLE_NATIVE"
|
||||||
|
MediaSortTitleNativeDesc MediaSort = "TITLE_NATIVE_DESC"
|
||||||
|
MediaSortType MediaSort = "TYPE"
|
||||||
|
MediaSortTypeDesc MediaSort = "TYPE_DESC"
|
||||||
|
MediaSortFormat MediaSort = "FORMAT"
|
||||||
|
MediaSortFormatDesc MediaSort = "FORMAT_DESC"
|
||||||
|
MediaSortStartDate MediaSort = "START_DATE"
|
||||||
|
MediaSortStartDateDesc MediaSort = "START_DATE_DESC"
|
||||||
|
MediaSortEndDate MediaSort = "END_DATE"
|
||||||
|
MediaSortEndDateDesc MediaSort = "END_DATE_DESC"
|
||||||
|
MediaSortScore MediaSort = "SCORE"
|
||||||
|
MediaSortScoreDesc MediaSort = "SCORE_DESC"
|
||||||
|
MediaSortPopularity MediaSort = "POPULARITY"
|
||||||
|
MediaSortPopularityDesc MediaSort = "POPULARITY_DESC"
|
||||||
|
MediaSortTrending MediaSort = "TRENDING"
|
||||||
|
MediaSortTrendingDesc MediaSort = "TRENDING_DESC"
|
||||||
|
MediaSortEpisodes MediaSort = "EPISODES"
|
||||||
|
MediaSortEpisodesDesc MediaSort = "EPISODES_DESC"
|
||||||
|
MediaSortDuration MediaSort = "DURATION"
|
||||||
|
MediaSortDurationDesc MediaSort = "DURATION_DESC"
|
||||||
|
MediaSortStatus MediaSort = "STATUS"
|
||||||
|
MediaSortStatusDesc MediaSort = "STATUS_DESC"
|
||||||
|
MediaSortChapters MediaSort = "CHAPTERS"
|
||||||
|
MediaSortChaptersDesc MediaSort = "CHAPTERS_DESC"
|
||||||
|
MediaSortVolumes MediaSort = "VOLUMES"
|
||||||
|
MediaSortVolumesDesc MediaSort = "VOLUMES_DESC"
|
||||||
|
MediaSortUpdatedAt MediaSort = "UPDATED_AT"
|
||||||
|
MediaSortUpdatedAtDesc MediaSort = "UPDATED_AT_DESC"
|
||||||
|
MediaSortSearchMatch MediaSort = "SEARCH_MATCH"
|
||||||
|
MediaSortFavourites MediaSort = "FAVOURITES"
|
||||||
|
MediaSortFavouritesDesc MediaSort = "FAVOURITES_DESC"
|
||||||
|
)
|
111
sub_selections.go
Normal file
111
sub_selections.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
const (
|
||||||
|
subSelectionAiringSchedule = `{
|
||||||
|
id
|
||||||
|
mediaId
|
||||||
|
airingAt
|
||||||
|
timeUntilAiring
|
||||||
|
episode
|
||||||
|
media ` + subSelectionMedia + `
|
||||||
|
}`
|
||||||
|
|
||||||
|
subSelectionMediaList = `{
|
||||||
|
id
|
||||||
|
userId
|
||||||
|
mediaId
|
||||||
|
status
|
||||||
|
score
|
||||||
|
progress
|
||||||
|
progressVolumes
|
||||||
|
repeat
|
||||||
|
priority
|
||||||
|
private
|
||||||
|
notes
|
||||||
|
hiddenFromStatusLists
|
||||||
|
startedAt ` + subSelectionFuzzyDate + `
|
||||||
|
completedAt ` + subSelectionFuzzyDate + `
|
||||||
|
updatedAt
|
||||||
|
createdAt
|
||||||
|
media ` + subSelectionMedia + `
|
||||||
|
user ` + subSelectionUser + `
|
||||||
|
}`
|
||||||
|
|
||||||
|
subSelectionUser = `{
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}`
|
||||||
|
|
||||||
|
subSelectionMedia = `{
|
||||||
|
id
|
||||||
|
title {
|
||||||
|
romaji
|
||||||
|
english
|
||||||
|
native
|
||||||
|
userPreferred
|
||||||
|
}
|
||||||
|
type
|
||||||
|
format
|
||||||
|
status
|
||||||
|
description
|
||||||
|
startDate ` + subSelectionFuzzyDate + `
|
||||||
|
endDate ` + subSelectionFuzzyDate + `
|
||||||
|
season
|
||||||
|
seasonYear
|
||||||
|
seasonInt
|
||||||
|
episodes
|
||||||
|
duration
|
||||||
|
chapters
|
||||||
|
volumes
|
||||||
|
countryOfOrigin
|
||||||
|
isLicensed
|
||||||
|
source
|
||||||
|
hashtag
|
||||||
|
trailer {
|
||||||
|
id
|
||||||
|
site
|
||||||
|
thumbnail
|
||||||
|
}
|
||||||
|
updatedAt
|
||||||
|
coverImage {
|
||||||
|
extraLarge
|
||||||
|
large
|
||||||
|
medium
|
||||||
|
color
|
||||||
|
}
|
||||||
|
bannerImage
|
||||||
|
genres
|
||||||
|
synonyms
|
||||||
|
averageScore
|
||||||
|
meanScore
|
||||||
|
popularity
|
||||||
|
isLocked
|
||||||
|
trending
|
||||||
|
favourites
|
||||||
|
tags {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
description
|
||||||
|
category
|
||||||
|
rank
|
||||||
|
isGeneralSpoiler
|
||||||
|
isMediaSpoiler
|
||||||
|
isAdult
|
||||||
|
userId
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
|
||||||
|
subSelectionFuzzyDate = `{
|
||||||
|
year
|
||||||
|
month
|
||||||
|
day
|
||||||
|
}`
|
||||||
|
|
||||||
|
subSelectionPageInfo = `{
|
||||||
|
total
|
||||||
|
currentPage
|
||||||
|
lastPage
|
||||||
|
hasNextPage
|
||||||
|
perPage
|
||||||
|
}`
|
||||||
|
)
|
214
types.go
Normal file
214
types.go
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID int `json:"id,omitempty"`
|
||||||
|
Name string `json:"name,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Media struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Title MediaTitle `json:"title"`
|
||||||
|
Type MediaType `json:"type"`
|
||||||
|
Format MediaFormat `json:"format"`
|
||||||
|
Status MediaStatus `json:"status"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
StartDate FuzzyDate `json:"startDate"`
|
||||||
|
EndDate FuzzyDate `json:"endDate"`
|
||||||
|
Season MediaSeason `json:"season"`
|
||||||
|
SeasonYear int `json:"seasonYear"`
|
||||||
|
SeasonInt int `json:"seasonInt"`
|
||||||
|
Episodes int `json:"episodes"`
|
||||||
|
Duration Minutes `json:"duration"`
|
||||||
|
Chapters int `json:"chapters"`
|
||||||
|
Volumes int `json:"volumes"`
|
||||||
|
CountryOfOrigin string `json:"countryOfOrigin"`
|
||||||
|
Licensed bool `json:"isLicensed"`
|
||||||
|
Source MediaSource `json:"source"`
|
||||||
|
Hashtag string `json:"hashtag"`
|
||||||
|
Trailer MediaTrailer `json:"trailer"`
|
||||||
|
UpdatedAt UnixTime `json:"updatedAt"`
|
||||||
|
CoverImage MediaCoverImage `json:"coverImage"`
|
||||||
|
BannerImage string `json:"bannerImage"`
|
||||||
|
Genres []string `json:"genres"`
|
||||||
|
Synonyms []string `json:"synonyms"`
|
||||||
|
AverageScore int `json:"averageScore"`
|
||||||
|
MeanScore int `json:"meanScore"`
|
||||||
|
Popularity int `json:"popularity"`
|
||||||
|
Locked bool `json:"isLocked"`
|
||||||
|
Trending int `json:"trending"`
|
||||||
|
Favourites int `json:"favourites"`
|
||||||
|
Tags []MediaTag `json:"tags"`
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaTitle struct {
|
||||||
|
Romaji string `json:"romaji"`
|
||||||
|
English string `json:"english"`
|
||||||
|
Native string `json:"native"`
|
||||||
|
UserPreferred string `json:"userPreferred"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaTypeAnime MediaType = "ANIME"
|
||||||
|
MediaTypeManga MediaType = "MANGA"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaFormat string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaFormatTV MediaFormat = "TV"
|
||||||
|
MediaFormatTVShort MediaFormat = "TV_SHORT"
|
||||||
|
MediaFormatMovie MediaFormat = "MOVIE"
|
||||||
|
MediaFormatSpecial MediaFormat = "SPECIAL"
|
||||||
|
MediaFormatOVA MediaFormat = "OVA"
|
||||||
|
MediaFormatONA MediaFormat = "ONA"
|
||||||
|
MediaFormatMusic MediaFormat = "MUSIC"
|
||||||
|
MediaFormatManga MediaFormat = "MANGA"
|
||||||
|
MediaFormatNovel MediaFormat = "NOVEL"
|
||||||
|
MediaFormatOneShot MediaFormat = "ONE_SHOT"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaStatusFinished MediaStatus = "FINISHED"
|
||||||
|
MediaStatusReleasing MediaStatus = "RELEASING"
|
||||||
|
MediaStatusNotYetReleased MediaStatus = "NOT_YET_RELEASED"
|
||||||
|
MediaStatusCancelled MediaStatus = "CANCELLED"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaSeason string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaSeasonWinter MediaSeason = "WINTER"
|
||||||
|
MediaSeasonSpring MediaSeason = "SPRING"
|
||||||
|
MediaSeasonSummer MediaSeason = "SUMMER"
|
||||||
|
MediaSeasonFall MediaSeason = "FALL"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaSource string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaSourceOriginal MediaSource = "ORIGINAL"
|
||||||
|
MediaSourceManga MediaSource = "MANGA"
|
||||||
|
MediaSourceLightNovel MediaSource = "LIGHT_NOVEL"
|
||||||
|
MediaSourceVisualNovel MediaSource = "VISUAL_NOVEL"
|
||||||
|
MediaSourceVideoGame MediaSource = "VIDEO_GAME"
|
||||||
|
MediaSourceOther MediaSource = "OTHER"
|
||||||
|
MediaSourceNovel MediaSource = "NOVEL"
|
||||||
|
MediaSourceDoujinshi MediaSource = "DOUJINSHI"
|
||||||
|
MediaSourceAnime MediaSource = "ANIME"
|
||||||
|
MediaSourceWebNovel MediaSource = "WEB_NOVEL"
|
||||||
|
MediaSourceLiveAction MediaSource = "LIVE_ACTION"
|
||||||
|
MediaSourceGame MediaSource = "GAME"
|
||||||
|
MediaSourceComic MediaSource = "COMIC"
|
||||||
|
MediaSourceMultimediaProject MediaSource = "MULTIMEDIA_PROJECT"
|
||||||
|
MediaSourcePictureBook MediaSource = "PICTURE_BOOK"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MediaTrailer struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Site string `json:"site"`
|
||||||
|
Thumbnail string `json:"thumbnail"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaCoverImage struct {
|
||||||
|
ExtraLarge string `json:"extraLarge"`
|
||||||
|
Large string `json:"large"`
|
||||||
|
Medium string `json:"medium"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaTag struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Category string `json:"category"`
|
||||||
|
Rank int `json:"rank"`
|
||||||
|
GeneralSpoiler bool `json:"isGeneralSpoiler"`
|
||||||
|
MediaSpoiler bool `json:"isMediaSpoiler"`
|
||||||
|
Adult bool `json:"isAdult"`
|
||||||
|
UserID int `json:"userId"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type FuzzyDate struct {
|
||||||
|
Year int `json:"year"`
|
||||||
|
Month int `json:"month"`
|
||||||
|
Day int `json:"day"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d FuzzyDate) Time() time.Time {
|
||||||
|
return time.Date(d.Year, time.Month(d.Month), d.Day, 0, 0, 0, 0, time.UTC)
|
||||||
|
}
|
||||||
|
|
||||||
|
type FuzzyDateInt int // YYYYMMDD
|
||||||
|
|
||||||
|
func (d FuzzyDateInt) Time() time.Time {
|
||||||
|
year, month, day := int(d/10000), int(d/100%100), int(d%100)
|
||||||
|
return time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
|
||||||
|
}
|
||||||
|
|
||||||
|
type UnixTime int64
|
||||||
|
|
||||||
|
func (t UnixTime) Time() time.Time {
|
||||||
|
return time.Unix(int64(t), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Minutes int
|
||||||
|
|
||||||
|
func (d Minutes) Duration() time.Duration {
|
||||||
|
return time.Duration(d) * time.Minute
|
||||||
|
}
|
||||||
|
|
||||||
|
type Seconds int
|
||||||
|
|
||||||
|
func (d Seconds) Duration() time.Duration {
|
||||||
|
return time.Duration(d) * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaList struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
UserID int `json:"userId"`
|
||||||
|
MediaID int `json:"mediaId"`
|
||||||
|
Status MediaListStatus `json:"status"`
|
||||||
|
Score float64 `json:"score"`
|
||||||
|
Progress int `json:"progress"`
|
||||||
|
ProgressVolumes int `json:"progressVolumes"`
|
||||||
|
Repeat int `json:"repeat"`
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
Private bool `json:"private"`
|
||||||
|
Notes string `json:"notes"`
|
||||||
|
HiddenFromStatusLists bool `json:"hiddenFromStatusLists"`
|
||||||
|
StartedAt FuzzyDate `json:"startedAt"`
|
||||||
|
CompletedAt FuzzyDate `json:"completedAt"`
|
||||||
|
UpdatedAt UnixTime `json:"updatedAt"`
|
||||||
|
CreatedAt UnixTime `json:"createdAt"`
|
||||||
|
Media *Media `json:"media"`
|
||||||
|
User *User `json:"user"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type MediaListStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
MediaListStatusCurrent MediaSource = "CURRENT"
|
||||||
|
MediaListStatusPlanning MediaSource = "PLANNING"
|
||||||
|
MediaListStatusCompleted MediaSource = "COMPLETED"
|
||||||
|
MediaListStatusDropped MediaSource = "DROPPED"
|
||||||
|
MediaListStatusPaused MediaSource = "PAUSED"
|
||||||
|
MediaListStatusRepeating MediaSource = "REPEATING"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AiringSchedule struct {
|
||||||
|
ID int `json:"id"`
|
||||||
|
MediaID int `json:"mediaId"`
|
||||||
|
AiringAt UnixTime `json:"airingAt"`
|
||||||
|
TimeUntilAiring Seconds `json:"timeUntilAiring"`
|
||||||
|
Episode int `json:"episode"`
|
||||||
|
Media *Media `json:"media"`
|
||||||
|
}
|
58
user.go
Normal file
58
user.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
func (api *Api) GetUserByName(name string) (*User, error) {
|
||||||
|
query := `query ($name: String) {
|
||||||
|
User (name: $name) ` + subSelectionUser + `
|
||||||
|
}`
|
||||||
|
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"name": name,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := responseObj[struct {
|
||||||
|
User *User
|
||||||
|
}]{}
|
||||||
|
|
||||||
|
err := request(api, query, vars, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Data.User, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) GetUserByID(id int) (*User, error) {
|
||||||
|
query := `query ($id: Int) {
|
||||||
|
User (id: $id) ` + subSelectionUser + `
|
||||||
|
}`
|
||||||
|
|
||||||
|
vars := map[string]interface{}{
|
||||||
|
"id": id,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp := responseObj[struct {
|
||||||
|
User *User
|
||||||
|
}]{}
|
||||||
|
|
||||||
|
err := request(api, query, vars, &resp)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp.Data.User, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (api *Api) SearchUsers(search string, onError func(error)) <-chan *User {
|
||||||
|
vars := map[string]interface{}{"search": search}
|
||||||
|
resp := responseObj[*page[User]]{}
|
||||||
|
return requestPaged(api, searchUsersQuery, vars, &resp, onError)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
searchUsersQuery = `query ($search: String, $page: Int) {
|
||||||
|
Page (page: $page) {
|
||||||
|
pageInfo ` + subSelectionPageInfo + `
|
||||||
|
users (search: $search) ` + subSelectionUser + `
|
||||||
|
}
|
||||||
|
}`
|
||||||
|
)
|
24
utils.go
Normal file
24
utils.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package anilist
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func addValue2InterfaceMap[K, T comparable](m map[K]interface{}, key K, value T) {
|
||||||
|
if value != *new(T) {
|
||||||
|
if reflect.TypeOf(new(T)).Elem() == reflect.TypeOf(new(time.Time)).Elem() {
|
||||||
|
var t interface{} = value
|
||||||
|
m[key] = t.(time.Time).Unix()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
m[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addSlice2InterfaceMap[K, T comparable](m map[K]interface{}, key K, value []T) {
|
||||||
|
if value != nil && len(value) > 0 {
|
||||||
|
m[key] = value
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user