refactor: pass watch order mode and paginate command palette

This commit is contained in:
2026-06-12 13:39:58 +02:00
parent 36c0e87ae8
commit 35a367d569
3 changed files with 42 additions and 19 deletions

View File

@@ -1,18 +1,19 @@
package anime package anime
import ( import (
"context"
"fmt" "fmt"
"mal/internal/db" "mal/internal/db"
"mal/internal/domain" "mal/internal/domain"
"mal/internal/server" "mal/internal/server"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
const commandPaletteAnimeLimit = 24
type commandPaletteItem struct { type commandPaletteItem struct {
ID string `json:"id"` ID string `json:"id"`
Type string `json:"type"` Type string `json:"type"`
@@ -23,6 +24,12 @@ type commandPaletteItem struct {
Icon string `json:"icon,omitempty"` Icon string `json:"icon,omitempty"`
} }
type commandPaletteResponse struct {
Items []commandPaletteItem `json:"items"`
HasNextPage bool `json:"hasNextPage"`
NextPage int `json:"nextPage,omitempty"`
}
func (h *AnimeHandler) HandleCommandPalette(c *gin.Context) { func (h *AnimeHandler) HandleCommandPalette(c *gin.Context) {
user := server.CurrentUser(c) user := server.CurrentUser(c)
if user == nil { if user == nil {
@@ -31,24 +38,40 @@ func (h *AnimeHandler) HandleCommandPalette(c *gin.Context) {
} }
query := strings.TrimSpace(c.Query("q")) query := strings.TrimSpace(c.Query("q"))
items := make([]commandPaletteItem, 0, 12) page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
if err != nil || page < 1 {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid page"})
return
}
items := make([]commandPaletteItem, 0, commandPaletteAnimeLimit)
if query != "" { if query != "" {
hasNextPage := false
if len(query) >= 2 { if len(query) >= 2 {
items = append(items, h.commandPaletteAnimeResults(c, query)...) var animeItems []commandPaletteItem
animeItems, hasNextPage = h.commandPaletteAnimeResults(c, query, page)
items = append(items, animeItems...)
} }
items = append(items, h.commandPaletteNavigationItems(query)...) if page == 1 {
items = append(items, h.commandPaletteContinueItems(c, user.ID, query)...) items = append(items, h.commandPaletteNavigationItems(query)...)
items = append(items, h.commandPalettePersonalItems(c, user.ID, query)...) items = append(items, h.commandPaletteContinueItems(c, user.ID, query)...)
c.JSON(http.StatusOK, items) items = append(items, h.commandPalettePersonalItems(c, user.ID, query)...)
}
c.JSON(http.StatusOK, commandPaletteResponse{
Items: items,
HasNextPage: hasNextPage,
NextPage: page + 1,
})
return return
} }
items = append(items, h.commandPaletteContinueItems(c, user.ID, query)...) items = append(items, h.commandPaletteContinueItems(c, user.ID, query)...)
items = append(items, h.commandPaletteNavigationItems(query)...) items = append(items, h.commandPaletteNavigationItems(query)...)
items = append(items, h.commandPalettePersonalItems(c, user.ID, query)...) items = append(items, h.commandPalettePersonalItems(c, user.ID, query)...)
c.JSON(http.StatusOK, items) c.JSON(http.StatusOK, commandPaletteResponse{Items: items})
} }
func (h *AnimeHandler) commandPaletteNavigationItems(query string) []commandPaletteItem { func (h *AnimeHandler) commandPaletteNavigationItems(query string) []commandPaletteItem {
@@ -71,13 +94,10 @@ func (h *AnimeHandler) commandPaletteNavigationItems(query string) []commandPale
return filtered return filtered
} }
func (h *AnimeHandler) commandPaletteAnimeResults(c *gin.Context, query string) []commandPaletteItem { func (h *AnimeHandler) commandPaletteAnimeResults(c *gin.Context, query string, page int) ([]commandPaletteItem, bool) {
searchCtx, cancel := context.WithTimeout(c.Request.Context(), 800*time.Millisecond) res, err := h.svc.SearchAdvanced(c.Request.Context(), query, "", "", "", "", nil, 0, true, page, commandPaletteAnimeLimit)
defer cancel()
res, err := h.svc.SearchAdvanced(searchCtx, query, "", "", "", "", nil, 0, true, 1, 24)
if err != nil { if err != nil {
return nil return nil, false
} }
animes := wrapAnimes(res.Animes) animes := wrapAnimes(res.Animes)
@@ -92,7 +112,7 @@ func (h *AnimeHandler) commandPaletteAnimeResults(c *gin.Context, query string)
Image: anime.ImageURL(), Image: anime.ImageURL(),
}) })
} }
return items return items, res.HasNextPage
} }
func (h *AnimeHandler) commandPalettePersonalItems(c *gin.Context, userID string, query string) []commandPaletteItem { func (h *AnimeHandler) commandPalettePersonalItems(c *gin.Context, userID string, query string) []commandPaletteItem {

View File

@@ -756,11 +756,12 @@ func (h *AnimeHandler) HandleHTMLWatchOrder(c *gin.Context) {
} }
userID := server.CurrentUserID(c) userID := server.CurrentUserID(c)
mode := jikan.NormalizeWatchOrderMode(c.Query("mode"))
relationsCtx, cancel := context.WithTimeout(c.Request.Context(), watchOrderTimeout) relationsCtx, cancel := context.WithTimeout(c.Request.Context(), watchOrderTimeout)
defer cancel() defer cancel()
relations, err := h.svc.GetRelations(relationsCtx, id) relations, err := h.svc.GetRelations(relationsCtx, id, mode)
if err != nil { if err != nil {
observability.Warn( observability.Warn(
"relations_fetch_failed", "relations_fetch_failed",
@@ -774,6 +775,7 @@ func (h *AnimeHandler) HandleHTMLWatchOrder(c *gin.Context) {
c.HTML(http.StatusOK, "anime.gohtml", gin.H{ c.HTML(http.StatusOK, "anime.gohtml", gin.H{
"_fragment": "watch_order_loading", "_fragment": "watch_order_loading",
"AnimeID": id, "AnimeID": id,
"Mode": string(mode),
}) })
return return
} }
@@ -790,6 +792,7 @@ func (h *AnimeHandler) HandleHTMLWatchOrder(c *gin.Context) {
"_fragment": "watch_order", "_fragment": "watch_order",
"Relations": relations, "Relations": relations,
"AnimeID": id, "AnimeID": id,
"Mode": string(mode),
"WatchlistMap": watchlistMap, "WatchlistMap": watchlistMap,
}) })
} }

View File

@@ -588,8 +588,8 @@ func (s *animeService) GetRecommendations(ctx context.Context, id int) ([]domain
return out, nil return out, nil
} }
func (s *animeService) GetRelations(ctx context.Context, id int) ([]jikan.RelationEntry, error) { func (s *animeService) GetRelations(ctx context.Context, id int, mode jikan.WatchOrderMode) ([]jikan.RelationEntry, error) {
return s.jikan.GetFullRelations(ctx, id) return s.jikan.GetFullRelations(ctx, id, mode)
} }
func (s *animeService) WarmDetailSections(id int) { func (s *animeService) WarmDetailSections(id int) {