From 994bccb068ea3422d8cc27286a9a32aa4c5caf90 Mon Sep 17 00:00:00 2001 From: daru Date: Mon, 18 Apr 2022 02:53:09 +0200 Subject: [PATCH] MAL progress fetch --- huso.go | 9 ++++++--- klotz.go | 16 ++++++++++++---- knecht.go | 16 ++++++++-------- nuss.go | 35 ++++++++++++++++++++++++++++++++++- ober.go | 4 +++- praktikant.go | 28 +++++++++++++++++++++++++++- schaffer.go | 35 +++++++++++++++++++++++++++++++++++ 7 files changed, 125 insertions(+), 18 deletions(-) diff --git a/huso.go b/huso.go index 30321f1..e95bdb5 100644 --- a/huso.go +++ b/huso.go @@ -42,6 +42,7 @@ var ( seasoncache *bigcache.BigCache userCache *bigcache.BigCache searchCache *bigcache.BigCache + animeListCache *bigcache.BigCache db *nutsdb.DB ) @@ -76,6 +77,11 @@ func main() { log.Fatal(err) } defer searchCache.Close() + animeListCache, err = bigcache.NewBigCache(bigcache.DefaultConfig(42 * time.Minute)) + if err != nil { + log.Fatal(err) + } + defer animeListCache.Close() nutsOpt := nutsdb.DefaultOptions nutsOpt.Dir = "nuts" @@ -93,8 +99,5 @@ func main() { go RunWebserv() - //list, _, _ := GetUserAnimeListData("ultrasn0w", malApiStatusW) - //fmt.Printf("%+v\n", list) - <-sc } diff --git a/klotz.go b/klotz.go index 9932991..5a8e8f6 100644 --- a/klotz.go +++ b/klotz.go @@ -53,9 +53,10 @@ type AnimeStudio struct { } type WatchUser struct { - Username string `json:"username"` - MalID int64 `json:"malId"` - Progress int `json:"progress"` + Username string `json:"username"` + MalID int64 `json:"malId"` + Progress int `json:"progress"` + Updated time.Time `json:"updated"` } type UserData struct { @@ -130,7 +131,14 @@ type AnimeDetailMal struct { type AnimeListMal struct { Data []struct { - Node AnimeDetailMal `json:"node"` + Node AnimeDetailMal `json:"node"` + ListStatus struct { + Status string `json:"status"` + Score int `json:"score"` + NumEpisodesWatched int `json:"num_episodes_watched"` + IsRewatching bool `json:"is_rewatching"` + UpdatedAt time.Time `json:"updated_at"` + } `json:"list_status"` } `json:"data"` Paging struct { Next string `json:"next"` diff --git a/knecht.go b/knecht.go index 79b88da..60944de 100644 --- a/knecht.go +++ b/knecht.go @@ -72,16 +72,16 @@ func GetAnimeDetailData(animeId int64) (*Anime, []byte, error) { func GetUserAnimeListData(username, status string) (*AnimeListMal, []byte, error) { var list AnimeListMal - body, err := GetUserAnimeListBytes(username, status) + data, err := animeListCache.Get(username + status) if err != nil { - return nil, body, err + data, err = GetDataMal(userApiMal + username + "/animelist?limit=1000&status=" + status + "&fields=list_status") + if err != nil { + return nil, nil, err + } + animeListCache.Set(username+status, data) } - err = json.Unmarshal(body, &list) - return &list, body, err -} - -func GetUserAnimeListBytes(username, status string) ([]byte, error) { - return GetDataMal(userApiMal + username + "/animelist?limit=1000&status=" + status) + err = json.Unmarshal(data, &list) + return &list, data, err } func GetUserData(username string) (*User, []byte, error) { diff --git a/nuss.go b/nuss.go index 4910a35..77304d7 100644 --- a/nuss.go +++ b/nuss.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "time" "github.com/xujiajun/nutsdb" ) @@ -30,7 +31,7 @@ func SaveUser(user *UserData) error { return err } -func AddUserToAnime(username string, userId, animeId int64) (*AnimeUser, error) { +func AddUserToAnime(username string, userId, animeId int64, progress int, updated time.Time) (*AnimeUser, error) { var anime AnimeUser err := db.Update( func(tx *nutsdb.Tx) error { @@ -62,6 +63,8 @@ func AddUserToAnime(username string, userId, animeId int64) (*AnimeUser, error) users = append(users, WatchUser{ Username: username, MalID: userId, + Progress: progress, + Updated: updated, }) anime = AnimeUser{ Anime: animeId, @@ -164,6 +167,36 @@ func DeleteUserFromAnimes(userId int64) error { }) } +func UpdateUserAnimeProgress(animeId, userId int64, progress int, updated time.Time) error { + return db.Update( + func(tx *nutsdb.Tx) error { + keyBytes := Int64ToByte(animeId) + e, err := tx.Get(bucketAnime, keyBytes) + if err != nil { + return err + } + // parse user list + users, err := parseWatchUserList(e.Value) + if err != nil { + return err + } + // find user + for i, u := range users { + // early terminate + if u.MalID == userId { + users[i].Progress = progress + users[i].Updated = updated + newData, err := json.Marshal(users) + if err != nil { + return err + } + return tx.Put(bucketAnime, keyBytes, newData, nutsdb.Persistent) + } + } + return fmt.Errorf("%d schaut nicht %d", userId, animeId) + }) +} + func ReadRegisteredUsers() ([]UserData, error) { var users []UserData err := db.View( diff --git a/ober.go b/ober.go index 8b0cc90..152b7ee 100644 --- a/ober.go +++ b/ober.go @@ -432,7 +432,9 @@ func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) { // update or delete request if update { // anime exitsts => save - animeData, err = AddUserToAnime(username, userId, anime.Anime) + // get watch progress + progress, updated, _ := FetchProgress(anime.Anime, userId, username, 0) + animeData, err = AddUserToAnime(username, userId, anime.Anime, progress, updated) } else { // anime exitsts => delete animeData, err = DeleteUserFromAnime(username, userId, anime.Anime) diff --git a/praktikant.go b/praktikant.go index 63a30e1..dcfda5c 100644 --- a/praktikant.go +++ b/praktikant.go @@ -27,7 +27,33 @@ func Arbeit() { } } // refresh animelist of users - // TODO + animesUsers, err := ReadAnimeUsers() + if err != nil { + if err != nutsdb.ErrBucketEmpty { + color.Errorln(err.Error()) + } + return + } + // iterate anime + for _, a := range animesUsers { + // iterate users + for _, u := range a.Users { + newProgress, updated, err := FetchProgress(a.Anime, u.MalID, u.Username, u.Progress) + if err != nil { + color.Errorln(err.Error()) + continue + } + if newProgress == u.Progress { + continue + } + // update db + color.Infof("%s progress von %d: %d -> %d\n", u.Username, a.Anime, u.Progress, newProgress) + err = UpdateUserAnimeProgress(a.Anime, u.MalID, newProgress, updated) + if err != nil { + color.Errorln(err.Error()) + } + } + } } func LangeArbeiten() { diff --git a/schaffer.go b/schaffer.go index a4dcdee..ea90a0d 100644 --- a/schaffer.go +++ b/schaffer.go @@ -128,3 +128,38 @@ func SearchSeason(animeId int64) (*Anime, error) { } return nil, errors.New("anime not found") } + +func FetchProgress(animeId, userId int64, username string, progress int) (int, time.Time, error) { + // check watching first + list, _, err := GetUserAnimeListData(username, malApiStatusW) + if err != nil { + return 0, time.Time{}, err + } + for _, a := range list.Data { + // check if found + if a.Node.ID == animeId { + // check if progress changed + if progress != a.ListStatus.NumEpisodesWatched { + return a.ListStatus.NumEpisodesWatched, a.ListStatus.UpdatedAt, nil + } + return progress, a.ListStatus.UpdatedAt, nil + } + } + // check completed + list, _, err = GetUserAnimeListData(username, malApiStatusC) + if err != nil { + return 0, time.Time{}, err + } + for _, a := range list.Data { + // check if found + if a.Node.ID == animeId { + // check if progress changed + if progress != a.ListStatus.NumEpisodesWatched { + return a.ListStatus.NumEpisodesWatched, a.ListStatus.UpdatedAt, nil + } + return progress, a.ListStatus.UpdatedAt, nil + } + } + // has no progress or dropped/hold + return 0, time.Now(), nil +}