mirror of
https://github.com/ultrasn0w/huso.git
synced 2025-12-14 17:19:53 +01:00
MAL progress fetch
This commit is contained in:
9
huso.go
9
huso.go
@@ -42,6 +42,7 @@ var (
|
|||||||
seasoncache *bigcache.BigCache
|
seasoncache *bigcache.BigCache
|
||||||
userCache *bigcache.BigCache
|
userCache *bigcache.BigCache
|
||||||
searchCache *bigcache.BigCache
|
searchCache *bigcache.BigCache
|
||||||
|
animeListCache *bigcache.BigCache
|
||||||
db *nutsdb.DB
|
db *nutsdb.DB
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -76,6 +77,11 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
defer searchCache.Close()
|
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 := nutsdb.DefaultOptions
|
||||||
nutsOpt.Dir = "nuts"
|
nutsOpt.Dir = "nuts"
|
||||||
@@ -93,8 +99,5 @@ func main() {
|
|||||||
|
|
||||||
go RunWebserv()
|
go RunWebserv()
|
||||||
|
|
||||||
//list, _, _ := GetUserAnimeListData("ultrasn0w", malApiStatusW)
|
|
||||||
//fmt.Printf("%+v\n", list)
|
|
||||||
|
|
||||||
<-sc
|
<-sc
|
||||||
}
|
}
|
||||||
|
|||||||
16
klotz.go
16
klotz.go
@@ -53,9 +53,10 @@ type AnimeStudio struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WatchUser struct {
|
type WatchUser struct {
|
||||||
Username string `json:"username"`
|
Username string `json:"username"`
|
||||||
MalID int64 `json:"malId"`
|
MalID int64 `json:"malId"`
|
||||||
Progress int `json:"progress"`
|
Progress int `json:"progress"`
|
||||||
|
Updated time.Time `json:"updated"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserData struct {
|
type UserData struct {
|
||||||
@@ -130,7 +131,14 @@ type AnimeDetailMal struct {
|
|||||||
|
|
||||||
type AnimeListMal struct {
|
type AnimeListMal struct {
|
||||||
Data []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"`
|
} `json:"data"`
|
||||||
Paging struct {
|
Paging struct {
|
||||||
Next string `json:"next"`
|
Next string `json:"next"`
|
||||||
|
|||||||
16
knecht.go
16
knecht.go
@@ -72,16 +72,16 @@ func GetAnimeDetailData(animeId int64) (*Anime, []byte, error) {
|
|||||||
|
|
||||||
func GetUserAnimeListData(username, status string) (*AnimeListMal, []byte, error) {
|
func GetUserAnimeListData(username, status string) (*AnimeListMal, []byte, error) {
|
||||||
var list AnimeListMal
|
var list AnimeListMal
|
||||||
body, err := GetUserAnimeListBytes(username, status)
|
data, err := animeListCache.Get(username + status)
|
||||||
if err != nil {
|
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)
|
err = json.Unmarshal(data, &list)
|
||||||
return &list, body, err
|
return &list, data, err
|
||||||
}
|
|
||||||
|
|
||||||
func GetUserAnimeListBytes(username, status string) ([]byte, error) {
|
|
||||||
return GetDataMal(userApiMal + username + "/animelist?limit=1000&status=" + status)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserData(username string) (*User, []byte, error) {
|
func GetUserData(username string) (*User, []byte, error) {
|
||||||
|
|||||||
35
nuss.go
35
nuss.go
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/xujiajun/nutsdb"
|
"github.com/xujiajun/nutsdb"
|
||||||
)
|
)
|
||||||
@@ -30,7 +31,7 @@ func SaveUser(user *UserData) error {
|
|||||||
return err
|
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
|
var anime AnimeUser
|
||||||
err := db.Update(
|
err := db.Update(
|
||||||
func(tx *nutsdb.Tx) error {
|
func(tx *nutsdb.Tx) error {
|
||||||
@@ -62,6 +63,8 @@ func AddUserToAnime(username string, userId, animeId int64) (*AnimeUser, error)
|
|||||||
users = append(users, WatchUser{
|
users = append(users, WatchUser{
|
||||||
Username: username,
|
Username: username,
|
||||||
MalID: userId,
|
MalID: userId,
|
||||||
|
Progress: progress,
|
||||||
|
Updated: updated,
|
||||||
})
|
})
|
||||||
anime = AnimeUser{
|
anime = AnimeUser{
|
||||||
Anime: animeId,
|
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) {
|
func ReadRegisteredUsers() ([]UserData, error) {
|
||||||
var users []UserData
|
var users []UserData
|
||||||
err := db.View(
|
err := db.View(
|
||||||
|
|||||||
4
ober.go
4
ober.go
@@ -432,7 +432,9 @@ func processUpdateReq(ctx *fasthttp.RequestCtx, update bool) {
|
|||||||
// update or delete request
|
// update or delete request
|
||||||
if update {
|
if update {
|
||||||
// anime exitsts => save
|
// 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 {
|
} else {
|
||||||
// anime exitsts => delete
|
// anime exitsts => delete
|
||||||
animeData, err = DeleteUserFromAnime(username, userId, anime.Anime)
|
animeData, err = DeleteUserFromAnime(username, userId, anime.Anime)
|
||||||
|
|||||||
@@ -27,7 +27,33 @@ func Arbeit() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// refresh animelist of users
|
// 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() {
|
func LangeArbeiten() {
|
||||||
|
|||||||
35
schaffer.go
35
schaffer.go
@@ -128,3 +128,38 @@ func SearchSeason(animeId int64) (*Anime, error) {
|
|||||||
}
|
}
|
||||||
return nil, errors.New("anime not found")
|
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
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user