navidrome/server/subsonic/helpers.go

165 lines
4.1 KiB
Go

package subsonic
import (
"context"
"fmt"
"mime"
"net/http"
"strconv"
"github.com/deluan/navidrome/consts"
"github.com/deluan/navidrome/engine"
"github.com/deluan/navidrome/model"
"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()}
}
func RequiredParamString(r *http.Request, param string, msg string) (string, error) {
p := utils.ParamString(r, param)
if p == "" {
return "", NewError(responses.ErrorMissingParameter, msg)
}
return p, nil
}
func RequiredParamStrings(r *http.Request, param string, msg string) ([]string, error) {
ps := utils.ParamStrings(r, param)
if len(ps) == 0 {
return nil, NewError(responses.ErrorMissingParameter, msg)
}
return ps, nil
}
func RequiredParamInt(r *http.Request, param string, msg string) (int, error) {
p := utils.ParamString(r, param)
if p == "" {
return 0, NewError(responses.ErrorMissingParameter, msg)
}
return utils.ParamInt(r, param, 0), nil
}
type SubsonicError struct {
code int
messages []interface{}
}
func NewError(code int, message ...interface{}) error {
return SubsonicError{
code: code,
messages: message,
}
}
func (e SubsonicError) 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 ToAlbums(ctx context.Context, entries engine.Entries) []responses.Child {
children := make([]responses.Child, len(entries))
for i, entry := range entries {
children[i] = ToAlbum(ctx, entry)
}
return children
}
func ToAlbum(ctx context.Context, entry engine.Entry) responses.Child {
album := ToChild(ctx, entry)
album.Name = album.Title
album.Title = ""
album.Parent = ""
album.Album = ""
album.AlbumId = ""
return album
}
func ToArtists(entries engine.Entries) []responses.Artist {
artists := make([]responses.Artist, len(entries))
for i, entry := range entries {
artists[i] = responses.Artist{
Id: entry.Id,
Name: entry.Title,
AlbumCount: entry.AlbumCount,
}
if !entry.Starred.IsZero() {
artists[i].Starred = &entry.Starred
}
}
return artists
}
func ToChildren(ctx context.Context, entries engine.Entries) []responses.Child {
children := make([]responses.Child, len(entries))
for i, entry := range entries {
children[i] = ToChild(ctx, entry)
}
return children
}
func ToChild(ctx context.Context, entry engine.Entry) responses.Child {
child := responses.Child{}
child.Id = entry.Id
child.Title = entry.Title
child.IsDir = entry.IsDir
child.Parent = entry.Parent
child.Album = entry.Album
child.Year = entry.Year
child.Artist = entry.Artist
child.Genre = entry.Genre
child.CoverArt = entry.CoverArt
child.Track = entry.Track
child.Duration = entry.Duration
child.Size = strconv.Itoa(entry.Size)
child.Suffix = entry.Suffix
child.BitRate = entry.BitRate
child.ContentType = entry.ContentType
if !entry.Starred.IsZero() {
child.Starred = &entry.Starred
}
child.Path = entry.Path
child.PlayCount = int64(entry.PlayCount)
child.DiscNumber = entry.DiscNumber
if !entry.Created.IsZero() {
child.Created = &entry.Created
}
child.AlbumId = entry.AlbumId
child.ArtistId = entry.ArtistId
child.Type = entry.Type
child.IsVideo = false
child.UserRating = entry.UserRating
child.SongCount = entry.SongCount
format, _ := getTranscoding(ctx)
if entry.Suffix != "" && format != "" && entry.Suffix != format {
child.TranscodedSuffix = format
child.TranscodedContentType = mime.TypeByExtension("." + format)
}
return child
}
func ToGenres(genres model.Genres) *responses.Genres {
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) {
if trc, ok := ctx.Value("transcoding").(model.Transcoding); ok {
format = trc.TargetFormat
}
if plr, ok := ctx.Value("player").(model.Player); ok {
bitRate = plr.MaxBitRate
}
return
}