diff --git a/internal/anime/handler/handler.go b/internal/anime/handler/handler.go index 22d0f39..debc670 100644 --- a/internal/anime/handler/handler.go +++ b/internal/anime/handler/handler.go @@ -22,6 +22,14 @@ type AnimeHandler struct { watchlistSvc domain.WatchlistService } +func wrapAnimes(in []jikan.Anime) []domain.Anime { + out := make([]domain.Anime, 0, len(in)) + for _, a := range in { + out = append(out, domain.Anime{Anime: a}) + } + return out +} + func NewAnimeHandler(svc domain.AnimeService, watchlistSvc domain.WatchlistService) *AnimeHandler { return &AnimeHandler{ svc: svc, @@ -405,7 +413,8 @@ func (h *AnimeHandler) HandleBrowse(c *gin.Context) { if u, ok := user.(*domain.User); ok { userID = u.ID } - watchlistMap := h.watchlistMapForAnimes(c.Request.Context(), userID, res.Animes) + animes := wrapAnimes(res.Animes) + watchlistMap := h.watchlistMapForAnimes(c.Request.Context(), userID, animes) studioName := "" if studioID > 0 { @@ -417,10 +426,10 @@ func (h *AnimeHandler) HandleBrowse(c *gin.Context) { if c.GetHeader("HX-Request") == "true" && page > 1 { c.HTML(http.StatusOK, "browse.gohtml", gin.H{ - "_fragment": "anime_card_scroll", - "Animes": res.Animes, - "NextPage": page + 1, - "HasNextPage": res.HasNextPage, + "_fragment": "anime_card_scroll", + "Animes": animes, + "NextPage": page + 1, + "HasNextPage": res.HasNextPage, "Query": q, "Type": animeType, "Status": status, @@ -450,9 +459,9 @@ func (h *AnimeHandler) HandleBrowse(c *gin.Context) { "Studio": studioID, "StudioName": studioName, "SFW": sfw, - "GenresList": genresList, - "Animes": res.Animes, - "HasNextPage": res.HasNextPage, + "GenresList": genresList, + "Animes": animes, + "HasNextPage": res.HasNextPage, "NextPage": page + 1, "User": user, "WatchlistMap": watchlistMap, @@ -472,8 +481,8 @@ func (h *AnimeHandler) HandleBrowse(c *gin.Context) { "StudioName": studioName, "SFW": sfw, "GenresList": genresList, - "Animes": res.Animes, - "HasNextPage": res.HasNextPage, + "Animes": animes, + "HasNextPage": res.HasNextPage, "NextPage": page + 1, "User": user, "WatchlistMap": watchlistMap, @@ -634,7 +643,8 @@ func (h *AnimeHandler) HandleQuickSearch(c *gin.Context) { if u, ok := user.(*domain.User); ok { userID = u.ID } - watchlistMap := h.watchlistMapForAnimes(c.Request.Context(), userID, res.Animes) + animes := wrapAnimes(res.Animes) + watchlistMap := h.watchlistMapForAnimes(c.Request.Context(), userID, animes) type quickSearchResult struct { ID int `json:"id"` @@ -645,8 +655,8 @@ func (h *AnimeHandler) HandleQuickSearch(c *gin.Context) { InWatchlist bool `json:"in_watchlist"` } - output := make([]quickSearchResult, len(res.Animes)) - for i, anime := range res.Animes { + output := make([]quickSearchResult, len(animes)) + for i, anime := range animes { output[i] = quickSearchResult{ ID: anime.MalID, Title: anime.DisplayTitle(), @@ -736,8 +746,9 @@ func (h *AnimeHandler) commandPaletteAnimeResults(c *gin.Context, query string) return nil } - items := make([]commandPaletteItem, 0, len(res.Animes)) - for _, anime := range res.Animes { + animes := wrapAnimes(res.Animes) + items := make([]commandPaletteItem, 0, len(animes)) + for _, anime := range animes { items = append(items, commandPaletteItem{ ID: fmt.Sprintf("anime:%d", anime.MalID), Type: "anime", diff --git a/internal/anime/service/service.go b/internal/anime/service/service.go index f6e19d7..e529f69 100644 --- a/internal/anime/service/service.go +++ b/internal/anime/service/service.go @@ -21,6 +21,14 @@ type animeService struct { repo domain.AnimeRepository } +func wrapAnimes(in []jikan.Anime) []domain.Anime { + out := make([]domain.Anime, 0, len(in)) + for _, a := range in { + out = append(out, domain.Anime{Anime: a}) + } + return out +} + func NewAnimeService(jikan *jikan.Client, repo domain.AnimeRepository) domain.AnimeService { return &animeService{jikan: jikan, repo: repo} } @@ -56,7 +64,7 @@ func (s *animeService) GetCatalogSection(ctx context.Context, userID string, sec return domain.CatalogSectionData{}, err } - animes := res.Animes + animes := wrapAnimes(res.Animes) if len(animes) > 6 { animes = animes[:6] } @@ -89,7 +97,7 @@ func (s *animeService) GetDiscoverSection(ctx context.Context, userID string, se return domain.DiscoverSectionData{}, err } - animes := res.Animes + animes := wrapAnimes(res.Animes) if len(animes) > 8 { animes = animes[:8] } @@ -197,7 +205,7 @@ func (s *animeService) GetDiscoverForYou(ctx context.Context, userID string) (do ) continue } - animes = append(animes, anime) + animes = append(animes, domain.Anime{Anime: anime}) } return domain.DiscoverSectionData{Animes: animes}, nil @@ -247,7 +255,7 @@ func (s *animeService) GetAiringSchedule(ctx context.Context, userID string) ([] return fetchErr } mu.Lock() - animes = append(animes, anime) + animes = append(animes, domain.Anime{Anime: anime}) mu.Unlock() return nil }) @@ -271,7 +279,11 @@ func (s *animeService) GetAiringSchedule(ctx context.Context, userID string) ([] } func (s *animeService) GetAnimeByID(ctx context.Context, id int) (domain.Anime, error) { - return s.jikan.GetAnimeByID(ctx, id) + anime, err := s.jikan.GetAnimeByID(ctx, id) + if err != nil { + return domain.Anime{}, err + } + return domain.Anime{Anime: anime}, nil } func (s *animeService) SearchAdvanced(ctx context.Context, q, animeType, status, orderBy, sort string, genres []int, studioID int, sfw bool, page, limit int) (jikan.SearchResult, error) { @@ -341,7 +353,7 @@ func (s *animeService) GetRandomAnime(ctx context.Context) (domain.Anime, error) anime, err := s.jikan.GetRandomAnime(randomCtx) if err == nil { - return anime, nil + return domain.Anime{Anime: anime}, nil } for _, fallback := range []func(context.Context, int) (jikan.TopAnimeResult, error){ @@ -350,12 +362,12 @@ func (s *animeService) GetRandomAnime(ctx context.Context) (domain.Anime, error) s.jikan.GetSeasonsUpcoming, } { res, fallbackErr := fallback(ctx, 1) - if fallbackErr != nil || len(res.Animes) == 0 { - continue + if fallbackErr != nil || len(res.Animes) == 0 { + continue + } + r := rand.New(rand.NewSource(time.Now().UnixNano())) + return domain.Anime{Anime: res.Animes[r.Intn(len(res.Animes))]}, nil } - r := rand.New(rand.NewSource(time.Now().UnixNano())) - return res.Animes[r.Intn(len(res.Animes))], nil - } return domain.Anime{}, err } diff --git a/internal/domain/anime.go b/internal/domain/anime.go index 9c8f008..7372cf4 100644 --- a/internal/domain/anime.go +++ b/internal/domain/anime.go @@ -6,7 +6,9 @@ import ( "mal/internal/db" ) -type Anime = jikan.Anime +type Anime struct { + jikan.Anime +} type TopAnimeResult = jikan.TopAnimeResult type Genre = jikan.Genre type Character = jikan.CharacterEntry diff --git a/internal/episodes/service/service.go b/internal/episodes/service/service.go index 5329973..50a8d4d 100644 --- a/internal/episodes/service/service.go +++ b/internal/episodes/service/service.go @@ -94,7 +94,7 @@ func (s *EpisodeService) RefreshTrackedDue(ctx context.Context, limit int) error ) continue } - if _, err := s.refresh(ctx, anime); err != nil { + if _, err := s.refresh(ctx, domain.Anime{Anime: anime}); err != nil { observability.Warn( "episodes_refresh_failed", "episodes", diff --git a/internal/episodes/service/service_test.go b/internal/episodes/service/service_test.go index 986ccf4..4c58f15 100644 --- a/internal/episodes/service/service_test.go +++ b/internal/episodes/service/service_test.go @@ -29,7 +29,7 @@ func TestMergeEpisodesUsesUnionAndSynthesizesProviderOnlyEntries(t *testing.T) { } func TestNextBroadcastAfterUsesJikanTimezone(t *testing.T) { - anime := domain.Anime{MalID: 1} + anime := domain.Anime{Anime: jikan.Anime{MalID: 1}} anime.Broadcast.Day = "Saturdays" anime.Broadcast.Time = "23:00" anime.Broadcast.Timezone = "Asia/Tokyo" @@ -44,7 +44,7 @@ func TestNextBroadcastAfterUsesJikanTimezone(t *testing.T) { } func TestNextRetryTimeWithinAndAfterRetryWindow(t *testing.T) { - anime := domain.Anime{MalID: 1} + anime := domain.Anime{Anime: jikan.Anime{MalID: 1}} anime.Broadcast.Day = "Saturdays" anime.Broadcast.Time = "12:00" anime.Broadcast.Timezone = "UTC" diff --git a/internal/playback/service/service.go b/internal/playback/service/service.go index 1dc6ff1..9cb3e22 100644 --- a/internal/playback/service/service.go +++ b/internal/playback/service/service.go @@ -143,7 +143,7 @@ func (s *playbackService) BuildWatchData(ctx context.Context, animeID int, title } } - canonicalEpisodes, err := s.episodes.GetCanonicalEpisodes(ctx, anime, false) + canonicalEpisodes, err := s.episodes.GetCanonicalEpisodes(ctx, domain.Anime{Anime: anime}, false) if err != nil { return domain.WatchPageData{}, fmt.Errorf("failed to fetch episodes: %w", err) } @@ -289,12 +289,12 @@ func (s *playbackService) BuildWatchData(ctx context.Context, animeID int, title Segments: segments, } - return domain.WatchPageData{ - WatchData: watchData, - Anime: anime, - Episodes: canonicalEpisodes.Episodes, - CurrentEpID: episode, - WatchlistStatus: watchlistStatus, + return domain.WatchPageData{ + WatchData: watchData, + Anime: domain.Anime{Anime: anime}, + Episodes: canonicalEpisodes.Episodes, + CurrentEpID: episode, + WatchlistStatus: watchlistStatus, WatchlistIDs: watchlistIDs, Seasons: seasons, }, nil