diff --git a/persistence/album_repository.go b/persistence/album_repository.go
index 4a9f73a7e..9c5d5d604 100644
--- a/persistence/album_repository.go
+++ b/persistence/album_repository.go
@@ -24,6 +24,7 @@ func NewAlbumRepository(ctx context.Context, o orm.Ormer) model.AlbumRepository
"artist": "compilation asc, album_artist asc, name asc",
}
r.filterMappings = map[string]filterFunc{
+ "name": fullTextFilter,
"compilation": booleanFilter,
}
diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go
index efb983524..e3411a817 100644
--- a/persistence/artist_repository.go
+++ b/persistence/artist_repository.go
@@ -25,6 +25,9 @@ func NewArtistRepository(ctx context.Context, o orm.Ormer) model.ArtistRepositor
r.ormer = o
r.indexGroups = utils.ParseIndexGroups(conf.Server.IndexGroups)
r.tableName = "artist"
+ r.filterMappings = map[string]filterFunc{
+ "name": fullTextFilter,
+ }
return r
}
diff --git a/persistence/mediafile_repository.go b/persistence/mediafile_repository.go
index 5c5bdce4b..38201529a 100644
--- a/persistence/mediafile_repository.go
+++ b/persistence/mediafile_repository.go
@@ -25,6 +25,9 @@ func NewMediaFileRepository(ctx context.Context, o orm.Ormer) *mediaFileReposito
"artist": "artist asc, album asc, disc_number asc, track_number asc",
"album": "album asc, disc_number asc, track_number asc",
}
+ r.filterMappings = map[string]filterFunc{
+ "title": fullTextFilter,
+ }
return r
}
diff --git a/persistence/sql_base_repository.go b/persistence/sql_base_repository.go
index 5db0cae4f..caa88646a 100644
--- a/persistence/sql_base_repository.go
+++ b/persistence/sql_base_repository.go
@@ -13,6 +13,7 @@ import (
"github.com/deluan/navidrome/model"
"github.com/deluan/rest"
"github.com/google/uuid"
+ "github.com/kennygrant/sanitize"
)
type filterFunc = func(field string, value interface{}) Sqlizer
@@ -249,3 +250,17 @@ func booleanFilter(field string, value interface{}) Sqlizer {
v := strings.ToLower(value.(string))
return Eq{field: strings.ToLower(v) == "true"}
}
+
+func fullTextFilter(field string, value interface{}) Sqlizer {
+ q := value.(string)
+ q = strings.TrimSpace(sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*"))))
+ parts := strings.Split(q, " ")
+ filters := And{}
+ for _, part := range parts {
+ filters = append(filters, Or{
+ Like{"full_text": part + "%"},
+ Like{"full_text": "%" + part + "%"},
+ })
+ }
+ return filters
+}
diff --git a/ui/src/album/AlbumList.js b/ui/src/album/AlbumList.js
index 7c0b35339..894f495c7 100644
--- a/ui/src/album/AlbumList.js
+++ b/ui/src/album/AlbumList.js
@@ -8,7 +8,7 @@ import {
NumberField,
FunctionField,
SearchInput,
- TextInput,
+ NumberInput,
Show,
SimpleShowLayout,
TextField
@@ -19,7 +19,7 @@ import { useMediaQuery } from '@material-ui/core'
const AlbumFilter = (props) => (
-
+
)
diff --git a/ui/src/song/SongList.js b/ui/src/song/SongList.js
index 21614ba05..f200d2441 100644
--- a/ui/src/song/SongList.js
+++ b/ui/src/song/SongList.js
@@ -9,8 +9,7 @@ import {
SearchInput,
Show,
SimpleShowLayout,
- TextField,
- TextInput
+ TextField
} from 'react-admin'
import { useMediaQuery } from '@material-ui/core'
import {
@@ -29,8 +28,6 @@ import { SongBulkActions } from './SongBulkActions'
const SongFilter = (props) => (
-
-
)