perf: reduce relations api calls by parsing relations directly from full anime endpoints

This commit is contained in:
2026-04-08 16:33:44 +02:00
parent 618b807b3d
commit 2780c8338f
3 changed files with 10 additions and 34 deletions

View File

@@ -1,31 +1,8 @@
package jikan
import (
"fmt"
"time"
)
// GetRelationsData fetches the raw relationships for an anime
func (c *Client) GetRelationsData(id int) (JikanRelationsResponse, error) {
cacheKey := fmt.Sprintf("relations:%d", id)
var cached JikanRelationsResponse
if c.getCache(cacheKey, &cached) {
return cached, nil
}
var result JikanRelationsResponse
reqURL := fmt.Sprintf("%s/anime/%d/relations", c.baseURL, id)
if err := c.fetchWithRetry(reqURL, &result); err != nil {
return JikanRelationsResponse{}, err
}
c.setCache(cacheKey, result, time.Hour*24)
return result, nil
}
// findFirstAnimeRelation extracts the first related anime ID for a specific relation type
func findFirstAnimeRelation(res JikanRelationsResponse, relType string) *int {
for _, group := range res.Data {
func findFirstAnimeRelation(groups []JikanRelationGroup, relType string) *int {
for _, group := range groups {
if group.Relation == relType {
for _, entry := range group.Entry {
if entry.Type == "anime" {
@@ -40,12 +17,12 @@ func findFirstAnimeRelation(res JikanRelationsResponse, relType string) *int {
// fetchChain recursively builds the relational chain (Prequels or Sequels)
func (c *Client) fetchChain(startID int, direction string, visited map[int]bool) ([]RelationEntry, error) {
rels, err := c.GetRelationsData(startID)
anime, err := c.GetAnimeByID(startID)
if err != nil {
return nil, err
}
nextIDPtr := findFirstAnimeRelation(rels, direction)
nextIDPtr := findFirstAnimeRelation(anime.Relations, direction)
if nextIDPtr == nil {
return nil, nil // normal end of chain
}
@@ -56,12 +33,12 @@ func (c *Client) fetchChain(startID int, direction string, visited map[int]bool)
}
visited[nextID] = true
anime, err := c.GetAnimeByID(nextID)
nextAnime, err := c.GetAnimeByID(nextID)
if err != nil {
return nil, err
}
entry := RelationEntry{Anime: anime, IsCurrent: false}
entry := RelationEntry{Anime: nextAnime, IsCurrent: false}
rest, err := c.fetchChain(nextID, direction, visited)
if err != nil {
return nil, err
@@ -91,8 +68,6 @@ func (c *Client) GetFullRelations(id int) ([]RelationEntry, error) {
sequels, err2 := c.fetchChain(id, "Sequel", visitedSeq)
// If both chains errored and it wasn't just "no relations", we should probably error out
// But it's safer to just return what we have and the error so the UI can decide
var result []RelationEntry
result = append(result, prequels...)
result = append(result, RelationEntry{Anime: currentAnime, IsCurrent: true})

View File

@@ -70,6 +70,7 @@ type Anime struct {
Name string `json:"name"`
URL string `json:"url"`
} `json:"streaming"`
Relations []JikanRelationGroup `json:"relations"`
}
// ImageURL returns the webp large image URL

View File

@@ -80,13 +80,13 @@ func (w *Worker) syncRelations(ctx context.Context) {
time.Sleep(400 * time.Millisecond)
}()
relations, err := w.client.GetRelationsData(int(a.ID))
animeData, err := w.client.GetAnimeByID(int(a.ID))
if err != nil {
log.Printf("worker: failed to fetch relations for %d: %v", a.ID, err)
log.Printf("worker: failed to fetch anime details for %d: %v", a.ID, err)
return
}
for _, rel := range relations.Data {
for _, rel := range animeData.Relations {
for _, entry := range rel.Entry {
if entry.Type == "anime" {
// We just insert the relation.