Files
mal/integrations/playback/allanime/sequels.go

134 lines
3.9 KiB
Go

package allanime
import (
"context"
"errors"
"fmt"
"strconv"
"strings"
)
type ProviderShow struct {
ID string
Name string
EnglishName string
MalID int
Status string
Thumbnail string
Type string
Year int
EpisodeCount int
SubEpisodes []int
DubEpisodes []int
}
func (c *AllAnimeProvider) DirectSequels(ctx context.Context, show ProviderShow) ([]string, error) {
query := `query($showId: String!) { show(_id: $showId) { relatedShows } }`
result, err := c.graphqlRequest(ctx, query, map[string]any{"showId": show.ID})
if err != nil {
return nil, err
}
data, _ := result["data"].(map[string]any)
rawShow, _ := data["show"].(map[string]any)
relations, _ := rawShow["relatedShows"].([]any)
ids := make([]string, 0, len(relations))
for _, raw := range relations {
relation, _ := raw.(map[string]any)
id, _ := relation["showId"].(string)
if relation["relation"] == "sequel" && id != "" {
ids = append(ids, id)
}
}
return ids, nil
}
func (c *AllAnimeProvider) GetProviderShow(ctx context.Context, showID string) (ProviderShow, error) {
query := `query($showId: String!) { show(_id: $showId) { _id name englishName malId status thumbnail type season episodeCount availableEpisodesDetail } }`
result, err := c.graphqlRequest(ctx, query, map[string]any{"showId": showID})
if err != nil {
return ProviderShow{}, err
}
data, _ := result["data"].(map[string]any)
raw, _ := data["show"].(map[string]any)
if raw == nil {
return ProviderShow{}, fmt.Errorf("allanime: show %s not found", showID)
}
return providerShowFrom(raw), nil
}
func (c *AllAnimeProvider) SeasonalShows(ctx context.Context, season string, year int) ([]ProviderShow, error) {
const pageSize = 40
query := `query($search: SearchInput, $page: Int) { shows(search: $search, limit: 40, page: $page, countryOrigin: ALL) { edges { _id name englishName malId status thumbnail type season episodeCount availableEpisodesDetail } } }`
if season == "" {
return nil, errors.New("allanime: season is required")
}
search := map[string]any{
"allowAdult": false,
"allowUnknown": false,
"season": strings.ToUpper(season[:1]) + strings.ToLower(season[1:]),
"year": year,
"types": []string{"TV"},
"includeTypes": true,
}
out := make([]ProviderShow, 0)
seen := make(map[int]bool)
for page := 1; page <= 20; page++ {
result, err := c.graphqlRequest(ctx, query, map[string]any{"search": search, "page": page})
if err != nil {
return nil, err
}
data, _ := result["data"].(map[string]any)
shows, _ := data["shows"].(map[string]any)
edges, _ := shows["edges"].([]any)
for _, edge := range edges {
raw, _ := edge.(map[string]any)
show := providerShowFrom(raw)
if show.MalID <= 0 || seen[show.MalID] || show.Type != "TV" || max(len(show.SubEpisodes), len(show.DubEpisodes)) == 0 {
continue
}
seen[show.MalID] = true
out = append(out, show)
}
if len(edges) < pageSize {
break
}
}
return out, nil
}
func providerShowFrom(raw map[string]any) ProviderShow {
detail, _ := raw["availableEpisodesDetail"].(map[string]any)
season, _ := raw["season"].(map[string]any)
return ProviderShow{
ID: stringValue(raw["_id"]),
Name: stringValue(raw["name"]),
EnglishName: stringValue(raw["englishName"]),
MalID: intValue(raw["malId"]),
Status: stringValue(raw["status"]),
Thumbnail: stringValue(raw["thumbnail"]),
Type: stringValue(raw["type"]),
Year: numericInt(season["year"]),
EpisodeCount: intValue(raw["episodeCount"]),
SubEpisodes: episodeNums(stringsFrom(detail["sub"])),
DubEpisodes: episodeNums(stringsFrom(detail["dub"])),
}
}
func stringValue(value any) string {
valueString, _ := value.(string)
return valueString
}
func intValue(value any) int {
n, _ := strconv.Atoi(stringValue(value))
return n
}
func numericInt(value any) int {
if n := intValue(value); n > 0 {
return n
}
n, _ := value.(float64)
return int(n)
}