+BUGFIX: better matching for series, persons, places in our API

This commit is contained in:
Simon Martens
2026-01-22 17:13:18 +01:00
parent 163d6cd992
commit 26b7a9dd9b
3 changed files with 92 additions and 0 deletions

View File

@@ -2,6 +2,7 @@ package controllers
import ( import (
"net/http" "net/http"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -45,6 +46,7 @@ func (p *AgentsAPI) Setup(router *router.Router[*core.RequestEvent], ia pagemode
func (p *AgentsAPI) searchHandler(app core.App) HandleFunc { func (p *AgentsAPI) searchHandler(app core.App) HandleFunc {
return func(e *core.RequestEvent) error { return func(e *core.RequestEvent) error {
query := strings.TrimSpace(e.Request.URL.Query().Get("q")) query := strings.TrimSpace(e.Request.URL.Query().Get("q"))
queryLower := strings.ToLower(query)
limit := parseAgentsLimit(e.Request.URL.Query().Get("limit")) limit := parseAgentsLimit(e.Request.URL.Query().Get("limit"))
results, err := dbmodels.TitleSearchAgents(app, query) 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{} seen := map[string]bool{}
response := make([]map[string]string, 0, len(results)) response := make([]map[string]string, 0, len(results))
for _, agent := range results { for _, agent := range results {

View File

@@ -2,6 +2,7 @@ package controllers
import ( import (
"net/http" "net/http"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -45,6 +46,7 @@ func (p *PlacesAPI) Setup(router *router.Router[*core.RequestEvent], ia pagemode
func (p *PlacesAPI) searchHandler(app core.App) HandleFunc { func (p *PlacesAPI) searchHandler(app core.App) HandleFunc {
return func(e *core.RequestEvent) error { return func(e *core.RequestEvent) error {
query := strings.TrimSpace(e.Request.URL.Query().Get("q")) query := strings.TrimSpace(e.Request.URL.Query().Get("q"))
queryLower := strings.ToLower(query)
limit := parseLimit(e.Request.URL.Query().Get("limit")) limit := parseLimit(e.Request.URL.Query().Get("limit"))
results, err := dbmodels.SearchPlaces(app, query, 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)) response := make([]map[string]string, 0, len(results))
for _, place := range results { for _, place := range results {
if place == nil { if place == nil {

View File

@@ -2,6 +2,7 @@ package controllers
import ( import (
"net/http" "net/http"
"sort"
"strconv" "strconv"
"strings" "strings"
@@ -45,6 +46,7 @@ func (p *SeriesAPI) Setup(router *router.Router[*core.RequestEvent], ia pagemode
func (p *SeriesAPI) searchHandler(app core.App) HandleFunc { func (p *SeriesAPI) searchHandler(app core.App) HandleFunc {
return func(e *core.RequestEvent) error { return func(e *core.RequestEvent) error {
query := strings.TrimSpace(e.Request.URL.Query().Get("q")) query := strings.TrimSpace(e.Request.URL.Query().Get("q"))
queryLower := strings.ToLower(query)
limit := parseSeriesLimit(e.Request.URL.Query().Get("limit")) limit := parseSeriesLimit(e.Request.URL.Query().Get("limit"))
primary, alt, err := dbmodels.BasicSearchSeries(app, query) primary, alt, err := dbmodels.BasicSearchSeries(app, query)
@@ -56,6 +58,34 @@ func (p *SeriesAPI) searchHandler(app core.App) HandleFunc {
} }
results := append(primary, alt...) 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{} seen := map[string]bool{}
response := make([]map[string]string, 0, len(results)) response := make([]map[string]string, 0, len(results))
for _, series := range results { for _, series := range results {