Compare commits
No commits in common. "main" and "v1.0.0" have entirely different histories.
1
.gitignore
vendored
1
.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
api_test.go
|
|
@ -1,10 +1,8 @@
|
|||||||
package anilist
|
package anilist
|
||||||
|
|
||||||
import "context"
|
func (api *Api) GetAiringSchedule(vars AiringScheduleQuery, onError func(error)) <-chan *AiringSchedule {
|
||||||
|
|
||||||
func (api *Api) GetAiringSchedule(ctx context.Context, vars AiringScheduleQuery, onError func(error)) *Cursor[AiringSchedule] {
|
|
||||||
resp := responseObj[*page[AiringSchedule]]{}
|
resp := responseObj[*page[AiringSchedule]]{}
|
||||||
return requestPaged(api, ctx, getAiringScheduleQuery, vars.toMap(), &resp, onError)
|
return requestPaged(api, getAiringScheduleQuery, vars.toMap(), &resp, onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
27
api.go
27
api.go
@ -2,7 +2,6 @@ package anilist
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@ -49,10 +48,6 @@ func request[T any](api *Api, query string, vars map[string]interface{}, respObj
|
|||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
|
||||||
return handleError(resp)
|
|
||||||
}
|
|
||||||
|
|
||||||
//data, _ := ioutil.ReadAll(resp.Body)
|
//data, _ := ioutil.ReadAll(resp.Body)
|
||||||
//fmt.Println(string(data))
|
//fmt.Println(string(data))
|
||||||
|
|
||||||
@ -65,19 +60,15 @@ func request[T any](api *Api, query string, vars map[string]interface{}, respObj
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestPaged[R any](api *Api, ctx context.Context, query string, vars map[string]interface{}, respObj *responseObj[*page[R]], onError func(error)) *Cursor[R] {
|
func requestPaged[R any](api *Api, query string, vars map[string]interface{}, respObj *responseObj[*page[R]], onError func(error)) <-chan *R {
|
||||||
resp := responseObj[struct {
|
resp := responseObj[struct {
|
||||||
Page *page[R] `json:"Page"`
|
Page *page[R] `json:"Page"`
|
||||||
}]{}
|
}]{}
|
||||||
|
|
||||||
var cancelFunc context.CancelFunc
|
|
||||||
ctx, cancelFunc = context.WithCancel(ctx)
|
|
||||||
|
|
||||||
out := make(chan *R, 50)
|
out := make(chan *R, 50)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
defer close(out)
|
defer close(out)
|
||||||
defer cancelFunc()
|
|
||||||
|
|
||||||
vars["page"] = 0
|
vars["page"] = 0
|
||||||
|
|
||||||
@ -94,17 +85,9 @@ func requestPaged[R any](api *Api, ctx context.Context, query string, vars map[s
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data.Page == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, value := range resp.Data.Page.Data() {
|
for _, value := range resp.Data.Page.Data() {
|
||||||
value := value
|
value := value
|
||||||
select {
|
out <- &value
|
||||||
case out <- &value:
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data.Page.PageInfo.CurrentPage == resp.Data.Page.PageInfo.LastPage {
|
if resp.Data.Page.PageInfo.CurrentPage == resp.Data.Page.PageInfo.LastPage {
|
||||||
@ -113,9 +96,5 @@ func requestPaged[R any](api *Api, ctx context.Context, query string, vars map[s
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return &Cursor[R]{
|
return out
|
||||||
Chan: out,
|
|
||||||
ctx: ctx,
|
|
||||||
cancelFunc: cancelFunc,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
32
api_error.go
32
api_error.go
@ -1,32 +0,0 @@
|
|||||||
package anilist
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"net/http"
|
|
||||||
)
|
|
||||||
|
|
||||||
type apiError struct {
|
|
||||||
Message string `json:"message"`
|
|
||||||
Status int `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type apiErrResp struct {
|
|
||||||
Errors []apiError `json:"errors"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleError(resp *http.Response) error {
|
|
||||||
respObj := &apiErrResp{}
|
|
||||||
|
|
||||||
dec := json.NewDecoder(resp.Body)
|
|
||||||
err := dec.Decode(respObj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(respObj.Errors) == 0 {
|
|
||||||
return errors.New("unknown API error")
|
|
||||||
}
|
|
||||||
|
|
||||||
return errors.New(respObj.Errors[0].Message)
|
|
||||||
}
|
|
35
cursor.go
35
cursor.go
@ -1,35 +0,0 @@
|
|||||||
package anilist
|
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
type Cursor[T any] struct {
|
|
||||||
ctx context.Context
|
|
||||||
cancelFunc context.CancelFunc
|
|
||||||
Chan <-chan *T
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cursor[T]) First() *T {
|
|
||||||
defer c.cancelFunc()
|
|
||||||
return <-c.Chan
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cursor[T]) Close() {
|
|
||||||
c.cancelFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cursor[T]) Next() (*T, bool) {
|
|
||||||
if c.ctx.Err() == nil {
|
|
||||||
value, ok := <-c.Chan
|
|
||||||
return value, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Cursor[T]) Slice() []T {
|
|
||||||
s := make([]T, 0)
|
|
||||||
for value, ok := c.Next(); ok; value, ok = c.Next() {
|
|
||||||
s = append(s, *value)
|
|
||||||
}
|
|
||||||
return s
|
|
||||||
}
|
|
2
go.mod
2
go.mod
@ -1,3 +1,3 @@
|
|||||||
module git.milar.in/milarin/anilist
|
module git.tordarus.net/Tordarus/anilist
|
||||||
|
|
||||||
go 1.18
|
go 1.18
|
||||||
|
6
media.go
6
media.go
@ -1,10 +1,8 @@
|
|||||||
package anilist
|
package anilist
|
||||||
|
|
||||||
import "context"
|
func (api *Api) GetMedia(vars MediaQuery, onError func(error)) <-chan *Media {
|
||||||
|
|
||||||
func (api *Api) GetMedia(ctx context.Context, vars MediaQuery, onError func(error)) *Cursor[Media] {
|
|
||||||
resp := responseObj[*page[Media]]{}
|
resp := responseObj[*page[Media]]{}
|
||||||
return requestPaged(api, ctx, getMediaQuery, vars.toMap(), &resp, onError)
|
return requestPaged(api, getMediaQuery, vars.toMap(), &resp, onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package anilist
|
package anilist
|
||||||
|
|
||||||
import "context"
|
func (api *Api) GetMediaList(vars MediaListQuery, onError func(error)) <-chan *MediaList {
|
||||||
|
|
||||||
func (api *Api) GetMediaList(ctx context.Context, vars MediaListQuery, onError func(error)) *Cursor[MediaList] {
|
|
||||||
resp := responseObj[*page[MediaList]]{}
|
resp := responseObj[*page[MediaList]]{}
|
||||||
return requestPaged(api, ctx, getMediaListQuery, vars.toMap(), &resp, onError)
|
return requestPaged(api, getMediaListQuery, vars.toMap(), &resp, onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -7,6 +7,7 @@ const (
|
|||||||
airingAt
|
airingAt
|
||||||
timeUntilAiring
|
timeUntilAiring
|
||||||
episode
|
episode
|
||||||
|
media ` + subSelectionMedia + `
|
||||||
}`
|
}`
|
||||||
|
|
||||||
subSelectionMediaList = `{
|
subSelectionMediaList = `{
|
||||||
@ -92,7 +93,7 @@ const (
|
|||||||
isAdult
|
isAdult
|
||||||
userId
|
userId
|
||||||
}
|
}
|
||||||
nextAiringEpisode ` + subSelectionAiringSchedule + `
|
nextAiringEpisode
|
||||||
}`
|
}`
|
||||||
|
|
||||||
subSelectionFuzzyDate = `{
|
subSelectionFuzzyDate = `{
|
||||||
|
37
types.go
37
types.go
@ -9,10 +9,8 @@ type User struct {
|
|||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaID int
|
|
||||||
|
|
||||||
type Media struct {
|
type Media struct {
|
||||||
ID MediaID `json:"id"`
|
ID int `json:"id"`
|
||||||
Title MediaTitle `json:"title"`
|
Title MediaTitle `json:"title"`
|
||||||
Type MediaType `json:"type"`
|
Type MediaType `json:"type"`
|
||||||
Format MediaFormat `json:"format"`
|
Format MediaFormat `json:"format"`
|
||||||
@ -115,10 +113,8 @@ const (
|
|||||||
MediaSourcePictureBook MediaSource = "PICTURE_BOOK"
|
MediaSourcePictureBook MediaSource = "PICTURE_BOOK"
|
||||||
)
|
)
|
||||||
|
|
||||||
type MediaTrailerID string
|
|
||||||
|
|
||||||
type MediaTrailer struct {
|
type MediaTrailer struct {
|
||||||
ID MediaTrailerID `json:"id"`
|
ID string `json:"id"`
|
||||||
Site string `json:"site"`
|
Site string `json:"site"`
|
||||||
Thumbnail string `json:"thumbnail"`
|
Thumbnail string `json:"thumbnail"`
|
||||||
}
|
}
|
||||||
@ -130,10 +126,8 @@ type MediaCoverImage struct {
|
|||||||
Color string `json:"color"`
|
Color string `json:"color"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaTagID int
|
|
||||||
|
|
||||||
type MediaTag struct {
|
type MediaTag struct {
|
||||||
MediaTagID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Category string `json:"category"`
|
Category string `json:"category"`
|
||||||
@ -179,12 +173,10 @@ func (d Seconds) Duration() time.Duration {
|
|||||||
return time.Duration(d) * time.Second
|
return time.Duration(d) * time.Second
|
||||||
}
|
}
|
||||||
|
|
||||||
type MediaListID int
|
|
||||||
|
|
||||||
type MediaList struct {
|
type MediaList struct {
|
||||||
ID MediaListID `json:"id"`
|
ID int `json:"id"`
|
||||||
UserID int `json:"userId"`
|
UserID int `json:"userId"`
|
||||||
MediaID MediaID `json:"mediaId"`
|
MediaID int `json:"mediaId"`
|
||||||
Status MediaListStatus `json:"status"`
|
Status MediaListStatus `json:"status"`
|
||||||
Score float64 `json:"score"`
|
Score float64 `json:"score"`
|
||||||
Progress int `json:"progress"`
|
Progress int `json:"progress"`
|
||||||
@ -205,20 +197,19 @@ type MediaList struct {
|
|||||||
type MediaListStatus string
|
type MediaListStatus string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
MediaListStatusCurrent MediaListStatus = "CURRENT"
|
MediaListStatusCurrent MediaSource = "CURRENT"
|
||||||
MediaListStatusPlanning MediaListStatus = "PLANNING"
|
MediaListStatusPlanning MediaSource = "PLANNING"
|
||||||
MediaListStatusCompleted MediaListStatus = "COMPLETED"
|
MediaListStatusCompleted MediaSource = "COMPLETED"
|
||||||
MediaListStatusDropped MediaListStatus = "DROPPED"
|
MediaListStatusDropped MediaSource = "DROPPED"
|
||||||
MediaListStatusPaused MediaListStatus = "PAUSED"
|
MediaListStatusPaused MediaSource = "PAUSED"
|
||||||
MediaListStatusRepeating MediaListStatus = "REPEATING"
|
MediaListStatusRepeating MediaSource = "REPEATING"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AiringScheduleID int
|
|
||||||
|
|
||||||
type AiringSchedule struct {
|
type AiringSchedule struct {
|
||||||
ID AiringScheduleID `json:"id"`
|
ID int `json:"id"`
|
||||||
MediaID MediaID `json:"mediaId"`
|
MediaID int `json:"mediaId"`
|
||||||
AiringAt UnixTime `json:"airingAt"`
|
AiringAt UnixTime `json:"airingAt"`
|
||||||
TimeUntilAiring Seconds `json:"timeUntilAiring"`
|
TimeUntilAiring Seconds `json:"timeUntilAiring"`
|
||||||
Episode int `json:"episode"`
|
Episode int `json:"episode"`
|
||||||
|
Media *Media `json:"media"`
|
||||||
}
|
}
|
||||||
|
6
user.go
6
user.go
@ -1,7 +1,5 @@
|
|||||||
package anilist
|
package anilist
|
||||||
|
|
||||||
import "context"
|
|
||||||
|
|
||||||
func (api *Api) GetUserByName(name string) (*User, error) {
|
func (api *Api) GetUserByName(name string) (*User, error) {
|
||||||
query := `query ($name: String) {
|
query := `query ($name: String) {
|
||||||
User (name: $name) ` + subSelectionUser + `
|
User (name: $name) ` + subSelectionUser + `
|
||||||
@ -44,10 +42,10 @@ func (api *Api) GetUserByID(id int) (*User, error) {
|
|||||||
return resp.Data.User, nil
|
return resp.Data.User, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *Api) SearchUsers(ctx context.Context, search string, onError func(error)) *Cursor[User] {
|
func (api *Api) SearchUsers(search string, onError func(error)) <-chan *User {
|
||||||
vars := map[string]interface{}{"search": search}
|
vars := map[string]interface{}{"search": search}
|
||||||
resp := responseObj[*page[User]]{}
|
resp := responseObj[*page[User]]{}
|
||||||
return requestPaged(api, ctx, searchUsersQuery, vars, &resp, onError)
|
return requestPaged(api, searchUsersQuery, vars, &resp, onError)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
2
utils.go
2
utils.go
@ -18,7 +18,7 @@ func addValue2InterfaceMap[K, T comparable](m map[K]interface{}, key K, value T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func addSlice2InterfaceMap[K, T comparable](m map[K]interface{}, key K, value []T) {
|
func addSlice2InterfaceMap[K, T comparable](m map[K]interface{}, key K, value []T) {
|
||||||
if len(value) > 0 {
|
if value != nil && len(value) > 0 {
|
||||||
m[key] = value
|
m[key] = value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user