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 LainGrJpFormat = "http://lain.gr.jp/%v" // Type 11
39 VNDBFormat = "http://vndb.org/v%v" // Type 14
40 MaruMeganeFormat = "http://www.anime.marumegane.com/%v.html" // Type 15
42 TVAnimationMuseum = "http://home-aki.cool.ne.jp/anime-list/%s.htm" // Type 17 (broken)
44 WikiKoreanformat = "http://ko.wikipedia.org/wiki/%v" // Type 19
45 WikiChineseFormat = "http://zh.wikipedia.org/wiki/%v" // Type 20
49 aniDBHTTPAPIBaseURL = "http://api.anidb.net:9001/httpapi"
51 clientStr = "goanidbhttp"
55 // Requests information about the given Anime ID.
56 func GetAnime(AID int) (a Anime, err error) {
57 if res, err := doRequest("anime", reqMap{"aid": AID}); err != nil {
60 dec := xml.NewDecoder(res.Body)
64 a.Error = strings.TrimSpace(a.Error)
67 for _, t := range a.Titles {
74 for _, r := range a.Resources {
76 case 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 14, 15, 17, 19, 20:
77 // documentation knows about these
79 log.Printf("HTTP -- Anime %d (%s) has unknown resource type %d", a.ID, title, r.Type)
80 log.Printf("HTTP -- Type %d external entities: %#v", r.Type, r.ExternalEntity)
88 type reqMap map[string]interface{}
90 func doRequest(request string, reqMap reqMap) (*http.Response, error) {
92 v.Set("protover", fmt.Sprint(aniDBProtoVer))
93 v.Set("client", clientStr)
94 v.Set("clientver", fmt.Sprint(clientVer))
95 v.Set("request", request)
97 for k, val := range reqMap {
98 v.Add(k, fmt.Sprint(val))
101 u, _ := url.Parse(aniDBHTTPAPIBaseURL)
102 u.RawQuery = v.Encode()
103 return http.Get(u.String())
106 // Title with language and type identifier.
108 // Title with Lang = ja, Type = official is the official Kanji title.
110 // Title with Lang = x-jat, Type = main is the romanized version, also known in other APIs as the Primary Title.
111 type AnimeTitle struct {
112 Lang string `xml:"lang,attr"` // Language in ISO-ish format
113 Type string `xml:"type,attr"` // "official", "short", etc
114 Title string `xml:",chardata"`
117 type RelatedAnime struct {
118 ID int `xml:"id,attr"` // AID of the related anime
119 Type string `xml:"type,attr"` // "prequel", "sequel", etc
120 Title string `xml:",chardata"` // Primary title of the related anime
123 type SimilarAnime struct {
124 ID int `xml:"id,attr"` // AID of the similar anime
125 Approval int `xml:"approval,attr"` // How many users have approved of this connection
126 Total int `xml:"total,attr"` // Total of votes in this connection
127 Title string `xml:",chardata"` // Primary title of the recommended anime
130 type Recommendation struct {
131 Type string `xml:"type,attr"` // "Recommended", "Must See", etc
132 ID int `xml:"uid,attr"` // User ID of the recommending user
133 Text string `xml:",chardata"` // Text of the user's recommendation
136 type Creator struct {
137 ID int `xml:"id,attr"` // Creator ID
138 Type string `xml:"type,attr"`
139 Name string `xml:",chardata"` // Always romaji
142 // Separate from regular Rating because the XML structure is different.
143 type AnimeRating struct {
144 Count int `xml:"count,attr"` // Amount of votes/reviews
145 Rating float32 `xml:",chardata"` // Average
148 type AnimeRatings struct {
149 Permanent AnimeRating `xml:"permanent"` // Votes from people who watched everything
150 Temporary AnimeRating `xml:"temporary"` // Votes from people who are still watching it
151 Review AnimeRating `xml:"review"` // Votes from reviews
154 type Category struct {
155 ID int `xml:"id,attr"` // Category ID
156 ParentID int `xml:"parentid,attr"` // ID of the parent category
157 R18 bool `xml:"hentai,attr"` // Whether the category represents porn works or not
158 Weight int `xml:"weight,attr"` // Weight of the category for this anime
160 Name string `xml:"name"` // Category name
161 Description string `xml:"description"` // Category description
164 type ExternalEntity struct {
165 Identifiers []string `xml:"identifier"`
166 URL []string `xml:"url"` // Used for some types
169 // Completely undocumented.
170 // Most entries just have one or two numbers as Identifiers.
172 // Empiric documentation:
174 // Type 1 is the ANN id.
176 // Type 2 is the MyAnimeList ID.
178 // Type 3 is the AnimeNfo ID tuple.
180 // Type 4 is the official japanese webpage. URL may contain additional URLs (official PV, etc)
182 // Type 5 is the official english webpage.
184 // Type 6 is the english wikipedia page name.
186 // Type 7 is the japanese wikipedia page name.
188 // Type 8 is the cal.syoboi.jp schedule ID.
190 // Type 9 is the AllCinema ID.
192 // Type 10 is the anison.info ID.
194 // Type 11 is the lain.gr.jp path.
196 // Type 14 is the VNDB ID.
198 // Type 15 is the MaruMegane ID.
200 // Type 17 would be the TV Animation Museum identifier, but the website is no more.
202 // Type 19 is the korean wikipedia page name.
204 // Type 20 is the chinese wikipedia page name.
205 type Resource struct {
206 Type int `xml:"type,attr"`
207 ExternalEntity []ExternalEntity `xml:"externalentity"`
211 ID int `xml:"id,attr"` // Tag ID
212 Approval int `xml:"approval,attr"` // How many users have approved of the tag
213 Spoiler bool `xml:"localspoiler,attr"` // undocumented
214 GlobalSpoiler bool `xml:"globalspoiler,attr"` // undocumented
215 Updated string `xml:"update,attr"` // YYYY-MM-DD
217 Name string `xml:"name"` // Tag name
218 Count int `xml:"count"` // undocumented
222 ID int `xml:"id,attr"` // Creator ID
223 Name string `xml:",chardata"` // Always romaji
224 Picture string `xml:"picture,attr"` // Picture basename; combine with AniDBImageBaseURL for full URL
227 type Character struct {
228 ID int `xml:"id,attr"` // Character ID
229 Type string `xml:"type,attr"` // "main character in", "secondary cast in", "appears in"
230 Updated string `xml:"update,attr"` // YYYY-MM-DD
232 Rating Rating `xml:"rating"`
233 Name string `xml:"name"` // Always romaji
234 Gender string `xml:"gender"` // "male", "female", "unknown", sometimes blank
235 Description string `xml:"description"`
236 CharacterType string `xml:"charactertype"` // "Character", "Organization", "Vessel", etc
237 Episodes string `xml:"episodes"` // List of episodes where character appears
238 Picture string `xml:"picture"` // Picture basename; combine with AniDBImageBaseURL for full URL
240 Seiyuu *Seiyuu `xml:"seiyuu"` // The voice actor, if present
243 type Characters []Character // Implements sort.Interface; groups by Type and sorts by Name
245 type EpisodeTitle struct {
246 Lang string `xml:"lang,attr"`
247 Title string `xml:",chardata"`
251 Votes int `xml:"votes,attr"`
252 Rating float32 `xml:",chardata"`
256 Type int `xml:"type,attr"` // 1 for regular episodes, 2 for specials, etc
257 EpNo string `xml:",chardata"` // Not necessarily a plain integer; may be prefixed by a single letter indicating the Type
260 type Episode struct {
261 ID int `xml:"id,attr"` // Episode ID
262 Updated string `xml:"update,attr"` // YYYY-MM-DD
264 EpNo EpNo `xml:"epno"`
265 Length int `xml:"length"` // Length in minutes (rounding method undocumented)
266 AirDate string `xml:"airdate"` // YYYY-MM-DD
267 Rating Rating `xml:"rating"`
268 Titles []EpisodeTitle `xml:"title"`
271 type Episodes []Episode // Implements sort.Interface; groups by EpNo.Type, orders by the integer portion of EpNo.EpNo
274 Error string `xml:",chardata"` // API request encountered an error if this is not ""
276 ID int `xml:"id,attr"` // AID of the anime
277 R18 bool `xml:"restricted,attr"` // Whether the anime is considered porn
279 Type string `xml:"type"` // "TV Series", "Movie", "OVA", etc
280 EpisodeCount int `xml:"episodecount"` // Unreliable, has a set value even when the total number is unknown
281 StartDate string `xml:"startdate"` // YYYY-MM-DD
282 EndDate string `xml:"enddate"` // YYYY-MM-DD
284 Titles []AnimeTitle `xml:"titles>title"`
285 RelatedAnime []RelatedAnime `xml:"relatedanime>anime"`
286 SimilarAnime []SimilarAnime `xml:"similaranime>anime"`
288 Recommendations []Recommendation `xml:"recommendations>recommendation"`
290 URL string `xml:"url"` // Official URL
292 Creators []Creator `xml:"creators>name"`
294 Description string `xml:"description"`
296 Ratings AnimeRatings `xml:"ratings"`
298 Picture string `xml:"picture"` // Picture basename; combine with AniDBImageBaseURL for full URL
300 Categories []Category `xml:"categories>category"` // Unsorted
301 Resources []Resource `xml:"resources>resource"` // undocumented
302 Tags []Tag `xml:"tags>tag"` // Unsorted
303 Characters Characters `xml:"characters>character"` // Unsorted
304 Episodes Episodes `xml:"episodes>episode"` // Unsorted