Searching by artists, spike mode

This commit is contained in:
Deluan 2016-03-11 00:37:07 -05:00
parent 29c2925a1c
commit ef31d1aca0
9 changed files with 136 additions and 28 deletions

View file

@ -3,10 +3,11 @@ package api
import ( import (
"encoding/xml" "encoding/xml"
"fmt" "fmt"
"time"
"github.com/astaxie/beego" "github.com/astaxie/beego"
"github.com/deluan/gosonic/api/responses" "github.com/deluan/gosonic/api/responses"
"github.com/deluan/gosonic/utils" "github.com/deluan/gosonic/utils"
"time"
) )
type BaseAPIController struct{ beego.Controller } type BaseAPIController struct{ beego.Controller }
@ -23,14 +24,18 @@ func (c *BaseAPIController) RequiredParamString(param string, msg string) string
return p return p
} }
func (c *BaseAPIController) ParamString(param string) string {
return c.Input().Get(param)
}
func (c *BaseAPIController) ParamTime(param string) time.Time { func (c *BaseAPIController) ParamTime(param string) time.Time {
var value int64 var value int64
c.Ctx.Input.Bind(&value, param) c.Ctx.Input.Bind(&value, param)
return utils.ToTime(value) return utils.ToTime(value)
} }
func (c *BaseAPIController) ParamInt(param string) int { func (c *BaseAPIController) ParamInt(param string, def int) int {
var value int value := def
c.Ctx.Input.Bind(&value, param) c.Ctx.Input.Bind(&value, param)
return value return value
} }

View file

