mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-18 21:07:44 +03:00
Searching by artists, spike mode
This commit is contained in:
parent
29c2925a1c
commit
ef31d1aca0
@ -3,10 +3,11 @@ package api
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/deluan/gosonic/api/responses"
|
||||
"github.com/deluan/gosonic/utils"
|
||||
"time"
|
||||
)
|
||||
|
||||
type BaseAPIController struct{ beego.Controller }
|
||||
@ -23,14 +24,18 @@ func (c *BaseAPIController) RequiredParamString(param string, msg string) string
|
||||
return p
|
||||
}
|
||||
|
||||
func (c *BaseAPIController) ParamString(param string) string {
|
||||
return c.Input().Get(param)
|
||||
}
|
||||
|
||||
func (c *BaseAPIController) ParamTime(param string) time.Time {
|
||||
var value int64
|
||||
c.Ctx.Input.Bind(&value, param)
|
||||
return utils.ToTime(value)
|
||||
}
|
||||
|
||||
func (c *BaseAPIController) ParamInt(param string) int {
|
||||
var value int
|
||||
func (c *BaseAPIController) ParamInt(param string, def int) int {
|
||||
value := def
|
||||
c.Ctx.Input.Bind(&value, param)
|
||||
return value
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ func (c *GetAlbumListController) Get() {
|
||||
c.SendError(responses.ERROR_GENERIC, "Not implemented!")
|
||||
}
|
||||
|
||||
offset := c.ParamInt("offset")
|
||||
size := utils.MinInt(c.ParamInt("size"), 500)
|
||||
offset := c.ParamInt("offset", 0)
|
||||
size := utils.MinInt(c.ParamInt("size", 0), 500)
|
||||
|
||||
albums, err := method(offset, size)
|
||||
if err != nil {
|
||||
|
@ -19,7 +19,7 @@ func (c *GetCoverArtController) Prepare() {
|
||||
|
||||
func (c *GetCoverArtController) Get() {
|
||||
id := c.RequiredParamString("id", "id parameter required")
|
||||
size := c.ParamInt("size")
|
||||
size := c.ParamInt("size", 0)
|
||||
|
||||
err := c.cover.Get(id, size, c.Ctx.ResponseWriter)
|
||||
|
||||
|
@ -6,18 +6,19 @@ import (
|
||||
)
|
||||
|
||||
type Subsonic struct {
|
||||
XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
|
||||
Status string `xml:"status,attr" json:"status"`
|
||||
Version string `xml:"version,attr" json:"version"`
|
||||
Error *Error `xml:"error,omitempty" json:"error,omitempty"`
|
||||
License *License `xml:"license,omitempty" json:"license,omitempty"`
|
||||
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
|
||||
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
|
||||
Directory *Directory `xml:"directory,omitempty" json:"directory,omitempty"`
|
||||
User *User `xml:"user,omitempty" json:"user,omitempty"`
|
||||
AlbumList *AlbumList `xml:"albumList,omitempty" json:"albumList,omitempty"`
|
||||
Playlists *Playlists `xml:"playlists,omitempty" json:"playlists,omitempty"`
|
||||
Playlist *PlaylistWithSongs `xml:"playlist,omitempty" json:"playlist,omitempty"`
|
||||
XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
|
||||
Status string `xml:"status,attr" json:"status"`
|
||||
Version string `xml:"version,attr" json:"version"`
|
||||
Error *Error `xml:"error,omitempty" json:"error,omitempty"`
|
||||
License *License `xml:"license,omitempty" json:"license,omitempty"`
|
||||
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
|
||||
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
|
||||
Directory *Directory `xml:"directory,omitempty" json:"directory,omitempty"`
|
||||
User *User `xml:"user,omitempty" json:"user,omitempty"`
|
||||
AlbumList *AlbumList `xml:"albumList,omitempty" json:"albumList,omitempty"`
|
||||
Playlists *Playlists `xml:"playlists,omitempty" json:"playlists,omitempty"`
|
||||
Playlist *PlaylistWithSongs `xml:"playlist,omitempty" json:"playlist,omitempty"`
|
||||
SearchResult2 *SearchResult2 `xml:"searchResult2,omitempty" json:"searchResult2,omitempty"`
|
||||
}
|
||||
|
||||
type JsonWrapper struct {
|
||||
@ -119,6 +120,12 @@ type PlaylistWithSongs struct {
|
||||
Entry []Child `xml:"entry" json:"entry,omitempty"`
|
||||
}
|
||||
|
||||
type SearchResult2 struct {
|
||||
Artist []Artist `xml:"artist" json:"artist,omitempty"`
|
||||
Album []Child `xml:"album" json:"album,omitempty"`
|
||||
Song []Child `xml:"song" json:"song,omitempty"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `xml:"username,attr" json:"username"`
|
||||
Email string `xml:"email,attr,omitempty" json:"email,omitempty"`
|
||||
|
43
api/search.go
Normal file
43
api/search.go
Normal file
@ -0,0 +1,43 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/deluan/gosonic/api/responses"
|
||||
"github.com/deluan/gosonic/engine"
|
||||
"github.com/deluan/gosonic/utils"
|
||||
"github.com/karlkfi/inject"
|
||||
)
|
||||
|
||||
type SearchingController struct {
|
||||
BaseAPIController
|
||||
search engine.Search
|
||||
}
|
||||
|
||||
func (c *SearchingController) Prepare() {
|
||||
inject.ExtractAssignable(utils.Graph, &c.search)
|
||||
}
|
||||
|
||||
func (c *SearchingController) Search2() {
|
||||
query := c.RequiredParamString("query", "Parameter query required")
|
||||
artistCount := c.ParamInt("artistCount", 20)
|
||||
artistOffset := c.ParamInt("artistOffset", 0)
|
||||
//albumCount := c.ParamInt("albumCount", 20)
|
||||
//albumOffset := c.ParamInt("albumOffset", 0)
|
||||
//songCount := c.ParamInt("songCount", 20)
|
||||
//songOffset := c.ParamInt("songOffset", 0)
|
||||
|
||||
as, err := c.search.SearchArtist(query, artistOffset, artistCount)
|
||||
if err != nil {
|
||||
beego.Error("Error searching for Artists:", err)
|
||||
c.SendError(responses.ERROR_GENERIC, "Internal Error")
|
||||
}
|
||||
|
||||
response := c.NewEmpty()
|
||||
searchResult2 := &responses.SearchResult2{}
|
||||
searchResult2.Artist = make([]responses.Artist, len(*as))
|
||||
for i, a := range *as {
|
||||
searchResult2.Artist[i] = responses.Artist{Id: a.Id, Name: a.Name}
|
||||
}
|
||||
response.SearchResult2 = searchResult2
|
||||
c.SendResponse(response)
|
||||
}
|
@ -38,7 +38,7 @@ func (c *StreamController) Prepare() {
|
||||
// TODO Still getting the "Conn.Write wrote more than the declared Content-Length" error.
|
||||
// Don't know if this causes any issues
|
||||
func (c *StreamController) Stream() {
|
||||
maxBitRate := c.ParamInt("maxBitRate")
|
||||
maxBitRate := c.ParamInt("maxBitRate", 0)
|
||||
maxBitRate = utils.MinInt(c.mf.BitRate, maxBitRate)
|
||||
|
||||
beego.Debug("Streaming file", c.id, ":", c.mf.Path)
|
||||
|
@ -29,7 +29,13 @@ func init() {
|
||||
|
||||
// Other dependencies
|
||||
utils.DefineSingleton(new(scanner.Scanner), scanner.NewItunesScanner)
|
||||
utils.DefineSingleton(new(gomate.Indexer), func() gomate.Indexer {
|
||||
return gomate.NewIndexer(gomate.NewLedisEmbeddedDB(persistence.Db()))
|
||||
utils.DefineSingleton(new(gomate.DB), func() gomate.DB {
|
||||
return gomate.NewLedisEmbeddedDB(persistence.Db())
|
||||
})
|
||||
//utils.DefineSingleton(new(gomate.Indexer), func() gomate.Indexer {
|
||||
// return gomate.NewIndexer(gomate.NewLedisEmbeddedDB(persistence.Db()))
|
||||
//})
|
||||
//utils.DefineSingleton(new(gomate.Searcher), func() gomate.Searcher {
|
||||
// return gomate.NewSearcher(gomate.NewLedisEmbeddedDB(persistence.Db()))
|
||||
//})
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ func mapEndpoints() {
|
||||
beego.NSRouter("/getIndexes.view", &api.BrowsingController{}, "*:GetIndexes"),
|
||||
beego.NSRouter("/getMusicDirectory.view", &api.BrowsingController{}, "*:GetDirectory"),
|
||||
|
||||
beego.NSRouter("/search2.view", &api.SearchingController{}, "*:Search2"),
|
||||
|
||||
beego.NSRouter("/getCoverArt.view", &api.GetCoverArtController{}, "*:Get"),
|
||||
beego.NSRouter("/stream.view", &api.StreamController{}, "*:Stream"),
|
||||
beego.NSRouter("/download.view", &api.StreamController{}, "*:Download"),
|
||||
|
@ -12,31 +12,76 @@ type Search interface {
|
||||
IndexArtist(ar *domain.Artist) error
|
||||
IndexAlbum(al *domain.Album) error
|
||||
IndexMediaFile(mf *domain.MediaFile) error
|
||||
|
||||
SearchArtist(q string, offset int, size int) (*domain.Artists, error)
|
||||
//SearchAlbum(q string, offset int, size int) (*domain.Albums, error)
|
||||
//SearchSong(q string, offset int, size int) (*domain.MediaFiles, error)
|
||||
}
|
||||
|
||||
type search struct {
|
||||
artistRepo domain.ArtistRepository
|
||||
albumRepo domain.AlbumRepository
|
||||
mfileRepo domain.MediaFileRepository
|
||||
indexer gomate.Indexer
|
||||
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, idx gomate.Indexer) Search {
|
||||
return search{ar, alr, mr, idx}
|
||||
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 {
|
||||
return s.indexer.Clear()
|
||||
return s.idxArtist.Clear()
|
||||
return s.idxAlbum.Clear()
|
||||
return s.idxSong.Clear()
|
||||
}
|
||||
|
||||
func (s search) IndexArtist(ar *domain.Artist) error {
|
||||
return s.indexer.Index("ar-"+ar.Id, strings.ToLower(ar.Name))
|
||||
return s.idxArtist.Index(ar.Id, strings.ToLower(ar.Name))
|
||||
}
|
||||
|
||||
func (s search) IndexAlbum(al *domain.Album) error {
|
||||
return s.indexer.Index("al-"+al.Id, strings.ToLower(al.Name))
|
||||
return s.idxAlbum.Index(al.Id, strings.ToLower(al.Name))
|
||||
}
|
||||
|
||||
func (s search) IndexMediaFile(mf *domain.MediaFile) error {
|
||||
return s.indexer.Index("mf-"+mf.Id, strings.ToLower(mf.Title))
|
||||
return s.idxSong.Index(mf.Id, strings.ToLower(mf.Title))
|
||||
}
|
||||
|
||||
func (s search) SearchArtist(q string, offset int, size int) (*domain.Artists, error) {
|
||||
q = strings.TrimSuffix(q, "*")
|
||||
res, err := s.sArtist.Search(q)
|
||||
if err != nil {
|
||||
return nil, nil
|
||||
}
|
||||
as := make(domain.Artists, 0, len(res))
|
||||
for _, id := range res {
|
||||
a, err := s.artistRepo.Get(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
as = append(as, *a)
|
||||
}
|
||||
return &as, nil
|
||||
}
|
||||
|
||||
//func (s search) SearchAlbum(q string, offset int, size int) (*domain.Albums, error) {
|
||||
// q := strings.TrimSuffix(q, "*")
|
||||
// return nil
|
||||
//}
|
||||
//
|
||||
//func (s search) SearchSong(q string, offset int, size int) (*domain.MediaFiles, error) {
|
||||
// q := strings.TrimSuffix(q, "*")
|
||||
// return nil
|
||||
//}
|
||||
|
Loading…
x
Reference in New Issue
Block a user