mirror of
https://github.com/sbondCo/Watcharr.git
synced 2026-08-07 07:14:44 +00:00
Games: Support searching with Year or FirstYear filters
This commit is contained in:
@@ -10,6 +10,7 @@ These changes are awaiting release:
|
||||
- Import(text list): Support parsing a rating (out of 10, supporting decimals) in square brackets.
|
||||
- Show `End Year` for TV Shows that have ended or been canceled.
|
||||
- Add full release date and last release date to their respective year elements as titles (browser tooltip).
|
||||
- Search: Support inline filters for Non-Multi searches (ex: You can now search `Spider Man year:2026` or `Spider Man fyear:2026` if you care strictly about the first release year).
|
||||
|
||||
## Changed
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/sbondCo/Watcharr/config"
|
||||
"github.com/sbondCo/Watcharr/database/entity"
|
||||
"github.com/sbondCo/Watcharr/domain"
|
||||
"github.com/sbondCo/Watcharr/media/igdb"
|
||||
"github.com/sbondCo/Watcharr/media/tmdb"
|
||||
"github.com/sbondCo/Watcharr/util"
|
||||
"gorm.io/gorm"
|
||||
@@ -80,7 +81,10 @@ func (s *Service) Search(
|
||||
Page: pp.Page,
|
||||
Adult: qfilters.Adult,
|
||||
}
|
||||
if err := s.searchMulti(sreq, &resp); err != nil {
|
||||
greq := igdb.SearchOptions{
|
||||
Query: query,
|
||||
}
|
||||
if err := s.searchMulti(sreq, greq, &resp); err != nil {
|
||||
return resp, errors.New("multi search failed")
|
||||
}
|
||||
case domain.SearchTypeMovie:
|
||||
@@ -119,7 +123,12 @@ func (s *Service) Search(
|
||||
return resp, errors.New("person search failed")
|
||||
}
|
||||
case domain.SearchTypeGame:
|
||||
if err := s.searchGame(r.Query, pp.Page, &resp); err != nil {
|
||||
greq := igdb.SearchOptions{
|
||||
Query: query,
|
||||
Year: qfilters.Year,
|
||||
PrimaryYear: qfilters.FirstYear,
|
||||
}
|
||||
if err := s.searchGame(greq, &resp); err != nil {
|
||||
return resp, errors.New("game search failed")
|
||||
}
|
||||
}
|
||||
@@ -132,6 +141,7 @@ func (s *Service) Search(
|
||||
// SearchMulti is TMDB Multi search but with game data added to first page.
|
||||
func (s *Service) searchMulti(
|
||||
req tmdb.SearchUniversalOptions,
|
||||
igdbReq igdb.SearchOptions,
|
||||
resp *domain.SearchResponse,
|
||||
) error {
|
||||
slog.Debug("searchMulti: Running.", "req", req)
|
||||
@@ -149,7 +159,7 @@ func (s *Service) searchMulti(
|
||||
}
|
||||
// IGDB (we will only get results for the first page)
|
||||
if req.Page == 1 && s.cfg.TwitchEnabled() {
|
||||
igdbRes, err := s.cfg.TWITCH.Search(req.Query)
|
||||
igdbRes, err := s.cfg.TWITCH.Search(igdbReq)
|
||||
if err != nil {
|
||||
slog.Error("SearchMulti: Failed to search igdb!", "error", err)
|
||||
return errors.New("content request failed")
|
||||
@@ -278,12 +288,11 @@ func (s *Service) searchPeople(
|
||||
}
|
||||
|
||||
func (s *Service) searchGame(
|
||||
query string,
|
||||
page int,
|
||||
req igdb.SearchOptions,
|
||||
resp *domain.SearchResponse,
|
||||
) error {
|
||||
slog.Debug("searchGame: Running.", "query", query, "page", page)
|
||||
igdbRes, err := s.cfg.TWITCH.Search(query)
|
||||
slog.Debug("searchGame: Running.", "req", req)
|
||||
igdbRes, err := s.cfg.TWITCH.Search(req)
|
||||
if err != nil {
|
||||
slog.Error("searchGame: Failed to search igdb!", "error", err)
|
||||
return errors.New("content request failed")
|
||||
|
||||
@@ -183,19 +183,68 @@ func (i *IGDB) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *IGDB) Search(q string) (GameSearchResponse, error) {
|
||||
slog.Debug("Search:", "query", q)
|
||||
type SearchOptions struct {
|
||||
Query string
|
||||
Year int
|
||||
PrimaryYear int
|
||||
}
|
||||
|
||||
// Turn supported filters from the SearchOptions struct into a `where` we can
|
||||
// send to APICalypse.
|
||||
func (o SearchOptions) AsWhere() string {
|
||||
f := []string{}
|
||||
if o.Year != 0 {
|
||||
y := strconv.Itoa(o.Year)
|
||||
// If `any` release of the game was on this year.
|
||||
f = append(f, "release_dates.y = "+y)
|
||||
}
|
||||
if o.PrimaryYear != 0 {
|
||||
start := strconv.FormatInt(
|
||||
time.
|
||||
Date(o.PrimaryYear, time.January, 1, 0, 0, 0, 0, time.UTC).
|
||||
Unix(),
|
||||
10)
|
||||
end := strconv.FormatInt(
|
||||
time.
|
||||
// We add one to the year and get the first day of the next year
|
||||
// BUT because day=0, we go back one day and end up with the
|
||||
// very last day of `PrimaryYear`.
|
||||
Date(o.PrimaryYear+1, time.January, 0, 23, 59, 59, 0, time.UTC).
|
||||
Unix(),
|
||||
10)
|
||||
// If `first` release of the game was on this year.
|
||||
f = append(f, "first_release_date > "+start)
|
||||
f = append(f, "first_release_date < "+end)
|
||||
}
|
||||
if len(f) <= 0 {
|
||||
return ""
|
||||
}
|
||||
return "where " + strings.Join(f, " & ") + ";"
|
||||
|
||||
}
|
||||
|
||||
func (i *IGDB) Search(o SearchOptions) (GameSearchResponse, error) {
|
||||
slog.Debug("Search:", "query", o.Query)
|
||||
var resp GameSearchResponse
|
||||
cacheKey := cache.CreateCacheKey("Search", q)
|
||||
cacheKey := cache.CreateCacheKey(
|
||||
"Search",
|
||||
o.Query,
|
||||
o.Year,
|
||||
o.PrimaryYear)
|
||||
if cache.GetCache(GameStore, cacheKey, &resp) {
|
||||
slog.Debug("Search: Returning cache.")
|
||||
return resp, nil
|
||||
}
|
||||
apiQuery := "fields " + fieldsForSearch + "; search \"" + o.Query + "\"; limit 40;"
|
||||
whereQ := o.AsWhere()
|
||||
if whereQ != "" {
|
||||
apiQuery += whereQ
|
||||
}
|
||||
err := i.req(
|
||||
igdbHost,
|
||||
"/games",
|
||||
map[string]string{},
|
||||
"fields "+fieldsForSearch+"; search \""+q+"\"; limit 40;",
|
||||
apiQuery,
|
||||
&resp,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user