diff --git a/huso.go b/huso.go index e9a930b..a845e7d 100644 --- a/huso.go +++ b/huso.go @@ -27,7 +27,7 @@ const ( malApiStatusD = "dropped" bucketUsers = "users" bucketAnime = "anime" - bucketmedia = "media" + bucketMedia = "media" ) var ( diff --git a/klotz.go b/klotz.go index 44b0a49..896b805 100644 --- a/klotz.go +++ b/klotz.go @@ -2,15 +2,26 @@ package main import "time" +type Anime struct { + Anime int64 `json:"anime"` + Users []WatchUser `json:"users"` +} + +type WatchUser struct { + Username string `json:"username"` + MalID int64 `json:"malId"` + Progress int `json:"progress"` +} + type UserData struct { Username string `json:"username"` - MalId int `json:"malId"` + MalID int64 `json:"malId"` Secret string `json:"secret"` } type RegisterData struct { Username string `json:"username"` - MalId int `json:"malId"` + MalID int64 `json:"malId"` Secret string `json:"secret"` Sauce string `json:"sauce"` } @@ -18,7 +29,7 @@ type RegisterData struct { type AnimeListMal struct { Data []struct { Node struct { - ID int `json:"id"` + ID int64 `json:"id"` Title string `json:"title"` MainPicture struct { Medium string `json:"medium"` @@ -33,7 +44,7 @@ type AnimeListMal struct { type UserJikan struct { Data struct { - MalID int `json:"mal_id"` + MalID int64 `json:"mal_id"` Username string `json:"username"` URL string `json:"url"` Images struct { @@ -44,18 +55,18 @@ type UserJikan struct { ImageURL string `json:"image_url"` } `json:"webp"` } `json:"images"` - LastOnline time.Time `json:"last_online"` - Gender interface{} `json:"gender"` - Birthday interface{} `json:"birthday"` - Location string `json:"location"` - Joined time.Time `json:"joined"` + LastOnline time.Time `json:"last_online"` + Gender string `json:"gender"` + Birthday time.Time `json:"birthday"` + Location string `json:"location"` + Joined time.Time `json:"joined"` } `json:"data"` } type SeasonMal struct { Data []struct { Node struct { - ID int `json:"id"` + ID int64 `json:"id"` Title string `json:"title"` MainPicture struct { Medium string `json:"medium"` @@ -84,7 +95,7 @@ type SeasonJikan struct { } `json:"items"` } `json:"pagination"` Data []struct { - MalID int `json:"mal_id"` + MalID int64 `json:"mal_id"` URL string `json:"url"` Images struct { Jpg struct { @@ -120,8 +131,8 @@ type SeasonJikan struct { Status string `json:"status"` Airing bool `json:"airing"` Aired struct { - From time.Time `json:"from"` - To interface{} `json:"to"` + From time.Time `json:"from"` + To time.Time `json:"to"` Prop struct { From struct { Day int `json:"day"` @@ -129,25 +140,25 @@ type SeasonJikan struct { Year int `json:"year"` } `json:"from"` To struct { - Day interface{} `json:"day"` - Month interface{} `json:"month"` - Year interface{} `json:"year"` + Day int `json:"day"` + Month int `json:"month"` + Year int `json:"year"` } `json:"to"` } `json:"prop"` String string `json:"string"` } `json:"aired"` - Duration string `json:"duration"` - Rating string `json:"rating"` - Score float64 `json:"score"` - ScoredBy int `json:"scored_by"` - Rank int `json:"rank"` - Popularity int `json:"popularity"` - Members int `json:"members"` - Favorites int `json:"favorites"` - Synopsis string `json:"synopsis"` - Background interface{} `json:"background"` - Season string `json:"season"` - Year int `json:"year"` + Duration string `json:"duration"` + Rating string `json:"rating"` + Score float64 `json:"score"` + ScoredBy int `json:"scored_by"` + Rank int `json:"rank"` + Popularity int `json:"popularity"` + Members int `json:"members"` + Favorites int `json:"favorites"` + Synopsis string `json:"synopsis"` + Background string `json:"background"` + Season string `json:"season"` + Year int `json:"year"` Broadcast struct { Day string `json:"day"` Time string `json:"time"` @@ -160,8 +171,13 @@ type SeasonJikan struct { Name string `json:"name"` URL string `json:"url"` } `json:"producers"` - Licensors []interface{} `json:"licensors"` - Studios []struct { + Licensors []struct { + MalID int `json:"mal_id"` + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"licensors"` + Studios []struct { MalID int `json:"mal_id"` Type string `json:"type"` Name string `json:"name"` @@ -180,6 +196,11 @@ type SeasonJikan struct { Name string `json:"name"` URL string `json:"url"` } `json:"themes"` - Demographics []interface{} `json:"demographics"` + Demographics []struct { + MalID int `json:"mal_id"` + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"demographics"` } `json:"data"` } diff --git a/nuss.go b/nuss.go index ef32870..83a911b 100644 --- a/nuss.go +++ b/nuss.go @@ -1,8 +1,10 @@ package main import ( + "encoding/binary" "encoding/json" "errors" + "fmt" "github.com/xujiajun/nutsdb" ) @@ -29,21 +31,52 @@ func SaveUser(user *UserData) error { return err } +func ReadAnimes() ([]Anime, error) { + var animes []Anime + err := db.View( + func(tx *nutsdb.Tx) error { + entries, err := tx.GetAll(bucketAnime) + if err != nil { + return err + } + animes = make([]Anime, len(entries)) + // iterate entries + for _, entry := range entries { + // decode anime list + malId, c := binary.Varint(entry.Key) + if c <= 0 { + return fmt.Errorf("int64 decode error: %s %s", entry.Key, entry.Value) + } + // parse user list + var users []WatchUser + err = json.Unmarshal(entry.Value, &users) + if err != nil { + return err + } + anime := Anime{ + Anime: malId, + Users: users, + } + animes = append(animes, anime) + } + return nil + }) + return animes, err +} + func DbClean() error { - err := db.Update( + return db.Update( func(tx *nutsdb.Tx) error { return db.Merge() }) - return err } func DbSave(bucket, key string, val []byte) error { - err := db.Update( + return db.Update( func(tx *nutsdb.Tx) error { keyBytes := []byte(key) return tx.Put(bucket, keyBytes, val, nutsdb.Persistent) }) - return err } func DbRead(bucket, key string) ([]byte, error) { @@ -63,10 +96,9 @@ func DbRead(bucket, key string) ([]byte, error) { } func DbDelete(bucket, key string, val []byte) error { - err := db.Update( + return db.Update( func(tx *nutsdb.Tx) error { keyBytes := []byte(key) return tx.Delete(bucket, keyBytes) }) - return err } diff --git a/ober.go b/ober.go index 7cd328d..aeaa0dc 100644 --- a/ober.go +++ b/ober.go @@ -10,13 +10,18 @@ import ( "github.com/fasthttp/router" "github.com/valyala/fasthttp" + "github.com/xujiajun/nutsdb" ) func RunWebserv() { r := router.New() r.GET("/", Start) r.GET("/api/season", Season) + r.GET("/api/watch/{user?}", WatchGet) r.POST("/api/register", Register) + r.POST("/api/watch/{user}", WatchPost) + r.PATCH("/api/watch/{user}", Start) + r.DELETE("/api/watch/{user}", Start) log.Fatal(fasthttp.ListenAndServe(":"+strconv.Itoa(*webServerPort), r.Handler)) } @@ -62,6 +67,58 @@ func Season(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusOK) } +func WatchGet(ctx *fasthttp.RequestCtx) { + usrVal := ctx.UserValue("user") + var userId int64 + if usrVal != nil { + // check user exists + user, err := ReadUser(fmt.Sprintf("%s", usrVal)) + if err != nil { + ctx.WriteString("Dich gibts nicht") + ctx.SetStatusCode(fasthttp.StatusNotFound) + return + } + userId = user.MalID + } + animes, err := ReadAnimes() + if err != nil { + // check if no anime were inserted + if err != nutsdb.ErrBucketEmpty { + addErrorToCtx(ctx, err) + return + } + animes = make([]Anime, 0) + } + + // apply single user logic + if usrVal != nil { + filteredAnimes := make([]Anime, 0) + for _, a := range animes { + for _, u := range a.Users { + if u.MalID == userId { + filteredAnimes = append(filteredAnimes, a) + break + } + } + } + animes = filteredAnimes + } + + bytes, err := json.Marshal(animes) + if err != nil { + addErrorToCtx(ctx, err) + return + } + _, err = ctx.Write(bytes) + if err != nil { + addErrorToCtx(ctx, err) + return + } + + ctx.SetContentType("application/json; charset=utf-8") + ctx.SetStatusCode(fasthttp.StatusOK) +} + func Register(ctx *fasthttp.RequestCtx) { if string(ctx.Request.Header.ContentType()) != "application/json" { ctx.SetStatusCode(fasthttp.StatusBadRequest) @@ -75,12 +132,13 @@ func Register(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusBadRequest) return } - if register.MalId == 0 || register.Username == "" || register.Secret == "" || register.Sauce == "" { + if register.MalID == 0 || register.Username == "" || register.Secret == "" || register.Sauce == "" { ctx.WriteString("Sprich JSON du Hurensohn") ctx.SetStatusCode(fasthttp.StatusBadRequest) return } - calcSauce := fmt.Sprintf("%x", sha512.Sum512([]byte(registerSecret+strconv.Itoa(register.MalId)+register.Username))) + + calcSauce := fmt.Sprintf("%x", sha512.Sum512([]byte(registerSecret+strconv.FormatInt(register.MalID, 10)+register.Username))) if calcSauce != strings.ToLower(register.Sauce) { ctx.WriteString("Möge die Sauce mit dir sein") ctx.SetStatusCode(fasthttp.StatusBadRequest) @@ -100,15 +158,15 @@ func Register(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusExpectationFailed) return } - if userData.Data.MalID != register.MalId { - ctx.WriteString("Dich gibts net auf MAL") + if userData.Data.MalID != register.MalID { + ctx.WriteString("Dich gibts nicht auf MAL") ctx.SetStatusCode(fasthttp.StatusExpectationFailed) return } // REGISTER user := UserData{ Username: register.Username, - MalId: register.MalId, + MalID: register.MalID, Secret: register.Secret, } err = SaveUser(&user) @@ -121,6 +179,10 @@ func Register(ctx *fasthttp.RequestCtx) { ctx.SetStatusCode(fasthttp.StatusOK) } +func WatchPost(ctx *fasthttp.RequestCtx) { + // +} + func addErrorToCtx(ctx *fasthttp.RequestCtx, err error) { ctx.WriteString(err.Error()) ctx.SetStatusCode(fasthttp.StatusInternalServerError) diff --git a/season.qtpl b/season.qtpl index a5f7def..568be2f 100644 --- a/season.qtpl +++ b/season.qtpl @@ -31,7 +31,7 @@ body { background-color: #1a1a1a; color: #fff; } {% for _, anime := range season.Data %}