4 "github.com/EliasFleckenstein03/go-anidb/misc"
5 "github.com/EliasFleckenstein03/go-anidb/udp"
6 "github.com/EliasFleckenstein03/go-fscache"
11 func (a *MyListAnime) setCachedTS(ts time.Time) {
15 func (a *MyListAnime) IsStale() bool {
20 return time.Now().Sub(a.Cached) > MyListCacheDuration
23 var _ cacheable = &MyListAnime{}
25 func (uid UID) MyListAnime(aid AID) *MyListAnime {
27 if CacheGet(&a, "mylist-anime", uid, aid) == nil {
33 func (u *User) MyListAnime(aid AID) *MyListAnime {
35 return u.UID.MyListAnime(aid)
40 func (a *Anime) MyList(adb *AniDB) <-chan *MyListAnime {
41 ch := make(chan *MyListAnime, 1)
50 user := <-adb.GetCurrentUser()
51 if user == nil || user.UID < 1 {
57 ch <- <-adb.MyListAnime(a.AID)
63 func (adb *AniDB) MyListAnime(aid AID) <-chan *MyListAnime {
64 ch := make(chan *MyListAnime, 1)
73 user := <-adb.GetCurrentUser()
74 if user == nil || user.UID < 1 {
79 key := []fscache.CacheKey{"mylist-anime", user.UID, aid}
81 ic := make(chan notification, 2)
82 go func() { ch <- (<-ic).(*MyListAnime); close(ch) }()
83 if intentMap.Intent(ic, key...) {
87 if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
88 intentMap.NotifyClose((*MyListAnime)(nil), key...)
92 entry := user.UID.MyListAnime(aid)
94 intentMap.NotifyClose(entry, key...)
98 reply := <-adb.udp.SendRecv("MYLIST", paramMap{"aid": aid})
100 switch reply.Code() {
102 r := adb.parseMylistReply(reply) // caches
104 // we have only a single file added for this anime -- construct a fake 312 struct
105 entry = &MyListAnime{AID: aid}
107 ep := <-adb.EpisodeByID(r.EID)
108 list := misc.EpisodeToList(&ep.Episode)
110 entry.EpisodesWithState = MyListStateMap{
114 if !r.DateWatched.IsZero() {
115 entry.WatchedEpisodes = list
118 entry.EpisodesPerGroup = GroupEpisodes{
122 entry = adb.parseMylistAnime(reply)
125 Cache.SetInvalid(key...)
128 CacheSet(entry, key...)
129 intentMap.NotifyClose(entry, key...)
134 func (adb *AniDB) UserMyListAnime(uid UID, aid AID) <-chan *MyListAnime {
135 key := []fscache.CacheKey{"mylist-anime", uid, aid}
136 ch := make(chan *MyListAnime, 1)
138 if uid < 1 || aid < 1 {
144 ic := make(chan notification, 1)
145 go func() { ch <- (<-ic).(*MyListAnime); close(ch) }()
146 if intentMap.Intent(ic, key...) {
150 if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
151 intentMap.NotifyClose((*MyListAnime)(nil), key...)
155 entry := uid.MyListAnime(aid)
156 if !entry.IsStale() {
157 intentMap.NotifyClose(entry, key...)
162 user := <-adb.GetCurrentUser()
164 if user.UID != uid { // we can't query other users' lists from API
165 intentMap.NotifyClose(entry, key...)
169 intentMap.NotifyClose(<-adb.MyListAnime(aid), key...)
174 func (adb *AniDB) parseMylistAnime(reply udpapi.APIReply) *MyListAnime {
175 if reply.Code() != 312 {
179 parts := strings.Split(reply.Lines()[1], "|")
181 // Everything from index 7 on is pairs of group name on odd positions and episode list on even
182 var groupParts []string
184 groupParts = parts[7:]
187 groupMap := make(GroupEpisodes, len(groupParts)/2)
189 for i := 0; i+1 < len(groupParts); i += 2 {
190 g := <-adb.GroupByName(groupParts[i])
195 groupMap[g.GID] = misc.ParseEpisodeList(groupParts[i+1])
199 EpisodesWithState: MyListStateMap{
200 MyListStateUnknown: misc.ParseEpisodeList(parts[2]),
201 MyListStateHDD: misc.ParseEpisodeList(parts[3]),
202 MyListStateCD: misc.ParseEpisodeList(parts[4]),
203 MyListStateDeleted: misc.ParseEpisodeList(parts[5]),
206 WatchedEpisodes: misc.ParseEpisodeList(parts[6]),
208 EpisodesPerGroup: groupMap,