The MyAnimeList API inconsistently returns statistics status fields (watching, completed, on_hold, dropped, plan_to_watch) as quoted strings for non-zero values (e.g. "8217") but as bare numbers for zero values (e.g. 0). This caused JSON unmarshal errors for anime with zero counts in any status field. Introduce a FlexString custom type that implements json.Unmarshaler to accept both JSON strings and JSON numbers, always storing the result as a string. The type definition lives in MALTypes.go and the unmarshal logic in MALFunctions.go to keep static types and behavior separate.
168 lines
7.8 KiB
Go
168 lines
7.8 KiB
Go
package main
|
|
|
|
import (
|
|
"time"
|
|
)
|
|
|
|
type FlexString string
|
|
|
|
type MyAnimeListJWT struct {
|
|
TokenType string `json:"token_type"`
|
|
ExpiresIn int `json:"expires_in"`
|
|
AccessToken string `json:"access_token"`
|
|
RefreshToken string `json:"refresh_token"`
|
|
}
|
|
|
|
type MyAnimeListUser struct {
|
|
Id int32 `json:"id" ts_type:"id"`
|
|
Name string `json:"name" ts_type:"name"`
|
|
Picture string `json:"picture" ts_type:"picture"`
|
|
Gender string `json:"gender" ts_type:"gender"`
|
|
Birthday string `json:"birthday" ts_type:"birthday"`
|
|
Location string `json:"location" ts_type:"location"`
|
|
JoinedAt string `json:"joined_at" ts_type:"joinedAt"`
|
|
AnimeStatistics `json:"anime_statistics" ts_type:"AnimeStatistics"`
|
|
TimeZone string `json:"time_zone" ts_type:"timeZone"`
|
|
IsSupporter bool `json:"is_supporter" ts_type:"isSupporter"`
|
|
}
|
|
|
|
type AnimeStatistics struct {
|
|
NumItemsWatching int `json:"num_items_watching" ts_type:"numItemsWatching"`
|
|
NumItemsCompleted int `json:"num_items_completed" ts_type:"numItemsCompleted"`
|
|
NumItemsOnHold int `json:"num_items_on_hold" ts_type:"numItemsOnHold"`
|
|
NumItemsDropped int `json:"num_items_dropped" ts_type:"numItemsDropped"`
|
|
NumItemsPlanToWatch int `json:"num_items_plan_to_watch" ts_type:"numItemsPlanToWatch"`
|
|
NumItems int `json:"num_items" ts_type:"numItems"`
|
|
NumDaysWatched float64 `json:"num_days_watched" ts_type:"numDaysWatched"`
|
|
NumDaysWatching float64 `json:"num_days_watching" ts_type:"numDaysWatching"`
|
|
NumDaysCompleted float64 `json:"num_days_completed" ts_type:"numDaysCompleted"`
|
|
NumDaysOnHold float64 `json:"num_days_on_hold" ts_type:"numDaysOnHold"`
|
|
NumDaysDropped float64 `json:"num_days_dropped" ts_type:"numDaysDropped"`
|
|
NumDays float64 `json:"num_days" ts_type:"numDays"`
|
|
NumEpisodes int `json:"num_episodes" ts_type:"numEpisodes"`
|
|
NumTimesRewatched int `json:"num_times_rewatched" ts_type:"numTimesRewatched"`
|
|
MeanScore float64 `json:"mean_score" ts_type:"meanScore"`
|
|
}
|
|
|
|
type MALWatchlist struct {
|
|
Data []struct {
|
|
Node struct {
|
|
Id int `json:"id" ts_type:"id"`
|
|
Title string `json:"title" ts_type:"title"`
|
|
MainPicture struct {
|
|
Medium string `json:"medium" ts_type:"medium"`
|
|
Large string `json:"large" ts_type:"large"`
|
|
} `json:"main_picture" ts_type:"mainPicture"`
|
|
} `json:"node" ts_type:"node"`
|
|
ListStatus struct {
|
|
Status string `json:"status" ts_type:"status"`
|
|
Score int `json:"score" ts_type:"score"`
|
|
NumEpisodesWatched int `json:"num_episodes_watched" ts_type:"numEpisodesWatched"`
|
|
IsRewatching bool `json:"is_rewatching" ts_type:"isRewatching"`
|
|
UpdatedAt time.Time `json:"updated_at" ts_type:"updatedAt"`
|
|
StartDate string `json:"start_date" ts_type:"startDate"`
|
|
FinishDate string `json:"finish_date" ts_type:"finishDate"`
|
|
} `json:"list_status" ts_type:"listStatus"`
|
|
} `json:"data" ts_type:"data"`
|
|
Paging struct {
|
|
Previous string `json:"previous" ts_type:"previous"`
|
|
Next string `json:"next" ts_type:"next"`
|
|
} `json:"paging" ts_type:"paging"`
|
|
}
|
|
|
|
type MALAnime struct {
|
|
Id int `json:"id" ts_type:"id"`
|
|
Title string `json:"title" ts_type:"title"`
|
|
MainPicture struct {
|
|
Large string `json:"large" ts_type:"large"`
|
|
Medium string `json:"medium" ts_type:"medium"`
|
|
} `json:"main_picture" ts_type:"mainPicture"`
|
|
AlternativeTitles struct {
|
|
Synonyms []string `json:"synonyms" ts_type:"synonyms"`
|
|
En string `json:"en" ts_type:"en"`
|
|
Ja string `json:"ja" ts_type:"ja"`
|
|
} `json:"alternative_titles" ts_type:"alternativeTitles"`
|
|
StartDate string `json:"start_date" ts_type:"startDate"`
|
|
EndDate string `json:"end_date" ts_type:"endDate"`
|
|
Synopsis string `json:"synopsis" ts_type:"synopsis"`
|
|
Mean float64 `json:"mean" ts_type:"mean"`
|
|
Rank int `json:"rank" ts_type:"rank"`
|
|
Popularity int `json:"popularity" ts_type:"popularity"`
|
|
NumListUsers int `json:"num_list_users" ts_type:"numListUsers"`
|
|
NumScoringUsers int `json:"num_scoring_users" ts_type:"numScoringUsers"`
|
|
NSFW string `json:"nsfw" ts_type:"nsfw"`
|
|
Genres []struct {
|
|
Id int `json:"id" ts_type:"id"`
|
|
Name string `json:"name" ts_type:"name"`
|
|
} `json:"genres" ts_type:"genres"`
|
|
CreatedAt string `json:"created_at" ts_type:"createdAt"`
|
|
UpdatedAt string `json:"updated_at" ts_type:"updatedAt"`
|
|
MediaType string `json:"media_type" ts_type:"mediaType"`
|
|
Status string `json:"status" ts_type:"status"`
|
|
MalListStatus MalListStatus `json:"my_list_status" ts_type:"MalListStatus"`
|
|
NumEpisodes int `json:"num_episodes" ts_type:"numEpisodes"`
|
|
StartSeason struct {
|
|
Year int `json:"year" ts_type:"year"`
|
|
Season string `json:"season" ts_type:"season"`
|
|
} `json:"start_season" ts_type:"startSeason"`
|
|
Broadcast struct {
|
|
DayOfTheWeek string `json:"day_of_the_week" ts_type:"dayOfTheWeek"`
|
|
StartTime string `json:"start_time" ts_type:"startTime"`
|
|
} `json:"broadcast" ts_type:"broadcast"`
|
|
Source string `json:"source" ts_type:"source"`
|
|
AverageEpisodeDuration int `json:"average_episode_duration" ts_type:"averageEpisodeDuration"`
|
|
Rating string `json:"rating" ts_type:"rating"`
|
|
Studios []struct {
|
|
Id int `json:"id" ts_type:"id"`
|
|
Name string `json:"name" ts_type:"name"`
|
|
} `json:"studios" ts_type:"studios"`
|
|
Pictures []struct {
|
|
Large string `json:"large" ts_type:"large"`
|
|
Medium string `json:"medium" ts_type:"medium"`
|
|
} `json:"pictures" ts_type:"pictures"`
|
|
Background string `json:"background" ts_type:"background"`
|
|
RelatedAnime []struct {
|
|
Node MALAnime `json:"node" ts_type:"node"`
|
|
RelationType string `json:"relation_type" ts_type:"relationType"`
|
|
RelationTypeFormatted string `json:"relation_type_formatted" ts_type:"relationTypeFormatted"`
|
|
} `json:"related_anime" ts_type:"relatedAnime"`
|
|
Recommendations []struct {
|
|
Node MALAnime `json:"node" ts_type:"node"`
|
|
NumRecommendations int `json:"num_recommendations" ts_type:"numRecommendations"`
|
|
} `json:"recommendations" ts_type:"recommendations"`
|
|
Statistics struct {
|
|
NumListUsers int `json:"num_list_users" ts_type:"numListUsers"`
|
|
Status struct {
|
|
Watching FlexString `json:"watching" ts_type:"string"`
|
|
Completed FlexString `json:"completed" ts_type:"string"`
|
|
OnHold FlexString `json:"on_hold" ts_type:"string"`
|
|
Dropped FlexString `json:"dropped" ts_type:"string"`
|
|
PlanToWatch FlexString `json:"plan_to_watch" ts_type:"string"`
|
|
}
|
|
}
|
|
}
|
|
|
|
type MalListStatus struct {
|
|
Status string `json:"status" ts_type:"status"`
|
|
Score int `json:"score" ts_type:"score"`
|
|
NumEpisodesWatched int `json:"num_episodes_watched" ts_type:"numEpisodesWatched"`
|
|
IsRewatching bool `json:"is_rewatching" ts_type:"isRewatching"`
|
|
StartDate string `json:"start_date" ts_type:"startDate"`
|
|
FinishDate string `json:"finish_date" ts_type:"finishDate"`
|
|
Priority int `json:"priority" ts_type:"priority"`
|
|
NumTimesRewatched int `json:"num_times_rewatched" ts_type:"numTimesRewatched"`
|
|
RewatchValue int `json:"rewatch_value" ts_type:"rewatchValue"`
|
|
Tags []string `json:"tags" ts_type:"tags"`
|
|
Comments string `json:"comments" ts_type:"comments"`
|
|
UpdatedAt string `json:"updated_at" ts_type:"updatedAt"`
|
|
}
|
|
|
|
type MALUploadStatus struct {
|
|
Status string `json:"status"`
|
|
IsRewatching bool `json:"is_rewatching"`
|
|
Score int `json:"score"`
|
|
NumWatchedEpisodes int `json:"num_watched_episodes"`
|
|
NumTimesRewatched int `json:"num_times_rewatched"`
|
|
Comments string `json:"comments"`
|
|
}
|