Initial support for playlists. Missing permissions

This commit is contained in:
Deluan 2020-01-21 16:35:57 -05:00
parent 3a44f37622
commit 57fcdac428
6 changed files with 117 additions and 36 deletions

View File

@ -3,15 +3,17 @@ package engine
import (
"context"
"github.com/cloudsonic/sonic-server/consts"
"github.com/cloudsonic/sonic-server/model"
"github.com/cloudsonic/sonic-server/utils"
)
type Playlists interface {
GetAll() (model.Playlists, error)
Get(id string) (*PlaylistInfo, error)
Create(ctx context.Context, name string, ids []string) error
Create(ctx context.Context, playlistId, name string, ids []string) error
Delete(ctx context.Context, playlistId string) error
Update(playlistId string, name *string, idsToAdd []string, idxToRemove []int) error
Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error
}
func NewPlaylists(ds model.DataStore) Playlists {
@ -22,6 +24,62 @@ type playlists struct {
ds model.DataStore
}
func (p *playlists) Create(ctx context.Context, playlistId, name string, ids []string) error {
owner := consts.InitialUserName
user, ok := ctx.Value("user").(*model.User)
if ok {
owner = user.UserName
}
var pls *model.Playlist
var err error
// If playlistID is present, override tracks
if playlistId != "" {
pls, err = p.ds.Playlist().Get(playlistId)
if err != nil {
return err
}
pls.Tracks = nil
} else {
pls = &model.Playlist{
Name: name,
Owner: owner,
}
}
for _, id := range ids {
pls.Tracks = append(pls.Tracks, model.MediaFile{ID: id})
}
return p.ds.Playlist().Put(pls)
}
func (p *playlists) Delete(ctx context.Context, playlistId string) error {
return p.ds.Playlist().Delete(playlistId)
}
func (p *playlists) Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error {
pls, err := p.ds.Playlist().Get(playlistId)
if err != nil {
return err
}
if name != nil {
pls.Name = *name
}
newTracks := model.MediaFiles{}
for i, t := range pls.Tracks {
if utils.IntInSlice(i, idxToRemove) {
continue
}
newTracks = append(newTracks, t)
}
for _, id := range idsToAdd {
newTracks = append(newTracks, model.MediaFile{ID: id})
}
pls.Tracks = newTracks
return p.ds.Playlist().Put(pls)
}
func (p *playlists) GetAll() (model.Playlists, error) {
return p.ds.Playlist().GetAll(model.QueryOptions{})
}
@ -37,21 +95,6 @@ type PlaylistInfo struct {
Comment string
}
func (p *playlists) Create(ctx context.Context, name string, ids []string) error {
// TODO
return nil
}
func (p *playlists) Delete(ctx context.Context, playlistId string) error {
// TODO
return nil
}
func (p *playlists) Update(playlistId string, name *string, idsToAdd []string, idxToRemove []int) error {
// TODO
return nil
}
func (p *playlists) Get(id string) (*PlaylistInfo, error) {
pl, err := p.ds.Playlist().Get(id)
if err != nil {
@ -70,8 +113,8 @@ func (p *playlists) Get(id string) (*PlaylistInfo, error) {
pinfo.Entries = make(Entries, len(pl.Tracks))
// TODO Optimize: Get all tracks at once
for i, mfId := range pl.Tracks {
mf, err := p.ds.MediaFile().Get(mfId)
for i, mf := range pl.Tracks {
mf, err := p.ds.MediaFile().Get(mf.ID)
if err != nil {
return nil, err
}

View File

@ -8,15 +8,16 @@ type Playlist struct {
Duration int
Owner string
Public bool
Tracks []string
Tracks MediaFiles
}
type PlaylistRepository interface {
CountAll() (int64, error)
Exists(id string) (bool, error)
Put(m *Playlist) error
Put(pls *Playlist) error
Get(id string) (*Playlist, error)
GetAll(options ...QueryOptions) (Playlists, error)
Delete(id string) error
}
type Playlists []Playlist

View File

@ -5,6 +5,7 @@ import (
"github.com/astaxie/beego/orm"
"github.com/cloudsonic/sonic-server/model"
"github.com/google/uuid"
)
type playlist struct {
@ -15,7 +16,7 @@ type playlist struct {
Duration int
Owner string
Public bool
Tracks string
Tracks string `orm:"type(text)"`
}
type playlistRepository struct {
@ -30,8 +31,16 @@ func NewPlaylistRepository(o orm.Ormer) model.PlaylistRepository {
}
func (r *playlistRepository) Put(p *model.Playlist) error {
if p.ID == "" {
id, _ := uuid.NewRandom()
p.ID = id.String()
}
tp := r.fromDomain(p)
return r.put(p.ID, &tp)
err := r.put(p.ID, &tp)
if err != nil {
return err
}
return err
}
func (r *playlistRepository) Get(id string) (*model.Playlist, error) {
@ -65,7 +74,7 @@ func (r *playlistRepository) toPlaylists(all []playlist) (model.Playlists, error
}
func (r *playlistRepository) toDomain(p *playlist) model.Playlist {
return model.Playlist{
pls := model.Playlist{
ID: p.ID,
Name: p.Name,
Comment: p.Comment,
@ -73,12 +82,18 @@ func (r *playlistRepository) toDomain(p *playlist) model.Playlist {
Duration: p.Duration,
Owner: p.Owner,
Public: p.Public,
Tracks: strings.Split(p.Tracks, ","),
}
if strings.TrimSpace(p.Tracks) != "" {
tracks := strings.Split(p.Tracks, ",")
for _, t := range tracks {
pls.Tracks = append(pls.Tracks, model.MediaFile{ID: t})
}
}
return pls
}
func (r *playlistRepository) fromDomain(p *model.Playlist) playlist {
return playlist{
pls := playlist{
ID: p.ID,
Name: p.Name,
Comment: p.Comment,
@ -86,8 +101,13 @@ func (r *playlistRepository) fromDomain(p *model.Playlist) playlist {
Duration: p.Duration,
Owner: p.Owner,
Public: p.Public,
Tracks: strings.Join(p.Tracks, ","),
}
var newTracks []string
for _, t := range p.Tracks {
newTracks = append(newTracks, t.ID)
}
pls.Tracks = strings.Join(newTracks, ",")
return pls
}
var _ model.PlaylistRepository = (*playlistRepository)(nil)

View File

@ -1,6 +1,7 @@
package subsonic
import (
"errors"
"fmt"
"net/http"
@ -60,15 +61,13 @@ func (c *PlaylistsController) GetPlaylist(w http.ResponseWriter, r *http.Request
}
func (c *PlaylistsController) CreatePlaylist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
songIds, err := RequiredParamStrings(r, "songId", "Required parameter songId is missing")
if err != nil {
return nil, err
songIds := ParamStrings(r, "songId")
playlistId := ParamString(r, "playlistId")
name := ParamString(r, "name")
if playlistId == "" && name == "" {
return nil, errors.New("Required parameter name is missing")
}
name, err := RequiredParamString(r, "name", "Required parameter name is missing")
if err != nil {
return nil, err
}
err = c.pls.Create(r.Context(), name, songIds)
err := c.pls.Create(r.Context(), playlistId, name, songIds)
if err != nil {
log.Error(r, err)
return nil, NewError(responses.ErrorGeneric, "Internal Error")
@ -110,7 +109,7 @@ func (c *PlaylistsController) UpdatePlaylist(w http.ResponseWriter, r *http.Requ
log.Debug(r, fmt.Sprintf("-- Adding: '%v'", songsToAdd))
log.Debug(r, fmt.Sprintf("-- Removing: '%v'", songIndexesToRemove))
err = c.pls.Update(playlistId, pname, songsToAdd, songIndexesToRemove)
err = c.pls.Update(r.Context(), playlistId, pname, songsToAdd, songIndexesToRemove)
if err != nil {
log.Error(r, err)
return nil, NewError(responses.ErrorGeneric, "Internal Error")

View File

@ -13,3 +13,12 @@ func MaxInt(x, y int) int {
}
return y
}
func IntInSlice(a int, list []int) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}

View File

@ -32,3 +32,12 @@ func LongestCommonPrefix(list []string) string {
}
return list[0]
}
func StringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
return true
}
}
return false
}