diff --git a/server/ctrlsubsonic/handlers_by_folder.go b/server/ctrlsubsonic/handlers_by_folder.go index f303ca4..8aae0d5 100644 --- a/server/ctrlsubsonic/handlers_by_folder.go +++ b/server/ctrlsubsonic/handlers_by_folder.go @@ -97,12 +97,8 @@ func (c *Controller) ServeGetMusicDirectory(r *http.Request) *spec.Response { // getAlbumListTwo() function func (c *Controller) ServeGetAlbumList(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - listType := params.Get("type") - if listType == "" { - return spec.NewError(10, "please provide a `type` parameter") - } q := c.DB.DB - switch listType { + switch v, _ := params.Get("type"); v { case "alphabeticalByArtist": q = q.Joins(` JOIN albums parent_albums @@ -129,7 +125,7 @@ func (c *Controller) ServeGetAlbumList(r *http.Request) *spec.Response { user.ID) q = q.Order("plays.time DESC") default: - return spec.NewError(10, "unknown value `%s` for parameter 'type'", listType) + return spec.NewError(10, "unknown value `%s` for parameter 'type'", v) } var folders []*db.Album // TODO: think about removing this extra join to count number @@ -139,8 +135,8 @@ func (c *Controller) ServeGetAlbumList(r *http.Request) *spec.Response { Joins("LEFT JOIN tracks ON tracks.album_id=albums.id"). Group("albums.id"). Where("albums.tag_artist_id IS NOT NULL"). - Offset(params.GetIntOr("offset", 0)). - Limit(params.GetIntOr("size", 10)). + Offset(params.GetOrInt("offset", 0)). + Limit(params.GetOrInt("size", 10)). Preload("Parent"). Find(&folders) sub := spec.NewResponse() @@ -155,8 +151,8 @@ func (c *Controller) ServeGetAlbumList(r *http.Request) *spec.Response { func (c *Controller) ServeSearchTwo(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - query := params.Get("query") - if query == "" { + query, err := params.Get("query") + if err != nil { return spec.NewError(10, "please provide a `query` parameter") } query = fmt.Sprintf("%%%s%%", strings.TrimSuffix(query, "*")) @@ -169,8 +165,8 @@ func (c *Controller) ServeSearchTwo(r *http.Request) *spec.Response { AND ( right_path LIKE ? OR right_path_u_dec LIKE ? )`, query, query). - Offset(params.GetIntOr("artistOffset", 0)). - Limit(params.GetIntOr("artistCount", 20)). + Offset(params.GetOrInt("artistOffset", 0)). + Limit(params.GetOrInt("artistCount", 20)). Find(&artists) for _, a := range artists { results.Artists = append(results.Artists, @@ -184,8 +180,8 @@ func (c *Controller) ServeSearchTwo(r *http.Request) *spec.Response { AND ( right_path LIKE ? OR right_path_u_dec LIKE ? )`, query, query). - Offset(params.GetIntOr("albumOffset", 0)). - Limit(params.GetIntOr("albumCount", 20)). + Offset(params.GetOrInt("albumOffset", 0)). + Limit(params.GetOrInt("albumCount", 20)). Find(&albums) for _, a := range albums { results.Albums = append(results.Albums, spec.NewTCAlbumByFolder(a)) @@ -196,8 +192,8 @@ func (c *Controller) ServeSearchTwo(r *http.Request) *spec.Response { Preload("Album"). Where("filename LIKE ? OR filename_u_dec LIKE ?", query, query). - Offset(params.GetIntOr("songOffset", 0)). - Limit(params.GetIntOr("songCount", 20)). + Offset(params.GetOrInt("songOffset", 0)). + Limit(params.GetOrInt("songCount", 20)). Find(&tracks) for _, t := range tracks { results.Tracks = append(results.Tracks, diff --git a/server/ctrlsubsonic/handlers_by_tags.go b/server/ctrlsubsonic/handlers_by_tags.go index 49538ea..d7fe0f5 100644 --- a/server/ctrlsubsonic/handlers_by_tags.go +++ b/server/ctrlsubsonic/handlers_by_tags.go @@ -97,8 +97,8 @@ func (c *Controller) ServeGetAlbum(r *http.Request) *spec.Response { // getAlbumList() function func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - listType := params.Get("type") - if listType == "" { + listType, err := params.Get("type") + if err != nil { return spec.NewError(10, "please provide a `type` parameter") } q := c.DB.DB @@ -111,8 +111,8 @@ func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response { case "byYear": q = q.Where( "tag_year BETWEEN ? AND ?", - params.GetIntOr("fromYear", 1800), - params.GetIntOr("toYear", 2200)) + params.GetOrInt("fromYear", 1800), + params.GetOrInt("toYear", 2200)) q = q.Order("tag_year") case "byGenre": q = q.Joins("JOIN genres ON albums.tag_genre_id=genres.id AND genres.name=?", @@ -142,8 +142,8 @@ func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response { Joins("LEFT JOIN tracks ON tracks.album_id=albums.id"). Group("albums.id"). Where("albums.tag_artist_id IS NOT NULL"). - Offset(params.GetIntOr("offset", 0)). - Limit(params.GetIntOr("size", 10)). + Offset(params.GetOrInt("offset", 0)). + Limit(params.GetOrInt("size", 10)). Preload("TagArtist"). Find(&albums) sub := spec.NewResponse() @@ -158,8 +158,8 @@ func (c *Controller) ServeGetAlbumListTwo(r *http.Request) *spec.Response { func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - query := params.Get("query") - if query == "" { + query, err := params.Get("query") + if err != nil { return spec.NewError(10, "please provide a `query` parameter") } query = fmt.Sprintf("%%%s%%", @@ -170,8 +170,8 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response { c.DB. Where("name LIKE ? OR name_u_dec LIKE ?", query, query). - Offset(params.GetIntOr("artistOffset", 0)). - Limit(params.GetIntOr("artistCount", 20)). + Offset(params.GetOrInt("artistOffset", 0)). + Limit(params.GetOrInt("artistCount", 20)). Find(&artists) for _, a := range artists { results.Artists = append(results.Artists, @@ -183,8 +183,8 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response { Preload("TagArtist"). Where("tag_title LIKE ? OR tag_title_u_dec LIKE ?", query, query). - Offset(params.GetIntOr("albumOffset", 0)). - Limit(params.GetIntOr("albumCount", 20)). + Offset(params.GetOrInt("albumOffset", 0)). + Limit(params.GetOrInt("albumCount", 20)). Find(&albums) for _, a := range albums { results.Albums = append(results.Albums, @@ -196,8 +196,8 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response { Preload("Album"). Where("tag_title LIKE ? OR tag_title_u_dec LIKE ?", query, query). - Offset(params.GetIntOr("songOffset", 0)). - Limit(params.GetIntOr("songCount", 20)). + Offset(params.GetOrInt("songOffset", 0)). + Limit(params.GetOrInt("songCount", 20)). Find(&tracks) for _, t := range tracks { results.Tracks = append(results.Tracks, @@ -210,7 +210,7 @@ func (c *Controller) ServeSearchThree(r *http.Request) *spec.Response { func (c *Controller) ServeGetArtistInfoTwo(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - id, err := params.GetInt("id") + id, err := params.GetIDDefault() if err != nil { return spec.NewError(10, "please provide an `id` parameter") } @@ -246,8 +246,8 @@ func (c *Controller) ServeGetArtistInfoTwo(r *http.Request) *spec.Response { sub.ArtistInfoTwo.LargeImageURL = image.Text } } - count := params.GetIntOr("count", 20) - includeNotPresent := params.Get("includeNotPresent") == "true" + count := params.GetOrInt("count", 20) + inclNotPresent := params.GetOrBool("includeNotPresent", false) for i, similarInfo := range info.Similar.Artists { if i == count { break @@ -260,7 +260,7 @@ func (c *Controller) ServeGetArtistInfoTwo(r *http.Request) *spec.Response { Group("artists.id"). Find(artist). Error - if gorm.IsRecordNotFoundError(err) && !includeNotPresent { + if gorm.IsRecordNotFoundError(err) && !inclNotPresent { continue } similar := &spec.SimilarArtist{ID: -1} @@ -295,8 +295,8 @@ func (c *Controller) ServeGetGenres(r *http.Request) *spec.Response { func (c *Controller) ServeGetSongsByGenre(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - genre := params.Get("genre") - if genre == "" { + genre, err := params.Get("genre") + if err != nil { return spec.NewError(10, "please provide an `genre` parameter") } // TODO: add musicFolderId parameter @@ -306,8 +306,8 @@ func (c *Controller) ServeGetSongsByGenre(r *http.Request) *spec.Response { Joins("JOIN albums ON tracks.album_id=albums.id"). Joins("JOIN genres ON tracks.tag_genre_id=genres.id AND genres.name=?", genre). Preload("Album"). - Offset(params.GetIntOr("offset", 0)). - Limit(params.GetIntOr("count", 10)). + Offset(params.GetOrInt("offset", 0)). + Limit(params.GetOrInt("count", 10)). Find(&tracks) sub := spec.NewResponse() sub.TracksByGenre = &spec.TracksByGenre{ diff --git a/server/ctrlsubsonic/handlers_common.go b/server/ctrlsubsonic/handlers_common.go index c2482e1..a5a62e2 100644 --- a/server/ctrlsubsonic/handlers_common.go +++ b/server/ctrlsubsonic/handlers_common.go @@ -4,7 +4,6 @@ import ( "log" "net/http" "sort" - "strconv" "time" "unicode" @@ -59,8 +58,8 @@ func (c *Controller) ServeScrobble(r *http.Request) *spec.Response { Track: track, // clients will provide time in miliseconds, so use that or // instead convert UnixNano to miliseconds - StampMili: params.GetIntOr("time", int(time.Now().UnixNano()/1e6)), - Submission: params.GetOr("submission", "true") != "false", + StampMili: params.GetOrInt("time", int(time.Now().UnixNano()/1e6)), + Submission: params.GetOrBool("submission", true), } err = lastfm.Scrobble( c.DB.GetSetting("lastfm_api_key"), @@ -179,10 +178,7 @@ func (c *Controller) ServeGetPlaylist(r *http.Request) *spec.Response { func (c *Controller) ServeUpdatePlaylist(r *http.Request) *spec.Response { user := r.Context().Value(CtxUser).(*db.User) params := r.Context().Value(CtxParams).(params.Params) - var playlistID int - if p := params.GetFirstList("id", "playlistId"); p != nil { - playlistID, _ = strconv.Atoi(p[0]) - } + playlistID := params.GetFirstOrInt( /* default */ 0, "id", "playlistId") // playlistID may be 0 from above. in that case we get a new playlist // as intended var playlist db.Playlist @@ -191,22 +187,22 @@ func (c *Controller) ServeUpdatePlaylist(r *http.Request) *spec.Response { FirstOrCreate(&playlist) // ** begin update meta info playlist.UserID = user.ID - if val := params.Get("name"); val != "" { + if val, err := params.Get("name"); err != nil { playlist.Name = val } - if val := params.Get("comment"); val != "" { + if val, err := params.Get("comment"); err != nil { playlist.Comment = val } trackIDs := playlist.GetItems() // ** begin delete items - if p := params.GetFirstListInt("songIndexToRemove"); p != nil { + if p, err := params.GetIntList("songIndexToRemove"); err == nil { sort.Sort(sort.Reverse(sort.IntSlice(p))) for _, i := range p { trackIDs = append(trackIDs[:i], trackIDs[i+1:]...) } } // ** begin add items - if p := params.GetFirstListInt("songId", "songIdToAdd"); p != nil { + if p, err := params.GetFirstIntList("songId", "songIdToAdd"); err == nil { trackIDs = append(trackIDs, p...) } // @@ -218,7 +214,7 @@ func (c *Controller) ServeUpdatePlaylist(r *http.Request) *spec.Response { func (c *Controller) ServeDeletePlaylist(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) c.DB. - Where("id=?", params.GetIntOr("id", 0)). + Where("id=?", params.GetOrInt("id", 0)). Delete(&db.Playlist{}) return spec.NewResponse() } @@ -255,16 +251,16 @@ func (c *Controller) ServeGetPlayQueue(r *http.Request) *spec.Response { func (c *Controller) ServeSavePlayQueue(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) - tracks := params.GetFirstListInt("id") - if tracks == nil { + tracks, err := params.GetIntList("id") + if err != nil { return spec.NewError(10, "please provide some `id` parameters") } user := r.Context().Value(CtxUser).(*db.User) queue := &db.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.Current = params.GetOrInt("current", 0) + queue.Position = params.GetOrInt("position", 0) + queue.ChangedBy = params.GetOr("c", "") // must exist, middleware checks queue.SetItems(tracks) c.DB.Save(queue) return spec.NewResponse() @@ -295,7 +291,7 @@ func (c *Controller) ServeGetRandomSongs(r *http.Request) *spec.Response { var tracks []*db.Track q := c.DB.DB. Joins("JOIN albums ON tracks.album_id=albums.id"). - Limit(params.GetIntOr("size", 10)). + Limit(params.GetOrInt("size", 10)). Preload("Album"). Order(gorm.Expr("random()")) if year, err := params.GetInt("fromYear"); err == nil { @@ -304,7 +300,7 @@ func (c *Controller) ServeGetRandomSongs(r *http.Request) *spec.Response { if year, err := params.GetInt("toYear"); err == nil { q = q.Where("albums.tag_year <= ?", year) } - if genre := params.Get("genre"); genre != "" { + if genre, err := params.Get("genre"); err == nil { q = q.Joins( "JOIN genres ON tracks.tag_genre_id=genres.id AND genres.name=?", genre, @@ -324,7 +320,10 @@ func (c *Controller) ServeJukebox(r *http.Request) *spec.Response { params := r.Context().Value(CtxParams).(params.Params) getTracks := func() []*db.Track { var tracks []*db.Track - ids := params.GetFirstListInt("id") + ids, err := params.GetIDList("id") + if err != nil { + return tracks + } for _, id := range ids { track := &db.Track{} c.DB.Preload("Album").First(track, id) @@ -351,7 +350,7 @@ func (c *Controller) ServeJukebox(r *http.Request) *spec.Response { } return ret } - switch act := params.Get("action"); act { + switch act, _ := params.Get("action"); act { case "set": c.Jukebox.SetTracks(getTracks()) case "add": diff --git a/server/ctrlsubsonic/middleware.go b/server/ctrlsubsonic/middleware.go index c301a5a..3d4daf4 100644 --- a/server/ctrlsubsonic/middleware.go +++ b/server/ctrlsubsonic/middleware.go @@ -41,13 +41,11 @@ func (c *Controller) WithRequiredParams(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { params := r.Context().Value(CtxParams).(params.Params) for _, req := range requiredParameters { - param := params.Get(req) - if param != "" { - continue + if _, err := params.Get(req); err != nil { + _ = writeResp(w, r, spec.NewError(10, + "please provide a `%s` parameter", req)) + return } - _ = writeResp(w, r, spec.NewError(10, - "please provide a `%s` parameter", req)) - return } next.ServeHTTP(w, r) }) @@ -56,10 +54,11 @@ func (c *Controller) WithRequiredParams(next http.Handler) http.Handler { func (c *Controller) WithUser(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { params := r.Context().Value(CtxParams).(params.Params) - username := params.Get("u") - password := params.Get("p") - token := params.Get("t") - salt := params.Get("s") + // ignoring errors here, a middleware has already ensured they exist + username, _ := params.Get("u") + password, _ := params.Get("p") + token, _ := params.Get("t") + salt, _ := params.Get("s") // passwordAuth := token == "" && salt == "" tokenAuth := password == ""