From 08121ae81a5d5be365d9ed76cca14275b6dfa97d Mon Sep 17 00:00:00 2001 From: "Diogo Franco (Kovensky)" Date: Fri, 26 Jul 2013 20:34:09 -0300 Subject: [PATCH] anidb: Implement MYLISTSTATS --- misc.go | 33 +++++++++++++++ misccache.go | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 145 insertions(+) create mode 100644 misc.go create mode 100644 misccache.go diff --git a/misc.go b/misc.go new file mode 100644 index 0000000..895196b --- /dev/null +++ b/misc.go @@ -0,0 +1,33 @@ +package anidb + +import ( + "github.com/Kovensky/go-fscache" + "strconv" + "strings" + "time" +) + +type MyListStats struct { + Anime int + Episodes int + Files int + Filesize int64 + AddedAnime int + AddedEpisodes int + AddedFiles int + AddedGroups int + + Leech float32 // rate of Files to AddedFiles + Glory float32 // meaning undocumented + ViewedPctDatabase float32 + MyListPctDatabase float32 + AnimePctDatabase float32 // Only valid if the titles database is loaded + ViewedPctMyList float32 + ViewedEpisodes int + Votes int + Reviews int + + ViewedTime time.Duration + + Cached time.Time +} diff --git a/misccache.go b/misccache.go new file mode 100644 index 0000000..9583903 --- /dev/null +++ b/misccache.go @@ -0,0 +1,112 @@ +package anidb + +import ( + "github.com/Kovensky/go-fscache" + "strconv" + "strings" + "time" +) + +func (s *MyListStats) setCachedTS(t time.Time) { s.Cached = t } + +func (s *MyListStats) IsStale() bool { + if s == nil || time.Now().Sub(s.Cached) > MyListCacheDuration { + return true + } + return false +} + +var _ cacheable = &MyListStats{} + +func (u *User) Stats() *MyListStats { + if u == nil { + return nil + } + var s MyListStats + if CacheGet(&s, "mylist-stats", u.UID) == nil { + return &s + } + return nil +} + +func (adb *AniDB) MyListStats(user *User) <-chan *MyListStats { + ch := make(chan *MyListStats, 1) + if user == nil || user.UID < 1 { + ch <- nil + close(ch) + return ch + } + + key := []fscache.CacheKey{"mylist-stats", user.UID} + + ic := make(chan notification, 1) + go func() { ch <- (<-ic).(*MyListStats) }() + if intentMap.Intent(ic, key...) { + return ch + } + + stats := user.Stats() + if !stats.IsStale() { + defer intentMap.NotifyClose(stats, key...) + return ch + } + + go func() { + if adb.User() == nil { + r := adb.udp.ReAuth() + if r.Code() >= 500 { + intentMap.NotifyClose(stats, key...) + return + } + } + + if user.UID != adb.User().UID { + intentMap.NotifyClose(stats, key...) + return + } + + reply := <-adb.udp.SendRecv("MYLISTSTATS", nil) + switch reply.Code() { + case 222: + parts := strings.Split(reply.Lines()[1], "|") + ints := make([]int64, len(parts)) + for i := range parts { + ints[i], _ = strconv.ParseInt(parts[i], 10, 64) + } + + stats = &MyListStats{ + Anime: int(ints[0]), + Episodes: int(ints[1]), + Files: int(ints[2]), + Filesize: ints[3] * 1024 * 1024, // it comes in MB + + AddedAnime: int(ints[4]), + AddedEpisodes: int(ints[5]), + AddedFiles: int(ints[6]), + AddedGroups: int(ints[7]), + + Leech: float32(ints[8]) / 100, + Glory: float32(ints[9]) / 100, + + ViewedPctDatabase: float32(ints[10]) / 100, + MyListPctDatabase: float32(ints[11]) / 100, + // ViewedPctMyList: float32(ints[12]) / 100, // we can calculate a more accurate value + ViewedEpisodes: int(ints[13]), + + Votes: int(ints[14]), + Reviews: int(ints[15]), + + ViewedTime: time.Duration(ints[16]) * time.Minute, + } + stats.ViewedPctMyList = float32(stats.ViewedEpisodes) / float32(stats.Episodes) + + if ac := AnimeCount(); ac > 0 { + stats.AnimePctDatabase = float32(stats.Anime) / float32(ac) + } + + CacheSet(stats, key...) + } + intentMap.NotifyClose(stats, key...) + }() + return ch +} -- 2.44.0