}
// Retrieves an Episode by its EID.
+//
+// If we know which AID owns this EID, then it's equivalent
+// to an Anime query. Otherwise, uses both the HTTP and UDP
+// APIs to retrieve it.
func (adb *AniDB) EpisodeByID(eid EID) <-chan *Episode {
keys := []cacheKey{"eid", eid}
ch := make(chan *Episode, 1)
+ if eid < 1 {
+ ch <- nil
+ close(ch)
+ return ch
+ }
+
ic := make(chan Cacheable, 1)
go func() { ch <- (<-ic).(*Episode); close(ch) }()
if intentMap.Intent(ic, keys...) {
}
if !cache.CheckValid(keys...) {
- intentMap.Notify((*Episode)(nil), keys...)
+ intentMap.NotifyClose((*Episode)(nil), keys...)
return ch
}
- if e := eid.Episode(); !e.IsStale() {
- intentMap.Notify(e, keys...)
+ e := eid.Episode()
+ if !e.IsStale() {
+ intentMap.NotifyClose(e, keys...)
return ch
}
udpDone := false
- var e *Episode
for i := 0; i < 2; i++ {
if !ok && udpDone {
// couldn't get anime and we already ran the EPISODE query
if id, err := strconv.ParseInt(parts[1], 10, 32); err == nil {
ok = true
aid = AID(id)
+ } else {
+ break
}
} else if reply.Code() == 340 {
cache.MarkInvalid(keys...)
+ cache.Delete(keys...) // deleted EID?
+ break
} else {
break
}
udpDone = true
}
- <-adb.AnimeByID(AID(aid)) // this caches episodes...
- e = eid.Episode() // ...so this is now a cache hit
+ a := <-adb.AnimeByID(AID(aid)) // updates the episode cache as well
+ ep := a.EpisodeByEID(eid)
- if e != nil {
+ if ep != nil {
+ e = ep
break
} else {
- // if this is somehow still a miss, then the EID<->AID map broke
- cache.Delete("aid", "by-eid", eid)
+ // the EID<->AID map broke
ok = false
+ cache.Delete("aid", "by-eid", eid)
}
}
- intentMap.Notify(e, keys...)
+ intentMap.NotifyClose(e, keys...)
}()
return ch
}