From 13b0128c3804591281e25d0344915472b7b46891 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Wed, 8 Apr 2026 16:10:56 +0200 Subject: [PATCH] feat: fetch full details for recommendations to prioritize english titles --- internal/features/anime/handler.go | 2 +- internal/features/anime/service.go | 4 +-- internal/jikan/recommendations.go | 57 +++++++++++++++++++----------- 3 files changed, 39 insertions(+), 24 deletions(-) diff --git a/internal/features/anime/handler.go b/internal/features/anime/handler.go index a494c6d..f830c5a 100644 --- a/internal/features/anime/handler.go +++ b/internal/features/anime/handler.go @@ -167,7 +167,7 @@ func (h *Handler) HandleAPIAnime(w http.ResponseWriter, r *http.Request) { relations := h.svc.GetRelations(id) templates.AnimeRelationsList(relations).Render(r.Context(), w) case "recommendations": - recs, err := h.svc.GetRecommendations(id) + recs, err := h.svc.GetRecommendations(id, 10) if err != nil { log.Printf("recommendations error for %d: %v", id, err) http.Error(w, "Failed to fetch recommendations", http.StatusInternalServerError) diff --git a/internal/features/anime/service.go b/internal/features/anime/service.go index b9946e7..aa52250 100644 --- a/internal/features/anime/service.go +++ b/internal/features/anime/service.go @@ -65,8 +65,8 @@ func (s *Service) GetSchedule(day string) (jikan.ScheduleResult, error) { return s.jikanClient.GetSchedule(day) } -func (s *Service) GetRecommendations(animeID int) ([]jikan.Anime, error) { - return s.jikanClient.GetRecommendations(animeID) +func (s *Service) GetRecommendations(animeID int, limit int) ([]jikan.Anime, error) { + return s.jikanClient.GetRecommendations(animeID, limit) } func (s *Service) GetWatchingAnime(ctx context.Context, userID string) ([]templates.WatchingAnimeWithDetails, error) { diff --git a/internal/jikan/recommendations.go b/internal/jikan/recommendations.go index b38bb50..62078f9 100644 --- a/internal/jikan/recommendations.go +++ b/internal/jikan/recommendations.go @@ -21,9 +21,12 @@ type RecommendationsResponse struct { Data []RecommendationEntry `json:"data"` } -// GetRecommendations fetches recommendations for an anime -func (c *Client) GetRecommendations(animeID int) ([]Anime, error) { +// GetRecommendations fetches full details for the top recommended anime +func (c *Client) GetRecommendations(animeID int, limit int) ([]Anime, error) { if cached, ok := c.recsCache.Get(animeID); ok { + if len(cached) > limit { + return cached[:limit], nil + } return cached, nil } @@ -33,27 +36,39 @@ func (c *Client) GetRecommendations(animeID int) ([]Anime, error) { return nil, err } - // Convert to Anime slice (partial data) - animes := make([]Anime, 0, len(result.Data)) - for _, rec := range result.Data { - animes = append(animes, Anime{ - MalID: rec.Entry.MalID, - Title: rec.Entry.Title, - Images: struct { - Jpg struct { - LargeImageURL string `json:"large_image_url"` - } `json:"jpg"` - Webp struct { - LargeImageURL string `json:"large_image_url"` - } `json:"webp"` - }{ - Webp: struct { - LargeImageURL string `json:"large_image_url"` + max := len(result.Data) + if limit > 0 && max > limit { + max = limit + } + + animes := make([]Anime, 0, max) + for i := 0; i < max; i++ { + rec := result.Data[i] + // Fetch full details so we get English/Japanese titles + fullAnime, err := c.GetAnimeByID(rec.Entry.MalID) + if err == nil { + animes = append(animes, fullAnime) + } else { + // Fallback to partial data if full fetch fails + animes = append(animes, Anime{ + MalID: rec.Entry.MalID, + Title: rec.Entry.Title, + Images: struct { + Jpg struct { + LargeImageURL string `json:"large_image_url"` + } `json:"jpg"` + Webp struct { + LargeImageURL string `json:"large_image_url"` + } `json:"webp"` }{ - LargeImageURL: rec.Entry.Images.Webp.LargeImageURL, + Webp: struct { + LargeImageURL string `json:"large_image_url"` + }{ + LargeImageURL: rec.Entry.Images.Webp.LargeImageURL, + }, }, - }, - }) + }) + } } c.recsCache.Add(animeID, animes)