diff --git a/model/model.go b/model/model.go index 6497c77..2401b2c 100644 --- a/model/model.go +++ b/model/model.go @@ -121,6 +121,7 @@ type Playlist struct { type PlaylistItem struct { ID int `gorm:"primary_key"` + CreatedAt time.Time Playlist Playlist PlaylistID int `sql:"default: null; type:int REFERENCES playlists(id) ON DELETE CASCADE"` Track Track diff --git a/server/ctrlsubsonic/handlers_common.go b/server/ctrlsubsonic/handlers_common.go index 4665bdc..028f24a 100644 --- a/server/ctrlsubsonic/handlers_common.go +++ b/server/ctrlsubsonic/handlers_common.go @@ -156,6 +156,7 @@ func (c *Controller) ServeGetPlaylist(r *http.Request) *spec.Response { `). Where("playlist_items.playlist_id = ?", playlistID). Group("tracks.id"). + Order("playlist_items.created_at"). Preload("Album"). Find(&tracks) user := r.Context().Value(key.User).(*model.User) @@ -169,38 +170,56 @@ func (c *Controller) ServeGetPlaylist(r *http.Request) *spec.Response { return sub } -func (c *Controller) ServeCreatePlaylist(r *http.Request) *spec.Response { - user := r.Context().Value(key.User).(*model.User) +func (c *Controller) ServeUpdatePlaylist(r *http.Request) *spec.Response { + playlistID, _ := parsing.GetFirstIntParamOf(r, "id", "playlistId") + // + // begin updating meta playlist := &model.Playlist{} c.DB. - Select("id"). - Where("id = ?", parsing.GetIntParamOr(r, "id", 0)). + Where("id = ?", playlistID). First(playlist) + user := r.Context().Value(key.User).(*model.User) playlist.UserID = user.ID - playlist.Name = parsing.GetStrParam(r, "name") + if name := parsing.GetStrParam(r, "name"); name != "" { + playlist.Name = name + } + if comment := parsing.GetStrParam(r, "comment"); comment != "" { + playlist.Comment = comment + } c.DB.Save(playlist) - sub := spec.NewResponse() - tracks, ok := r.URL.Query()["songId"] - if !ok { - return sub - } - for _, trackIDStr := range tracks { - trackID, err := strconv.Atoi(trackIDStr) - if err != nil { - continue + // + // begin delete tracks + if indexes, ok := r.URL.Query()["songIndexToRemove"]; ok { + trackIDs := []int{} + c.DB. + Order("created_at"). + Model(&model.PlaylistItem{}). + Where("playlist_id = ?", playlistID). + Pluck("track_id", &trackIDs) + for _, indexStr := range indexes { + i, err := strconv.Atoi(indexStr) + if err != nil { + continue + } + c.DB.Delete(&model.PlaylistItem{}, + "track_id = ?", trackIDs[i]) } - c.DB.Save(&model.PlaylistItem{ - PlaylistID: playlist.ID, - TrackID: trackID, - }) } - return sub -} - -func (c *Controller) ServeUpdatePlaylist(r *http.Request) *spec.Response { - // user := r.Context().Value(key.User).(*model.User) - sub := spec.NewResponse() - return sub + // + // begin add tracks + if toAdd := parsing.GetFirstParamOf(r, "songId", "songIdToAdd"); toAdd != nil { + for _, trackIDStr := range toAdd { + trackID, err := strconv.Atoi(trackIDStr) + if err != nil { + continue + } + c.DB.Save(&model.PlaylistItem{ + PlaylistID: playlist.ID, + TrackID: trackID, + }) + } + } + return spec.NewResponse() } func (c *Controller) ServeDeletePlaylist(r *http.Request) *spec.Response { diff --git a/server/ctrlsubsonic/spec/construct.go b/server/ctrlsubsonic/spec/construct.go index 9850158..70d8d46 100644 --- a/server/ctrlsubsonic/spec/construct.go +++ b/server/ctrlsubsonic/spec/construct.go @@ -4,8 +4,10 @@ import "senan.xyz/g/gonic/model" func NewPlaylist(p *model.Playlist) *Playlist { return &Playlist{ - ID: p.ID, - Name: p.Name, - Comment: p.Comment, + ID: p.ID, + Name: p.Name, + Comment: p.Comment, + Duration: "1", + Public: true, } } diff --git a/server/ctrlsubsonic/spec/spec.go b/server/ctrlsubsonic/spec/spec.go index 1bce3d7..eb66ce7 100644 --- a/server/ctrlsubsonic/spec/spec.go +++ b/server/ctrlsubsonic/spec/spec.go @@ -210,5 +210,7 @@ type Playlist struct { Owner string `xml:"owner,attr" json:"owner,omitempty"` SongCount string `xml:"songCount,attr" json:"songCount,omitempty"` Created string `xml:"created,attr" json:"created,omitempty"` + Duration string `xml:"duration,attr" json:"duration,omitempty"` + Public bool `xml:"public,attr" json:"public,omitempty"` List []*TrackChild `xml:"entry" json:"entry,omitempty"` } diff --git a/server/parsing/parsing.go b/server/parsing/parsing.go index 83ae906..3f2438a 100644 --- a/server/parsing/parsing.go +++ b/server/parsing/parsing.go @@ -37,3 +37,21 @@ func GetIntParamOr(r *http.Request, key string, or int) int { } return val } + +func GetFirstParamOf(r *http.Request, keys ...string) []string { + for _, key := range keys { + if val, ok := r.URL.Query()[key]; ok { + return val + } + } + return nil +} + +func GetFirstIntParamOf(r *http.Request, keys ...string) (int, bool) { + for _, key := range keys { + if v, err := GetIntParam(r, key); err == nil { + return v, true + } + } + return 0, false +} diff --git a/server/server.go b/server/server.go index 57b8332..7a58511 100644 --- a/server/server.go +++ b/server/server.go @@ -128,7 +128,7 @@ func (s *Server) SetupSubsonic() error { rout.Handle("/getUser{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetUser)) rout.Handle("/getPlaylists{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetPlaylists)) rout.Handle("/getPlaylist{_:(?:\\.view)?}", ctrl.H(ctrl.ServeGetPlaylist)) - rout.Handle("/createPlaylist{_:(?:\\.view)?}", ctrl.H(ctrl.ServeCreatePlaylist)) + rout.Handle("/createPlaylist{_:(?:\\.view)?}", ctrl.H(ctrl.ServeUpdatePlaylist)) rout.Handle("/updatePlaylist{_:(?:\\.view)?}", ctrl.H(ctrl.ServeUpdatePlaylist)) rout.Handle("/deletePlaylist{_:(?:\\.view)?}", ctrl.H(ctrl.ServeDeletePlaylist)) //