]> git.lizzy.rs Git - go-anidb.git/blob - mylistanimecache.go
Modernize
[go-anidb.git] / mylistanimecache.go
1 package anidb
2
3 import (
4         "github.com/EliasFleckenstein03/go-anidb/misc"
5         "github.com/EliasFleckenstein03/go-anidb/udp"
6         "github.com/EliasFleckenstein03/go-fscache"
7         "strings"
8         "time"
9 )
10
11 func (a *MyListAnime) setCachedTS(ts time.Time) {
12         a.Cached = ts
13 }
14
15 func (a *MyListAnime) IsStale() bool {
16         if a == nil {
17                 return true
18         }
19
20         return time.Now().Sub(a.Cached) > MyListCacheDuration
21 }
22
23 var _ cacheable = &MyListAnime{}
24
25 func (uid UID) MyListAnime(aid AID) *MyListAnime {
26         var a MyListAnime
27         if CacheGet(&a, "mylist-anime", uid, aid) == nil {
28                 return &a
29         }
30         return nil
31 }
32
33 func (u *User) MyListAnime(aid AID) *MyListAnime {
34         if u != nil {
35                 return u.UID.MyListAnime(aid)
36         }
37         return nil
38 }
39
40 func (a *Anime) MyList(adb *AniDB) <-chan *MyListAnime {
41         ch := make(chan *MyListAnime, 1)
42
43         if a == nil {
44                 ch <- nil
45                 close(ch)
46                 return ch
47         }
48
49         go func() {
50                 user := <-adb.GetCurrentUser()
51                 if user == nil || user.UID < 1 {
52                         ch <- nil
53                         close(ch)
54                         return
55                 }
56
57                 ch <- <-adb.MyListAnime(a.AID)
58                 close(ch)
59         }()
60         return ch
61 }
62
63 func (adb *AniDB) MyListAnime(aid AID) <-chan *MyListAnime {
64         ch := make(chan *MyListAnime, 1)
65
66         if aid < 1 {
67                 ch <- nil
68                 close(ch)
69                 return ch
70         }
71
72         go func() {
73                 user := <-adb.GetCurrentUser()
74                 if user == nil || user.UID < 1 {
75                         ch <- nil
76                         close(ch)
77                         return
78                 }
79                 key := []fscache.CacheKey{"mylist-anime", user.UID, aid}
80
81                 ic := make(chan notification, 2)
82                 go func() { ch <- (<-ic).(*MyListAnime); close(ch) }()
83                 if intentMap.Intent(ic, key...) {
84                         return
85                 }
86
87                 if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
88                         intentMap.NotifyClose((*MyListAnime)(nil), key...)
89                         return
90                 }
91
92                 entry := user.UID.MyListAnime(aid)
93                 if !entry.IsStale() {
94                         intentMap.NotifyClose(entry, key...)
95                         return
96                 }
97
98                 reply := <-adb.udp.SendRecv("MYLIST", paramMap{"aid": aid})
99
100                 switch reply.Code() {
101                 case 221:
102                         r := adb.parseMylistReply(reply) // caches
103
104                         // we have only a single file added for this anime -- construct a fake 312 struct
105                         entry = &MyListAnime{AID: aid}
106
107                         ep := <-adb.EpisodeByID(r.EID)
108                         list := misc.EpisodeToList(&ep.Episode)
109
110                         entry.EpisodesWithState = MyListStateMap{
111                                 r.MyListState: list,
112                         }
113
114                         if !r.DateWatched.IsZero() {
115                                 entry.WatchedEpisodes = list
116                         }
117
118                         entry.EpisodesPerGroup = GroupEpisodes{
119                                 r.GID: list,
120                         }
121                 case 312:
122                         entry = adb.parseMylistAnime(reply)
123                         entry.AID = aid
124                 case 321:
125                         Cache.SetInvalid(key...)
126                 }
127
128                 CacheSet(entry, key...)
129                 intentMap.NotifyClose(entry, key...)
130         }()
131         return ch
132 }
133
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)
137
138         if uid < 1 || aid < 1 {
139                 ch <- nil
140                 close(ch)
141                 return ch
142         }
143
144         ic := make(chan notification, 1)
145         go func() { ch <- (<-ic).(*MyListAnime); close(ch) }()
146         if intentMap.Intent(ic, key...) {
147                 return ch
148         }
149
150         if !Cache.IsValid(InvalidKeyCacheDuration, key...) {
151                 intentMap.NotifyClose((*MyListAnime)(nil), key...)
152                 return ch
153         }
154
155         entry := uid.MyListAnime(aid)
156         if !entry.IsStale() {
157                 intentMap.NotifyClose(entry, key...)
158                 return ch
159         }
160
161         go func() {
162                 user := <-adb.GetCurrentUser()
163
164                 if user.UID != uid { // we can't query other users' lists from API
165                         intentMap.NotifyClose(entry, key...)
166                         return
167                 }
168
169                 intentMap.NotifyClose(<-adb.MyListAnime(aid), key...)
170         }()
171         return ch
172 }
173
174 func (adb *AniDB) parseMylistAnime(reply udpapi.APIReply) *MyListAnime {
175         if reply.Code() != 312 {
176                 return nil
177         }
178
179         parts := strings.Split(reply.Lines()[1], "|")
180
181         // Everything from index 7 on is pairs of group name on odd positions and episode list on even
182         var groupParts []string
183         if len(parts) > 7 {
184                 groupParts = parts[7:]
185         }
186
187         groupMap := make(GroupEpisodes, len(groupParts)/2)
188
189         for i := 0; i+1 < len(groupParts); i += 2 {
190                 g := <-adb.GroupByName(groupParts[i])
191                 if g == nil {
192                         continue
193                 }
194
195                 groupMap[g.GID] = misc.ParseEpisodeList(groupParts[i+1])
196         }
197
198         return &MyListAnime{
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]),
204                 },
205
206                 WatchedEpisodes: misc.ParseEpisodeList(parts[6]),
207
208                 EpisodesPerGroup: groupMap,
209         }
210 }