mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-03 20:47:35 +03:00
158 lines
4 KiB
Go
158 lines
4 KiB
Go
package engine
|
|
|
|
import (
|
|
"strings"
|
|
|
|
"github.com/astaxie/beego"
|
|
"github.com/cloudsonic/sonic-server/domain"
|
|
"github.com/deluan/gomate"
|
|
"github.com/kennygrant/sanitize"
|
|
)
|
|
|
|
type Search interface {
|
|
ClearAll() error
|
|
IndexArtist(ar *domain.Artist) error
|
|
IndexAlbum(al *domain.Album) error
|
|
IndexMediaFile(mf *domain.MediaFile) error
|
|
|
|
RemoveArtist(ids ...string) error
|
|
RemoveAlbum(ids ...string) error
|
|
RemoveMediaFile(ids ...string) error
|
|
|
|
SearchArtist(q string, offset int, size int) (Entries, error)
|
|
SearchAlbum(q string, offset int, size int) (Entries, error)
|
|
SearchSong(q string, offset int, size int) (Entries, error)
|
|
}
|
|
|
|
type search struct {
|
|
artistRepo domain.ArtistRepository
|
|
albumRepo domain.AlbumRepository
|
|
mfileRepo domain.MediaFileRepository
|
|
idxArtist gomate.Indexer
|
|
idxAlbum gomate.Indexer
|
|
idxSong gomate.Indexer
|
|
sArtist gomate.Searcher
|
|
sAlbum gomate.Searcher
|
|
sSong gomate.Searcher
|
|
}
|
|
|
|
func NewSearch(ar domain.ArtistRepository, alr domain.AlbumRepository, mr domain.MediaFileRepository, db gomate.DB) Search {
|
|
s := &search{artistRepo: ar, albumRepo: alr, mfileRepo: mr}
|
|
s.idxArtist = gomate.NewIndexer(db, "gomate-artist-idx")
|
|
s.sArtist = gomate.NewSearcher(db, "gomate-artist-idx")
|
|
s.idxAlbum = gomate.NewIndexer(db, "gomate-album-idx")
|
|
s.sAlbum = gomate.NewSearcher(db, "gomate-album-idx")
|
|
s.idxSong = gomate.NewIndexer(db, "gomate-song-idx")
|
|
s.sSong = gomate.NewSearcher(db, "gomate-song-idx")
|
|
return s
|
|
}
|
|
|
|
func (s *search) ClearAll() error {
|
|
if err := s.idxArtist.Clear(); err != nil {
|
|
return err
|
|
}
|
|
if err := s.idxAlbum.Clear(); err != nil {
|
|
return err
|
|
}
|
|
if err := s.idxSong.Clear(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (s *search) IndexArtist(ar *domain.Artist) error {
|
|
return s.idxArtist.Index(ar.Id, sanitize.Accents(strings.ToLower(ar.Name)))
|
|
}
|
|
|
|
func (s *search) IndexAlbum(al *domain.Album) error {
|
|
return s.idxAlbum.Index(al.Id, sanitize.Accents(strings.ToLower(al.Name)))
|
|
}
|
|
|
|
func (s *search) IndexMediaFile(mf *domain.MediaFile) error {
|
|
return s.idxSong.Index(mf.Id, sanitize.Accents(strings.ToLower(mf.Title)))
|
|
}
|
|
|
|
func (s *search) RemoveArtist(ids ...string) error {
|
|
return s.idxArtist.Remove(ids...)
|
|
}
|
|
|
|
func (s *search) RemoveAlbum(ids ...string) error {
|
|
return s.idxAlbum.Remove(ids...)
|
|
}
|
|
|
|
func (s *search) RemoveMediaFile(ids ...string) error {
|
|
return s.idxSong.Remove(ids...)
|
|
}
|
|
|
|
func (s *search) SearchArtist(q string, offset int, size int) (Entries, error) {
|
|
q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
|
|
min := offset
|
|
max := min + size - 1
|
|
resp, err := s.sArtist.Search(q, min, max)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
res := make(Entries, 0, len(resp))
|
|
for _, id := range resp {
|
|
a, err := s.artistRepo.Get(id)
|
|
if criticalError("Artist", id, err) {
|
|
return nil, err
|
|
}
|
|
if err == nil {
|
|
res = append(res, FromArtist(a))
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (s *search) SearchAlbum(q string, offset int, size int) (Entries, error) {
|
|
q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
|
|
min := offset
|
|
max := min + size - 1
|
|
resp, err := s.sAlbum.Search(q, min, max)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
res := make(Entries, 0, len(resp))
|
|
for _, id := range resp {
|
|
al, err := s.albumRepo.Get(id)
|
|
if criticalError("Album", id, err) {
|
|
return nil, err
|
|
}
|
|
if err == nil {
|
|
res = append(res, FromAlbum(al))
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func (s *search) SearchSong(q string, offset int, size int) (Entries, error) {
|
|
q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
|
|
min := offset
|
|
max := min + size - 1
|
|
resp, err := s.sSong.Search(q, min, max)
|
|
if err != nil {
|
|
return nil, nil
|
|
}
|
|
res := make(Entries, 0, len(resp))
|
|
for _, id := range resp {
|
|
mf, err := s.mfileRepo.Get(id)
|
|
if criticalError("Song", id, err) {
|
|
return nil, err
|
|
}
|
|
if err == nil {
|
|
res = append(res, FromMediaFile(mf))
|
|
}
|
|
}
|
|
return res, nil
|
|
}
|
|
|
|
func criticalError(kind, id string, err error) bool {
|
|
switch {
|
|
case err != nil:
|
|
return true
|
|
case err == domain.ErrNotFound:
|
|
beego.Warn(kind, "Id", id, "not in the DB. Need a reindex?")
|
|
}
|
|
return false
|
|
}
|