MAL progress fetch

This commit is contained in:
daru
2022-04-18 02:53:09 +02:00
parent 8fe7bf4d4b
commit 994bccb068
7 changed files with 125 additions and 18 deletions

View File

@@ -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
}

View File

@@ -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"`

View File

@@ -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) {

35
nuss.go
View File

@@ -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(

View File

@@ -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)

View File

@@ -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() {

View File

@@ -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
}