feat: add dedicated search API handler
This commit is contained in:
80
internal/anime/search_api.go
Normal file
80
internal/anime/search_api.go
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
package anime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"mal/internal/server"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
const searchAnimeLimit = 24
|
||||||
|
|
||||||
|
type searchItem struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Label string `json:"label"`
|
||||||
|
Subtitle string `json:"subtitle"`
|
||||||
|
Href string `json:"href"`
|
||||||
|
Image string `json:"image,omitempty"`
|
||||||
|
Icon string `json:"icon,omitempty"`
|
||||||
|
InWatchlist bool `json:"inWatchlist,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type searchResponse struct {
|
||||||
|
Items []searchItem `json:"items"`
|
||||||
|
HasNextPage bool `json:"hasNextPage"`
|
||||||
|
NextPage int `json:"nextPage,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *AnimeHandler) HandleSearchAPI(c *gin.Context) {
|
||||||
|
user := server.CurrentUser(c)
|
||||||
|
if user == nil {
|
||||||
|
c.JSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
query := strings.TrimSpace(c.Query("q"))
|
||||||
|
page, err := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||||
|
if err != nil || page < 1 {
|
||||||
|
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid page"})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if query == "" || len(query) < 2 {
|
||||||
|
c.JSON(http.StatusOK, searchResponse{})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
items, hasNextPage := h.searchAnimeResults(c, user.ID, query, page)
|
||||||
|
c.JSON(http.StatusOK, searchResponse{
|
||||||
|
Items: items,
|
||||||
|
HasNextPage: hasNextPage,
|
||||||
|
NextPage: page + 1,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *AnimeHandler) searchAnimeResults(c *gin.Context, userID string, query string, page int) ([]searchItem, bool) {
|
||||||
|
res, err := h.svc.SearchAdvanced(c.Request.Context(), query, "", "", "", "", nil, 0, true, page, searchAnimeLimit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
animes := wrapAnimes(res.Animes)
|
||||||
|
watchlistMap := h.watchlistMapForAnimes(c.Request.Context(), userID, animes)
|
||||||
|
items := make([]searchItem, 0, len(animes))
|
||||||
|
for _, anime := range animes {
|
||||||
|
items = append(items, searchItem{
|
||||||
|
ID: fmt.Sprintf("anime:%d", anime.MalID),
|
||||||
|
Type: "anime",
|
||||||
|
Label: anime.DisplayTitle(),
|
||||||
|
Subtitle: strings.TrimSpace("Anime " + anime.Type),
|
||||||
|
Href: fmt.Sprintf("/anime/%d", anime.MalID),
|
||||||
|
Image: anime.ImageURL(),
|
||||||
|
InWatchlist: watchlistMap[int64(anime.MalID)],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return items, res.HasNextPage
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user