implemented getStarred (just for albums, for now)

This commit is contained in:
Deluan 2016-03-14 11:35:48 -04:00
parent 14934dccf7
commit e36a4201db
9 changed files with 95 additions and 13 deletions

View file

@ -10,7 +10,7 @@ import (
"github.com/deluan/gosonic/utils" "github.com/deluan/gosonic/utils"
) )
type GetAlbumListController struct { type AlbumListController struct {
BaseAPIController BaseAPIController
listGen engine.ListGenerator listGen engine.ListGenerator
types map[string]strategy types map[string]strategy
@ -18,7 +18,7 @@ type GetAlbumListController struct {
type strategy func(offset int, size int) (*domain.Albums, error) type strategy func(offset int, size int) (*domain.Albums, error)
func (c *GetAlbumListController) Prepare() { func (c *AlbumListController) Prepare() {
utils.ResolveDependencies(&c.listGen) utils.ResolveDependencies(&c.listGen)
c.types = map[string]strategy{ c.types = map[string]strategy{
@ -30,12 +30,12 @@ func (c *GetAlbumListController) Prepare() {
} }
} }
func (c *GetAlbumListController) Get() { func (c *AlbumListController) GetAlbumList() {
typ := c.RequiredParamString("type", "Required string parameter 'type' is not present") typ := c.RequiredParamString("type", "Required string parameter 'type' is not present")
method, found := c.types[typ] method, found := c.types[typ]
if !found { if !found {
beego.Error("getAlbumList type", typ, "not implemented!") beego.Error("albumList type", typ, "not implemented!")
c.SendError(responses.ERROR_GENERIC, "Not implemented!") c.SendError(responses.ERROR_GENERIC, "Not implemented!")
} }
@ -70,3 +70,21 @@ func (c *GetAlbumListController) Get() {
response.AlbumList = &responses.AlbumList{Album: albumList} response.AlbumList = &responses.AlbumList{Album: albumList}
c.SendResponse(response) c.SendResponse(response)
} }
func (c *AlbumListController) GetStarred() {
albums, err := c.listGen.GetStarred()
if err != nil {
beego.Error("Error retrieving starred albums:", err)
c.SendError(responses.ERROR_GENERIC, "Internal Error")
}
response := c.NewEmpty()
response.Starred = &responses.Starred{}
response.Starred.Album = make([]responses.Child, len(*albums))
for i, entry := range *albums {
response.Starred.Album[i] = c.ToChild(entry)
}
c.SendResponse(response)
}

View file

@ -19,6 +19,7 @@ type Subsonic struct {
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"` SearchResult2 *SearchResult2 `xml:"searchResult2,omitempty" json:"searchResult2,omitempty"`
Starred *Starred `xml:"starred,omitempty" json:"starred,omitempty"`
} }
type JsonWrapper struct { type JsonWrapper struct {
@ -131,6 +132,12 @@ type SearchResult2 struct {
Song []Child `xml:"song" json:"song,omitempty"` Song []Child `xml:"song" json:"song,omitempty"`
} }
type Starred 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"`

View file

@ -31,7 +31,8 @@ func mapEndpoints() {
beego.NSRouter("/scrobble.view", &api.MediaAnnotationController{}, "*:Scrobble"), beego.NSRouter("/scrobble.view", &api.MediaAnnotationController{}, "*:Scrobble"),
beego.NSRouter("/getAlbumList.view", &api.GetAlbumListController{}, "*:Get"), beego.NSRouter("/getAlbumList.view", &api.AlbumListController{}, "*:GetAlbumList"),
beego.NSRouter("/getStarred.view", &api.AlbumListController{}, "*:GetStarred"),
beego.NSRouter("/getPlaylists.view", &api.PlaylistsController{}, "*:GetAll"), beego.NSRouter("/getPlaylists.view", &api.PlaylistsController{}, "*:GetAll"),
beego.NSRouter("/getPlaylist.view", &api.PlaylistsController{}, "*:Get"), beego.NSRouter("/getPlaylist.view", &api.PlaylistsController{}, "*:Get"),

View file

@ -31,4 +31,5 @@ type AlbumRepository interface {
GetAll(QueryOptions) (*Albums, error) GetAll(QueryOptions) (*Albums, error)
PurgeInactive(active *Albums) error PurgeInactive(active *Albums) error
GetAllIds() (*[]string, error) GetAllIds() (*[]string, error)
GetStarred(QueryOptions) (*Albums, error)
} }

View file

@ -26,6 +26,8 @@ type Entry struct {
ContentType string ContentType string
} }
type Entries []Entry
var ( var (
ErrDataNotFound = errors.New("Data Not Found") ErrDataNotFound = errors.New("Data Not Found")
) )

View file

@ -14,6 +14,7 @@ type ListGenerator interface {
GetFrequent(offset int, size int) (*domain.Albums, error) GetFrequent(offset int, size int) (*domain.Albums, error)
GetHighest(offset int, size int) (*domain.Albums, error) GetHighest(offset int, size int) (*domain.Albums, error)
GetRandom(offset int, size int) (*domain.Albums, error) GetRandom(offset int, size int) (*domain.Albums, error)
GetStarred() (*Entries, error)
} }
func NewListGenerator(alr domain.AlbumRepository) ListGenerator { func NewListGenerator(alr domain.AlbumRepository) ListGenerator {
@ -69,3 +70,17 @@ func (g listGenerator) GetRandom(offset int, size int) (*domain.Albums, error) {
} }
return &r, nil return &r, nil
} }
func (g listGenerator) GetStarred() (*Entries, error) {
albums, err := g.albumRepo.GetStarred(domain.QueryOptions{})
if err != nil {
return nil, err
}
entries := make(Entries, len(*albums))
for i, al := range *albums {
entries[i] = FromAlbum(&al)
}
return &entries, nil
}

View file

@ -74,4 +74,10 @@ func (r *albumRepository) PurgeInactive(active *domain.Albums) error {
return r.DeleteAll(inactiveIds) return r.DeleteAll(inactiveIds)
} }
func (r *albumRepository) GetStarred(options domain.QueryOptions) (*domain.Albums, error) {
var as = make(domain.Albums, 0)
err := r.loadRange("Starred", true, true, &as, options)
return &as, err
}
var _ domain.AlbumRepository = (*albumRepository)(nil) var _ domain.AlbumRepository = (*albumRepository)(nil)

View file

@ -167,23 +167,25 @@ func (r *ledisRepository) saveOrUpdate(id string, entity interface{}) error {
} }
func calcScore(entity interface{}, fieldName string) int64 { func calcScore(entity interface{}, fieldName string) int64 {
var score int64
dv := reflect.ValueOf(entity).Elem() dv := reflect.ValueOf(entity).Elem()
v := dv.FieldByName(fieldName) v := dv.FieldByName(fieldName)
switch v.Interface().(type) { return toScore(v.Interface())
}
func toScore(value interface{}) int64 {
switch v := value.(type) {
case int: case int:
score = v.Int() return int64(v)
case bool: case bool:
if v.Bool() { if v {
score = 1 return 1
} }
case time.Time: case time.Time:
score = utils.ToMillis(v.Interface().(time.Time)) return utils.ToMillis(v)
} }
return score return 0
} }
func (r *ledisRepository) getParentRelationKey(entity interface{}) string { func (r *ledisRepository) getParentRelationKey(entity interface{}) string {
@ -243,6 +245,36 @@ func (r *ledisRepository) toEntity(response [][]byte, entity interface{}) error
return utils.ToStruct(record, entity) return utils.ToStruct(record, entity)
} }
func (r *ledisRepository) loadRange(idxName string, min interface{}, max interface{}, entities interface{}, qo ...domain.QueryOptions) error {
o := domain.QueryOptions{}
if len(qo) > 0 {
o = qo[0]
}
if o.Size == 0 {
o.Size = -1
}
minS := toScore(min)
maxS := toScore(max)
idxKey := fmt.Sprintf("%s:idx:%s", r.table, idxName)
resp, err := Db().ZRangeByScore([]byte(idxKey), minS, maxS, o.Offset, o.Size)
if err != nil {
return err
}
reflected := reflect.ValueOf(entities).Elem()
for _, pair := range resp {
e, err := r.readEntity(string(pair.Member))
if err != nil {
return err
}
reflected.Set(reflect.Append(reflected, reflect.ValueOf(e).Elem()))
}
return nil
}
func (r *ledisRepository) loadAll(entities interface{}, qo ...domain.QueryOptions) error { func (r *ledisRepository) loadAll(entities interface{}, qo ...domain.QueryOptions) error {
setName := r.table + "s:all" setName := r.table + "s:all"
return r.loadFromSet(setName, entities, qo...) return r.loadFromSet(setName, entities, qo...)