mirror of
https://github.com/Apologieze/Benri.git
synced 2026-01-18 17:17:21 +01:00
Adding custom verniy, new sorting, fix window build
This commit is contained in:
129
verniy/character.go
Normal file
129
verniy/character.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type characterResponse struct {
|
||||
Data struct {
|
||||
Character Character `json:"character"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) characterQuery(params QueryParam, fields ...CharacterField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("Character", params, p...)
|
||||
}
|
||||
|
||||
// GetCharacter to get character data.
|
||||
func (c *Client) GetCharacter(id int, fields ...CharacterField) (*Character, error) {
|
||||
return c.GetCharacterWithContext(context.Background(), id, fields...)
|
||||
}
|
||||
|
||||
// GetCharacterWithContext to get character data with context.
|
||||
func (c *Client) GetCharacterWithContext(ctx context.Context, id int, fields ...CharacterField) (*Character, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []CharacterField{
|
||||
CharacterFieldID,
|
||||
CharacterFieldName(
|
||||
CharacterNameFieldFirst,
|
||||
CharacterNameFieldMiddle,
|
||||
CharacterNameFieldLast,
|
||||
CharacterNameFieldFull,
|
||||
CharacterNameFieldNative,
|
||||
CharacterNameFieldAlternative,
|
||||
CharacterNameFieldAlternativeSpoiler),
|
||||
CharacterFieldImage(CharacterImageFieldLarge),
|
||||
CharacterFieldDescription,
|
||||
CharacterFieldGender,
|
||||
CharacterFieldDateOfBirth,
|
||||
CharacterFieldAge,
|
||||
CharacterFieldFavourite,
|
||||
}
|
||||
}
|
||||
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$id": "Int",
|
||||
}, c.characterQuery(QueryParam{
|
||||
"id": "$id",
|
||||
}, fields...))
|
||||
|
||||
var d characterResponse
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"id": id,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d.Data.Character, nil
|
||||
}
|
||||
|
||||
// GetCharacterAnime to get list of anime the character play.
|
||||
func (c *Client) GetCharacterAnime(id int, page int, perPage int) (*Character, error) {
|
||||
return c.GetCharacterAnimeWithContext(context.Background(), id, page, perPage)
|
||||
}
|
||||
|
||||
// GetCharacterAnimeWithContext to get list of anime the character play with context.
|
||||
func (c *Client) GetCharacterAnimeWithContext(ctx context.Context, id int, page int, perPage int) (*Character, error) {
|
||||
return c.GetCharacterWithContext(ctx, id, CharacterFieldMedia(CharacterParamMedia{
|
||||
Type: MediaTypeAnime,
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldCharacterRole,
|
||||
MediaEdgeFieldVoiceActors(
|
||||
MediaEdgeParamVoiceActors{},
|
||||
StaffFieldID,
|
||||
StaffFieldLanguage,
|
||||
StaffFieldName(StaffNameFieldFull),
|
||||
StaffFieldImage(StaffImageFieldMedium)),
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldType,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative,
|
||||
MediaTitleFieldRomaji),
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldMedium)))))
|
||||
}
|
||||
|
||||
// GetCharacterManga to get list of manga the character play.
|
||||
func (c *Client) GetCharacterManga(id int, page int, perPage int) (*Character, error) {
|
||||
return c.GetCharacterMangaWithContext(context.Background(), id, page, perPage)
|
||||
}
|
||||
|
||||
// GetCharacterMangaWithContext to get list of manga the character play with context.
|
||||
func (c *Client) GetCharacterMangaWithContext(ctx context.Context, id int, page int, perPage int) (*Character, error) {
|
||||
return c.GetCharacterWithContext(ctx, id, CharacterFieldMedia(CharacterParamMedia{
|
||||
Type: MediaTypeManga,
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldCharacterRole,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldType,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative,
|
||||
MediaTitleFieldRomaji),
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldMedium)))))
|
||||
}
|
||||
422
verniy/constant.go
Normal file
422
verniy/constant.go
Normal file
@@ -0,0 +1,422 @@
|
||||
package verniy
|
||||
|
||||
// MediaType is main media type.
|
||||
type MediaType string
|
||||
|
||||
// Options for MediaType.
|
||||
const (
|
||||
MediaTypeAnime MediaType = "ANIME"
|
||||
MediaTypeManga MediaType = "MANGA"
|
||||
)
|
||||
|
||||
// MediaFormat is anime & manga format.
|
||||
type MediaFormat string
|
||||
|
||||
// Options for MediaFormat.
|
||||
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"
|
||||
)
|
||||
|
||||
// MediaStatus is anime & manga status.
|
||||
type MediaStatus string
|
||||
|
||||
// Options for MediaStatus.
|
||||
const (
|
||||
MediaStatusFinished MediaStatus = "FINISHED"
|
||||
MediaStatusReleasing MediaStatus = "RELEASING"
|
||||
MediaStatusNotYetReleased MediaStatus = "NOT_YET_RELEASED"
|
||||
MediaStatusCancelled MediaStatus = "CANCELLED"
|
||||
MediaStatusHiatus MediaStatus = "HIATUS"
|
||||
)
|
||||
|
||||
// MediaSeason is anime season.
|
||||
type MediaSeason string
|
||||
|
||||
// Options for MediaSeason.
|
||||
const (
|
||||
MediaSeasonWinter MediaSeason = "WINTER" // 12-2
|
||||
MediaSeasonSpring MediaSeason = "SPRING" // 3-5
|
||||
MediaSeasonSummer MediaSeason = "SUMMER" // 6-8
|
||||
MediaSeasonFall MediaSeason = "FALL" // 9-11
|
||||
)
|
||||
|
||||
// MediaSource is anime & manga source.
|
||||
type MediaSource string
|
||||
|
||||
// Options for MediaSource.
|
||||
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"
|
||||
)
|
||||
|
||||
// MediaRankType is type of ranking.
|
||||
type MediaRankType string
|
||||
|
||||
// Options for MediaRankType
|
||||
const (
|
||||
MediaRankTypeRated MediaRankType = "RATED"
|
||||
MediaRankTypePopular MediaRankType = "POPULAR"
|
||||
)
|
||||
|
||||
// MediaListStatus is user's anime & manga status.
|
||||
type MediaListStatus string
|
||||
|
||||
// Options for MediaListStatus.
|
||||
const (
|
||||
MediaListStatusCurrent MediaListStatus = "CURRENT"
|
||||
MediaListStatusPlanning MediaListStatus = "PLANNING"
|
||||
MediaListStatusCompleted MediaListStatus = "COMPLETED"
|
||||
MediaListStatusDropped MediaListStatus = "DROPPED"
|
||||
MediaListStatusPaused MediaListStatus = "PAUSED"
|
||||
MediaListStatusRepeating MediaListStatus = "REPEATING"
|
||||
)
|
||||
|
||||
// MediaRelation is anime & manga relation.
|
||||
type MediaRelation string
|
||||
|
||||
// Options for MediaRelation.
|
||||
const (
|
||||
MediaRelationAdaptation MediaRelation = "ADAPTATION"
|
||||
MediaRelationPrequel MediaRelation = "PREQUEL"
|
||||
MediaRelationSequel MediaRelation = "SEQUEL"
|
||||
MediaRelationParent MediaRelation = "PARENT"
|
||||
MediaRelationSideStory MediaRelation = "SIDE_STORY"
|
||||
MediaRelationCharacter MediaRelation = "CHARACTER"
|
||||
MediaRelationSummary MediaRelation = "SUMMARY"
|
||||
MediaRelationAlternative MediaRelation = "ALTERNATIVE"
|
||||
MediaRelationSpinOff MediaRelation = "SPIN_OFF"
|
||||
MediaRelationOther MediaRelation = "OTHER"
|
||||
MediaRelationSource MediaRelation = "SOURCE"
|
||||
MediaRelationCompilation MediaRelation = "COMPILATION"
|
||||
MediaRelationContains MediaRelation = "CONTAINS"
|
||||
)
|
||||
|
||||
// CharacterRole is type of character role.
|
||||
type CharacterRole string
|
||||
|
||||
// Options for CharacterRole.
|
||||
const (
|
||||
CharacterRoleMain CharacterRole = "MAIN"
|
||||
CharacterRoleSupporting CharacterRole = "SUPPORTING"
|
||||
CharacterRoleBackground CharacterRole = "BACKGROUND"
|
||||
)
|
||||
|
||||
// UserTitleLanguage is default user anime & manga title language.
|
||||
type UserTitleLanguage string
|
||||
|
||||
// Options for UserTitleLanguage.
|
||||
const (
|
||||
UserTitleLanguageRomaji UserTitleLanguage = "ROMAJI"
|
||||
UserTitleLanguageEnglish UserTitleLanguage = "ENGLISH"
|
||||
UserTitleLanguageNative UserTitleLanguage = "NATIVE"
|
||||
UserTitleLanguageRomajiStylised UserTitleLanguage = "ROMAJI_STYLISED"
|
||||
UserTitleLanguageEnglishStylised UserTitleLanguage = "ENGLISH_STYLISED"
|
||||
UserTitleLanguageNativeStylised UserTitleLanguage = "NATIVE_STYLISED"
|
||||
)
|
||||
|
||||
// NotificationType is user notification type.
|
||||
type NotificationType string
|
||||
|
||||
// Options for NotificationType.
|
||||
const (
|
||||
NotificationTypeActivityMessage NotificationType = "ACTIVITY_MESSAGE"
|
||||
NotificationTypeActivityReply NotificationType = "ACTIVITY_REPLY"
|
||||
NotificationTypeActivityFollowing NotificationType = "FOLLOWING"
|
||||
NotificationTypeActivityMention NotificationType = "ACTIVITY_MENTION"
|
||||
NotificationTypeThreadCommentMention NotificationType = "THREAD_COMMENT_MENTION"
|
||||
NotificationTypeThreadSubscribed NotificationType = "THREAD_SUBSCRIBED"
|
||||
NotificationTypeThreadCommentReply NotificationType = "THREAD_COMMENT_REPLY"
|
||||
NotificationTypeAiring NotificationType = "AIRING"
|
||||
NotificationTypeActivityLike NotificationType = "ACTIVITY_LIKE"
|
||||
NotificationTypeActivityReplyLike NotificationType = "ACTIVITY_REPLY_LIKE"
|
||||
NotificationTypeThreadLike NotificationType = "THREAD_LIKE"
|
||||
NotificationTypeThreadCommentLike NotificationType = "THREAD_COMMENT_LIKE"
|
||||
NotificationTypeActivityReplySubscribed NotificationType = "ACTIVITY_REPLY_SUBSCRIBED"
|
||||
NotificationTypeRelatedMediaAddition NotificationType = "RELATED_MEDIA_ADDITION"
|
||||
)
|
||||
|
||||
// UserStaffNameLanguage is default user staff naming language.
|
||||
type UserStaffNameLanguage string
|
||||
|
||||
// Options for UserStaffNameLanguage
|
||||
const (
|
||||
UserStaffNameLanguageRomajiWestern UserStaffNameLanguage = "ROMAJI_WESTERN"
|
||||
UserStaffNameLanguageRomaji UserStaffNameLanguage = "ROMAJI"
|
||||
UserStaffNameLanguageNative UserStaffNameLanguage = "NATIVE"
|
||||
)
|
||||
|
||||
// ReviewRating is type of review rating.
|
||||
type ReviewRating string
|
||||
|
||||
// Options for ReviewRating.
|
||||
const (
|
||||
ReviewRatingNoVote ReviewRating = "NO_VOTE"
|
||||
ReviewRatingUpVote ReviewRating = "UP_VOTE"
|
||||
ReviewRatingDownVote ReviewRating = "DOWN_VOTE"
|
||||
)
|
||||
|
||||
// RecommendationRating is type of recommendation rating.
|
||||
type RecommendationRating string
|
||||
|
||||
// Options for RecommendationRating.
|
||||
const (
|
||||
RecommendationRatingNoRating RecommendationRating = "NO_RATING"
|
||||
RecommendationRatingRateUp RecommendationRating = "RATE_UP"
|
||||
RecommendationRatingRateDown RecommendationRating = "RATE_DOWN"
|
||||
)
|
||||
|
||||
// ScoreFormat is scoring format.
|
||||
type ScoreFormat string
|
||||
|
||||
// Options for ScoreFormat.
|
||||
const (
|
||||
ScoreFormatPoint100 ScoreFormat = "POINT_100"
|
||||
ScoreFormatPoint100Decimal ScoreFormat = "POINT_10_DECIMAL"
|
||||
ScoreFormatPoint10 ScoreFormat = "POINT_10"
|
||||
ScoreFormatPoint5 ScoreFormat = "POINT_5"
|
||||
ScoreFormatPoint3 ScoreFormat = "POINT_3"
|
||||
)
|
||||
|
||||
// ModRole is mod role.
|
||||
type ModRole string
|
||||
|
||||
// Options for ModRole.
|
||||
const (
|
||||
ModRoleAdmin ModRole = "ADMIN"
|
||||
ModRoleLeadDeveloper ModRole = "LEAD_DEVELOPER"
|
||||
ModRoleDeveloper ModRole = "DEVELOPER"
|
||||
ModRoleLeadCommunity ModRole = "LEAD_COMMUNITY"
|
||||
ModRoleCommunity ModRole = "COMMUNITY"
|
||||
ModRoleDiscordCommunity ModRole = "DISCORD_COMMUNITY"
|
||||
ModRoleLeadAnimeData ModRole = "LEAD_ANIME_DATA"
|
||||
ModRoleAnimeData ModRole = "ANIME_DATA"
|
||||
ModRoleLeadMangaData ModRole = "LEAD_MANGA_DATA"
|
||||
ModRoleMangaData ModRole = "MANGA_DATA"
|
||||
ModRoleLeadSocialMedia ModRole = "LEAD_SOCIAL_MEDIA"
|
||||
ModRoleSocialMedia ModRole = "SOCIAL_MEDIA"
|
||||
ModRoleRetired ModRole = "RETIRED"
|
||||
)
|
||||
|
||||
// CharacterSort is sorting option for character list.
|
||||
type CharacterSort string
|
||||
|
||||
// Options for CharacterSort.
|
||||
const (
|
||||
CharacterSortID CharacterSort = "ID"
|
||||
CharacterSortIDDesc CharacterSort = "ID_DESC"
|
||||
CharacterSortRole CharacterSort = "ROLE"
|
||||
CharacterSortRoleDesc CharacterSort = "ROLE_DESC"
|
||||
CharacterSortSearchMatch CharacterSort = "SEARCH_MATCH"
|
||||
CharacterSortFavourites CharacterSort = "FAVOURITES"
|
||||
CharacterSortFavouritesDesc CharacterSort = "FAVOURITES_DESC"
|
||||
CharacterSortRelevance CharacterSort = "RELEVANCE"
|
||||
)
|
||||
|
||||
// StaffSort is sorting option for staff list.
|
||||
type StaffSort string
|
||||
|
||||
// Options for StaffSort.
|
||||
const (
|
||||
StaffSortID StaffSort = "ID"
|
||||
StaffSortIDDesc StaffSort = "ID_DESC"
|
||||
StaffSortRole StaffSort = "ROLE"
|
||||
StaffSortRoleDesc StaffSort = "ROLE_DESC"
|
||||
StaffSortLanguage StaffSort = "LANGUAGE"
|
||||
StaffSortLanguageDesc StaffSort = "LANGUAGE_DESC"
|
||||
StaffSortSearchMatch StaffSort = "SEARCH_MATCH"
|
||||
StaffSortFavourites StaffSort = "FAVOURITES"
|
||||
StaffSortFavouritesDesc StaffSort = "FAVOURITES_DESC"
|
||||
StaffSortRelevance StaffSort = "RELEVANCE"
|
||||
)
|
||||
|
||||
// MediaSort is sorting option for anime & manga list.
|
||||
type MediaSort string
|
||||
|
||||
// Options for MediaSort.
|
||||
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"
|
||||
)
|
||||
|
||||
// StaffLanguage is staff language.
|
||||
type StaffLanguage string
|
||||
|
||||
// Options for StaffLanguage.
|
||||
const (
|
||||
StaffLanguageJapanese StaffLanguage = "JAPANESE"
|
||||
StaffLanguageEnglish StaffLanguage = "ENGLISH"
|
||||
StaffLanguageKorean StaffLanguage = "KOREAN"
|
||||
StaffLanguageItalian StaffLanguage = "ITALIAN"
|
||||
StaffLanguageSpanish StaffLanguage = "SPANISH"
|
||||
StaffLanguagePortuguese StaffLanguage = "PORTUGUESE"
|
||||
StaffLanguageFrench StaffLanguage = "FRENCH"
|
||||
StaffLanguageGerman StaffLanguage = "GERMAN"
|
||||
StaffLanguageHebrew StaffLanguage = "HEBREW"
|
||||
StaffLanguageHungarian StaffLanguage = "HUNGARIAN"
|
||||
)
|
||||
|
||||
// StudioSort is sorting option for studio list.
|
||||
type StudioSort string
|
||||
|
||||
// Options for StudioSort.
|
||||
const (
|
||||
StudioSortID StudioSort = "ID"
|
||||
StudioSortIDDesc StudioSort = "ID_DESC"
|
||||
StudioSortName StudioSort = "NAME"
|
||||
StudioSortNameDesc StudioSort = "NAME_DESC"
|
||||
StudioSortSearchMatch StudioSort = "SEARCH_MATCH"
|
||||
StudioSortFavourites StudioSort = "FAVOURITES"
|
||||
StudioSortFavouritesDesc StudioSort = "FAVOURITES_DESC"
|
||||
)
|
||||
|
||||
// MediaTrendSort is sorting option for media trend list.
|
||||
type MediaTrendSort string
|
||||
|
||||
// Options for MediaTrendSort.
|
||||
const (
|
||||
MediaTrendSortID MediaTrendSort = "ID"
|
||||
MediaTrendSortIDDesc MediaTrendSort = "ID_DESC"
|
||||
MediaTrendSortMediaID MediaTrendSort = "MEDIA_ID"
|
||||
MediaTrendSortMediaIDDesc MediaTrendSort = "MEDIA_ID_DESC"
|
||||
MediaTrendSortDate MediaTrendSort = "DATE"
|
||||
MediaTrendSortDateDesc MediaTrendSort = "DATE_DESC"
|
||||
MediaTrendSortScore MediaTrendSort = "SCORE"
|
||||
MediaTrendSortScoreDesc MediaTrendSort = "SCORE_DESC"
|
||||
MediaTrendSortPopularity MediaTrendSort = "POPULARITY"
|
||||
MediaTrendSortPopularityDesc MediaTrendSort = "POPULARITY_DESC"
|
||||
MediaTrendSortTrending MediaTrendSort = "TRENDING"
|
||||
MediaTrendSortTrendingDesc MediaTrendSort = "TRENDING_DESC"
|
||||
MediaTrendSortEpisode MediaTrendSort = "EPISODE"
|
||||
MediaTrendSortEpisodeDesc MediaTrendSort = "EPISODE_DESC"
|
||||
)
|
||||
|
||||
// ReviewSort is sorting option for review list.
|
||||
type ReviewSort string
|
||||
|
||||
// Options for ReviewSort.
|
||||
const (
|
||||
ReviewSortID ReviewSort = "ID"
|
||||
ReviewSortIDDesc ReviewSort = "ID_DESC"
|
||||
ReviewSortScore ReviewSort = "SCORE"
|
||||
ReviewSortScoreDesc ReviewSort = "SCORE_DESC"
|
||||
ReviewSortRating ReviewSort = "RATING"
|
||||
ReviewSortRatingDesc ReviewSort = "RATING_DESC"
|
||||
ReviewSortCreatedAt ReviewSort = "CREATED_AT"
|
||||
ReviewSortCreatedAtDesc ReviewSort = "CREATED_AT_DESC"
|
||||
ReviewSortUpdatedAt ReviewSort = "UPDATED_AT"
|
||||
ReviewSortUpdatedAtDesc ReviewSort = "UPDATED_AT_DESC"
|
||||
)
|
||||
|
||||
// RecommendationSort is sorting option for recommendation list.
|
||||
type RecommendationSort string
|
||||
|
||||
// Options for RecommendationSort.
|
||||
const (
|
||||
RecommendationSortID RecommendationSort = "ID"
|
||||
RecommendationSortIDDesc RecommendationSort = "ID_DESC"
|
||||
RecommendationSortRating RecommendationSort = "RATING"
|
||||
RecommendationSortRatingDesc RecommendationSort = "RATING_DESC"
|
||||
)
|
||||
|
||||
// UserStatisticsSort is sorting option for user statistics list.
|
||||
type UserStatisticsSort string
|
||||
|
||||
// Options for UserStatisticsSort.
|
||||
const (
|
||||
UserStatisticsSortID UserStatisticsSort = "ID"
|
||||
UserStatisticsSortIDDesc UserStatisticsSort = "ID_DESC"
|
||||
UserStatisticsSortCount UserStatisticsSort = "COUNT"
|
||||
UserStatisticsSortCountDesc UserStatisticsSort = "COUNT_DESC"
|
||||
UserStatisticsSortProgress UserStatisticsSort = "PROGRESS"
|
||||
UserStatisticsSortProgessDesc UserStatisticsSort = "PROGRESS_DESC"
|
||||
UserStatisticsSortMeanScore UserStatisticsSort = "MEAN_SCORE"
|
||||
UserStatisticsSortMeanScoreDesc UserStatisticsSort = "MEAN_SCORE_DESC"
|
||||
)
|
||||
|
||||
// MediaListSort is sorting option for media list.
|
||||
type MediaListSort string
|
||||
|
||||
// Options for MediaListSort.
|
||||
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"
|
||||
)
|
||||
74
verniy/doc.go
Normal file
74
verniy/doc.go
Normal file
@@ -0,0 +1,74 @@
|
||||
// Package verniy is unofficial Anilist GraphQL API library.
|
||||
//
|
||||
// Verniy will generate graphql query string according to your request,
|
||||
// make request to Anilist, parse response body, and convert it
|
||||
// to struct. The goal of this library is to make a flexible and easy to
|
||||
// call Anilist API.
|
||||
//
|
||||
// // Init verniy.
|
||||
// v := verniy.New()
|
||||
//
|
||||
// // Get anime One Piece data (with default fields).
|
||||
// data, err := v.GetAnime(21)
|
||||
//
|
||||
// // Get anime One Piece data (with custom fields).
|
||||
// data, err := v.GetAnime(21,
|
||||
// verniy.MediaFieldID,
|
||||
// verniy.MediaFieldTitle(
|
||||
// verniy.MediaTitleFieldRomaji,
|
||||
// verniy.MediaTitleFieldEnglish,
|
||||
// verniy.MediaTitleFieldNative),
|
||||
// verniy.MediaFieldType,
|
||||
// verniy.MediaFieldFormat,
|
||||
// verniy.MediaFieldStatusV2,
|
||||
// verniy.MediaFieldDescription,
|
||||
// verniy.MediaFieldStartDate,
|
||||
// verniy.MediaFieldEndDate,
|
||||
// verniy.MediaFieldSeason,
|
||||
// verniy.MediaFieldSeasonYear)
|
||||
//
|
||||
// # Functions
|
||||
//
|
||||
// There are alot of functions in verniy package but
|
||||
// most of the time, you just need functions in `Client` struct.
|
||||
// And it's recommended to use them to make your life easier.
|
||||
// If you want to make a custom request, you can use function
|
||||
// `MakeRequest()` (go to the function for more details).
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// Yes, there are tons of custom types and functions but let
|
||||
// your IDE auto-complete helps you choose the params for the
|
||||
// functions. Not only constant value but also function (like
|
||||
// `MediaFieldTitle` in the example) to fill the params.
|
||||
// But, most of the functions have variadic parameters,
|
||||
// so you don't need to actually fill it. There is already default
|
||||
// value and you can read the code yourself to see the default
|
||||
// value of the variadic parameters.
|
||||
//
|
||||
// If you want the complete list of available params,
|
||||
// read the official docs (https://anilist.github.io/ApiV2-GraphQL-Docs/).
|
||||
//
|
||||
// # Response
|
||||
//
|
||||
// Most of the functions in `Client` struct return a struct and error.
|
||||
// Yes, most of the fields in the returned struct are pointers because,
|
||||
// like any graphql, Anilist will not return fields that we didn't
|
||||
// request. It is recommended to make your own pointer handler when
|
||||
// using the field. For example.
|
||||
//
|
||||
// // Handle *string to string.
|
||||
// func ptrToString(str *string) string {
|
||||
// if str == nil {
|
||||
// return ""
|
||||
// }
|
||||
// return *str
|
||||
// }
|
||||
//
|
||||
// # Rate Limit
|
||||
//
|
||||
// Anilist has default rate limit 90 requests per minute. If you go over
|
||||
// the rate limit you'll receive a 1-minute timeout. But, verniy has
|
||||
// a built-in rate limiter to prevent the requests going over the limit.
|
||||
// It will put your request on hold until the limit is available again.
|
||||
package verniy
|
||||
1968
verniy/field.go
Normal file
1968
verniy/field.go
Normal file
File diff suppressed because it is too large
Load Diff
27
verniy/genres.go
Normal file
27
verniy/genres.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type genreResponse struct {
|
||||
Data struct {
|
||||
Genres []string `json:"genreCollection"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// GetGenres to get all genre list.
|
||||
func (c *Client) GetGenres() ([]string, error) {
|
||||
return c.GetGenresWithContext(context.Background())
|
||||
}
|
||||
|
||||
// GetGenresWithContext to get all genre list with context.
|
||||
func (c *Client) GetGenresWithContext(ctx context.Context) ([]string, error) {
|
||||
query := FieldObject("query", nil, "GenreCollection")
|
||||
|
||||
var d genreResponse
|
||||
err := c.post(ctx, query, nil, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d.Data.Genres, nil
|
||||
}
|
||||
130
verniy/http.go
Normal file
130
verniy/http.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package verniy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type queryRequest struct {
|
||||
Query string `json:"query"`
|
||||
Variables queryVariable `json:"variables"`
|
||||
}
|
||||
|
||||
type queryVariable map[string]interface{}
|
||||
|
||||
type errorResponse struct {
|
||||
Errors []struct {
|
||||
Message string `json:"message"`
|
||||
Status int `json:"status"`
|
||||
} `json:"errors"`
|
||||
}
|
||||
|
||||
func (c *Client) handleError(body []byte) error {
|
||||
var e errorResponse
|
||||
if err := json.Unmarshal(body, &e); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
errMsgs := make([]string, len(e.Errors))
|
||||
for i, b := range e.Errors {
|
||||
errMsgs[i] = b.Message
|
||||
}
|
||||
|
||||
return errors.New(strings.Join(errMsgs, " | "))
|
||||
}
|
||||
|
||||
func (c *Client) post(ctx context.Context, query string, v map[string]interface{}, model interface{}) error {
|
||||
d, err := json.Marshal(queryRequest{
|
||||
Query: query,
|
||||
Variables: v,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
body, code, err := c.MakeRequest(ctx, d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if code != http.StatusOK {
|
||||
return c.handleError(body)
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(body, &model); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MakeRequest to make direct HTTP request without any wrapper.
|
||||
// Prepare your body request and handle the response by yourself.
|
||||
//
|
||||
// Use this if you want to make custom request. Also, need to read the
|
||||
// docs of how to prepare the body request and read the response
|
||||
// (https://anilist.github.io/ApiV2-GraphQL-Docs/).
|
||||
//
|
||||
// Params requestBody is your data in JSON format. So, marshal your data
|
||||
// first before passing it to this function. And will return response body,
|
||||
// response code, and error.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// query := verniy.FieldObject("query", verniy.QueryParam{
|
||||
// "$id": "Int",
|
||||
// "$type": "MediaType",
|
||||
// }, verniy.FieldObject("Media", verniy.QueryParam{
|
||||
// "id": "$id",
|
||||
// "type": "$type",
|
||||
// }, "id"))
|
||||
//
|
||||
// body := map[string]interface{}{
|
||||
// "query": query,
|
||||
// "variables": map[string]interface{}{
|
||||
// "id": 1,
|
||||
// "type": "ANIME",
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// jsonBody, _ := json.Marshal(body)
|
||||
//
|
||||
// data, code, err := c.MakeRequest(jsonBody)
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
//
|
||||
// fmt.Println(code)
|
||||
// fmt.Println(string(data))
|
||||
func (c *Client) MakeRequest(ctx context.Context, requestBody []byte) ([]byte, int, error) {
|
||||
c.Limiter.Take()
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.Host, bytes.NewBuffer(requestBody))
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
req.Header.Add("Accept", "application/json")
|
||||
if c.AccessToken != "" {
|
||||
req.Header.Add("Authorization", "Bearer "+c.AccessToken)
|
||||
}
|
||||
|
||||
resp, err := c.Http.Do(req)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, http.StatusInternalServerError, err
|
||||
}
|
||||
|
||||
return body, resp.StatusCode, nil
|
||||
}
|
||||
75
verniy/limiter/limiter.go
Normal file
75
verniy/limiter/limiter.go
Normal file
@@ -0,0 +1,75 @@
|
||||
// Package limiter is a copy of "github.com/uber-go/ratelimit" library.
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Limiter is interface for rate limiter.
|
||||
type Limiter interface {
|
||||
Take() time.Time
|
||||
}
|
||||
|
||||
type mutexLimiter struct {
|
||||
sync.Mutex
|
||||
last time.Time
|
||||
sleepFor time.Duration
|
||||
perRequest time.Duration
|
||||
maxSlack time.Duration
|
||||
clock clocker
|
||||
}
|
||||
|
||||
type clocker interface {
|
||||
Now() time.Time
|
||||
Sleep(time.Duration)
|
||||
}
|
||||
|
||||
// New returns a new atomic based limiter.
|
||||
func New(rate int, interval time.Duration) Limiter {
|
||||
perRequest := interval / time.Duration(rate)
|
||||
return &mutexLimiter{
|
||||
perRequest: perRequest,
|
||||
maxSlack: -1 * time.Duration(10) * perRequest,
|
||||
clock: newClock(),
|
||||
}
|
||||
}
|
||||
|
||||
// Take blocks to ensure that the time spent between multiple
|
||||
// Take calls is on average time.Second/rate.
|
||||
func (t *mutexLimiter) Take() time.Time {
|
||||
t.Lock()
|
||||
defer t.Unlock()
|
||||
|
||||
now := t.clock.Now()
|
||||
|
||||
// If this is our first request, then we allow it.
|
||||
if t.last.IsZero() {
|
||||
t.last = now
|
||||
return t.last
|
||||
}
|
||||
|
||||
// sleepFor calculates how much time we should sleep based on
|
||||
// the perRequest budget and how long the last request took.
|
||||
// Since the request may take longer than the budget, this number
|
||||
// can get negative, and is summed across requests.
|
||||
t.sleepFor += t.perRequest - now.Sub(t.last)
|
||||
|
||||
// We shouldn't allow sleepFor to get too negative, since it would mean that
|
||||
// a service that slowed down a lot for a short period of time would get
|
||||
// a much higher RPS following that.
|
||||
if t.sleepFor < t.maxSlack {
|
||||
t.sleepFor = t.maxSlack
|
||||
}
|
||||
|
||||
// If sleepFor is positive, then we should sleep now.
|
||||
if t.sleepFor > 0 {
|
||||
t.clock.Sleep(t.sleepFor)
|
||||
t.last = now.Add(t.sleepFor)
|
||||
t.sleepFor = 0
|
||||
} else {
|
||||
t.last = now
|
||||
}
|
||||
|
||||
return t.last
|
||||
}
|
||||
24
verniy/limiter/time.go
Normal file
24
verniy/limiter/time.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package limiter
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// newClock returns an instance of a real-time clock.
|
||||
// Taken from `github.com/andres-erbsen/clock`.
|
||||
func newClock() *clock {
|
||||
return &clock{}
|
||||
}
|
||||
|
||||
// clock implements a real-time clock by simply wrapping the time package functions.
|
||||
type clock struct{}
|
||||
|
||||
// Now to get time now.
|
||||
func (c *clock) Now() time.Time {
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// Sleep to sleep.
|
||||
func (c *clock) Sleep(d time.Duration) {
|
||||
time.Sleep(d)
|
||||
}
|
||||
364
verniy/media.go
Normal file
364
verniy/media.go
Normal file
@@ -0,0 +1,364 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type mediaResponse struct {
|
||||
Data struct {
|
||||
Media Media `json:"media"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) mediaQuery(params QueryParam, fields ...MediaField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("Media", params, p...)
|
||||
}
|
||||
|
||||
func (c *Client) getMedia(ctx context.Context, id int, mediaType MediaType, fields ...MediaField) (*Media, error) {
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$id": "Int",
|
||||
"$type": "MediaType",
|
||||
}, c.mediaQuery(QueryParam{
|
||||
"id": "$id",
|
||||
"type": "$type",
|
||||
}, fields...))
|
||||
|
||||
var d mediaResponse
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"id": id,
|
||||
"type": mediaType,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d.Data.Media, nil
|
||||
}
|
||||
|
||||
// GetAnime to get anime data.
|
||||
func (c *Client) GetAnime(id int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetAnimeWithContext(context.Background(), id, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeWithContext to get anime data with context.
|
||||
func (c *Client) GetAnimeWithContext(ctx context.Context, id int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldDescription,
|
||||
MediaFieldStartDate,
|
||||
MediaFieldEndDate,
|
||||
MediaFieldCountryOfOrigin,
|
||||
MediaFieldSourceV2,
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldExtraLarge,
|
||||
MediaCoverImageFieldLarge,
|
||||
MediaCoverImageFieldMedium,
|
||||
MediaCoverImageFieldColor),
|
||||
MediaFieldBannerImage,
|
||||
MediaFieldGenres,
|
||||
MediaFieldSynonyms,
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldMeanScore,
|
||||
MediaFieldPopularity,
|
||||
MediaFieldFavourites,
|
||||
MediaFieldTags(
|
||||
MediaTagFieldName,
|
||||
MediaTagFieldDescription,
|
||||
MediaTagFieldCategory,
|
||||
MediaTagFieldRank,
|
||||
MediaTagFieldIsGeneralSpoiler,
|
||||
MediaTagFieldIsMediaSpoiler,
|
||||
MediaTagFieldIsAdult),
|
||||
MediaFieldRelations(
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldRelationTypeV2,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldFormat,
|
||||
MediaFieldType,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldMedium)))),
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldRankings(
|
||||
MediaRankFieldID,
|
||||
MediaRankFieldRank,
|
||||
MediaRankFieldType,
|
||||
MediaRankFieldFormat,
|
||||
MediaRankFieldYear,
|
||||
MediaRankFieldSeason,
|
||||
MediaRankFieldAllTime,
|
||||
MediaRankFieldContext,
|
||||
),
|
||||
MediaFieldSeason,
|
||||
MediaFieldSeasonYear,
|
||||
MediaFieldEpisodes,
|
||||
MediaFieldDuration,
|
||||
MediaFieldStudios(
|
||||
MediaParamStudios{},
|
||||
StudioConnectionFieldEdges(
|
||||
StudioEdgeFieldIsMain,
|
||||
StudioEdgeFieldNode(
|
||||
StudioFieldID,
|
||||
StudioFieldName,
|
||||
StudioFieldIsAnimationStudio))),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeAnime, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeCharacters to get list of characters in anime.
|
||||
func (c *Client) GetAnimeCharacters(id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetAnimeCharactersWithContext(context.Background(), id, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeCharactersWithContext to get list of characters in anime with context.
|
||||
func (c *Client) GetAnimeCharactersWithContext(ctx context.Context, id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldCharacters(
|
||||
MediaParamCharacters{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Sort: []CharacterSort{CharacterSortRole, CharacterSortRelevance, CharacterSortID},
|
||||
},
|
||||
CharacterConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
CharacterConnectionFieldEdges(
|
||||
CharacterEdgeFieldRole,
|
||||
CharacterEdgeFieldNode(
|
||||
CharacterFieldID,
|
||||
CharacterFieldName(CharacterNameFieldFull),
|
||||
CharacterFieldImage(CharacterImageFieldMedium)),
|
||||
CharacterEdgeFieldVoiceActors(
|
||||
CharacterEdgeParamVoiceActors{},
|
||||
StaffFieldID,
|
||||
StaffFieldName(StaffNameFieldFull),
|
||||
StaffFieldImage(StaffImageFieldMedium),
|
||||
StaffFieldLanguage))),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeAnime, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeStaff to get list of staff in anime.
|
||||
func (c *Client) GetAnimeStaff(id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetAnimeStaffWithContext(context.Background(), id, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeStaffWithContext to get list of staff in anime with context.
|
||||
func (c *Client) GetAnimeStaffWithContext(ctx context.Context, id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldStaff(
|
||||
MediaParamStaff{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Sort: []StaffSort{StaffSortRelevance, StaffSortID},
|
||||
},
|
||||
StaffConnectionFieldEdges(
|
||||
StaffEdgeFieldRole,
|
||||
StaffEdgeFieldNode(
|
||||
StaffFieldID,
|
||||
StaffFieldName(StaffNameFieldFull),
|
||||
StaffFieldImage(StaffImageFieldMedium)))),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeAnime, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeStats to get anime stats.
|
||||
func (c *Client) GetAnimeStats(id int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetAnimeStatsWithContext(context.Background(), id, fields...)
|
||||
}
|
||||
|
||||
// GetAnimeStatsWithContext to get anime stats with context.
|
||||
func (c *Client) GetAnimeStatsWithContext(ctx context.Context, id int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldStats(
|
||||
MediaStatsFieldScoreDistribution,
|
||||
MediaStatsFieldStatusDistribution),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeAnime, fields...)
|
||||
}
|
||||
|
||||
// GetManga to get manga data.
|
||||
func (c *Client) GetManga(id int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetMangaWithContext(context.Background(), id, fields...)
|
||||
}
|
||||
|
||||
// GetMangaWithContext to get manga data with context.
|
||||
func (c *Client) GetMangaWithContext(ctx context.Context, id int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldDescription,
|
||||
MediaFieldStartDate,
|
||||
MediaFieldEndDate,
|
||||
MediaFieldCountryOfOrigin,
|
||||
MediaFieldSourceV2,
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldExtraLarge,
|
||||
MediaCoverImageFieldLarge,
|
||||
MediaCoverImageFieldMedium,
|
||||
MediaCoverImageFieldColor),
|
||||
MediaFieldBannerImage,
|
||||
MediaFieldGenres,
|
||||
MediaFieldSynonyms,
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldMeanScore,
|
||||
MediaFieldPopularity,
|
||||
MediaFieldFavourites,
|
||||
MediaFieldTags(
|
||||
MediaTagFieldName,
|
||||
MediaTagFieldDescription,
|
||||
MediaTagFieldCategory,
|
||||
MediaTagFieldRank,
|
||||
MediaTagFieldIsGeneralSpoiler,
|
||||
MediaTagFieldIsMediaSpoiler,
|
||||
MediaTagFieldIsAdult),
|
||||
MediaFieldRelations(
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldRelationTypeV2,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldFormat,
|
||||
MediaFieldType,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldMedium)))),
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldRankings(
|
||||
MediaRankFieldID,
|
||||
MediaRankFieldRank,
|
||||
MediaRankFieldType,
|
||||
MediaRankFieldFormat,
|
||||
MediaRankFieldYear,
|
||||
MediaRankFieldSeason,
|
||||
MediaRankFieldAllTime,
|
||||
MediaRankFieldContext,
|
||||
),
|
||||
MediaFieldChapters,
|
||||
MediaFieldVolumes,
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeManga, fields...)
|
||||
}
|
||||
|
||||
// GetMangaCharacters to get list of characters in manga.
|
||||
func (c *Client) GetMangaCharacters(id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetMangaCharactersWithContext(context.Background(), id, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// GetMangaCharactersWithContext to get list of characters in manga with context.
|
||||
func (c *Client) GetMangaCharactersWithContext(ctx context.Context, id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldCharacters(
|
||||
MediaParamCharacters{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Sort: []CharacterSort{CharacterSortRole, CharacterSortRelevance, CharacterSortID},
|
||||
},
|
||||
CharacterConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
CharacterConnectionFieldEdges(
|
||||
CharacterEdgeFieldRole,
|
||||
CharacterEdgeFieldNode(
|
||||
CharacterFieldID,
|
||||
CharacterFieldName(CharacterNameFieldFull),
|
||||
CharacterFieldImage(CharacterImageFieldMedium)))),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeManga, fields...)
|
||||
}
|
||||
|
||||
// GetMangaStaff to get list of staff in manga.
|
||||
func (c *Client) GetMangaStaff(id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetMangaStaffWithContext(context.Background(), id, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// GetMangaStaffWithContext to get list of staff in manga with context.
|
||||
func (c *Client) GetMangaStaffWithContext(ctx context.Context, id int, page int, perPage int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldStaff(
|
||||
MediaParamStaff{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Sort: []StaffSort{StaffSortRelevance, StaffSortID},
|
||||
},
|
||||
StaffConnectionFieldEdges(
|
||||
StaffEdgeFieldRole,
|
||||
StaffEdgeFieldNode(
|
||||
StaffFieldID,
|
||||
StaffFieldName(StaffNameFieldFull),
|
||||
StaffFieldImage(StaffImageFieldMedium)))),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeManga, fields...)
|
||||
}
|
||||
|
||||
// GetMangaStats to get manga stats.
|
||||
func (c *Client) GetMangaStats(id int, fields ...MediaField) (*Media, error) {
|
||||
return c.GetMangaStatsWithContext(context.Background(), id, fields...)
|
||||
}
|
||||
|
||||
// GetMangaStatsWithContext to get manga stats with context.
|
||||
func (c *Client) GetMangaStatsWithContext(ctx context.Context, id int, fields ...MediaField) (*Media, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldStats(
|
||||
MediaStatsFieldScoreDistribution,
|
||||
MediaStatsFieldStatusDistribution),
|
||||
}
|
||||
}
|
||||
return c.getMedia(ctx, id, MediaTypeManga, fields...)
|
||||
}
|
||||
694
verniy/model.go
Normal file
694
verniy/model.go
Normal file
@@ -0,0 +1,694 @@
|
||||
package verniy
|
||||
|
||||
// Media is main anime & manga model.
|
||||
type Media struct {
|
||||
ID int `json:"id"`
|
||||
IDMAL *int `json:"idMal"`
|
||||
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 *int `json:"duration"` // in minutes
|
||||
Chapters *int `json:"chapters"`
|
||||
Volumes *int `json:"volumes"`
|
||||
CountryOfOrigin *string `json:"countryOfOrigin"`
|
||||
IsLicensed *bool `json:"isLicensed"`
|
||||
Source *MediaSource `json:"source"`
|
||||
HashTag *string `json:"hashTag"`
|
||||
Trailer *MediaTrailer `json:"trailer"`
|
||||
UpdatedAt *int `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"`
|
||||
IsLocked *bool `json:"isLocked"`
|
||||
Trending *int `json:"trending"`
|
||||
Favourites *int `json:"favourites"`
|
||||
Tags []MediaTag `json:"tags"`
|
||||
Relations *MediaConnection `json:"relations"`
|
||||
Characters *CharacterConnection `json:"characters"`
|
||||
Staff *StaffConnection `json:"staff"`
|
||||
Studios *StudioConnection `json:"studios"`
|
||||
IsFavourite *bool `json:"isFavourite"`
|
||||
IsAdult *bool `json:"isAdult"`
|
||||
NextAiringEpisode *AiringSchedule `json:"nextAiringEpisode"`
|
||||
AiringSchedule *AiringScheduleConnection `json:"airingSchedule"`
|
||||
Trends *MediaTrendConnection `json:"trends"`
|
||||
ExternalLinks []MediaExternalLink `json:"externalLinks"`
|
||||
StreamingEpisodes []MediaStreamingEpisode `json:"streamingEpisodes"`
|
||||
Rankings []MediaRank `json:"rankings"`
|
||||
MediaListEntry *MediaList `json:"mediaListEntry"`
|
||||
Reviews *ReviewConnection `json:"reviews"`
|
||||
Recommendations *RecommendationConnection `json:"recommendations"`
|
||||
Stats *MediaStats `json:"stats"`
|
||||
SiteURL *string `json:"siteUrl"`
|
||||
AutoCreateForumThread *bool `json:"autoCreateForumThread"`
|
||||
IsRecommendationBlocked *bool `json:"isRecommendationBlocked"`
|
||||
ModNotes *string `json:"modNotes"`
|
||||
}
|
||||
|
||||
// MediaTitle is anime & manga titles.
|
||||
type MediaTitle struct {
|
||||
Romaji *string `json:"romaji"`
|
||||
English *string `json:"english"`
|
||||
Native *string `json:"native"`
|
||||
UserPreferred *string `json:"userPreferred"`
|
||||
}
|
||||
|
||||
// FuzzyDateInt is 8 digit long date integer (YYYYMMDD).
|
||||
type FuzzyDateInt int
|
||||
|
||||
// FuzzyDate is common date format.
|
||||
type FuzzyDate struct {
|
||||
Year *int `json:"year"`
|
||||
Month *int `json:"month"`
|
||||
Day *int `json:"day"`
|
||||
}
|
||||
|
||||
// MediaTrailer is anime & manga trailer data.
|
||||
type MediaTrailer struct {
|
||||
ID *string `json:"id"`
|
||||
Site *string `json:"site"`
|
||||
Thumbnail *string `json:"thumbnail"`
|
||||
}
|
||||
|
||||
// MediaCoverImage is anime & manga cover image model.
|
||||
type MediaCoverImage struct {
|
||||
ExtraLarge *string `json:"extraLarge"`
|
||||
Large *string `json:"large"`
|
||||
Medium *string `json:"medium"`
|
||||
Color *string `json:"color"`
|
||||
}
|
||||
|
||||
// MediaTag is anime & manga tag model.
|
||||
type MediaTag struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description *string `json:"description"`
|
||||
Category *string `json:"category"`
|
||||
Rank *int `json:"rank"`
|
||||
IsGeneralSpoiler *bool `json:"isGeneralSpoiler"`
|
||||
IsMediaSpoiler *bool `json:"isMediaSpoiler"`
|
||||
IsAdult *bool `json:"isAdult"`
|
||||
}
|
||||
|
||||
// MediaConnection is anime & manga related model.
|
||||
type MediaConnection struct {
|
||||
Edges []MediaEdge `json:"edges"`
|
||||
Nodes []Media `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// MediaEdge is anime & manga detail related model.
|
||||
type MediaEdge struct {
|
||||
Node *Media `json:"node"`
|
||||
ID *int `json:"id"`
|
||||
RelationType *MediaRelation `json:"relationType"`
|
||||
IsMainStudio bool `json:"isMainStudio"`
|
||||
Characters []Character `json:"characters"`
|
||||
CharacterRole *CharacterRole `json:"characterRole"`
|
||||
CharacterName *string `json:"characterName"`
|
||||
RoleNotes *string `json:"roleNotes"`
|
||||
DubGroup *string `json:"dubGroup"`
|
||||
StaffRole *string `json:"staffRole"`
|
||||
VoiceActors []Staff `json:"voiceActors"`
|
||||
VoiceActorRoles []StaffRoleType `json:"voiceActorRoles"`
|
||||
FavouriteOrder *int `json:"favouriteOrder"`
|
||||
}
|
||||
|
||||
// StaffRoleType is type of staff role.
|
||||
type StaffRoleType struct {
|
||||
VoiceActor *Staff `json:"voiceActor"`
|
||||
RoleNotes *string `json:"roleNotes"`
|
||||
DubGroup *string `json:"dubGroup"`
|
||||
}
|
||||
|
||||
// PageInfo is common pagination model.
|
||||
type PageInfo struct {
|
||||
Total *int `json:"total"`
|
||||
PerPage *int `json:"perPage"`
|
||||
CurrentPage *int `json:"currentPage"`
|
||||
LastPage *int `json:"lastPage"`
|
||||
HasNextPage *bool `json:"hasNextPage"`
|
||||
}
|
||||
|
||||
// CharacterConnection is character related model.
|
||||
type CharacterConnection struct {
|
||||
Edges []CharacterEdge `json:"edges"`
|
||||
Nodes []Character `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// CharacterEdge is detail character related model.
|
||||
type CharacterEdge struct {
|
||||
Node *Character `json:"node"`
|
||||
ID *int `json:"id"`
|
||||
Role *CharacterRole `json:"role"`
|
||||
Name *string `json:"name"`
|
||||
VoiceActors []Staff `json:"voiceActors"`
|
||||
VoiceActorRoles []StaffRoleType `json:"voiceActorRoles"`
|
||||
Media []Media `json:"media"`
|
||||
FavouriteOrder *int `json:"favouriteOrder"`
|
||||
}
|
||||
|
||||
// Character is main character model.
|
||||
type Character struct {
|
||||
ID int `json:"id"`
|
||||
Name *CharacterName `json:"name"`
|
||||
Image *CharacterImage `json:"image"`
|
||||
Description *string `json:"description"`
|
||||
Gender *string `json:"gender"`
|
||||
DateOfBirth *FuzzyDate `json:"dateOfBirth"`
|
||||
Age *string `json:"age"`
|
||||
IsFavourite *bool `json:"isFavourite"`
|
||||
IsFavouriteBlocked *bool `json:"isFavouriteBlocked"`
|
||||
SiteURL *string `json:"siteURL"`
|
||||
Media *MediaConnection `json:"media"`
|
||||
Favourites *int `json:"favourites"`
|
||||
ModNotes *string `json:"modNotes"`
|
||||
}
|
||||
|
||||
// CharacterName is character names.
|
||||
type CharacterName struct {
|
||||
First *string `json:"first"`
|
||||
Middle *string `json:"middle"`
|
||||
Last *string `json:"last"`
|
||||
Full *string `json:"full"`
|
||||
Native *string `json:"native"`
|
||||
Alternative []string `json:"alternative"`
|
||||
AlternativeSpoiler []string `json:"alternativeSpoiler"`
|
||||
UserPreferred *string `json:"userPreferred"`
|
||||
}
|
||||
|
||||
// CharacterImage is character image.
|
||||
type CharacterImage struct {
|
||||
Large *string `json:"large"`
|
||||
Medium *string `json:"medium"`
|
||||
}
|
||||
|
||||
// StaffConnection is staff related model.
|
||||
type StaffConnection struct {
|
||||
Edges []StaffEdge `json:"edges"`
|
||||
Nodes []Staff `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// StaffEdge is detail staff related model.
|
||||
type StaffEdge struct {
|
||||
Node *Staff `json:"node"`
|
||||
ID *int `json:"id"`
|
||||
Role *string `json:"role"`
|
||||
FavouriteOrder *int `json:"favouriteOrder"`
|
||||
}
|
||||
|
||||
// Staff is main staff model.
|
||||
type Staff struct {
|
||||
ID int `json:"id"`
|
||||
Name *StaffName `json:"name"`
|
||||
LanguageV2 *string `json:"languageV2"`
|
||||
Image *StaffImage `json:"image"`
|
||||
Description *string `json:"description"`
|
||||
PrimaryOccupations []string `json:"primaryOccupation"`
|
||||
Gender *string `json:"gender"`
|
||||
DateOfBirth *FuzzyDate `json:"dateOfBirth"`
|
||||
DateOfDeath *FuzzyDate `json:"dateOfDeath"`
|
||||
Age *int `json:"age"`
|
||||
YearsActive []int `json:"yearsActive"`
|
||||
HomeTown *string `json:"homeTown"`
|
||||
IsFavourite bool `json:"isFavourite"`
|
||||
IsFavouriteBlocked bool `json:"isFavouriteBlocked"`
|
||||
SiteURL *string `json:"siteURL"`
|
||||
StaffMedia *MediaConnection `json:"staffMedia"`
|
||||
Characters *CharacterConnection `json:"characters"`
|
||||
CharacterMedia *MediaConnection `json:"characterMedia"`
|
||||
Staff *Staff `json:"staff"`
|
||||
Submitter *User `json:"submitter"`
|
||||
SubmissionStatus *int `json:"submissionStatus"`
|
||||
SubmissionNotes *string `json:"submissionNotes"`
|
||||
Favourites *int `json:"favourites"`
|
||||
ModNotes *string `json:"modNotes"`
|
||||
}
|
||||
|
||||
// StaffName is staff names.
|
||||
type StaffName struct {
|
||||
First *string `json:"first"`
|
||||
Middle *string `json:"middle"`
|
||||
Last *string `json:"last"`
|
||||
Full *string `json:"full"`
|
||||
Native *string `json:"native"`
|
||||
Alternative []string `json:"alternative"`
|
||||
UserPreferred *string `json:"userPreferred"`
|
||||
}
|
||||
|
||||
// StaffImage is staff image.
|
||||
type StaffImage struct {
|
||||
Large *string `json:"large"`
|
||||
Medium *string `json:"medium"`
|
||||
}
|
||||
|
||||
// StudioConnection is studio related model.
|
||||
type StudioConnection struct {
|
||||
Edges []StudioEdge `json:"edges"`
|
||||
Nodes []Studio `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// StudioEdge is detail studio related model.
|
||||
type StudioEdge struct {
|
||||
Node *Studio `json:"node"`
|
||||
ID *int `json:"id"`
|
||||
IsMain bool `json:"isMain"`
|
||||
FavouriteOrder *int `json:"favouriteOrder"`
|
||||
}
|
||||
|
||||
// Studio is main studio model.
|
||||
type Studio struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
IsAnimationStudio bool `json:"isAnimationStudio"`
|
||||
Media *MediaConnection `json:"media"`
|
||||
SiteURL *string `json:"siteURL"`
|
||||
IsFavourite bool `json:"isFavourite"`
|
||||
Favourites *int `json:"favourites"`
|
||||
}
|
||||
|
||||
// AiringSchedule is anime airing schedule model.
|
||||
type AiringSchedule struct {
|
||||
ID int `json:"id"`
|
||||
AiringAt int `json:"airingAt"`
|
||||
TimeUntilAiring int `json:"timeUntilAiring"`
|
||||
Episode int `json:"episode"`
|
||||
MediaID int `json:"mediaId"`
|
||||
Media *Media `json:"media"`
|
||||
}
|
||||
|
||||
// AiringScheduleConnection is anime related airing schedule model.
|
||||
type AiringScheduleConnection struct {
|
||||
Edges []AiringScheduleEdge `json:"edges"`
|
||||
Nodes []AiringSchedule `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// AiringScheduleEdge is airing schedule edge model.
|
||||
type AiringScheduleEdge struct {
|
||||
Node *AiringSchedule `json:"node"`
|
||||
ID *int `json:"id"`
|
||||
}
|
||||
|
||||
// MediaTrendConnection is media trend connection model.
|
||||
type MediaTrendConnection struct {
|
||||
Edges []MediaTrendEdge `json:"edges"`
|
||||
Nodes []MediaTrend `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// MediaTrendEdge is media trend edge model.
|
||||
type MediaTrendEdge struct {
|
||||
Node *MediaTrend `json:"node"`
|
||||
}
|
||||
|
||||
// MediaTrend is media trend model.
|
||||
type MediaTrend struct {
|
||||
MediaID int `json:"mediaId"`
|
||||
Date int `json:"date"`
|
||||
Trending int `json:"trending"`
|
||||
AverageScore *int `json:"averageScore"`
|
||||
Popularity *int `json:"popularity"`
|
||||
InProgress *int `json:"inProgress"`
|
||||
Releasing bool `json:"releasing"`
|
||||
Episode *int `json:"episode"`
|
||||
Media *Media `json:"media"`
|
||||
}
|
||||
|
||||
// MediaExternalLink is anime & manga site links.
|
||||
type MediaExternalLink struct {
|
||||
ID int `json:"id"`
|
||||
URL string `json:"url"`
|
||||
Site string `json:"site"`
|
||||
}
|
||||
|
||||
// MediaStreamingEpisode is anime streaming site links.
|
||||
type MediaStreamingEpisode struct {
|
||||
Title *string `json:"title"`
|
||||
Thumbnail *string `json:"thumbnail"`
|
||||
URL *string `json:"url"`
|
||||
Site *string `json:"site"`
|
||||
}
|
||||
|
||||
// MediaRank is anime & manga ranking model.
|
||||
type MediaRank struct {
|
||||
ID int `json:"id"`
|
||||
Rank int `json:"rank"`
|
||||
Type MediaRankType `json:"type"`
|
||||
Format MediaFormat `json:"format"`
|
||||
Year *int `json:"year"`
|
||||
Season *MediaSeason `json:"season"`
|
||||
AllTime *bool `json:"allTime"`
|
||||
Context string `json:"context"`
|
||||
}
|
||||
|
||||
// MediaList is user's anime & manga model.
|
||||
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"`
|
||||
CustomLists *string `json:"customLists"` // json
|
||||
AdvancedScores *string `json:"advancedScores"` // json
|
||||
StartedAt *FuzzyDate `json:"startedAt"`
|
||||
CompletedAt *FuzzyDate `json:"completedAt"`
|
||||
UpdatedAt *int `json:"updatedAt"`
|
||||
CreatedAt *int `json:"createdAt"`
|
||||
Media *Media `json:"media"`
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
// User is main user model.
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
Name string `json:"name"`
|
||||
About *string `json:"about"`
|
||||
Avatar *UserAvatar `json:"avatar"`
|
||||
BannerImage *string `json:"bannerImage"`
|
||||
IsFollowing *bool `json:"isFollowing"`
|
||||
IsFollower *bool `json:"isFollower"`
|
||||
IsBlocked *bool `json:"isBlocked"`
|
||||
Bans *string `json:"bans"` // json
|
||||
Options *UserOptions `json:"options"`
|
||||
MediaListOptions *MediaListOptions `json:"mediaListOptions"`
|
||||
Favourites *Favourites `json:"favourites"`
|
||||
Statistics *UserStatisticTypes `json:"statistics"`
|
||||
UnreadNotificationCount *int `json:"unreadNotificationCount"`
|
||||
SiteURL *string `json:"siteUrl"`
|
||||
DonatorTier *int `json:"donatorTier"`
|
||||
DonatorBadge *string `json:"donatorBadge"`
|
||||
ModeratorRoles []ModRole `json:"moderatorRoles"`
|
||||
CreatedAt *int `json:"createdAt"`
|
||||
UpdatedAt *int `json:"updatedAt"`
|
||||
}
|
||||
|
||||
// UserAvatar is user avatar image.
|
||||
type UserAvatar struct {
|
||||
Large *string `json:"large"`
|
||||
Medium *string `json:"medium"`
|
||||
}
|
||||
|
||||
// UserOptions is user option model.
|
||||
type UserOptions struct {
|
||||
TitleLanguage *UserTitleLanguage `json:"titleLanguage"`
|
||||
DisplayAdultContent *bool `json:"displayAdultContent"`
|
||||
AiringNotifications *bool `json:"airingNotification"`
|
||||
ProfileColor *string `json:"profileColor"`
|
||||
NotificationOptions []NotificationOption `json:"notificationOptions"`
|
||||
Timezone *string `json:"timezone"`
|
||||
ActivityMergeTime *int `json:"activityMergeTime"`
|
||||
StaffNameLanguage *UserStaffNameLanguage `json:"staffNameLanguage"`
|
||||
}
|
||||
|
||||
// NotificationOption is user notification option model.
|
||||
type NotificationOption struct {
|
||||
Type *NotificationType `json:"type"`
|
||||
Enabled *bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// MediaListOptions is user anime & manga option model.
|
||||
type MediaListOptions struct {
|
||||
ScoreFormat *ScoreFormat `json:"scoreFormat"`
|
||||
RowOrder *string `json:"rowOrder"`
|
||||
AnimeList *MediaListTypeOptions `json:"animeList"`
|
||||
MangaList *MediaListTypeOptions `json:"mangaList"`
|
||||
}
|
||||
|
||||
// MediaListTypeOptions is media list type options model.
|
||||
type MediaListTypeOptions struct {
|
||||
SectionOrder []string `json:"sectionOrder"`
|
||||
SplitCompletedSectionByFormat *bool `json:"splitCompletedSectionByFormat"`
|
||||
CustomLists []string `json:"customLists"`
|
||||
AdvancedScoring []string `json:"advancedScoring"`
|
||||
AdvancedScoringEnabled *bool `json:"advancedScoringEnabled"`
|
||||
}
|
||||
|
||||
// Favourites is user's favourite model.
|
||||
type Favourites struct {
|
||||
Anime *MediaConnection `json:"anime"`
|
||||
Manga *MediaConnection `json:"manga"`
|
||||
Characters *CharacterConnection `json:"characters"`
|
||||
Staff *StaffConnection `json:"staff"`
|
||||
Studios *StudioConnection `json:"studios"`
|
||||
}
|
||||
|
||||
// UserStatisticTypes is user statistic data.
|
||||
type UserStatisticTypes struct {
|
||||
Anime *UserStatistics `json:"anime"`
|
||||
Manga *UserStatistics `json:"manga"`
|
||||
}
|
||||
|
||||
// UserStatistics is detail user statistic data.
|
||||
type UserStatistics struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
StandardDeviation float64 `json:"standardDeviation"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
EpisodesWatched int `json:"episodesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
VolumesRead int `json:"volumesRead"`
|
||||
Formats []UserFormatStatistic `json:"formats"`
|
||||
Statuses []UserStatusStatistic `json:"statuses"`
|
||||
Scores []UserScoreStatistic `json:"scores"`
|
||||
Lengths []UserLengthStatistic `json:"lengths"`
|
||||
ReleaseYears []UserReleaseYearStatistic `json:"releaseYears"`
|
||||
StartYears []UserStartYearStatistic `json:"startYears"`
|
||||
Genres []UserGenreStatistic `json:"genres"`
|
||||
Tags []UserTagStatistic `json:"tags"`
|
||||
Countries []UserCountryStatistic `json:"countries"`
|
||||
VoiceActors []UserVoiceActorStatistic `json:"voiceActors"`
|
||||
Staff []UserStaffStatistic `json:"staff"`
|
||||
Studios []UserStudioStatistic `json:"studios"`
|
||||
}
|
||||
|
||||
// UserFormatStatistic is user format stats.
|
||||
type UserFormatStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChapterRead int `json:"chapterRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Format *MediaFormat `json:"format"`
|
||||
}
|
||||
|
||||
// UserStatusStatistic is user status stats.
|
||||
type UserStatusStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Status *MediaListStatus `json:"status"`
|
||||
}
|
||||
|
||||
// UserScoreStatistic is user score stats.
|
||||
type UserScoreStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Score *int `json:"score"`
|
||||
}
|
||||
|
||||
// UserLengthStatistic is user watch/read duration stats.
|
||||
type UserLengthStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Length *string `json:"length"`
|
||||
}
|
||||
|
||||
// UserReleaseYearStatistic is user anime & manga release year stats.
|
||||
type UserReleaseYearStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
ReleaseYear *int `json:"releaseYear"`
|
||||
}
|
||||
|
||||
// UserStartYearStatistic is user start year stats.
|
||||
type UserStartYearStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
StartYear *int `json:"startYear"`
|
||||
}
|
||||
|
||||
// UserGenreStatistic is user genre stats.
|
||||
type UserGenreStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Genre *string `json:"genre"`
|
||||
}
|
||||
|
||||
// UserTagStatistic is user tag stats.
|
||||
type UserTagStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Tag *MediaTag `json:"tag"`
|
||||
}
|
||||
|
||||
// UserCountryStatistic is user anime & manga country stats.
|
||||
type UserCountryStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Country *string `json:"country"`
|
||||
}
|
||||
|
||||
// UserVoiceActorStatistic is user voice actor stats.
|
||||
type UserVoiceActorStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
VoiceActor *Staff `json:"voiceActor"`
|
||||
CharacterIDs []int `json:"characterIDs"`
|
||||
}
|
||||
|
||||
// UserStaffStatistic is user staff stats.
|
||||
type UserStaffStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Staff *Staff `json:"staff"`
|
||||
}
|
||||
|
||||
// UserStudioStatistic is user studio stats.
|
||||
type UserStudioStatistic struct {
|
||||
Count int `json:"count"`
|
||||
MeanScore float64 `json:"meanScore"`
|
||||
MinutesWatched int `json:"minutesWatched"`
|
||||
ChaptersRead int `json:"chaptersRead"`
|
||||
MediaIDs []int `json:"mediaIDs"`
|
||||
Studio *Studio `json:"studio"`
|
||||
}
|
||||
|
||||
// ReviewConnection is anime & manga related review.
|
||||
type ReviewConnection struct {
|
||||
Edges []ReviewEdge `json:"edges"`
|
||||
Nodes []Review `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// ReviewEdge is detail anime & manga related review.
|
||||
type ReviewEdge struct {
|
||||
Node *Review `json:"node"`
|
||||
}
|
||||
|
||||
// Review is main review model.
|
||||
type Review struct {
|
||||
ID int `json:"id"`
|
||||
UserID int `json:"userId"`
|
||||
MediaID int `json:"mediaId"`
|
||||
MediaType *MediaType `json:"mediaType"`
|
||||
Summary *string `json:"summary"`
|
||||
Body *string `json:"body"`
|
||||
Rating *int `json:"rating"`
|
||||
RatingAmount *int `json:"ratingAmount"`
|
||||
UserRating *ReviewRating `json:"userRating"`
|
||||
Score *int `json:"score"`
|
||||
Private *bool `json:"private"`
|
||||
SiteURL *string `json:"siteUrl"`
|
||||
CreatedAt int `json:"createdAt"`
|
||||
UpdatedAt int `json:"updatedAt"`
|
||||
User *User `json:"user"`
|
||||
Media *Media `json:"media"`
|
||||
}
|
||||
|
||||
// RecommendationConnection is anime & manga related recommendation.
|
||||
type RecommendationConnection struct {
|
||||
Edges []RecommendationEdge `json:"edges"`
|
||||
Nodes []Recommendation `json:"nodes"`
|
||||
PageInfo *PageInfo `json:"pageInfo"`
|
||||
}
|
||||
|
||||
// RecommendationEdge is detail anime & manga related recommendation.
|
||||
type RecommendationEdge struct {
|
||||
Node *Recommendation `json:"node"`
|
||||
}
|
||||
|
||||
// Recommendation is main recommendation model.
|
||||
type Recommendation struct {
|
||||
ID int `json:"id"`
|
||||
Rating *int `json:"rating"`
|
||||
UserRating *RecommendationRating `json:"userRating"`
|
||||
Media *Media `json:"media"`
|
||||
MediaRecommendation *Media `json:"mediaRecommendation"`
|
||||
User *User `json:"user"`
|
||||
}
|
||||
|
||||
// MediaStats is anime & manga stats.
|
||||
type MediaStats struct {
|
||||
ScoreDistribution []ScoreDistribution `json:"scoreDistribution"`
|
||||
StatusDistribution []StatusDistribution `json:"statusDistribution"`
|
||||
}
|
||||
|
||||
// ScoreDistribution is detail anime & manga score stats.
|
||||
type ScoreDistribution struct {
|
||||
Score *int `json:"score"`
|
||||
Amount *int `json:"amount"`
|
||||
}
|
||||
|
||||
// StatusDistribution is detail anime & manga status stats.
|
||||
type StatusDistribution struct {
|
||||
Status *MediaListStatus `json:"status"`
|
||||
Amount *int `json:"amount"`
|
||||
}
|
||||
|
||||
// MediaListCollection is collection of media list.
|
||||
type MediaListCollection struct {
|
||||
Lists []MediaListGroup `json:"lists"`
|
||||
User *User `json:"user"`
|
||||
HasNextChunk *bool `json:"hasNextChunk"`
|
||||
}
|
||||
|
||||
// MediaListGroup is group of media list.
|
||||
type MediaListGroup struct {
|
||||
Entries []MediaList `json:"entries"`
|
||||
Name *string `json:"name"`
|
||||
IsCustomList *bool `json:"isCustomList"`
|
||||
IsSplitCompletedList *bool `json:"isSplitCompletedList"`
|
||||
Status *MediaListStatus `json:"status"`
|
||||
}
|
||||
55
verniy/page.go
Normal file
55
verniy/page.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type pageResponse struct {
|
||||
Data struct {
|
||||
Page Page `json:"Page"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// Page is pagination response from anilist.
|
||||
type Page struct {
|
||||
PageInfo PageInfo `json:"pageInfo"`
|
||||
Media []Media `json:"media"`
|
||||
Characters []Character `json:"characters"`
|
||||
Staff []Staff `json:"staff"`
|
||||
Studios []Studio `json:"studios"`
|
||||
}
|
||||
|
||||
func (c *Client) pageQuery(params QueryParam, fields ...PageField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("Page", params, p...)
|
||||
}
|
||||
|
||||
func (c *Client) page(ctx context.Context, page int, perPage int, fields ...PageField) (*Page, error) {
|
||||
fields = append(fields, PageFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage,
|
||||
))
|
||||
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$page": "Int",
|
||||
"$perPage": "Int",
|
||||
}, c.pageQuery(QueryParam{
|
||||
"page": "$page",
|
||||
"perPage": "$perPage",
|
||||
}, fields...))
|
||||
|
||||
var d pageResponse
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"page": page,
|
||||
"perPage": perPage,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d.Data.Page, nil
|
||||
}
|
||||
352
verniy/param.go
Normal file
352
verniy/param.go
Normal file
@@ -0,0 +1,352 @@
|
||||
package verniy
|
||||
|
||||
// MediaEdgeParamVoiceActors is media edge param for voice actors.
|
||||
type MediaEdgeParamVoiceActors struct {
|
||||
Language StaffLanguage
|
||||
Sort []StaffSort
|
||||
}
|
||||
|
||||
// CharacterEdgeParamVoiceActors is character edge param for voice actors.
|
||||
type CharacterEdgeParamVoiceActors struct {
|
||||
Language StaffLanguage
|
||||
Sort []StaffSort
|
||||
}
|
||||
|
||||
// MediaEdgeParamVoiceActorRoles is media edge param for voice actor roles.
|
||||
type MediaEdgeParamVoiceActorRoles struct {
|
||||
Language StaffLanguage
|
||||
Sort []StaffSort
|
||||
}
|
||||
|
||||
// CharacterEdgeParamVoiceActorRoles is character edge param for voice actor roles.
|
||||
type CharacterEdgeParamVoiceActorRoles struct {
|
||||
Language StaffLanguage
|
||||
Sort []StaffSort
|
||||
}
|
||||
|
||||
// MediaParamCharacters is media param for characters.
|
||||
type MediaParamCharacters struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Role CharacterRole
|
||||
Sort []CharacterSort
|
||||
}
|
||||
|
||||
// CharacterParamMedia is character param for media.
|
||||
type CharacterParamMedia struct {
|
||||
Type MediaType
|
||||
OnList *bool
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []MediaSort
|
||||
}
|
||||
|
||||
// StaffParamStaffMedia is staff param for staff media.
|
||||
type StaffParamStaffMedia struct {
|
||||
Type MediaType
|
||||
OnList *bool
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []MediaSort
|
||||
}
|
||||
|
||||
// StaffParamCharacters is staff param for characters.
|
||||
type StaffParamCharacters struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []CharacterSort
|
||||
}
|
||||
|
||||
// StaffParamCharacterMedia is staff param for character media.
|
||||
type StaffParamCharacterMedia struct {
|
||||
OnList *bool
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []MediaSort
|
||||
}
|
||||
|
||||
// MediaParamStaff is media param for staff.
|
||||
type MediaParamStaff struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []StaffSort
|
||||
}
|
||||
|
||||
// MediaParamStudios is media param for studios.
|
||||
type MediaParamStudios struct {
|
||||
IsMain *bool
|
||||
Sort []StudioSort
|
||||
}
|
||||
|
||||
// StudioParamMedia is studio param for media.
|
||||
type StudioParamMedia struct {
|
||||
IsMain *bool
|
||||
OnList *bool
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []MediaSort
|
||||
}
|
||||
|
||||
// MediaParamAiringSchedule is media param for airing schedule.
|
||||
type MediaParamAiringSchedule struct {
|
||||
NotYetAired *bool
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// MediaParamTrends is media param for trends.
|
||||
type MediaParamTrends struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Releasing *bool
|
||||
Sort []MediaTrendSort
|
||||
}
|
||||
|
||||
// MediaParamReviews is media param for reviews.
|
||||
type MediaParamReviews struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []ReviewSort
|
||||
Limit int
|
||||
}
|
||||
|
||||
// MediaParamRecommendations is media param for recommendation
|
||||
type MediaParamRecommendations struct {
|
||||
Page int
|
||||
PerPage int
|
||||
Sort []RecommendationSort
|
||||
}
|
||||
|
||||
// PageParamStudios is page param for studios.
|
||||
type PageParamStudios struct {
|
||||
Search string
|
||||
ID int
|
||||
IDNot int
|
||||
IDIn []int
|
||||
IDNotIn []int
|
||||
Sort []StudioSort
|
||||
}
|
||||
|
||||
// PageParamMedia is page param for media.
|
||||
type PageParamMedia struct {
|
||||
ID int
|
||||
IDMAL int
|
||||
StartDate int
|
||||
EndDate int
|
||||
Season MediaSeason
|
||||
SeasonYear int
|
||||
Type MediaType
|
||||
Format MediaFormat
|
||||
Status MediaStatus
|
||||
Episodes int
|
||||
Duration int
|
||||
Chapters int
|
||||
Volumes int
|
||||
IsAdult *bool
|
||||
Genre string
|
||||
Tag string
|
||||
MinimumTagRank int
|
||||
TagCategory string
|
||||
OnList *bool
|
||||
LicensedBy string
|
||||
AverageScore int
|
||||
Popularity int
|
||||
Source MediaSource
|
||||
CountryOfOrigin string
|
||||
Search string
|
||||
IDNot int
|
||||
IDIn []int
|
||||
IDNotIn []int
|
||||
IDMALNot int
|
||||
IDMALIn []int
|
||||
IDMALNotIn []int
|
||||
StartDateGreater int
|
||||
StartDateLesser int
|
||||
StartDateLike string
|
||||
EndDateGreater int
|
||||
EndDateLesser int
|
||||
EndDateLike string
|
||||
FormatIn []MediaFormat
|
||||
FormatNot MediaFormat
|
||||
FormatNotIn []MediaFormat
|
||||
StatusIn []MediaStatus
|
||||
StatusNot MediaStatus
|
||||
StatusNotIn []MediaStatus
|
||||
EpisodesGreater int
|
||||
EpisodesLesser int
|
||||
DurationGreater int
|
||||
DurationLesser int
|
||||
ChaptersGreater int
|
||||
ChaptersLesser int
|
||||
VolumesGreater int
|
||||
VolumesLesser int
|
||||
GenreIn []string
|
||||
GenreNotIn []string
|
||||
TagIn []string
|
||||
TagNotIn []string
|
||||
TagCategoryIn []string
|
||||
TagCategoryNotIn []string
|
||||
LicensedByIn []string
|
||||
AverageScoreNot int
|
||||
AverageScoreGreater int
|
||||
AverageScoreLesser int
|
||||
PopularityNot int
|
||||
PopularityGreater int
|
||||
PopularityLesser int
|
||||
SourceIn []MediaSource
|
||||
Sort []MediaSort
|
||||
}
|
||||
|
||||
// PageParamCharacters is page param for characters.
|
||||
type PageParamCharacters struct {
|
||||
ID int
|
||||
IsBirthday *bool
|
||||
Search string
|
||||
IDNot int
|
||||
IDIn []int
|
||||
IDNotIn []int
|
||||
Sort []CharacterSort
|
||||
}
|
||||
|
||||
// PageParamStaff is page param for staff.
|
||||
type PageParamStaff struct {
|
||||
ID int
|
||||
IsBirthday *bool
|
||||
Search string
|
||||
IDNot int
|
||||
IDIn []int
|
||||
IDNotIn []int
|
||||
Sort []StaffSort
|
||||
}
|
||||
|
||||
// UserParamFavourites is user param for favourites.
|
||||
type UserParamFavourites struct {
|
||||
Page int
|
||||
}
|
||||
|
||||
// FavouritesParamAnime is favourites param for anime.
|
||||
type FavouritesParamAnime struct {
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// FavouritesParamManga is favourites param for manga.
|
||||
type FavouritesParamManga struct {
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// FavouritesParamCharacters is favourites param for characters.
|
||||
type FavouritesParamCharacters struct {
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// FavouritesParamStaff is favourites param for staff.
|
||||
type FavouritesParamStaff struct {
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// FavouritesParamStudios is favourites param for studios.
|
||||
type FavouritesParamStudios struct {
|
||||
Page int
|
||||
PerPage int
|
||||
}
|
||||
|
||||
// UserStatisticsParamFormats is user statistics param for formats.
|
||||
type UserStatisticsParamFormats struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamStatuses is user statistics param for statuses.
|
||||
type UserStatisticsParamStatuses struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamScores is user statistics param for scores.
|
||||
type UserStatisticsParamScores struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamLengths is user statistics param for lengths.
|
||||
type UserStatisticsParamLengths struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamReleaseYears is user statistics param for release years.
|
||||
type UserStatisticsParamReleaseYears struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamStartYears is user statistics param for start years.
|
||||
type UserStatisticsParamStartYears struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamGenres is user statistics param for genres.
|
||||
type UserStatisticsParamGenres struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamTags is user statistics param for tags.
|
||||
type UserStatisticsParamTags struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamCountries is user statistics param for countries.
|
||||
type UserStatisticsParamCountries struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamVoiceActors is user statistics param for voice actors.
|
||||
type UserStatisticsParamVoiceActors struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamStaff is user statistics param for staff.
|
||||
type UserStatisticsParamStaff struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// UserStatisticsParamStudios is user statistics param for studios.
|
||||
type UserStatisticsParamStudios struct {
|
||||
Limit int
|
||||
Sort []UserStatisticsSort
|
||||
}
|
||||
|
||||
// MediaListCollectionParam is media list collection param.
|
||||
type MediaListCollectionParam struct {
|
||||
UserID int
|
||||
Username string
|
||||
Type MediaType
|
||||
Status MediaListStatus
|
||||
Notes string
|
||||
StartedAt FuzzyDateInt
|
||||
CompletedAt FuzzyDateInt
|
||||
ForceSingleCompletedList *bool
|
||||
Chunk int
|
||||
PerChunk int
|
||||
StatusIn []MediaListStatus
|
||||
StatusNotIn []MediaListStatus
|
||||
StatusNot MediaListStatus
|
||||
NotesLike string
|
||||
StartedAtGreater FuzzyDateInt
|
||||
StartedAtLesser FuzzyDateInt
|
||||
StartedAtLike string
|
||||
CompletedAtGreater FuzzyDateInt
|
||||
CompletedAtLesser FuzzyDateInt
|
||||
CompletedAtLike string
|
||||
Sort []MediaListSort
|
||||
}
|
||||
131
verniy/search.go
Normal file
131
verniy/search.go
Normal file
@@ -0,0 +1,131 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
// SearchAnime to search anime.
|
||||
func (c *Client) SearchAnime(query PageParamMedia, page int, perPage int, fields ...MediaField) (*Page, error) {
|
||||
return c.SearchAnimeWithContext(context.Background(), query, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// SearchAnimeWithContext to search anime with context.
|
||||
func (c *Client) SearchAnimeWithContext(ctx context.Context, query PageParamMedia, page int, perPage int, fields ...MediaField) (*Page, error) {
|
||||
query.Type = MediaTypeAnime
|
||||
if len(fields) == 0 {
|
||||
isMain := true
|
||||
fields = []MediaField{
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldSynonyms,
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldLarge,
|
||||
MediaCoverImageFieldColor),
|
||||
MediaFieldStartDate,
|
||||
MediaFieldEndDate,
|
||||
MediaFieldSeason,
|
||||
MediaFieldSeasonYear,
|
||||
MediaFieldDescription,
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldEpisodes,
|
||||
MediaFieldDuration,
|
||||
MediaFieldGenres,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldPopularity,
|
||||
MediaFieldStudios(
|
||||
MediaParamStudios{IsMain: &isMain},
|
||||
StudioConnectionFieldEdges(
|
||||
StudioEdgeFieldIsMain,
|
||||
StudioEdgeFieldNode(
|
||||
StudioFieldID,
|
||||
StudioFieldName,
|
||||
StudioFieldIsAnimationStudio))),
|
||||
}
|
||||
}
|
||||
if len(query.Sort) == 0 {
|
||||
query.Sort = []MediaSort{MediaSortPopularityDesc, MediaSortScoreDesc}
|
||||
}
|
||||
return c.page(ctx, page, perPage, PageFieldMedia(query, "", fields...))
|
||||
}
|
||||
|
||||
// SearchManga to search manga.
|
||||
func (c *Client) SearchManga(query PageParamMedia, page int, perPage int, fields ...MediaField) (*Page, error) {
|
||||
return c.SearchMangaWithContext(context.Background(), query, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// SearchMangaWithContext to search manga with context.
|
||||
func (c *Client) SearchMangaWithContext(ctx context.Context, query PageParamMedia, page int, perPage int, fields ...MediaField) (*Page, error) {
|
||||
query.Type = MediaTypeManga
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaField{
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldLarge,
|
||||
MediaCoverImageFieldColor),
|
||||
MediaFieldStartDate,
|
||||
MediaFieldEndDate,
|
||||
MediaFieldDescription,
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldChapters,
|
||||
MediaFieldVolumes,
|
||||
MediaFieldGenres,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldPopularity,
|
||||
}
|
||||
}
|
||||
if len(query.Sort) == 0 {
|
||||
query.Sort = []MediaSort{MediaSortPopularityDesc, MediaSortScoreDesc}
|
||||
}
|
||||
return c.page(ctx, page, perPage, PageFieldMedia(query, "", fields...))
|
||||
}
|
||||
|
||||
// SearchCharacter to search character.
|
||||
func (c *Client) SearchCharacter(query PageParamCharacters, page int, perPage int, fields ...CharacterField) (*Page, error) {
|
||||
return c.SearchCharacterWithContext(context.Background(), query, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// SearchCharacterWithContext to search character with context.
|
||||
func (c *Client) SearchCharacterWithContext(ctx context.Context, query PageParamCharacters, page int, perPage int, fields ...CharacterField) (*Page, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []CharacterField{
|
||||
CharacterFieldID,
|
||||
CharacterFieldName(CharacterNameFieldFull),
|
||||
CharacterFieldImage(CharacterImageFieldLarge),
|
||||
}
|
||||
}
|
||||
if len(query.Sort) == 0 {
|
||||
query.Sort = []CharacterSort{CharacterSortSearchMatch, CharacterSortFavouritesDesc}
|
||||
}
|
||||
return c.page(ctx, page, perPage, PageFieldCharacters(query, "", fields...))
|
||||
}
|
||||
|
||||
// SearchStaff to search staff.
|
||||
func (c *Client) SearchStaff(query PageParamStaff, page int, perPage int, fields ...StaffField) (*Page, error) {
|
||||
return c.SearchStaffWithContext(context.Background(), query, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// SearchStaffWithContext to search staff with context.
|
||||
func (c *Client) SearchStaffWithContext(ctx context.Context, query PageParamStaff, page int, perPage int, fields ...StaffField) (*Page, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []StaffField{
|
||||
StaffFieldID,
|
||||
StaffFieldName(StaffNameFieldFull),
|
||||
StaffFieldImage(StaffImageFieldLarge),
|
||||
}
|
||||
}
|
||||
if len(query.Sort) == 0 {
|
||||
query.Sort = []StaffSort{StaffSortSearchMatch, StaffSortFavouritesDesc}
|
||||
}
|
||||
return c.page(ctx, page, perPage, PageFieldStaff(query, "", fields...))
|
||||
}
|
||||
140
verniy/staff.go
Normal file
140
verniy/staff.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type staffResponse struct {
|
||||
Data struct {
|
||||
Staff Staff `json:"staff"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) staffQuery(params QueryParam, fields ...StaffField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("Staff", params, p...)
|
||||
}
|
||||
|
||||
// GetStaff to get staff & voice actor data.
|
||||
func (c *Client) GetStaff(id int, fields ...StaffField) (*Staff, error) {
|
||||
return c.GetStaffWithContext(context.Background(), id, fields...)
|
||||
}
|
||||
|
||||
// GetStaffWithContext to get staff & voice actor data with context.
|
||||
func (c *Client) GetStaffWithContext(ctx context.Context, id int, fields ...StaffField) (*Staff, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []StaffField{
|
||||
StaffFieldID,
|
||||
StaffFieldName(
|
||||
StaffNameFieldFirst,
|
||||
StaffNameFieldMiddle,
|
||||
StaffNameFieldLast,
|
||||
StaffNameFieldFull,
|
||||
StaffNameFieldNative,
|
||||
StaffNameFieldAlternative),
|
||||
StaffFieldImage(StaffImageFieldLarge),
|
||||
StaffFieldDescription,
|
||||
StaffFieldFavourites,
|
||||
StaffFieldAge,
|
||||
StaffFieldHomeTown,
|
||||
StaffFieldDateOfBirth,
|
||||
StaffFieldDateOfDeath,
|
||||
}
|
||||
}
|
||||
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$id": "Int",
|
||||
}, c.staffQuery(QueryParam{
|
||||
"id": "$id",
|
||||
}, fields...))
|
||||
|
||||
var d staffResponse
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"id": id,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d.Data.Staff, nil
|
||||
}
|
||||
|
||||
// GetStaffCharacters to get list of character the staff play.
|
||||
func (c *Client) GetStaffCharacters(id int, page int, perPage int) (*Staff, error) {
|
||||
return c.GetStaffCharactersWithContext(context.Background(), id, page, perPage)
|
||||
}
|
||||
|
||||
// GetStaffCharactersWithContext to get list of character the staff play with context.
|
||||
func (c *Client) GetStaffCharactersWithContext(ctx context.Context, id int, page int, perPage int) (*Staff, error) {
|
||||
return c.GetStaffWithContext(ctx, id, StaffFieldCharacterMedia(StaffParamCharacterMedia{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Sort: []MediaSort{MediaSortStartDateDesc},
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldCharacterRole,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldType,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative,
|
||||
MediaTitleFieldRomaji),
|
||||
MediaFieldCoverImage(MediaCoverImageFieldMedium)),
|
||||
MediaEdgeFieldCharacters(
|
||||
CharacterFieldID,
|
||||
CharacterFieldName(CharacterNameFieldFull),
|
||||
CharacterFieldImage(CharacterImageFieldMedium)))))
|
||||
}
|
||||
|
||||
func (c *Client) getStaffMedia(ctx context.Context, id int, mediaType MediaType, page int, perPage int) (*Staff, error) {
|
||||
return c.GetStaffWithContext(ctx, id, StaffFieldStaffMedia(StaffParamStaffMedia{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Type: mediaType,
|
||||
Sort: []MediaSort{MediaSortStartDateDesc},
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldStaffRole,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldType,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative,
|
||||
MediaTitleFieldRomaji),
|
||||
MediaFieldCoverImage(MediaCoverImageFieldMedium)))))
|
||||
}
|
||||
|
||||
// GetStaffAnime to get staff anime list.
|
||||
func (c *Client) GetStaffAnime(id int, page int, perPage int) (*Staff, error) {
|
||||
return c.GetStaffAnimeWithContext(context.Background(), id, page, perPage)
|
||||
}
|
||||
|
||||
// GetStaffAnimeWithContext to get staff anime list with context.
|
||||
func (c *Client) GetStaffAnimeWithContext(ctx context.Context, id int, page int, perPage int) (*Staff, error) {
|
||||
return c.getStaffMedia(ctx, id, MediaTypeAnime, page, perPage)
|
||||
}
|
||||
|
||||
// GetStaffManga to get staff manga list.
|
||||
func (c *Client) GetStaffManga(id int, page int, perPage int) (*Staff, error) {
|
||||
return c.GetStaffMangaWithContext(context.Background(), id, page, perPage)
|
||||
}
|
||||
|
||||
// GetStaffMangaWithContext to get staff manga list with context.
|
||||
func (c *Client) GetStaffMangaWithContext(ctx context.Context, id int, page int, perPage int) (*Staff, error) {
|
||||
return c.getStaffMedia(ctx, id, MediaTypeManga, page, perPage)
|
||||
}
|
||||
103
verniy/studio.go
Normal file
103
verniy/studio.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type studioResponse struct {
|
||||
Data struct {
|
||||
Studio Studio `json:"studio"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) studioQuery(params QueryParam, fields ...StudioField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("Studio", params, p...)
|
||||
}
|
||||
|
||||
// GetStudio to get anime list produced by the studio.
|
||||
func (c *Client) GetStudio(id int, page int, perPage int, fields ...StudioField) (*Studio, error) {
|
||||
return c.GetStudioWithContext(context.Background(), id, page, perPage, fields...)
|
||||
}
|
||||
|
||||
// GetStudioWithContext to get anime list produced by the studio with context.
|
||||
func (c *Client) GetStudioWithContext(ctx context.Context, id int, page int, perPage int, fields ...StudioField) (*Studio, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []StudioField{
|
||||
StudioFieldID,
|
||||
StudioFieldName,
|
||||
StudioFieldIsAnimationStudio,
|
||||
StudioFieldFavourites,
|
||||
StudioFieldMedia(StudioParamMedia{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
Sort: []MediaSort{MediaSortStartDateDesc},
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldIsMainStudio,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative,
|
||||
MediaTitleFieldRomaji),
|
||||
MediaFieldCoverImage(MediaCoverImageFieldMedium),
|
||||
MediaFieldStartDate,
|
||||
MediaFieldEndDate,
|
||||
MediaFieldDescription,
|
||||
MediaFieldSeason,
|
||||
MediaFieldSeasonYear,
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldGenres,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldPopularity))),
|
||||
}
|
||||
}
|
||||
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$id": "Int",
|
||||
}, c.studioQuery(QueryParam{
|
||||
"id": "$id",
|
||||
}, fields...))
|
||||
|
||||
var d studioResponse
|
||||
err := c.post(ctx, query, QueryParam{
|
||||
"id": id,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d.Data.Studio, nil
|
||||
}
|
||||
|
||||
// GetStudios to get list of studios.
|
||||
func (c *Client) GetStudios(page int, perPage int, fields ...StudioField) (*Page, error) {
|
||||
return c.GetStudiosWithContext(context.Background(), page, perPage, fields...)
|
||||
}
|
||||
|
||||
// GetStudiosWithContext to get list of studios with context.
|
||||
func (c *Client) GetStudiosWithContext(ctx context.Context, page int, perPage int, fields ...StudioField) (*Page, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []StudioField{
|
||||
StudioFieldID,
|
||||
StudioFieldName,
|
||||
StudioFieldIsAnimationStudio,
|
||||
StudioFieldFavourites,
|
||||
}
|
||||
}
|
||||
pageFields := PageFieldStudios(PageParamStudios{
|
||||
Sort: []StudioSort{StudioSortName},
|
||||
}, "", fields...)
|
||||
return c.page(ctx, page, perPage, pageFields)
|
||||
}
|
||||
44
verniy/tag.go
Normal file
44
verniy/tag.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package verniy
|
||||
|
||||
import "context"
|
||||
|
||||
type tagResponse struct {
|
||||
Data struct {
|
||||
Tags []MediaTag `json:"mediaTagCollection"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) tagQuery(fields ...MediaTagField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("MediaTagCollection", nil, p...)
|
||||
}
|
||||
|
||||
// GetTags to get all tag list.
|
||||
func (c *Client) GetTags(fields ...MediaTagField) ([]MediaTag, error) {
|
||||
return c.GetTagsWithContext(context.Background(), fields...)
|
||||
}
|
||||
|
||||
// GetTagsWithContext to get all tag list with context.
|
||||
func (c *Client) GetTagsWithContext(ctx context.Context, fields ...MediaTagField) ([]MediaTag, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaTagField{
|
||||
MediaTagFieldName,
|
||||
MediaTagFieldDescription,
|
||||
MediaTagFieldCategory,
|
||||
MediaTagFieldIsAdult,
|
||||
}
|
||||
}
|
||||
|
||||
query := FieldObject("query", nil, c.tagQuery(fields...))
|
||||
|
||||
var d tagResponse
|
||||
err := c.post(ctx, query, nil, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d.Data.Tags, nil
|
||||
}
|
||||
357
verniy/user.go
Normal file
357
verniy/user.go
Normal file
@@ -0,0 +1,357 @@
|
||||
package verniy
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
type userResponse struct {
|
||||
Data struct {
|
||||
User User `json:"user"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) userQuery(params QueryParam, fields ...UserField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("User", params, p...)
|
||||
}
|
||||
|
||||
// GetUser to get user data.
|
||||
func (c *Client) GetUser(username string, fields ...UserField) (*User, error) {
|
||||
return c.GetUserWithContext(context.Background(), username, fields...)
|
||||
}
|
||||
|
||||
// GetUserWithContext to get user data with context.
|
||||
func (c *Client) GetUserWithContext(ctx context.Context, username string, fields ...UserField) (*User, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []UserField{
|
||||
UserFieldID,
|
||||
UserFieldName,
|
||||
UserFieldAbout,
|
||||
UserFieldAvatar(UserAvatarFieldLarge),
|
||||
UserFieldBannerImage,
|
||||
UserFieldStatistics(
|
||||
UserStatisticTypesFieldAnime(
|
||||
UserStatisticsFieldCount,
|
||||
UserStatisticsFieldMeanScore,
|
||||
UserStatisticsFieldStandardDeviation,
|
||||
UserStatisticsFieldMinutesWatched,
|
||||
UserStatisticsFieldEpisodesWatched),
|
||||
UserStatisticTypesFieldManga(
|
||||
UserStatisticsFieldCount,
|
||||
UserStatisticsFieldMeanScore,
|
||||
UserStatisticsFieldStandardDeviation,
|
||||
UserStatisticsFieldChaptersRead,
|
||||
UserStatisticsFieldVolumesRead)),
|
||||
}
|
||||
}
|
||||
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$name": "String",
|
||||
}, c.userQuery(QueryParam{
|
||||
"name": "$name",
|
||||
}, fields...))
|
||||
|
||||
var d userResponse
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"name": username,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &d.Data.User, nil
|
||||
}
|
||||
|
||||
// GetUserFavouriteAnime to get user's favourite anime.
|
||||
func (c *Client) GetUserFavouriteAnime(username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserFavouriteAnimeWithContext(context.Background(), username, page, perPage)
|
||||
}
|
||||
|
||||
// GetUserFavouriteAnimeWithContext to get user's favourite anime with context.
|
||||
func (c *Client) GetUserFavouriteAnimeWithContext(ctx context.Context, username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserWithContext(ctx, username, UserFieldFavourites(UserParamFavourites{
|
||||
Page: page,
|
||||
}, FavouritesFieldAnime(FavouritesParamAnime{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldFavouriteOrder,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldLarge,
|
||||
MediaCoverImageFieldLarge))))))
|
||||
}
|
||||
|
||||
// GetUserFavouriteManga to get user's favourite manga.
|
||||
func (c *Client) GetUserFavouriteManga(username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserFavouriteMangaWithContext(context.Background(), username, page, perPage)
|
||||
}
|
||||
|
||||
// GetUserFavouriteMangaWithContext to get user's favourite manga with context.
|
||||
func (c *Client) GetUserFavouriteMangaWithContext(ctx context.Context, username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserWithContext(ctx, username, UserFieldFavourites(UserParamFavourites{
|
||||
Page: page,
|
||||
}, FavouritesFieldManga(FavouritesParamManga{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
MediaConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
MediaConnectionFieldEdges(
|
||||
MediaEdgeFieldFavouriteOrder,
|
||||
MediaEdgeFieldNode(
|
||||
MediaFieldID,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldCoverImage(
|
||||
MediaCoverImageFieldLarge,
|
||||
MediaCoverImageFieldLarge))))))
|
||||
}
|
||||
|
||||
// GetUserFavouriteCharacters to get user's favourite characters.
|
||||
func (c *Client) GetUserFavouriteCharacters(username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserFavouriteCharactersWithContext(context.Background(), username, page, perPage)
|
||||
}
|
||||
|
||||
// GetUserFavouriteCharactersWithContext to get user's favourite characters with context.
|
||||
func (c *Client) GetUserFavouriteCharactersWithContext(ctx context.Context, username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserWithContext(ctx, username, UserFieldFavourites(UserParamFavourites{
|
||||
Page: page,
|
||||
}, FavouritesFieldCharacters(FavouritesParamCharacters{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
CharacterConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
CharacterConnectionFieldEdges(
|
||||
CharacterEdgeFieldFavouriteOrder,
|
||||
CharacterEdgeFieldNode(
|
||||
CharacterFieldID,
|
||||
CharacterFieldName(
|
||||
CharacterNameFieldFull,
|
||||
CharacterNameFieldNative),
|
||||
CharacterFieldImage(CharacterImageFieldLarge))))))
|
||||
}
|
||||
|
||||
// GetUserFavouriteStaff to get user's favourite staff.
|
||||
func (c *Client) GetUserFavouriteStaff(username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserFavouriteStaffWithContext(context.Background(), username, page, perPage)
|
||||
}
|
||||
|
||||
// GetUserFavouriteStaffWithContext to get user's favourite staff with context.
|
||||
func (c *Client) GetUserFavouriteStaffWithContext(ctx context.Context, username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserWithContext(ctx, username, UserFieldFavourites(UserParamFavourites{
|
||||
Page: page,
|
||||
}, FavouritesFieldStaff(FavouritesParamStaff{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
StaffConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
StaffConnectionFieldEdges(
|
||||
StaffEdgeFieldFavouriteOrder,
|
||||
StaffEdgeFieldNode(
|
||||
StaffFieldID,
|
||||
StaffFieldName(
|
||||
StaffNameFieldFull,
|
||||
StaffNameFieldNative),
|
||||
StaffFieldImage(StaffImageFieldLarge))))))
|
||||
}
|
||||
|
||||
// GetUserFavouriteStudios to get user's favourite studios.
|
||||
func (c *Client) GetUserFavouriteStudios(username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserFavouriteStudiosWithContext(context.Background(), username, page, perPage)
|
||||
}
|
||||
|
||||
// GetUserFavouriteStudiosWithContext to get user's favourite studios with context.
|
||||
func (c *Client) GetUserFavouriteStudiosWithContext(ctx context.Context, username string, page int, perPage int) (*User, error) {
|
||||
return c.GetUserWithContext(ctx, username, UserFieldFavourites(UserParamFavourites{
|
||||
Page: page,
|
||||
}, FavouritesFieldStudios(FavouritesParamStudios{
|
||||
Page: page,
|
||||
PerPage: perPage,
|
||||
},
|
||||
StudioConnectionFieldPageInfo(
|
||||
PageInfoFieldTotal,
|
||||
PageInfoFieldPerPage,
|
||||
PageInfoFieldCurrentPage,
|
||||
PageInfoFieldLastPage,
|
||||
PageInfoFieldHasNextPage),
|
||||
StudioConnectionFieldEdges(
|
||||
StudioEdgeFieldFavouriteOrder,
|
||||
StudioEdgeFieldNode(
|
||||
StudioFieldID,
|
||||
StudioFieldName)))))
|
||||
}
|
||||
|
||||
type userAnimeListResponse struct {
|
||||
Data struct {
|
||||
MediaListCollection *MediaListCollection `json:"mediaListCollection"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
func (c *Client) mediaListCollectionQuery(params QueryParam, fields ...MediaListCollectionField) string {
|
||||
p := make([]string, len(fields))
|
||||
for i := range fields {
|
||||
p[i] = string(fields[i])
|
||||
}
|
||||
return FieldObject("MediaListCollection", params, p...)
|
||||
}
|
||||
|
||||
func (c *Client) getMediaListCollection(ctx context.Context, username string, mediaType MediaType, fields ...MediaListGroupField) ([]MediaListGroup, error) {
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$username": "String",
|
||||
"$type": "MediaType",
|
||||
}, c.mediaListCollectionQuery(QueryParam{
|
||||
"userName": "$username",
|
||||
"type": "$type",
|
||||
}, MediaListCollectionFieldLists(MediaListGroupFieldStatus, fields...)))
|
||||
|
||||
var d userAnimeListResponse
|
||||
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"username": username,
|
||||
"type": mediaType,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d.Data.MediaListCollection.Lists, nil
|
||||
}
|
||||
|
||||
// GetUserAnimeList to get user's anime list.
|
||||
func (c *Client) GetUserAnimeList(username string, fields ...MediaListGroupField) ([]MediaListGroup, error) {
|
||||
return c.GetUserAnimeListWithContext(context.Background(), username, fields...)
|
||||
}
|
||||
|
||||
// GetUserAnimeListSort Added custom function to get user's anime list sorted
|
||||
func (c *Client) GetUserAnimeListSort(username string, sort MediaListSort, fields ...MediaListGroupField) ([]MediaListGroup, error) {
|
||||
ctx := context.Background()
|
||||
query := FieldObject("query", QueryParam{
|
||||
"$username": "String",
|
||||
"$type": "MediaType",
|
||||
"$sort": "[MediaListSort]",
|
||||
}, c.mediaListCollectionQuery(QueryParam{
|
||||
"userName": "$username",
|
||||
"type": "$type",
|
||||
"sort": "$sort",
|
||||
}, MediaListCollectionFieldLists(MediaListGroupFieldStatus, fields...)))
|
||||
|
||||
var d userAnimeListResponse
|
||||
|
||||
err := c.post(ctx, query, queryVariable{
|
||||
"username": username,
|
||||
"type": MediaTypeAnime,
|
||||
"sort": sort,
|
||||
}, &d)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return d.Data.MediaListCollection.Lists, nil
|
||||
}
|
||||
|
||||
// GetUserAnimeListWithContext to get user's anime list with context.
|
||||
func (c *Client) GetUserAnimeListWithContext(ctx context.Context, username string, fields ...MediaListGroupField) ([]MediaListGroup, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaListGroupField{
|
||||
MediaListGroupFieldName,
|
||||
MediaListGroupFieldStatus,
|
||||
MediaListGroupFieldEntries(
|
||||
MediaListFieldID,
|
||||
MediaListFieldStatus,
|
||||
MediaListFieldScore,
|
||||
MediaListFieldProgress,
|
||||
MediaListFieldNotes,
|
||||
MediaListFieldStartedAt,
|
||||
MediaListFieldCompletedAt,
|
||||
MediaListFieldMedia(
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldCoverImage(MediaCoverImageFieldLarge),
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldPopularity,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldEpisodes)),
|
||||
}
|
||||
}
|
||||
return c.getMediaListCollection(ctx, username, MediaTypeAnime, fields...)
|
||||
}
|
||||
|
||||
// GetUserMangaList to get user's manga list.
|
||||
func (c *Client) GetUserMangaList(username string, fields ...MediaListGroupField) ([]MediaListGroup, error) {
|
||||
return c.GetUserMangaListWithContext(context.Background(), username, fields...)
|
||||
}
|
||||
|
||||
// GetUserMangaListWithContext to get user's manga list with context.
|
||||
func (c *Client) GetUserMangaListWithContext(ctx context.Context, username string, fields ...MediaListGroupField) ([]MediaListGroup, error) {
|
||||
if len(fields) == 0 {
|
||||
fields = []MediaListGroupField{
|
||||
MediaListGroupFieldName,
|
||||
MediaListGroupFieldStatus,
|
||||
MediaListGroupFieldEntries(
|
||||
MediaListFieldID,
|
||||
MediaListFieldStatus,
|
||||
MediaListFieldScore,
|
||||
MediaListFieldProgress,
|
||||
MediaListFieldProgressVolumes,
|
||||
MediaListFieldNotes,
|
||||
MediaListFieldStartedAt,
|
||||
MediaListFieldCompletedAt,
|
||||
MediaListFieldMedia(
|
||||
MediaFieldID,
|
||||
MediaFieldTitle(
|
||||
MediaTitleFieldRomaji,
|
||||
MediaTitleFieldEnglish,
|
||||
MediaTitleFieldNative),
|
||||
MediaFieldType,
|
||||
MediaFieldFormat,
|
||||
MediaFieldStatusV2,
|
||||
MediaFieldCoverImage(MediaCoverImageFieldLarge),
|
||||
MediaFieldAverageScore,
|
||||
MediaFieldPopularity,
|
||||
MediaFieldIsAdult,
|
||||
MediaFieldChapters,
|
||||
MediaFieldVolumes)),
|
||||
}
|
||||
}
|
||||
return c.getMediaListCollection(ctx, username, MediaTypeManga, fields...)
|
||||
}
|
||||
84
verniy/utils.go
Normal file
84
verniy/utils.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package verniy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FieldObject to generate query string.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// FieldObject("key", map[string]interface{}{
|
||||
// "name1": "value1",
|
||||
// "name2": []string{"value2", "value3"},
|
||||
// }, "field1", "field2")
|
||||
//
|
||||
// Will generate:
|
||||
//
|
||||
// key(name1:value1, name2:[value2,value3]) {
|
||||
// field1
|
||||
// field2
|
||||
// }
|
||||
//
|
||||
// Or just see usage example in some functions in verniy package.
|
||||
func FieldObject(key string, params map[string]interface{}, fields ...string) string {
|
||||
var paramStr string
|
||||
if params != nil || len(params) > 0 {
|
||||
var paramArr []string
|
||||
for k, p := range params {
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
switch reflect.TypeOf(p).Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
v := reflect.ValueOf(p)
|
||||
if v.Len() > 0 {
|
||||
vArr := make([]string, v.Len())
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
vArr[i] = fmt.Sprintf("%v", v.Index(i))
|
||||
}
|
||||
paramArr = append(paramArr, fmt.Sprintf("%v:[%v]", k, strings.Join(vArr, ",")))
|
||||
}
|
||||
case reflect.String:
|
||||
if reflect.ValueOf(p).Len() != 0 {
|
||||
paramArr = append(paramArr, fmt.Sprintf("%v:%v", k, p))
|
||||
}
|
||||
case reflect.Int:
|
||||
if reflect.ValueOf(p).Int() != 0 {
|
||||
paramArr = append(paramArr, fmt.Sprintf("%v:%v", k, p))
|
||||
}
|
||||
case reflect.Ptr:
|
||||
if !reflect.ValueOf(p).IsNil() {
|
||||
paramArr = append(paramArr, fmt.Sprintf("%v:%v", k, reflect.ValueOf(p).Elem()))
|
||||
}
|
||||
default:
|
||||
paramArr = append(paramArr, fmt.Sprintf("%v:%v", k, p))
|
||||
}
|
||||
}
|
||||
if len(paramArr) > 0 {
|
||||
paramStr = fmt.Sprintf("(%s)", strings.Join(paramArr, ","))
|
||||
}
|
||||
}
|
||||
var fieldStr string
|
||||
if len(fields) > 0 {
|
||||
fieldStr = fmt.Sprintf("{%s}", strings.Join(fields, " "))
|
||||
}
|
||||
return fmt.Sprintf("%s%s%s", key, paramStr, fieldStr)
|
||||
}
|
||||
|
||||
func toQueryString(str string) string {
|
||||
if str == "" {
|
||||
return str
|
||||
}
|
||||
return fmt.Sprintf(`"%s"`, str)
|
||||
}
|
||||
|
||||
func toQueryStringArray(strs []string) []string {
|
||||
for i := range strs {
|
||||
strs[i] = fmt.Sprintf(`"%s"`, strs[i])
|
||||
}
|
||||
return strs
|
||||
}
|
||||
27
verniy/verniy.go
Normal file
27
verniy/verniy.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package verniy
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"AnimeGUI/verniy/limiter"
|
||||
)
|
||||
|
||||
// Client is anilist client.
|
||||
type Client struct {
|
||||
Host string
|
||||
Http http.Client
|
||||
Limiter limiter.Limiter
|
||||
AccessToken string
|
||||
}
|
||||
|
||||
// New to create new anilist client.
|
||||
func New() *Client {
|
||||
return &Client{
|
||||
Host: "https://graphql.anilist.co",
|
||||
Http: http.Client{
|
||||
Timeout: 10 * time.Second,
|
||||
},
|
||||
Limiter: limiter.New(90, time.Minute),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user