]> git.lizzy.rs Git - go-anidb.git/blob - mylistmanip.go
Modernize
[go-anidb.git] / mylistmanip.go
1 package anidb
2
3 import (
4         "github.com/EliasFleckenstein03/go-fscache"
5         "strconv"
6         "time"
7 )
8
9 // These are all pointers because they're not
10 // sent at all if they're nil
11 type MyListSet struct {
12         State    *MyListState
13         Watched  *bool
14         ViewDate *time.Time
15         Source   *string
16         Storage  *string
17         Other    *string
18 }
19
20 func (set *MyListSet) toParamMap() (pm paramMap) {
21         pm = paramMap{}
22         if set == nil {
23                 return
24         }
25
26         if set.State != nil {
27                 pm["state"] = *set.State
28         }
29         if set.Watched != nil {
30                 pm["viewed"] = *set.Watched
31         }
32         if set.ViewDate != nil {
33                 if set.ViewDate.IsZero() {
34                         pm["viewdate"] = 0
35                 } else {
36                         pm["viewdate"] = int(int32(set.ViewDate.Unix()))
37                 }
38         }
39         if set.Source != nil {
40                 pm["source"] = *set.Source
41         }
42         if set.Storage != nil {
43                 pm["storage"] = *set.Storage
44         }
45         if set.Other != nil {
46                 pm["other"] = *set.Other
47         }
48         return
49 }
50
51 func (set *MyListSet) update(uid UID, f *File, lid LID) {
52         if f.LID[uid] != lid {
53                 f.LID[uid] = lid
54                 Cache.Set(f, "fid", f.FID)
55                 Cache.Chtime(f.Cached, "fid", f.FID)
56         }
57
58         mla := uid.MyListAnime(f.AID)
59         if mla == nil {
60                 mla = &MyListAnime{
61                         EpisodesWithState: MyListStateMap{},
62                         EpisodesPerGroup:  GroupEpisodes{},
63                 }
64         }
65         // We only ever add, not remove -- we don't know if other files also satisfy the list
66         eg := mla.EpisodesPerGroup[f.GID]
67         eg.Add(f.EpisodeNumber)
68         mla.EpisodesPerGroup[f.GID] = eg
69
70         newState := MyListStateUnknown
71         if set != nil {
72                 if set.State != nil {
73                         newState = *set.State
74                 }
75
76                 if set.Watched != nil && *set.Watched ||
77                         set.ViewDate != nil && !set.ViewDate.IsZero() {
78                         mla.WatchedEpisodes.Add(f.EpisodeNumber)
79                 }
80         }
81
82         es := mla.EpisodesWithState[newState]
83         es.Add(f.EpisodeNumber)
84         mla.EpisodesWithState[newState] = es
85
86         Cache.Set(mla, "mylist-anime", uid, f.AID)
87         Cache.Chtime(mla.Cached, "mylist-anime", uid, f.AID)
88
89         e := lid.MyListEntry()
90         if set == nil ||
91                 (set.ViewDate == nil && set.Watched == nil && set.State == nil &&
92                         set.Source == nil && set.Storage == nil && set.Other == nil) {
93                 return
94         }
95         if e == nil {
96                 now := time.Now()
97                 e = &MyListEntry{
98                         LID: lid,
99
100                         AID: f.AID,
101                         EID: f.EID,
102                         FID: f.FID,
103                         GID: f.GID,
104
105                         DateAdded: now,
106
107                         // make sure it's expired
108                         Cached: time.Unix(0, 0),
109                 }
110         }
111
112         if set.ViewDate != nil {
113                 e.DateWatched = *set.ViewDate
114         } else if set.Watched != nil {
115                 if *set.Watched {
116                         e.DateWatched = time.Now()
117                 } else {
118                         e.DateWatched = time.Time{}
119                 }
120         }
121         if set.State != nil {
122                 e.MyListState = *set.State
123         }
124         if set.Source != nil {
125                 e.Source = *set.Source
126         }
127         if set.Storage != nil {
128                 e.Storage = *set.Storage
129         }
130         if set.Other != nil {
131                 e.Other = *set.Other
132         }
133         Cache.Set(e, "mylist", lid)
134         Cache.Chtime(e.Cached, "mylist", lid)
135 }
136
137 func (adb *AniDB) MyListAdd(f *File, set *MyListSet) <-chan LID {
138         ch := make(chan LID, 1)
139         if f == nil {
140                 ch <- 0
141                 close(ch)
142                 return ch
143         }
144
145         go func() {
146                 user := <-adb.GetCurrentUser()
147                 if user == nil || user.UID < 1 {
148                         ch <- 0
149                         close(ch)
150                         return
151                 }
152
153                 // for the intent map; doesn't get cached
154                 key := []fscache.CacheKey{"mylist-add", user.UID, f.FID}
155
156                 ic := make(chan notification, 1)
157                 go func() { ch <- (<-ic).(LID); close(ch) }()
158                 if intentMap.Intent(ic, key...) {
159                         return
160                 }
161
162                 pm := set.toParamMap()
163                 pm["fid"] = f.FID
164
165                 reply := <-adb.udp.SendRecv("MYLISTADD", pm)
166
167                 lid := LID(0)
168
169                 switch reply.Code() {
170                 case 310:
171                         e := adb.parseMylistReply(reply)
172                         if e != nil {
173                                 lid = e.LID
174                         }
175                 case 210:
176                         id, _ := strconv.ParseInt(reply.Lines()[1], 10, 64)
177                         lid = LID(id)
178
179                         // the 310 case does this in parseMylistReply
180                         set.update(user.UID, f, lid)
181                 }
182
183                 intentMap.NotifyClose(lid, key...)
184         }()
185
186         return ch
187 }
188
189 func (adb *AniDB) MyListAddByEd2kSize(ed2k string, size int64, set *MyListSet) <-chan LID {
190         ch := make(chan LID, 1)
191         if size < 1 || !validEd2kHash.MatchString(ed2k) {
192                 ch <- 0
193                 close(ch)
194                 return ch
195         }
196
197         go func() {
198                 ch <- <-adb.MyListAdd(<-adb.FileByEd2kSize(ed2k, size), set)
199                 close(ch)
200         }()
201         return ch
202 }
203
204 func (adb *AniDB) MyListEdit(f *File, set *MyListSet) <-chan bool {
205         ch := make(chan bool, 1)
206         if f == nil {
207                 ch <- false
208                 close(ch)
209                 return ch
210         }
211
212         go func() {
213                 user := <-adb.GetCurrentUser()
214                 if user == nil || user.UID < 1 {
215                         ch <- false
216                         close(ch)
217                         return
218                 }
219
220                 // for the intent map; doesn't get cached
221                 key := []fscache.CacheKey{"mylist-edit", user.UID, f.FID}
222
223                 ic := make(chan notification, 1)
224                 go func() { ch <- (<-ic).(bool); close(ch) }()
225                 if intentMap.Intent(ic, key...) {
226                         return
227                 }
228
229                 pm := set.toParamMap()
230                 pm["edit"] = 1
231                 if lid := f.LID[user.UID]; lid > 0 {
232                         pm["lid"] = lid
233                 } else {
234                         pm["fid"] = f.FID
235                 }
236
237                 reply := <-adb.udp.SendRecv("MYLISTADD", pm)
238
239                 switch reply.Code() {
240                 case 311:
241                         intentMap.NotifyClose(true, key...)
242
243                         set.update(user.UID, f, 0)
244                 default:
245                         intentMap.NotifyClose(false, key...)
246                 }
247         }()
248
249         return ch
250 }
251
252 func (adb *AniDB) MyListDel(f *File) <-chan bool {
253         ch := make(chan bool)
254         if f == nil {
255                 ch <- false
256                 close(ch)
257                 return ch
258         }
259
260         go func() {
261                 user := <-adb.GetCurrentUser()
262                 if user == nil || user.UID < 1 {
263                         ch <- false
264                         close(ch)
265                         return
266                 }
267
268                 // for the intent map; doesn't get cached
269                 key := []fscache.CacheKey{"mylist-del", user.UID, f.FID}
270
271                 ic := make(chan notification, 1)
272                 go func() { ch <- (<-ic).(bool); close(ch) }()
273                 if intentMap.Intent(ic, key...) {
274                         return
275                 }
276
277                 pm := paramMap{}
278                 if lid := f.LID[user.UID]; lid > 0 {
279                         pm["lid"] = lid
280                 } else {
281                         pm["fid"] = f.FID
282                 }
283
284                 reply := <-adb.udp.SendRecv("MYLISTDEL", pm)
285
286                 switch reply.Code() {
287                 case 211:
288                         delete(f.LID, user.UID)
289                         Cache.Set(f, "fid", f.FID)
290                         Cache.Chtime(f.Cached, "fid", f.FID)
291
292                         intentMap.NotifyClose(true, key...)
293                 default:
294                         intentMap.NotifyClose(false, key...)
295                 }
296         }()
297
298         return ch
299 }