feat: add genres filter to browse page

This commit is contained in:
2026-05-02 16:08:46 +02:00
committed by Mikkel Elvers
parent 4869bc055d
commit 056b5ad93e
4 changed files with 57 additions and 5 deletions

View File

@@ -119,11 +119,24 @@ func (h *Handler) HandleBrowse(w http.ResponseWriter, r *http.Request) {
orderBy := r.URL.Query().Get("order_by")
sort := r.URL.Query().Get("sort")
res, err := h.jikanClient.SearchAdvanced(r.Context(), q, animeType, status, orderBy, sort, 1, 24)
var genres []int
for _, g := range r.URL.Query()["genres"] {
id, err := strconv.Atoi(g)
if err == nil {
genres = append(genres, id)
}
}
res, err := h.jikanClient.SearchAdvanced(r.Context(), q, animeType, status, orderBy, sort, genres, 1, 24)
if err != nil {
log.Printf("browse error: %v", err)
}
genresList, err := h.jikanClient.GetAnimeGenres(r.Context())
if err != nil {
log.Printf("genres error: %v", err)
}
watchlistMap := make(map[int64]bool)
var watchlistIDs []int64
if user != nil {
@@ -137,12 +150,14 @@ func (h *Handler) HandleBrowse(w http.ResponseWriter, r *http.Request) {
if err := templates.GetRenderer().ExecuteTemplate(w, "browse.gohtml", map[string]any{
"User": user,
"CurrentPath": r.URL.Path,
"CurrentPath": r.URL.Path,
"Query": q,
"Type": animeType,
"Status": status,
"OrderBy": orderBy,
"Sort": sort,
"Genres": genres,
"GenresList": genresList,
"Animes": res.Animes,
"WatchlistMap": watchlistMap,
"WatchlistIDs": watchlistIDs,
@@ -255,7 +270,7 @@ func (h *Handler) HandleQuickSearch(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode([]quickSearchResult{})
return
}
res, err := h.jikanClient.SearchAdvanced(r.Context(), query, "", "", "", "", 1, 5)
res, err := h.jikanClient.SearchAdvanced(r.Context(), query, "", "", "", "", nil, 1, 5)
if err != nil {
log.Printf("quick search error: %v", err)
w.WriteHeader(http.StatusOK)

View File

@@ -3,3 +3,4 @@ package jikan
import "time"
const shortCacheTTL = time.Hour
const longCacheTTL = time.Hour * 24

View File

@@ -4,13 +4,15 @@ import (
"context"
"fmt"
"net/url"
"strconv"
"strings"
)
func (c *Client) Search(ctx context.Context, query string, page int) (SearchResult, error) {
return c.search(ctx, query, page, 0)
}
func (c *Client) SearchAdvanced(ctx context.Context, query, animeType, status, orderBy, sort string, page, limit int) (SearchResult, error) {
func (c *Client) SearchAdvanced(ctx context.Context, query, animeType, status, orderBy, sort string, genres []int, page, limit int) (SearchResult, error) {
if page < 1 {
page = 1
}
@@ -18,7 +20,16 @@ func (c *Client) SearchAdvanced(ctx context.Context, query, animeType, status, o
limit = 0
}
cacheKey := fmt.Sprintf("search:%s:%s:%s:%s:%s:%d:%d", query, animeType, status, orderBy, sort, page, limit)
genresParam := ""
if len(genres) > 0 {
ids := make([]string, len(genres))
for i, g := range genres {
ids[i] = strconv.Itoa(g)
}
genresParam = strings.Join(ids, ",")
}
cacheKey := fmt.Sprintf("search:%s:%s:%s:%s:%s:%s:%d:%d", query, animeType, status, orderBy, sort, genresParam, page, limit)
var result SearchResponse
reqURL := fmt.Sprintf("%s/anime?page=%d", c.baseURL, page)
@@ -37,6 +48,9 @@ func (c *Client) SearchAdvanced(ctx context.Context, query, animeType, status, o
if sort != "" {
reqURL += "&sort=" + url.QueryEscape(sort)
}
if genresParam != "" {
reqURL += "&genres=" + genresParam
}
if limit > 0 {
reqURL += fmt.Sprintf("&limit=%d", limit)
}
@@ -127,3 +141,16 @@ func (c *Client) GetTopAnime(ctx context.Context, page int) (TopAnimeResult, err
HasNextPage: result.Pagination.HasNextPage,
}, nil
}
func (c *Client) GetAnimeGenres(ctx context.Context) ([]Genre, error) {
const cacheKey = "anime_genres"
var result GenresResponse
reqURL := fmt.Sprintf("%s/genres/anime", c.baseURL)
if err := c.getWithCache(ctx, cacheKey, longCacheTTL, reqURL, &result); err != nil {
return nil, err
}
return result.Data, nil
}

View File

@@ -143,6 +143,15 @@ type AnimeResponse struct {
Data Anime `json:"data"`
}
type Genre struct {
MalID int `json:"mal_id"`
Name string `json:"name"`
}
type GenresResponse struct {
Data []Genre `json:"data"`
}
type SearchResponse struct {
Data []Anime `json:"data"`
Pagination Pagination `json:"pagination"`