mirror of
https://github.com/ultrasn0w/huso.git
synced 2025-12-13 22:49:53 +01:00
243 lines
7.1 KiB
Go
243 lines
7.1 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gookit/color"
|
|
"github.com/valyala/fasthttp"
|
|
)
|
|
|
|
func SearchAnime(query string) ([]Anime, []byte, error) {
|
|
var animes []Anime
|
|
data, err := searchCache.Get(query)
|
|
if err != nil {
|
|
err = nil
|
|
dataMal, err := GetDataMal(searchApiMal + query + "&fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,media_type,status,genres,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,studios&limit=100")
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
var animeList AnimeListMal
|
|
animes = make([]Anime, 0)
|
|
err = json.Unmarshal(dataMal, &animeList)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
// convert to anime
|
|
for _, a := range animeList.Data {
|
|
animes = append(animes, MalConvert(&a.Node))
|
|
}
|
|
data, err = json.Marshal(animes)
|
|
if err != nil {
|
|
return animes, data, err
|
|
}
|
|
searchCache.Set(query, data)
|
|
} else {
|
|
err = json.Unmarshal(data, &animes)
|
|
}
|
|
return animes, data, err
|
|
}
|
|
|
|
func GetAnimeDetailData(animeId int64) (*Anime, []byte, error) {
|
|
var anime Anime
|
|
key := strconv.FormatInt(animeId, 10)
|
|
data, err := animeCache.Get(key)
|
|
if err != nil {
|
|
err = nil
|
|
dataMal, err := GetDataMal(animeApiMal + key + "?fields=id,title,main_picture,alternative_titles,start_date,end_date,synopsis,mean,rank,popularity,num_list_users,num_scoring_users,nsfw,media_type,status,genres,my_list_status,num_episodes,start_season,broadcast,source,average_episode_duration,rating,studios")
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
var animeMal AnimeDetailMal
|
|
err = json.Unmarshal(dataMal, &animeMal)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
// convert to anime
|
|
anime = MalConvert(&animeMal)
|
|
data, err = json.Marshal(&anime)
|
|
if err != nil {
|
|
return &anime, data, err
|
|
}
|
|
animeCache.Set(key, data)
|
|
} else {
|
|
err = json.Unmarshal(data, &anime)
|
|
}
|
|
return &anime, data, err
|
|
}
|
|
|
|
func GetUserAnimeListData(username, status string) (*AnimeListMal, []byte, error) {
|
|
var list AnimeListMal
|
|
data, err := animeListCache.Get(username + status)
|
|
if err != nil {
|
|
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(data, &list)
|
|
return &list, data, err
|
|
}
|
|
|
|
func GetUserData(username string) (*User, []byte, error) {
|
|
var user User
|
|
data, err := userCache.Get(username)
|
|
if err != nil {
|
|
err = nil
|
|
dataJikan, err := GetDataJikan(userApiJikan + username)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if strings.Contains(string(dataJikan), "BadResponseException") {
|
|
return nil, nil, fmt.Errorf("user not found: %s", username)
|
|
}
|
|
var userJikan UserJikan
|
|
err = json.Unmarshal(dataJikan, &userJikan)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
// workaround number #2 bcs jikan kekw
|
|
if userJikan.Data.MalID == 0 {
|
|
dataJikan, err = GetDataJikan(userApiJikan + username)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if strings.Contains(string(dataJikan), "BadResponseException") {
|
|
return nil, nil, fmt.Errorf("user not found: %s", username)
|
|
}
|
|
err = json.Unmarshal(dataJikan, &userJikan)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
if userJikan.Data.MalID == 0 {
|
|
return nil, nil, fmt.Errorf("user returned empty object: %s", username)
|
|
}
|
|
// convert to user
|
|
user = UserConvert(&userJikan)
|
|
data, err = json.Marshal(&user)
|
|
if err != nil {
|
|
return &user, data, err
|
|
}
|
|
userCache.Set(username, data)
|
|
} else {
|
|
err = json.Unmarshal(data, &user)
|
|
}
|
|
|
|
return &user, data, err
|
|
}
|
|
|
|
func GetSeasonDataAll() ([]Anime, []byte, error) {
|
|
color.Infoln("Aktuelle Season abfragen...")
|
|
logOut.WriteLine("📺 Aktuelle Season abfragen...")
|
|
data, _, err := GetSeasonData(1)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
color.Infof("%d Anime auf %d Seiten\n", data.Pagination.Items.Total, data.Pagination.LastVisiblePage)
|
|
logOut.WriteLine(fmt.Sprintf("📺 %d Anime auf %d Seiten", data.Pagination.Items.Total, data.Pagination.LastVisiblePage))
|
|
animes := make([]Anime, 0)
|
|
// convert to anime
|
|
for _, a := range data.Data {
|
|
animes = append(animes, JikanConvert(&a))
|
|
}
|
|
for i := 2; data.Pagination.HasNextPage; i++ {
|
|
color.Infof("Seite %d abfragen...\n", i)
|
|
logOut.WriteLine(fmt.Sprintf("📺 Seite %d abfragen...", i))
|
|
newData, _, err := GetSeasonData(i)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
data.Pagination.CurrentPage = newData.Pagination.CurrentPage
|
|
data.Pagination.HasNextPage = newData.Pagination.HasNextPage
|
|
data.Pagination.Items.Count += newData.Pagination.Items.Count
|
|
// convert to anime
|
|
for _, a := range newData.Data {
|
|
animes = append(animes, JikanConvert(&a))
|
|
}
|
|
}
|
|
color.Infof("%d Anime bekommen\n", len(animes))
|
|
logOut.WriteLine(fmt.Sprintf("📺 %d Anime bekommen", len(animes)))
|
|
bytes, err := json.Marshal(animes)
|
|
return animes, bytes, err
|
|
}
|
|
|
|
func GetSeasonData(page int) (*SeasonJikan, []byte, error) {
|
|
var data SeasonJikan
|
|
body, err := GetSeasonBytes(page)
|
|
if err != nil {
|
|
return nil, body, err
|
|
}
|
|
err = json.Unmarshal(body, &data)
|
|
return &data, body, err
|
|
}
|
|
|
|
func GetSeasonBytes(page int) ([]byte, error) {
|
|
if page != 0 {
|
|
return GetDataJikan(seasonApiJikan + "?page=" + strconv.Itoa(page))
|
|
}
|
|
return GetDataJikan(seasonApiJikan)
|
|
}
|
|
|
|
func GetDataMal(apiAddr string) ([]byte, error) {
|
|
var body []byte
|
|
req := fasthttp.AcquireRequest()
|
|
resp := fasthttp.AcquireResponse()
|
|
defer fasthttp.ReleaseRequest(req)
|
|
defer fasthttp.ReleaseResponse(resp)
|
|
|
|
req.SetRequestURI(*malApiBaseUri + apiAddr)
|
|
req.Header.SetMethod(fasthttp.MethodGet)
|
|
req.Header.Add("X-MAL-CLIENT-ID", *malApiId)
|
|
err := fasthttp.Do(req, resp)
|
|
contentEncoding := resp.Header.Peek(fasthttp.HeaderContentEncoding)
|
|
if bytes.EqualFold(contentEncoding, []byte("gzip")) {
|
|
body, _ = resp.BodyGunzip()
|
|
} else {
|
|
body = resp.Body()
|
|
}
|
|
|
|
if resp.StatusCode() != fasthttp.StatusOK {
|
|
return body, fmt.Errorf("unexpected response code: %s %d", *malApiBaseUri+apiAddr, resp.StatusCode())
|
|
}
|
|
return body, err
|
|
}
|
|
|
|
func GetDataJikan(apiAddr string) ([]byte, error) {
|
|
var body []byte
|
|
ctx := context.Background()
|
|
jikanLimiter.Wait(ctx)
|
|
statusCode, body, err := fasthttp.Get(body, *jikanApiBaseUri+apiAddr)
|
|
// retry bcs jikan kekw
|
|
if statusCode == fasthttp.StatusInternalServerError {
|
|
jikanLimiter.Wait(ctx)
|
|
statusCode, body, err = fasthttp.Get(body, *jikanApiBaseUri+apiAddr)
|
|
}
|
|
if statusCode != fasthttp.StatusOK {
|
|
return body, fmt.Errorf("unexpected response code: %s %d", *jikanApiBaseUri+apiAddr, statusCode)
|
|
}
|
|
return body, err
|
|
}
|
|
|
|
func GetCurrentSeasonString() string {
|
|
var now = time.Now()
|
|
switch now.Month() {
|
|
case time.January, time.February, time.March:
|
|
return fmt.Sprintf("%04d/winter", now.Year())
|
|
case time.April, time.May, time.June:
|
|
return fmt.Sprintf("%04d/spring", now.Year())
|
|
case time.July, time.August, time.September:
|
|
return fmt.Sprintf("%04d/summer", now.Year())
|
|
case time.October, time.November, time.December:
|
|
return fmt.Sprintf("%04d/fall", now.Year())
|
|
default:
|
|
return fmt.Sprintf("%04d", now.Year())
|
|
}
|
|
}
|