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("HTTP -- Anime %d (%s) has unknown resource type %d", a.ID, title, r.Type)
72 log.Printf("HTTP -- 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 return http.Get(u.String())
98 // Title with language and type identifier.
100 // Title with Lang = ja, Type = official is the official Kanji title.
102 // Title with Lang = x-jat, Type = main is the romanized version, also known in other APIs as the Primary Title.
103 type AnimeTitle struct {
104 Lang string `xml:"lang,attr"` // Language in ISO-ish format
105 Type string `xml:"type,attr"` // "official", "short", etc
106 Title string `xml:",chardata"`
109 type RelatedAnime struct {
110 ID int `xml:"id,attr"` // AID of the related anime
111 Type string `xml:"type,attr"` // "prequel", "sequel", etc
112 Title string `xml:",chardata"` // Primary title of the related anime
115 type SimilarAnime struct {
116 ID int `xml:"id,attr"` // AID of the similar anime
117 Approval int `xml:"approval,attr"` // How many users have approved of this connection
118 Total int `xml:"total,attr"` // Total of votes in this connection
119 Title string `xml:",chardata"` // Primary title of the recommended anime
122 type Recommendation struct {
123 Type string `xml:"type,attr"` // "Recommended", "Must See", etc
124 ID int `xml:"uid,attr"` // User ID of the recommending user
125 Text string `xml:",chardata"` // Text of the user's recommendation
128 type Creator struct {
129 ID int `xml:"id,attr"` // Creator ID
130 Type string `xml:"type,attr"`
131 Name string `xml:",chardata"` // Always romaji
134 // Separate from regular Rating because the XML structure is different.
135 type AnimeRating struct {
136 Count int `xml:"count,attr"` // Amount of votes/reviews
137 Rating float32 `xml:",chardata"` // Average
140 type AnimeRatings struct {
141 Permanent AnimeRating `xml:"permanent"` // Votes from people who watched everything
142 Temporary AnimeRating `xml:"temporary"` // Votes from people who are still watching it
143 Review AnimeRating `xml:"review"` // Votes from reviews
146 type Category struct {
147 ID int `xml:"id,attr"` // Category ID
148 ParentID int `xml:"parentid,attr"` // ID of the parent category
149 R18 bool `xml:"hentai,attr"` // Whether the category represents porn works or not
150 Weight int `xml:"weight,attr"` // Weight of the category for this anime
152 Name string `xml:"name"` // Category name
153 Description string `xml:"description"` // Category description
156 type ExternalEntity struct {
157 Identifiers []string `xml:"identifier"`
158 URL []string `xml:"url"` // Used for types 5 and 6
161 // Completely undocumented.
162 // Most entries just have one or two numbers as Identifiers.
164 // Empiric documentation:
166 // Type 1 is the ANN id.
168 // Type 2 is the MyAnimeList ID.
170 // Type 3 is the AnimeNfo ID tuple.
172 // Type 4 is the official japanese webpage.
174 // Type 5 is the official english webpage.
176 // Type 6 is the english wikipedia page name.
178 // Type 7 is the japanese wikipedia page name.
180 // Type 8 is the cal.syoboi.jp schedule ID.
182 // Type 9 is the AllCinema ID.
184 // Type 10 is the anison.info ID.
186 // Type 14 is the VNDB ID.
188 // Type 15 is the MaruMegane ID.
189 type Resource struct {
190 Type int `xml:"type,attr"`
191 ExternalEntity []ExternalEntity `xml:"externalentity"`
195 ID int `xml:"id,attr"` // Tag ID
196 Approval int `xml:"approval,attr"` // How many users have approved of the tag
197 Spoiler bool `xml:"localspoiler,attr"` // undocumented
198 GlobalSpoiler bool `xml:"globalspoiler,attr"` // undocumented
199 Updated string `xml:"update,attr"` // YYYY-MM-DD
201 Name string `xml:"name"` // Tag name
202 Count int `xml:"count"` // undocumented
206 ID int `xml:"id,attr"` // Creator ID
207 Name string `xml:",chardata"` // Always romaji
208 Picture string `xml:"picture,attr"` // Picture basename; combine with AniDBImageBaseURL for full URL
211 type Character struct {
212 ID int `xml:"id,attr"` // Character ID
213 Type string `xml:"type,attr"` // "main character in", "secondary cast in", "appears in"
214 Updated string `xml:"update,attr"` // YYYY-MM-DD
216 Rating Rating `xml:"rating"`
217 Name string `xml:"name"` // Always romaji
218 Gender string `xml:"gender"` // "male", "female", "unknown", sometimes blank
219 Description string `xml:"description"`
220 CharacterType string `xml:"charactertype"` // "Character", "Organization", "Vessel", etc
221 Episodes string `xml:"episodes"` // List of episodes where character appears
222 Picture string `xml:"picture"` // Picture basename; combine with AniDBImageBaseURL for full URL
224 Seiyuu *Seiyuu `xml:"seiyuu"` // The voice actor, if present
227 type Characters []Character // Implements sort.Interface; groups by Type and sorts by Name
229 type EpisodeTitle struct {
230 Lang string `xml:"lang,attr"`
231 Title string `xml:",chardata"`
235 Votes int `xml:"votes,attr"`
236 Rating float32 `xml:",chardata"`
240 Type int `xml:"type,attr"` // 1 for regular episodes, 2 for specials, etc
241 EpNo string `xml:",chardata"` // Not necessarily a plain integer; may be prefixed by a single letter indicating the Type
244 type Episode struct {
245 ID int `xml:"id,attr"` // Episode ID
246 Updated string `xml:"update,attr"` // YYYY-MM-DD
248 EpNo EpNo `xml:"epno"`
249 Length int `xml:"length"` // Length in minutes (rounding method undocumented)
250 AirDate string `xml:"airdate"` // YYYY-MM-DD
251 Rating Rating `xml:"rating"`
252 Titles []EpisodeTitle `xml:"title"`
255 type Episodes []Episode // Implements sort.Interface; groups by EpNo.Type, orders by the integer portion of EpNo.EpNo
258 Error string `xml:",chardata"` // API request encountered an error if this is not ""
260 ID int `xml:"id,attr"` // AID of the anime
261 R18 bool `xml:"restricted,attr"` // Whether the anime is considered porn
263 Type string `xml:"type"` // "TV Series", "Movie", "OVA", etc
264 EpisodeCount int `xml:"episodecount"` // Unreliable, has a set value even when the total number is unknown
265 StartDate string `xml:"startdate"` // YYYY-MM-DD
266 EndDate string `xml:"enddate"` // YYYY-MM-DD
268 Titles []AnimeTitle `xml:"titles>title"`
269 RelatedAnime []RelatedAnime `xml:"relatedanime>anime"`
270 SimilarAnime []SimilarAnime `xml:"similaranime>anime"`
272 Recommendations []Recommendation `xml:"recommendations>recommendation"`
274 URL string `xml:"url"` // Official URL
276 Creators []Creator `xml:"creators>name"`
278 Description string `xml:"description"`
280 Ratings AnimeRatings `xml:"ratings"`
282 Picture string `xml:"picture"` // Picture basename; combine with AniDBImageBaseURL for full URL
284 Categories []Category `xml:"categories>category"` // Unsorted
285 Resources []Resource `xml:"resources>resource"` // undocumented
286 Tags []Tag `xml:"tags>tag"` // Unsorted
287 Characters Characters `xml:"characters>character"` // Unsorted
288 Episodes Episodes `xml:"episodes>episode"` // Unsorted