feat(jikan): add advanced search and video episodes support
This commit is contained in:
@@ -19,6 +19,19 @@ func (c *Client) GetEpisodes(ctx context.Context, animeID int, page int) (Episod
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetVideoEpisodes(ctx context.Context, animeID int, page int) (EpisodesResponse, error) {
|
||||||
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheKey := fmt.Sprintf("anime:%d:videos:episodes:%d", animeID, page)
|
||||||
|
var result EpisodesResponse
|
||||||
|
reqURL := fmt.Sprintf("%s/anime/%d/videos/episodes?page=%d", c.baseURL, animeID, page)
|
||||||
|
|
||||||
|
err := c.getWithCache(ctx, cacheKey, 12*time.Hour, reqURL, &result)
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Client) GetEpisode(ctx context.Context, animeID int, episode int) (EpisodeResponse, error) {
|
func (c *Client) GetEpisode(ctx context.Context, animeID int, episode int) (EpisodeResponse, error) {
|
||||||
cacheKey := fmt.Sprintf("anime:%d:episode:%d", animeID, episode)
|
cacheKey := fmt.Sprintf("anime:%d:episode:%d", animeID, episode)
|
||||||
var result EpisodeResponse
|
var result EpisodeResponse
|
||||||
|
|||||||
@@ -10,8 +10,53 @@ func (c *Client) Search(ctx context.Context, query string, page int) (SearchResu
|
|||||||
return c.search(ctx, query, page, 0)
|
return c.search(ctx, query, page, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) SearchWithLimit(ctx context.Context, query string, page int, limit int) (SearchResult, error) {
|
func (c *Client) SearchAdvanced(ctx context.Context, query, animeType, status, orderBy, sort string, page, limit int) (SearchResult, error) {
|
||||||
return c.search(ctx, query, page, limit)
|
if page < 1 {
|
||||||
|
page = 1
|
||||||
|
}
|
||||||
|
if limit < 0 {
|
||||||
|
limit = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
cacheKey := fmt.Sprintf("search:%s:%s:%s:%s:%s:%d:%d", query, animeType, status, orderBy, sort, page, limit)
|
||||||
|
|
||||||
|
var result SearchResponse
|
||||||
|
reqURL := fmt.Sprintf("%s/anime?page=%d", c.baseURL, page)
|
||||||
|
if query != "" {
|
||||||
|
reqURL += "&q=" + url.QueryEscape(query)
|
||||||
|
}
|
||||||
|
if animeType != "" {
|
||||||
|
reqURL += "&type=" + url.QueryEscape(animeType)
|
||||||
|
}
|
||||||
|
if status != "" {
|
||||||
|
reqURL += "&status=" + url.QueryEscape(status)
|
||||||
|
}
|
||||||
|
if orderBy != "" {
|
||||||
|
reqURL += "&order_by=" + url.QueryEscape(orderBy)
|
||||||
|
}
|
||||||
|
if sort != "" {
|
||||||
|
reqURL += "&sort=" + url.QueryEscape(sort)
|
||||||
|
}
|
||||||
|
if limit > 0 {
|
||||||
|
reqURL += fmt.Sprintf("&limit=%d", limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.getWithCache(ctx, cacheKey, shortCacheTTL, reqURL, &result); err != nil {
|
||||||
|
if IsRetryableError(err) {
|
||||||
|
if fallbackErr := c.fetchWithRetry(ctx, reqURL, &result); fallbackErr == nil {
|
||||||
|
return SearchResult{
|
||||||
|
Animes: result.Data,
|
||||||
|
HasNextPage: result.Pagination.HasNextPage,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SearchResult{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchResult{
|
||||||
|
Animes: result.Data,
|
||||||
|
HasNextPage: result.Pagination.HasNextPage,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) search(ctx context.Context, query string, page int, limit int) (SearchResult, error) {
|
func (c *Client) search(ctx context.Context, query string, page int, limit int) (SearchResult, error) {
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ type Anime struct {
|
|||||||
Status string `json:"status"`
|
Status string `json:"status"`
|
||||||
Airing bool `json:"airing"`
|
Airing bool `json:"airing"`
|
||||||
Episodes int `json:"episodes"`
|
Episodes int `json:"episodes"`
|
||||||
|
Score float64 `json:"score"`
|
||||||
Season string `json:"season"`
|
Season string `json:"season"`
|
||||||
Year int `json:"year"`
|
Year int `json:"year"`
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
@@ -159,8 +160,14 @@ type TopAnimeResponse struct {
|
|||||||
type Episode struct {
|
type Episode struct {
|
||||||
MalID int `json:"mal_id"`
|
MalID int `json:"mal_id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
|
Episode string `json:"episode"`
|
||||||
Filler bool `json:"filler"`
|
Filler bool `json:"filler"`
|
||||||
Recap bool `json:"recap"`
|
Recap bool `json:"recap"`
|
||||||
|
Images *struct {
|
||||||
|
Jpg struct {
|
||||||
|
ImageURL string `json:"image_url"`
|
||||||
|
} `json:"jpg"`
|
||||||
|
} `json:"images,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EpisodesResponse struct {
|
type EpisodesResponse struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user