@ -40,8 +40,8 @@ func (c *GetAlbumListController) Get() {
c.SendError(responses.ERROR_GENERIC, "Not implemented!") c.SendError(responses.ERROR_GENERIC, "Not implemented!")
} }
offset := c.ParamInt("offset") offset := c.ParamInt("offset", 0)
size := utils.MinInt(c.ParamInt("size"), 500) size := utils.MinInt(c.ParamInt("size", 0), 500)
albums, err := method(offset, size) albums, err := method(offset, size)
if err != nil { if err != nil {

View file

@ -19,7 +19,7 @@ func (c *GetCoverArtController) Prepare() {
func (c *GetCoverArtController) Get() { func (c *GetCoverArtController) Get() {
id := c.RequiredParamString("id", "id parameter required") 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) err := c.cover.Get(id, size, c.Ctx.ResponseWriter)

View file

@ -6,18 +6,19 @@ import (
) )
type Subsonic struct { type Subsonic struct {
XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"` XMLName xml.Name `xml:"http://subsonic.org/restapi subsonic-response" json:"-"`
Status string `xml:"status,attr" json:"status"` Status string `xml:"status,attr" json:"status"`
Version string `xml:"version,attr" json:"version"` Version string `xml:"version,attr" json:"version"`
Error *Error `xml:"error,omitempty" json:"error,omitempty"` Error *Error `xml:"error,omitempty" json:"error,omitempty"`
License *License `xml:"license,omitempty" json:"license,omitempty"` License *License `xml:"license,omitempty" json:"license,omitempty"`
MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"` MusicFolders *MusicFolders `xml:"musicFolders,omitempty" json:"musicFolders,omitempty"`
Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"` Indexes *Indexes `xml:"indexes,omitempty" json:"indexes,omitempty"`
Directory *Directory `xml:"directory,omitempty" json:"directory,omitempty"` Directory *Directory `xml:"directory,omitempty" json:"directory,omitempty"`
User *User `xml:"user,omitempty" json:"user,omitempty"` User *User `xml:"user,omitempty" json:"user,omitempty"`
AlbumList *AlbumList `xml:"albumList,omitempty" json:"albumList,omitempty"` AlbumList *AlbumList `xml:"albumList,omitempty" json:"albumList,omitempty"`
Playlists *Playlists `xml:"playlists,omitempty" json:"playlists,omitempty"` Playlists *Playlists `xml:"playlists,omitempty" json:"playlists,omitempty"`
Playlist *PlaylistWithSongs `xml:"playlist,omitempty" json:"playlist,omitempty"` Playlist *PlaylistWithSongs `xml:"playlist,omitempty" json:"playlist,omitempty"`
SearchResult2 *SearchResult2 `xml:"searchResult2,omitempty" json:"searchResult2,omitempty"`
} }
type JsonWrapper struct { type JsonWrapper struct {
@ -119,6 +120,12 @@ type PlaylistWithSongs struct {
Entry []Child `xml:"entry" json:"entry,omitempty"` 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 { type User struct {
Username string `xml:"username,attr" json:"username"` Username string `xml:"username,attr" json:"username"`
Email string `xml:"email,attr,omitempty" json:"email,omitempty"` Email string `xml:"email,attr,omitempty" json:"email,omitempty"`

43
api/search.go Normal file
View 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)
}

View file

@ -38,7 +38,7 @@ func (c *StreamController) Prepare() {
// TODO Still getting the "Conn.Write wrote more than the declared Content-Length" error. // TODO Still getting the "Conn.Write wrote more than the declared Content-Length" error.
// Don't know if this causes any issues // Don't know if this causes any issues
func (c *StreamController) Stream() { func (c *StreamController) Stream() {
maxBitRate := c.ParamInt("maxBitRate") maxBitRate := c.ParamInt("maxBitRate", 0)
maxBitRate = utils.MinInt(c.mf.BitRate, maxBitRate) maxBitRate = utils.MinInt(c.mf.BitRate, maxBitRate)
beego.Debug("Streaming file", c.id, ":", c.mf.Path) beego.Debug("Streaming file", c.id, ":", c.mf.Path)

View file

@ -29,7 +29,13 @@ func init() {
// Other dependencies // Other dependencies
utils.DefineSingleton(new(scanner.Scanner), scanner.NewItunesScanner) utils.DefineSingleton(new(scanner.Scanner), scanner.NewItunesScanner)
utils.DefineSingleton(new(gomate.Indexer), func() gomate.Indexer { utils.DefineSingleton(new(gomate.DB), func() gomate.DB {
return gomate.NewIndexer(gomate.NewLedisEmbeddedDB(persistence.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()))
//})
} }

View file

@ -23,6 +23,8 @@ func mapEndpoints() {
beego.NSRouter("/getIndexes.view", &api.BrowsingController{}, "*:GetIndexes"), beego.NSRouter("/getIndexes.view", &api.BrowsingController{}, "*:GetIndexes"),
beego.NSRouter("/getMusicDirectory.view", &api.BrowsingController{}, "*:GetDirectory"), beego.NSRouter("/getMusicDirectory.view", &api.BrowsingController{}, "*:GetDirectory"),
beego.NSRouter("/search2.view", &api.SearchingController{}, "*:Search2"),
beego.NSRouter("/getCoverArt.view", &api.GetCoverArtController{}, "*:Get"), beego.NSRouter("/getCoverArt.view", &api.GetCoverArtController{}, "*:Get"),
beego.NSRouter("/stream.view", &api.StreamController{}, "*:Stream"), beego.NSRouter("/stream.view", &api.StreamController{}, "*:Stream"),
beego.NSRouter("/download.view", &api.StreamController{}, "*:Download"), beego.NSRouter("/download.view", &api.StreamController{}, "*:Download"),

View file

@ -12,31 +12,76 @@ type Search interface {
IndexArtist(ar *domain.Artist) error IndexArtist(ar *domain.Artist) error
IndexAlbum(al *domain.Album) error IndexAlbum(al *domain.Album) error
IndexMediaFile(mf *domain.MediaFile) 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 { type search struct {
artistRepo domain.ArtistRepository artistRepo domain.ArtistRepository
albumRepo domain.AlbumRepository albumRepo domain.AlbumRepository
mfileRepo domain.MediaFileRepository 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 { func NewSearch(ar domain.ArtistRepository, alr domain.AlbumRepository, mr domain.MediaFileRepository, db gomate.DB) Search {
return search{ar, alr, mr, idx} 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 { 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 { 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 { 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 { 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
//}