1 // Low-level wrapper around the AniDB HTTP API.
2 // Only implements the 'anime' and 'categorylist' requests.
4 // This wrapper does not implement caching. The API requires
7 // http://wiki.anidb.info/w/HTTP_API_Definition
20 AniDBImageBaseURL = "http://img7.anidb.net/pics/anime/" // Base URL for the various Pictures in the response
22 DateFormat = "2006-01-02" // Use to convert the various YYYY-MM-DD timestamps to a time.Time.
24 // Base URLs for the various resources.
25 // Meant for use with fmt.Sprintf.
26 ANNFormat = "http://www.animenewsnetwork.com/encyclopedia/anime.php?id=%v" // Type 1
27 MyAnimeListFormat = "http://myanimelist.net/anime/%v" // Type 2
28 AnimeNfoFormat = "http://www.animenfo.com/animetitle,%v,%v,a.html" // Type 3
31 WikiEnglishFormat = "http://en.wikipedia.org/wiki/%v" // Type 6
32 WikiJapaneseFormat = "http://ja.wikipedia.org/wiki/%v" // Type 7
33 SyoboiFormat = "http://cal.syoboi.jp/tid/%v/time" // Type 8
34 AllCinemaFormat = "http://www.allcinema.net/prog/show_c.php?num_c=%v" // Type 9
35 AnisonFormat = "http://anison.info/data/program/%v.html" // Type 10
36 VNDBFormat = "http://vndb.org/v%v" // Type 14
37 MaruMeganeFormat = "http://www.anime.marumegane.com/%v.html" // Type 15
41 aniDBHTTPAPIBaseURL = "http://api.anidb.net:9001/httpapi"
43 clientStr = "goanidbhttp"
47 // Requests information about the given Anime ID.
48 func GetAnime(AID int) (a Anime, err error) {
49 if res, err := doRequest("anime", reqMap{"aid": AID}); err != nil {
52 dec := xml.NewDecoder(res.Body)
56 a.Error = strings.TrimSpace(a.Error)
59 for _, t := range a.Titles {
66 for _, r := range a.Resources {
68 case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 14, 15:
69 // documentation knows about these
71 log.Printf("Anime %d (%s) has unknown resource type %d", a.ID, title, r.Type)
72 log.Printf("Type %d external entities: %#v", r.Type, r.ExternalEntity)
80 type reqMap map[string]interface{}
82 func doRequest(request string, reqMap reqMap) (*http.Response, error) {
84 v.Set("protover", fmt.Sprint(aniDBProtoVer))
85 v.Set("client", clientStr)
86 v.Set("clientver", fmt.Sprint(clientVer))
87 v.Set("request", request)
89 for k, val := range reqMap {
90 v.Add(k, fmt.Sprint(val))
93 u, _ := url.Parse(aniDBHTTPAPIBaseURL)
94 u.RawQuery = v.Encode()
95 log.Println(u.String())
96 return http.Get(u.String())
99 // Title with language and type identifier.
101 // Title with Lang = ja, Type = official is the official Kanji title.
103 // Title with Lang = x-jat, Type = main is the romanized version, also known in other APIs as the Primary Title.
104 type AnimeTitle struct {
105 Lang string `xml:"lang,attr"` // Language in ISO-ish format
106 Type string `xml:"type,attr"` // "official", "short", etc
107 Title string `xml:",chardata"`
110 type RelatedAnime struct {
111 ID int `xml:"id,attr"` // AID of the related anime
112 Type string `xml:"type,attr"` // "prequel", "sequel", etc
113 Title string `xml:",chardata"` // Primary title of the related anime
116 type SimilarAnime struct {
117 ID int `xml:"id,attr"` // AID of the similar anime
118 Approval int `xml:"approval,attr"` // How many users have approved of this connection
119 Total int `xml:"total,attr"` // Total of votes in this connection
120 Title string `xml:",chardata"` // Primary title of the recommended anime
123 type Recommendation struct {
124 Type string `xml:"type,attr"` // "Recommended", "Must See", etc
125 ID int `xml:"uid,attr"` // User ID of the recommending user
126 Text string `xml:",chardata"` // Text of the user's recommendation
129 type Creator struct {
130 ID int `xml:"id,attr"` // Creator ID
131 Type string `xml:"type,attr"`
132 Name string `xml:",chardata"` // Always romaji
135 // Separate from regular Rating because the XML structure is different.
136 type AnimeRating struct {
137 Count int `xml:"count,attr"` // Amount of votes/reviews
138 Rating float32 `xml:",chardata"` // Average
141 type AnimeRatings struct {
142 Permanent AnimeRating `xml:"permanent"` // Votes from people who watched everything
143 Temporary AnimeRating `xml:"temporary"` // Votes from people who are still watching it
144 Review AnimeRating `xml:"review"` // Votes from reviews
147 type Category struct {
148 ID int `xml:"id,attr"` // Category ID
149 ParentID int `xml:"parentid,attr"` // ID of the parent category
150 R18 bool `xml:"hentai,attr"` // Whether the category represents porn works or not
151 Weight int `xml:"weight,attr"` // Weight of the category for this anime
153 Name string `xml:"name"` // Category name
154 Description string `xml:"description"` // Category description
157 type ExternalEntity struct {
158 Identifiers []string `xml:"identifier"`
159 URL []string `xml:"url"` // Used for types 5 and 6
162 // Completely undocumented.
163 // Most entries just have one or two numbers as Identifiers.
165 // Empiric documentation:
167 // Type 1 is the ANN id.
169 // Type 2 is the MyAnimeList ID.
171 // Type 3 is the AnimeNfo ID tuple.
173 // Type 4 is the official japanese webpage.
175 // Type 5 is the official english webpage.
177 // Type 6 is the english wikipedia page name.
179 // Type 7 is the japanese wikipedia page name.
181 // Type 8 is the cal.syoboi.jp schedule ID.
183 // Type 9 is the AllCinema ID.
185 // Type 10 is the anison.info ID.
187 // Type 14 is the VNDB ID.
189 // Type 15 is the MaruMegane ID.
190 type Resource struct {
191 Type int `xml:"type,attr"`
192 ExternalEntity []ExternalEntity `xml:"externalentity"`
196 ID int `xml:"id,attr"` // Tag ID
197 Approval int `xml:"approval,attr"` // How many users have approved of the tag
198 Spoiler bool `xml:"localspoiler,attr"` // undocumented
199 GlobalSpoiler bool `xml:"globalspoiler,attr"` // undocumented
200 Updated string `xml:"update,attr"` // YYYY-MM-DD
202 Name string `xml:"name"` // Tag name
203 Count int `xml:"count"` // undocumented
207 ID int `xml:"id,attr"` // Creator ID
208 Name string `xml:",chardata"` // Always romaji
209 Picture string `xml:"picture,attr"` // Picture basename; combine with AniDBImageBaseURL for full URL
212 type Character struct {
213 ID int `xml:"id,attr"` // Character ID
214 Type string `xml:"type,attr"` // "main character in", "secondary cast in", "appears in"
215 Updated string `xml:"update,attr"` // YYYY-MM-DD
217 Rating Rating `xml:"rating"`
218 Name string `xml:"name"` // Always romaji
219 Gender string `xml:"gender"` // "male", "female", "unknown", sometimes blank
220 Description string `xml:"description"`
221 CharacterType string `xml:"charactertype"` // "Character", "Organization", "Vessel", etc
222 Episodes string `xml:"episodes"` // List of episodes where character appears
223 Picture string `xml:"picture"` // Picture basename; combine with AniDBImageBaseURL for full URL
225 Seiyuu *Seiyuu `xml:"seiyuu"` // The voice actor, if present
228 type Characters []Character // Implements sort.Interface; groups by Type and sorts by Name
230 type EpisodeTitle struct {
231 Lang string `xml:"lang,attr"`
232 Title string `xml:",chardata"`
236 Votes int `xml:"votes,attr"`
237 Rating float32 `xml:",chardata"`
241 Type int `xml:"type,attr"` // 1 for regular episodes, 2 for specials, etc
242 EpNo string `xml:",chardata"` // Not necessarily a plain integer; may be prefixed by a single letter indicating the Type
245 type Episode struct {
246 ID int `xml:"id,attr"` // Episode ID
247 Updated string `xml:"update,attr"` // YYYY-MM-DD
249 EpNo EpNo `xml:"epno"`
250 Length int `xml:"length"` // Length in minutes (rounding method undocumented)
251 AirDate string `xml:"airdate"` // YYYY-MM-DD
252 Rating Rating `xml:"rating"`
253 Titles []EpisodeTitle `xml:"title"`
256 type Episodes []Episode // Implements sort.Interface; groups by EpNo.Type, orders by the integer portion of EpNo.EpNo
259 Error string `xml:",chardata"` // API request encountered an error if this is not ""
261 ID int `xml:"id,attr"` // AID of the anime
262 R18 bool `xml:"restricted,attr"` // Whether the anime is considered porn
264 Type string `xml:"type"` // "TV Series", "Movie", "OVA", etc
265 EpisodeCount int `xml:"episodecount"` // Unreliable, has a set value even when the total number is unknown
266 StartDate string `xml:"startdate"` // YYYY-MM-DD
267 EndDate string `xml:"enddate"` // YYYY-MM-DD
269 Titles []AnimeTitle `xml:"titles>title"`
270 RelatedAnime []RelatedAnime `xml:"relatedanime>anime"`
271 SimilarAnime []SimilarAnime `xml:"similaranime>anime"`
273 Recommendations []Recommendation `xml:"recommendations>recommendation"`
275 URL string `xml:"url"` // Official URL
277 Creators []Creator `xml:"creators>name"`
279 Description string `xml:"description"`
281 Ratings AnimeRatings `xml:"ratings"`
283 Picture string `xml:"picture"` // Picture basename; combine with AniDBImageBaseURL for full URL
285 Categories []Category `xml:"categories>category"` // Unsorted
286 Resources []Resource `xml:"resources>resource"` // undocumented
287 Tags []Tag `xml:"tags>tag"` // Unsorted
288 Characters Characters `xml:"characters>character"` // Unsorted
289 Episodes Episodes `xml:"episodes>episode"` // Unsorted