From 136afa05a5771fa4da7a6d0c76de3b310999c258 Mon Sep 17 00:00:00 2001 From: mkelvers Date: Thu, 4 Jun 2026 11:28:27 +0200 Subject: [PATCH] feat: wire background warming for detail sections --- internal/anime/handler.go | 24 +++++++++++++++++++++--- internal/anime/service.go | 5 +++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/internal/anime/handler.go b/internal/anime/handler.go index d6c93cd..e01d608 100644 --- a/internal/anime/handler.go +++ b/internal/anime/handler.go @@ -16,6 +16,11 @@ import ( "github.com/gin-gonic/gin" ) +const ( + animeSectionTimeout = 12 * time.Second + watchOrderTimeout = 15 * time.Second +) + type AnimeHandler struct { svc Service watchlistSvc domain.WatchlistService @@ -29,6 +34,7 @@ type Service interface { domain.AnimeDiscoverService domain.AnimeSearchService domain.AnimeDetailsService + WarmDetailSections(id int) } func NewAnimeHandler(svc Service, watchlistSvc domain.WatchlistService) *AnimeHandler { @@ -481,7 +487,7 @@ func (h *AnimeHandler) HandleAnimeDetails(c *gin.Context) { section := c.Query("section") if section != "" && c.GetHeader("HX-Request") == "true" { - sectionCtx, cancel := context.WithTimeout(c.Request.Context(), 4*time.Second) + sectionCtx, cancel := context.WithTimeout(c.Request.Context(), animeSectionTimeout) defer cancel() var data any @@ -514,6 +520,13 @@ func (h *AnimeHandler) HandleAnimeDetails(c *gin.Context) { }, err, ) + if section == "recommendations" { + c.HTML(http.StatusOK, "anime.gohtml", gin.H{ + "_fragment": "anime_recommendations_loading", + "AnimeID": id, + }) + return + } c.Status(http.StatusNoContent) return } @@ -531,6 +544,8 @@ func (h *AnimeHandler) HandleAnimeDetails(c *gin.Context) { return } + h.svc.WarmDetailSections(id) + user := server.CurrentUser(c) status := "" var watchlistIDs []int64 @@ -570,7 +585,7 @@ func (h *AnimeHandler) HandleHTMLWatchOrder(c *gin.Context) { userID := server.CurrentUserID(c) - relationsCtx, cancel := context.WithTimeout(c.Request.Context(), 5*time.Second) + relationsCtx, cancel := context.WithTimeout(c.Request.Context(), watchOrderTimeout) defer cancel() relations, err := h.svc.GetRelations(relationsCtx, id) @@ -584,7 +599,10 @@ func (h *AnimeHandler) HandleHTMLWatchOrder(c *gin.Context) { }, err, ) - c.Status(http.StatusNoContent) + c.HTML(http.StatusOK, "anime.gohtml", gin.H{ + "_fragment": "watch_order_loading", + "AnimeID": id, + }) return } diff --git a/internal/anime/service.go b/internal/anime/service.go index d6fb36e..ad017b1 100644 --- a/internal/anime/service.go +++ b/internal/anime/service.go @@ -400,6 +400,11 @@ func (s *animeService) GetRelations(ctx context.Context, id int) ([]jikan.Relati return s.jikan.GetFullRelations(ctx, id) } +func (s *animeService) WarmDetailSections(id int) { + s.jikan.WarmAnimeRecommendations(id) + s.jikan.WarmFullRelations(id) +} + func (s *animeService) GetEpisodes(ctx context.Context, id int, page int) (jikan.EpisodesResponse, error) { return s.jikan.GetEpisodes(ctx, id, page) }