diff --git a/db/db.go b/db/db.go index 8328f54..53f571d 100644 --- a/db/db.go +++ b/db/db.go @@ -45,6 +45,7 @@ func New(path string) (*DB, error) { model.Play{}, model.Album{}, model.Playlist{}, + model.PlayQueue{}, ) // TODO: don't log if user already exists db.FirstOrCreate(&model.User{}, model.User{ diff --git a/model/model.go b/model/model.go index 317f93e..9cf228d 100644 --- a/model/model.go +++ b/model/model.go @@ -155,3 +155,23 @@ func (p *Playlist) SetItems(items []int) { p.Items = joinInt(items, ",") p.TrackCount = len(items) } + +type PlayQueue struct { + ID int `gorm:"primary_key"` + CreatedAt time.Time + UpdatedAt time.Time + User *User + UserID int `sql:"default: null; type:int REFERENCES users(id) ON DELETE CASCADE"` + Current int + Position int + ChangedBy string + Items string +} + +func (p *PlayQueue) GetItems() []int { + return splitInt(p.Items, ",") +} + +func (p *PlayQueue) SetItems(items []int) { + p.Items = joinInt(items, ",") +} diff --git a/server/ctrlsubsonic/handlers_common.go b/server/ctrlsubsonic/handlers_common.go index c34f6e7..9e1336f 100644 --- a/server/ctrlsubsonic/handlers_common.go +++ b/server/ctrlsubsonic/handlers_common.go @@ -213,9 +213,48 @@ func (c *Controller) ServeDeletePlaylist(r *http.Request) *spec.Response { } func (c *Controller) ServeGetPlayQueue(r *http.Request) *spec.Response { - return spec.NewResponse() + user := r.Context().Value(CtxUser).(*model.User) + queue := model.PlayQueue{} + err := c.DB. + Where("user_id = ?", user.ID). + Find(&queue). + Error + if gorm.IsRecordNotFoundError(err) { + return spec.NewResponse() + } + sub := spec.NewResponse() + sub.PlayQueue = &spec.PlayQueue{} + sub.PlayQueue.Username = user.Name + sub.PlayQueue.Position = queue.Position + sub.PlayQueue.Current = queue.Current + sub.PlayQueue.Changed = queue.UpdatedAt + sub.PlayQueue.ChangedBy = queue.ChangedBy + trackIDs := queue.GetItems() + sub.PlayQueue.List = make([]*spec.TrackChild, len(trackIDs)) + for i, id := range trackIDs { + track := model.Track{} + c.DB. + Where("id = ?", id). + Preload("Album"). + Find(&track) + sub.PlayQueue.List[i] = spec.NewTCTrackByFolder(&track, track.Album) + } + return sub } func (c *Controller) ServeSavePlayQueue(r *http.Request) *spec.Response { + params := r.Context().Value(CtxParams).(params.Params) + tracks := params.GetFirstListInt("id") + if tracks == nil { + return spec.NewError(10, "please provide some `id` parameters") + } + user := r.Context().Value(CtxUser).(*model.User) + queue := &model.PlayQueue{UserID: user.ID} + c.DB.Where(queue).First(queue) + queue.Current = params.GetIntOr("current", 0) + queue.Position = params.GetIntOr("position", 0) + queue.ChangedBy = params.Get("c") + queue.SetItems(tracks) + c.DB.Save(queue) return spec.NewResponse() } diff --git a/server/ctrlsubsonic/spec/spec.go b/server/ctrlsubsonic/spec/spec.go index da7afa4..40a9fd5 100644 --- a/server/ctrlsubsonic/spec/spec.go +++ b/server/ctrlsubsonic/spec/spec.go @@ -39,6 +39,7 @@ type Response struct { ArtistInfo *ArtistInfo `xml:"artistInfo" json:"artistInfo,omitempty"` ArtistInfoTwo *ArtistInfo `xml:"artistInfo2" json:"artistInfo2,omitempty"` Genres *Genres `xml:"genres" json:"genres,omitempty"` + PlayQueue *PlayQueue `xml:"playQueue" json:"playQueue,omitempty"` } func NewResponse() *Response { @@ -249,3 +250,12 @@ type Genre struct { type Genres struct { Genre []*Genres `xml:"genre" json:"genre"` } + +type PlayQueue struct { + Current int `xml:"current,attr,omitempty" json:"current,omitempty"` + Position int `xml:"position,attr,omitempty" json:"position,omitempty"` + Username string `xml:"username,attr" json:"username"` + Changed time.Time `xml:"changed,attr" json:"changed"` + ChangedBy string `xml:"changedBy,attr" json:"changedBy"` + List []*TrackChild `xml:"entry,omitempty" json:"entry,omitempty"` +}