diff --git a/controllers/api_agents.go b/controllers/api_agents.go index 0dc48ee..1d18df5 100644 --- a/controllers/api_agents.go +++ b/controllers/api_agents.go @@ -2,6 +2,7 @@ package controllers import ( "net/http" + "sort" "strconv" "strings" @@ -45,6 +46,7 @@ func (p *AgentsAPI) Setup(router *router.Router[*core.RequestEvent], ia pagemode func (p *AgentsAPI) searchHandler(app core.App) HandleFunc { return func(e *core.RequestEvent) error { query := strings.TrimSpace(e.Request.URL.Query().Get("q")) + queryLower := strings.ToLower(query) limit := parseAgentsLimit(e.Request.URL.Query().Get("limit")) results, err := dbmodels.TitleSearchAgents(app, query) @@ -55,6 +57,35 @@ func (p *AgentsAPI) searchHandler(app core.App) HandleFunc { }) } + if queryLower != "" { + sort.SliceStable(results, func(i, j int) bool { + ai := results[i] + aj := results[j] + if ai == nil && aj == nil { + return false + } + if ai == nil { + return false + } + if aj == nil { + return true + } + aiName := strings.ToLower(ai.Name()) + ajName := strings.ToLower(aj.Name()) + aiExact := aiName == queryLower + ajExact := ajName == queryLower + if aiExact != ajExact { + return aiExact && !ajExact + } + aiPrefix := strings.HasPrefix(aiName, queryLower) + ajPrefix := strings.HasPrefix(ajName, queryLower) + if aiPrefix == ajPrefix { + return false + } + return aiPrefix && !ajPrefix + }) + } + seen := map[string]bool{} response := make([]map[string]string, 0, len(results)) for _, agent := range results { diff --git a/controllers/api_places.go b/controllers/api_places.go index de9529e..643fdc3 100644 --- a/controllers/api_places.go +++ b/controllers/api_places.go @@ -2,6 +2,7 @@ package controllers import ( "net/http" + "sort" "strconv" "strings" @@ -45,6 +46,7 @@ func (p *PlacesAPI) Setup(router *router.Router[*core.RequestEvent], ia pagemode func (p *PlacesAPI) searchHandler(app core.App) HandleFunc { return func(e *core.RequestEvent) error { query := strings.TrimSpace(e.Request.URL.Query().Get("q")) + queryLower := strings.ToLower(query) limit := parseLimit(e.Request.URL.Query().Get("limit")) results, err := dbmodels.SearchPlaces(app, query, limit) @@ -55,6 +57,35 @@ func (p *PlacesAPI) searchHandler(app core.App) HandleFunc { }) } + if queryLower != "" { + sort.SliceStable(results, func(i, j int) bool { + ai := results[i] + aj := results[j] + if ai == nil && aj == nil { + return false + } + if ai == nil { + return false + } + if aj == nil { + return true + } + aiName := strings.ToLower(ai.Name()) + ajName := strings.ToLower(aj.Name()) + aiExact := aiName == queryLower + ajExact := ajName == queryLower + if aiExact != ajExact { + return aiExact && !ajExact + } + aiPrefix := strings.HasPrefix(aiName, queryLower) + ajPrefix := strings.HasPrefix(ajName, queryLower) + if aiPrefix == ajPrefix { + return false + } + return aiPrefix && !ajPrefix + }) + } + response := make([]map[string]string, 0, len(results)) for _, place := range results { if place == nil { diff --git a/controllers/api_series.go b/controllers/api_series.go index f050c97..bfde943 100644 --- a/controllers/api_series.go +++ b/controllers/api_series.go @@ -2,6 +2,7 @@ package controllers import ( "net/http" + "sort" "strconv" "strings" @@ -45,6 +46,7 @@ func (p *SeriesAPI) Setup(router *router.Router[*core.RequestEvent], ia pagemode func (p *SeriesAPI) searchHandler(app core.App) HandleFunc { return func(e *core.RequestEvent) error { query := strings.TrimSpace(e.Request.URL.Query().Get("q")) + queryLower := strings.ToLower(query) limit := parseSeriesLimit(e.Request.URL.Query().Get("limit")) primary, alt, err := dbmodels.BasicSearchSeries(app, query) @@ -56,6 +58,34 @@ func (p *SeriesAPI) searchHandler(app core.App) HandleFunc { } results := append(primary, alt...) + if queryLower != "" { + sort.SliceStable(results, func(i, j int) bool { + ai := results[i] + aj := results[j] + if ai == nil && aj == nil { + return false + } + if ai == nil { + return false + } + if aj == nil { + return true + } + aiTitle := strings.ToLower(ai.Title()) + ajTitle := strings.ToLower(aj.Title()) + aiExact := aiTitle == queryLower + ajExact := ajTitle == queryLower + if aiExact != ajExact { + return aiExact && !ajExact + } + aiPrefix := strings.HasPrefix(aiTitle, queryLower) + ajPrefix := strings.HasPrefix(ajTitle, queryLower) + if aiPrefix == ajPrefix { + return false + } + return aiPrefix && !ajPrefix + }) + } seen := map[string]bool{} response := make([]map[string]string, 0, len(results)) for _, series := range results {