navidrome/server/subsonic/helpers.go

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

221 lines
5.5 KiB
Go
Raw Normal View History

package subsonic
import (
"context"
"fmt"
"mime"
"net/http"
"github.com/deluan/navidrome/consts"
2020-01-24 01:44:08 +01:00
"github.com/deluan/navidrome/model"
2020-05-13 22:49:55 +02:00
"github.com/deluan/navidrome/model/request"
2020-01-24 01:44:08 +01:00
"github.com/deluan/navidrome/server/subsonic/responses"
"github.com/deluan/navidrome/utils"
)
func newResponse() *responses.Subsonic {
return &responses.Subsonic{Status: "ok", Version: Version, Type: consts.AppName, ServerVersion: consts.Version()}
}
2020-10-27 20:23:29 +01:00
func requiredParamString(r *http.Request, param string) (string, error) {
p := utils.ParamString(r, param)
if p == "" {
2020-10-27 20:23:29 +01:00
return "", newError(responses.ErrorMissingParameter, "required '%s' parameter is missing", param)
}
return p, nil
}
2020-10-27 20:23:29 +01:00
func requiredParamStrings(r *http.Request, param string) ([]string, error) {
ps := utils.ParamStrings(r, param)
if len(ps) == 0 {
2020-10-27 20:23:29 +01:00
return nil, newError(responses.ErrorMissingParameter, "required '%s' parameter is missing", param)
}
return ps, nil
}
2020-10-27 20:23:29 +01:00
func requiredParamInt(r *http.Request, param string) (int, error) {
p := utils.ParamString(r, param)
if p == "" {
2020-10-27 20:23:29 +01:00
return 0, newError(responses.ErrorMissingParameter, "required '%s' parameter is missing", param)
}
return utils.ParamInt(r, param, 0), nil
}
2020-10-27 20:23:29 +01:00
type subError struct {
code int
messages []interface{}
}
func newError(code int, message ...interface{}) error {
2020-10-27 20:23:29 +01:00
return subError{
code: code,
messages: message,
}
}
2020-10-27 20:23:29 +01:00
func (e subError) Error() string {
var msg string
if len(e.messages) == 0 {
msg = responses.ErrorMsg(e.code)
} else {
msg = fmt.Sprintf(e.messages[0].(string), e.messages[1:]...)
}
return msg
}
func getUser(ctx context.Context) string {
user, ok := request.UserFrom(ctx)
if ok {
return user.UserName
}
return ""
}
func toArtists(ctx context.Context, artists model.Artists) []responses.Artist {
as := make([]responses.Artist, len(artists))
for i, artist := range artists {
as[i] = toArtist(ctx, artist)
}
return as
}
func toArtist(ctx context.Context, a model.Artist) responses.Artist {
artist := responses.Artist{
Id: a.ID,
Name: a.Name,
AlbumCount: a.AlbumCount,
UserRating: a.Rating,
ArtistImageUrl: a.ArtistImageUrl(),
}
if a.Starred {
artist.Starred = &a.StarredAt
}
return artist
}
func toArtistID3(ctx context.Context, a model.Artist) responses.ArtistID3 {
artist := responses.ArtistID3{
Id: a.ID,
Name: a.Name,
AlbumCount: a.AlbumCount,
ArtistImageUrl: a.ArtistImageUrl(),
}
if a.Starred {
artist.Starred = &a.StarredAt
}
return artist
}
func toGenres(genres model.Genres) *responses.Genres {
2020-01-15 23:49:09 +01:00
response := make([]responses.Genre, len(genres))
for i, g := range genres {
response[i] = responses.Genre(g)
}
return &responses.Genres{Genre: response}
}
func getTranscoding(ctx context.Context) (format string, bitRate int) {
2020-05-13 22:49:55 +02:00
if trc, ok := request.TranscodingFrom(ctx); ok {
format = trc.TargetFormat
}
2020-05-13 22:49:55 +02:00
if plr, ok := request.PlayerFrom(ctx); ok {
bitRate = plr.MaxBitRate
}
return
}
// This seems to be duplicated, but it is an initial step into merging `engine` and the `subsonic` packages,
// In the future there won't be any conversion to/from `engine. Entry` anymore
func childFromMediaFile(ctx context.Context, mf model.MediaFile) responses.Child {
child := responses.Child{}
child.Id = mf.ID
child.Title = mf.Title
child.IsDir = false
child.Parent = mf.AlbumID
child.Album = mf.Album
child.Year = mf.Year
child.Artist = mf.Artist
child.Genre = mf.Genre
child.Track = mf.TrackNumber
child.Duration = int(mf.Duration)
child.Size = mf.Size
child.Suffix = mf.Suffix
child.BitRate = mf.BitRate
if mf.HasCoverArt {
child.CoverArt = mf.ID
} else {
child.CoverArt = "al-" + mf.AlbumID
}
child.ContentType = mf.ContentType()
2020-08-14 00:50:28 +02:00
child.Path = fmt.Sprintf("%s/%s/%s.%s", realArtistName(mf), mf.Album, mf.Title, mf.Suffix)
child.DiscNumber = mf.DiscNumber
child.Created = &mf.CreatedAt
child.AlbumId = mf.AlbumID
child.ArtistId = mf.ArtistID
child.Type = "music"
child.PlayCount = mf.PlayCount
if mf.Starred {
child.Starred = &mf.StarredAt
}
child.UserRating = mf.Rating
format, _ := getTranscoding(ctx)
if mf.Suffix != "" && format != "" && mf.Suffix != format {
child.TranscodedSuffix = format
child.TranscodedContentType = mime.TypeByExtension("." + format)
}
child.BookmarkPosition = mf.BookmarkPosition
return child
}
2020-08-14 00:50:28 +02:00
func realArtistName(mf model.MediaFile) string {
switch {
case mf.Compilation:
return consts.VariousArtists
case mf.AlbumArtist != "":
return mf.AlbumArtist
}
return mf.Artist
}
func childrenFromMediaFiles(ctx context.Context, mfs model.MediaFiles) []responses.Child {
children := make([]responses.Child, len(mfs))
for i, mf := range mfs {
children[i] = childFromMediaFile(ctx, mf)
}
return children
}
2020-08-14 00:37:54 +02:00
func childFromAlbum(ctx context.Context, al model.Album) responses.Child {
2020-08-14 00:37:54 +02:00
child := responses.Child{}
child.Id = al.ID
child.IsDir = true
child.Title = al.Name
2020-08-14 00:37:54 +02:00
child.Name = al.Name
child.Album = al.Name
2020-08-14 00:37:54 +02:00
child.Artist = al.AlbumArtist
child.Year = al.MaxYear
child.Genre = al.Genre
child.CoverArt = al.CoverArtId
child.Created = &al.CreatedAt
child.Parent = al.AlbumArtistID
2020-08-14 00:37:54 +02:00
child.ArtistId = al.AlbumArtistID
child.Duration = int(al.Duration)
child.SongCount = al.SongCount
if al.Starred {
child.Starred = &al.StarredAt
}
child.PlayCount = al.PlayCount
child.UserRating = al.Rating
return child
}
func childrenFromAlbums(ctx context.Context, als model.Albums) []responses.Child {
2020-08-14 00:37:54 +02:00
children := make([]responses.Child, len(als))
for i, al := range als {
children[i] = childFromAlbum(ctx, al)
2020-08-14 00:37:54 +02:00
}
return children
}