5 "github.com/Kovensky/go-anidb/http"
6 "github.com/Kovensky/go-anidb/udp"
13 gob.RegisterName("*github.com/Kovensky/go-anidb.Group", &Group{})
14 gob.RegisterName("github.com/Kovensky/go-anidb.GID", GID(0))
15 gob.RegisterName("*github.com/Kovensky/go-anidb.gidCache", &gidCache{})
18 func (g *Group) Touch() {
22 func (g *Group) IsStale() bool {
26 return time.Now().Sub(g.Cached) > GroupCacheDuration
29 // Unique Group IDentifier
34 func (e GID) Touch() {}
35 func (e GID) IsStale() bool { return false }
37 // Retrieves the Group from the cache.
38 func (gid GID) Group() *Group {
40 if cache.Get(&g, "gid", gid) == nil {
46 type gidCache struct {
51 func (c *gidCache) Touch() { c.Time = time.Now() }
52 func (c *gidCache) IsStale() bool {
53 if c != nil && time.Now().Sub(c.Time) < GroupCacheDuration {
59 // Retrieves a Group by its GID. Uses the UDP API.
60 func (adb *AniDB) GroupByID(gid GID) <-chan *Group {
61 keys := []cacheKey{"gid", gid}
62 ch := make(chan *Group, 1)
70 ic := make(chan Cacheable, 1)
71 go func() { ch <- (<-ic).(*Group); close(ch) }()
72 if intentMap.Intent(ic, keys...) {
76 if !cache.CheckValid(keys...) {
77 intentMap.NotifyClose((*Group)(nil), keys...)
83 intentMap.NotifyClose(g, keys...)
88 reply := <-adb.udp.SendRecv("GROUP",
91 if reply.Error() == nil {
92 g = parseGroupReply(reply)
94 cache.Set(&gidCache{GID: g.GID}, "gid", "by-name", g.Name)
95 cache.Set(&gidCache{GID: g.GID}, "gid", "by-shortname", g.ShortName)
97 } else if reply.Code() == 350 {
98 cache.MarkInvalid(keys...)
99 cache.Delete(keys...) // deleted group?
102 intentMap.NotifyClose(g, keys...)
107 // Retrieves a Group by its name. Either full or short names are matched.
109 func (adb *AniDB) GroupByName(gname string) <-chan *Group {
110 keys := []cacheKey{"gid", "by-name", gname}
111 altKeys := []cacheKey{"gid", "by-shortname", gname}
112 ch := make(chan *Group, 1)
120 ic := make(chan Cacheable, 1)
124 ch <- <-adb.GroupByID(gid)
128 if intentMap.Intent(ic, keys...) {
132 if !cache.CheckValid(keys...) {
133 intentMap.NotifyClose(GID(0), keys...)
140 if cache.Get(&gc, keys...) == nil && !gc.IsStale() {
141 intentMap.NotifyClose(gc.GID, keys...)
147 if cache.Get(&gc, altKeys...) == nil && !gc.IsStale() {
148 intentMap.NotifyClose(gc.GID, keys...)
155 reply := <-adb.udp.SendRecv("GROUP",
156 paramMap{"gname": gname})
159 if reply.Error() == nil {
160 g = parseGroupReply(reply)
164 cache.Set(&gidCache{GID: gid}, keys...)
165 cache.Set(&gidCache{GID: gid}, altKeys...)
166 cache.Set(g, "gid", gid)
167 } else if reply.Code() == 350 {
168 cache.MarkInvalid(keys...)
169 cache.Delete(keys...) // renamed group?
170 cache.Delete(altKeys...)
173 intentMap.NotifyClose(gid, keys...)
178 func parseGroupReply(reply udpapi.APIReply) *Group {
179 parts := strings.Split(reply.Lines()[1], "|")
180 ints := make([]int64, len(parts))
181 for i := range parts {
182 ints[i], _ = strconv.ParseInt(parts[i], 10, 32)
187 irc = "irc://" + parts[8] + "/" + parts[7][1:]
192 pic = httpapi.AniDBImageBaseURL + parts[10]
195 rellist := strings.Split(parts[16], "'")
196 relations := make(map[GID]GroupRelationType, len(rellist))
197 for _, rel := range rellist {
198 r := strings.Split(rel, ",")
202 gid, _ := strconv.ParseInt(r[0], 10, 32)
203 typ, _ := strconv.ParseInt(r[1], 10, 32)
205 relations[GID(gid)] = GroupRelationType(typ)
208 ft := time.Unix(ints[11], 0)
212 dt := time.Unix(ints[12], 0)
216 lr := time.Unix(ints[14], 0)
220 la := time.Unix(ints[15], 0)
242 Rating: float32(ints[1]) / 100,
243 VoteCount: int(ints[2]),
245 AnimeCount: int(ints[3]),
246 FileCount: int(ints[4]),
248 RelatedGroups: relations,