diff --git a/klotz.go b/klotz.go index 31e1565..58a45e6 100644 --- a/klotz.go +++ b/klotz.go @@ -127,6 +127,116 @@ type SeasonMal struct { } `json:"season"` } +type SeasonAnimeJikan struct { + MalID int64 `json:"mal_id"` + URL string `json:"url"` + Images struct { + Jpg struct { + ImageURL string `json:"image_url"` + SmallImageURL string `json:"small_image_url"` + LargeImageURL string `json:"large_image_url"` + } `json:"jpg"` + Webp struct { + ImageURL string `json:"image_url"` + SmallImageURL string `json:"small_image_url"` + LargeImageURL string `json:"large_image_url"` + } `json:"webp"` + } `json:"images"` + Trailer struct { + YoutubeID string `json:"youtube_id"` + URL string `json:"url"` + EmbedURL string `json:"embed_url"` + Images struct { + ImageURL string `json:"image_url"` + SmallImageURL string `json:"small_image_url"` + MediumImageURL string `json:"medium_image_url"` + LargeImageURL string `json:"large_image_url"` + MaximumImageURL string `json:"maximum_image_url"` + } `json:"images"` + } `json:"trailer"` + Title string `json:"title"` + TitleEnglish string `json:"title_english"` + TitleJapanese string `json:"title_japanese"` + TitleSynonyms []string `json:"title_synonyms"` + Type string `json:"type"` + Source string `json:"source"` + Episodes int `json:"episodes"` + Status string `json:"status"` + Airing bool `json:"airing"` + Aired struct { + From time.Time `json:"from"` + To time.Time `json:"to"` + Prop struct { + From struct { + Day int `json:"day"` + Month int `json:"month"` + Year int `json:"year"` + } `json:"from"` + To struct { + 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 string `json:"background"` + Season string `json:"season"` + Year int `json:"year"` + Broadcast struct { + Day string `json:"day"` + Time string `json:"time"` + Timezone string `json:"timezone"` + String string `json:"string"` + } `json:"broadcast"` + Producers []struct { + MalID int `json:"mal_id"` + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"producers"` + 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"` + URL string `json:"url"` + } `json:"studios"` + Genres []struct { + MalID int `json:"mal_id"` + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"genres"` + ExplicitGenres []interface{} `json:"explicit_genres"` + Themes []struct { + MalID int `json:"mal_id"` + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"themes"` + Demographics []struct { + MalID int `json:"mal_id"` + Type string `json:"type"` + Name string `json:"name"` + URL string `json:"url"` + } `json:"demographics"` +} + type SeasonJikan struct { Pagination struct { LastVisiblePage int `json:"last_visible_page"` @@ -138,113 +248,5 @@ type SeasonJikan struct { PerPage int `json:"per_page"` } `json:"items"` } `json:"pagination"` - Data []struct { - MalID int64 `json:"mal_id"` - URL string `json:"url"` - Images struct { - Jpg struct { - ImageURL string `json:"image_url"` - SmallImageURL string `json:"small_image_url"` - LargeImageURL string `json:"large_image_url"` - } `json:"jpg"` - Webp struct { - ImageURL string `json:"image_url"` - SmallImageURL string `json:"small_image_url"` - LargeImageURL string `json:"large_image_url"` - } `json:"webp"` - } `json:"images"` - Trailer struct { - YoutubeID string `json:"youtube_id"` - URL string `json:"url"` - EmbedURL string `json:"embed_url"` - Images struct { - ImageURL string `json:"image_url"` - SmallImageURL string `json:"small_image_url"` - MediumImageURL string `json:"medium_image_url"` - LargeImageURL string `json:"large_image_url"` - MaximumImageURL string `json:"maximum_image_url"` - } `json:"images"` - } `json:"trailer"` - Title string `json:"title"` - TitleEnglish string `json:"title_english"` - TitleJapanese string `json:"title_japanese"` - TitleSynonyms []string `json:"title_synonyms"` - Type string `json:"type"` - Source string `json:"source"` - Episodes int `json:"episodes"` - Status string `json:"status"` - Airing bool `json:"airing"` - Aired struct { - From time.Time `json:"from"` - To time.Time `json:"to"` - Prop struct { - From struct { - Day int `json:"day"` - Month int `json:"month"` - Year int `json:"year"` - } `json:"from"` - To struct { - 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 string `json:"background"` - Season string `json:"season"` - Year int `json:"year"` - Broadcast struct { - Day string `json:"day"` - Time string `json:"time"` - Timezone string `json:"timezone"` - String string `json:"string"` - } `json:"broadcast"` - Producers []struct { - MalID int `json:"mal_id"` - Type string `json:"type"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"producers"` - 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"` - URL string `json:"url"` - } `json:"studios"` - Genres []struct { - MalID int `json:"mal_id"` - Type string `json:"type"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"genres"` - ExplicitGenres []interface{} `json:"explicit_genres"` - Themes []struct { - MalID int `json:"mal_id"` - Type string `json:"type"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"themes"` - Demographics []struct { - MalID int `json:"mal_id"` - Type string `json:"type"` - Name string `json:"name"` - URL string `json:"url"` - } `json:"demographics"` - } `json:"data"` + Data []SeasonAnimeJikan `json:"data"` } diff --git a/nuss.go b/nuss.go index 83a911b..3e18a9b 100644 --- a/nuss.go +++ b/nuss.go @@ -1,10 +1,8 @@ package main import ( - "encoding/binary" "encoding/json" "errors" - "fmt" "github.com/xujiajun/nutsdb" ) @@ -31,6 +29,41 @@ func SaveUser(user *UserData) error { return err } +func AddUserToAnime(username string, userId, animeId int64) (*Anime, error) { + var anime Anime + err := db.Update( + func(tx *nutsdb.Tx) error { + keyBytes := Int64ToByte(animeId) + e, err := tx.Get(bucketAnime, keyBytes) + var users []WatchUser + if err != nil { + users = make([]WatchUser, 1) + } else { + // parse user list + users, err = parseUserList(e.Value) + if err != nil { + return err + } + } + + // add user + users = append(users, WatchUser{ + Username: username, + MalID: userId, + }) + anime = Anime{ + Anime: animeId, + Users: users, + } + newData, err := json.Marshal(users) + if err != nil { + return err + } + return tx.Put(bucketAnime, keyBytes, newData, nutsdb.Persistent) + }) + return &anime, err +} + func ReadAnimes() ([]Anime, error) { var animes []Anime err := db.View( @@ -41,20 +74,19 @@ func ReadAnimes() ([]Anime, error) { } animes = make([]Anime, len(entries)) // iterate entries - for _, entry := range entries { + for _, e := 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) + animeId, err := BytesToInt64(e.Key) + if err != nil { + return err } // parse user list - var users []WatchUser - err = json.Unmarshal(entry.Value, &users) + users, err := parseUserList(e.Value) if err != nil { return err } anime := Anime{ - Anime: malId, + Anime: animeId, Users: users, } animes = append(animes, anime) @@ -102,3 +134,9 @@ func DbDelete(bucket, key string, val []byte) error { return tx.Delete(bucket, keyBytes) }) } + +func parseUserList(data []byte) ([]WatchUser, error) { + var users []WatchUser + err := json.Unmarshal(data, &users) + return users, err +} diff --git a/ober.go b/ober.go index bff2bac..f24d7c3 100644 --- a/ober.go +++ b/ober.go @@ -1,7 +1,6 @@ package main import ( - "crypto/sha512" "encoding/json" "fmt" "log" @@ -45,14 +44,11 @@ func Season(ctx *fasthttp.RequestCtx) { return } - _, err = ctx.Write(data) + err = writeResponseBody(ctx, data) if err != nil { addErrorToCtx(ctx, err) return } - - ctx.SetContentType("application/json; charset=utf-8") - ctx.SetStatusCode(fasthttp.StatusOK) } func WatchGet(ctx *fasthttp.RequestCtx) { @@ -126,7 +122,7 @@ func Register(ctx *fasthttp.RequestCtx) { return } - calcSauce := fmt.Sprintf("%x", sha512.Sum512([]byte(registerSecret+strconv.FormatInt(register.MalID, 10)+register.Username))) + calcSauce := Sauce(register.MalID, register.Username) if calcSauce != strings.ToLower(register.Sauce) { ctx.WriteString("Möge die Sauce mit dir sein") ctx.SetStatusCode(fasthttp.StatusBadRequest) @@ -174,7 +170,8 @@ func WatchPost(ctx *fasthttp.RequestCtx) { return } username := fmt.Sprintf("%s", ctx.UserValue("user")) - if !GheddoAuth(username, string(auth)) { + legit, userId := GheddoAuth(username, string(auth)) + if !legit { ctx.SetStatusCode(fasthttp.StatusUnauthorized) return } @@ -188,10 +185,21 @@ func WatchPost(ctx *fasthttp.RequestCtx) { return } + // iterate sent animes for _, anime := range animes { - // TODO check if anime is in season + // check if anime is in season + _, err = SearchSeason(anime.Anime) + if err == nil { + // anime exitsts => save + animeData, err := AddUserToAnime(username, userId, anime.Anime) + if err != nil { + addErrorToCtx(ctx, err) + return + } + anime.Users = animeData.Users + } - // iterate sent animes + // TODO detail, _, err := GetAnimeDetailData(anime.Anime) if err != nil { ctx.WriteString(err.Error()) @@ -199,15 +207,36 @@ func WatchPost(ctx *fasthttp.RequestCtx) { return } fmt.Printf("%+v\n", detail) + + data, err := json.Marshal(animes) + if err != nil { + addErrorToCtx(ctx, err) + return + } + err = writeResponseBody(ctx, data) + if err != nil { + addErrorToCtx(ctx, err) + return + } } } -func GheddoAuth(username, auth string) bool { +func GheddoAuth(username, auth string) (bool, int64) { user, err := ReadUser(username) if err != nil { - return false + return false, 0 } - return user.Secret == auth + return user.Secret == auth, user.MalID +} + +func writeResponseBody(ctx *fasthttp.RequestCtx, bytes []byte) error { + _, err := ctx.Write(bytes) + if err != nil { + return err + } + ctx.SetContentType("application/json; charset=utf-8") + ctx.SetStatusCode(fasthttp.StatusOK) + return err } func addErrorToCtx(ctx *fasthttp.RequestCtx, err error) { diff --git a/raser.go b/raser.go deleted file mode 100644 index 6919d4d..0000000 --- a/raser.go +++ /dev/null @@ -1,13 +0,0 @@ -package main - -import "encoding/json" - -func GetSeasonCache() (*SeasonJikan, error) { - data, err := cache.Get(seasonApiJikan) - if err != nil { - return nil, err - } - var seasonData SeasonJikan - err = json.Unmarshal(data, &seasonData) - return &seasonData, err -} diff --git a/rechner.go b/rechner.go new file mode 100644 index 0000000..c2c79a2 --- /dev/null +++ b/rechner.go @@ -0,0 +1,26 @@ +package main + +import ( + "crypto/sha512" + "encoding/binary" + "fmt" + "strconv" +) + +func Sauce(malid int64, username string) string { + return fmt.Sprintf("%x", sha512.Sum512([]byte(registerSecret+strconv.FormatInt(malid, 10)+username))) +} + +func BytesToInt64(bytes []byte) (int64, error) { + yes, c := binary.Varint(bytes) + if c <= 0 { + return yes, fmt.Errorf("int64 decode error: %s", bytes) + } + return yes, nil +} + +func Int64ToByte(yes int64) []byte { + buf := make([]byte, binary.MaxVarintLen64) + n := binary.PutVarint(buf, yes) + return buf[:n] +} diff --git a/schaffer.go b/schaffer.go new file mode 100644 index 0000000..aada714 --- /dev/null +++ b/schaffer.go @@ -0,0 +1,32 @@ +package main + +import ( + "encoding/json" + "errors" +) + +func GetSeasonCache() (*SeasonJikan, error) { + data, err := cache.Get(seasonApiJikan) + if err != nil { + return nil, err + } + var seasonData SeasonJikan + err = json.Unmarshal(data, &seasonData) + return &seasonData, err +} + +func SearchSeason(malId int64) (*SeasonAnimeJikan, error) { + season, err := GetSeasonCache() + if err != nil { + return nil, err + } + if season.Pagination.Items.Count == 0 { + return nil, errors.New("no seasonal anime") + } + for _, a := range season.Data { + if a.MalID == malId { + return &a, err + } + } + return nil, errors.New("anime not found") +}