]> git.lizzy.rs Git - go-anidb.git/blob - mylistmanip.go
anidb: Implement MyListAdd / MyListEdit / MyListDel
[go-anidb.git] / mylistmanip.go
1 package anidb
2
3 import (
4         "github.com/Kovensky/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         if set.State != nil {
71                 es := mla.EpisodesWithState[*set.State]
72                 es.Add(f.EpisodeNumber)
73                 mla.EpisodesWithState[*set.State] = es
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         Cache.Set(mla, "mylist-anime", uid, f.AID)
82         Cache.Chtime(mla.Cached, "mylist-anime", uid, f.AID)
83
84         if set.ViewDate == nil && set.Watched == nil && set.State == nil &&
85                 set.Source == nil && set.Storage == nil && set.Other == nil {
86                 return
87         }
88
89         e := lid.MyListEntry()
90         if set.ViewDate != nil {
91                 e.DateWatched = *set.ViewDate
92         } else if set.Watched != nil {
93                 if *set.Watched {
94                         e.DateWatched = time.Now()
95                 } else {
96                         e.DateWatched = time.Time{}
97                 }
98         }
99         if set.State != nil {
100                 e.MyListState = *set.State
101         }
102         if set.Source != nil {
103                 e.Source = *set.Source
104         }
105         if set.Storage != nil {
106                 e.Storage = *set.Storage
107         }
108         if set.Other != nil {
109                 e.Other = *set.Other
110         }
111         Cache.Set(e, "mylist", lid)
112         Cache.Chtime(e.Cached, "mylist", lid)
113 }
114
115 func (adb *AniDB) MyListAdd(f *File, set *MyListSet) <-chan LID {
116         ch := make(chan LID, 1)
117         if f == nil {
118                 ch <- 0
119                 close(ch)
120                 return ch
121         }
122
123         go func() {
124                 user := <-adb.GetCurrentUser()
125                 if user == nil || user.UID < 1 {
126                         ch <- 0
127                         close(ch)
128                         return
129                 }
130
131                 // for the intent map; doesn't get cached
132                 key := []fscache.CacheKey{"mylist-add", user.UID, f.FID}
133
134                 ic := make(chan notification, 1)
135                 go func() { ch <- (<-ic).(LID); close(ch) }()
136                 if intentMap.Intent(ic, key...) {
137                         return
138                 }
139
140                 pm := set.toParamMap()
141                 pm["fid"] = f.FID
142
143                 reply := <-adb.udp.SendRecv("MYLISTADD", pm)
144
145                 lid := LID(0)
146
147                 switch reply.Code() {
148                 case 310:
149                         e := adb.parseMylistReply(reply)
150                         if e != nil {
151                                 lid = e.LID
152                         }
153                 case 210:
154                         id, _ := strconv.ParseInt(reply.Lines()[1], 10, 64)
155                         lid = LID(id)
156
157                         // the 310 case does this in parseMylistReply
158                         set.update(user.UID, f, lid)
159                 }
160
161                 intentMap.NotifyClose(lid, key...)
162         }()
163
164         return ch
165 }
166
167 func (adb *AniDB) MyListAddByEd2kSize(ed2k string, size int64, set *MyListSet) <-chan LID {
168         ch := make(chan LID, 1)
169         if size < 1 || !validEd2kHash.MatchString(ed2k) {
170                 ch <- 0
171                 close(ch)
172                 return ch
173         }
174
175         go func() {
176                 ch <- <-adb.MyListAdd(<-adb.FileByEd2kSize(ed2k, size), set)
177                 close(ch)
178         }()
179         return ch
180 }
181
182 func (adb *AniDB) MyListEdit(f *File, set *MyListSet) <-chan bool {
183         ch := make(chan bool, 1)
184         if f == nil {
185                 ch <- false
186                 close(ch)
187                 return ch
188         }
189
190         go func() {
191                 user := <-adb.GetCurrentUser()
192                 if user == nil || user.UID < 1 {
193                         ch <- false
194                         close(ch)
195                         return
196                 }
197
198                 // for the intent map; doesn't get cached
199                 key := []fscache.CacheKey{"mylist-edit", user.UID, f.FID}
200
201                 ic := make(chan notification, 1)
202                 go func() { ch <- (<-ic).(bool); close(ch) }()
203                 if intentMap.Intent(ic, key...) {
204                         return
205                 }
206
207                 pm := set.toParamMap()
208                 pm["edit"] = 1
209                 if lid := f.LID[user.UID]; lid > 0 {
210                         pm["lid"] = lid
211                 } else {
212                         pm["fid"] = f.FID
213                 }
214
215                 reply := <-adb.udp.SendRecv("MYLISTADD", pm)
216
217                 switch reply.Code() {
218                 case 311:
219                         intentMap.NotifyClose(true, key...)
220
221                         set.update(user.UID, f, 0)
222                 default:
223                         intentMap.NotifyClose(false, key...)
224                 }
225         }()
226
227         return ch
228 }
229
230 func (adb *AniDB) MyListDel(f *File) <-chan bool {
231         ch := make(chan bool)
232         if f == nil {
233                 ch <- false
234                 close(ch)
235                 return ch
236         }
237
238         go func() {
239                 user := <-adb.GetCurrentUser()
240                 if user == nil || user.UID < 1 {
241                         ch <- false
242                         close(ch)
243                         return
244                 }
245
246                 // for the intent map; doesn't get cached
247                 key := []fscache.CacheKey{"mylist-del", user.UID, f.FID}
248
249                 ic := make(chan notification, 1)
250                 go func() { ch <- (<-ic).(bool); close(ch) }()
251                 if intentMap.Intent(ic, key...) {
252                         return
253                 }
254
255                 pm := paramMap{}
256                 if lid := f.LID[user.UID]; lid > 0 {
257                         pm["lid"] = lid
258                 } else {
259                         pm["fid"] = f.FID
260                 }
261
262                 reply := <-adb.udp.SendRecv("MYLISTDEL", pm)
263
264                 switch reply.Code() {
265                 case 211:
266                         delete(f.LID, user.UID)
267                         Cache.Set(f, "fid", f.FID)
268                         Cache.Chtime(f.Cached, "fid", f.FID)
269
270                         intentMap.NotifyClose(true, key...)
271                 default:
272                         intentMap.NotifyClose(false, key...)
273                 }
274         }()
275
276         return ch
277 }