2020-01-20 00:21:44 +01:00
|
|
|
package subsonic
|
2016-03-03 02:00:55 +01:00
|
|
|
|
|
|
|
import (
|
2020-03-16 17:56:15 +01:00
|
|
|
"context"
|
2020-01-07 20:56:26 +01:00
|
|
|
"net/http"
|
2020-08-14 04:07:50 +02:00
|
|
|
"sort"
|
2020-08-13 23:51:57 +02:00
|
|
|
"strconv"
|
2020-08-14 04:07:50 +02:00
|
|
|
"strings"
|
2016-03-12 02:49:01 +01:00
|
|
|
"time"
|
|
|
|
|
2020-01-24 01:44:08 +01:00
|
|
|
"github.com/navidrome/navidrome/conf"
|
2020-10-19 01:10:11 +02:00
|
|
|
"github.com/navidrome/navidrome/core"
|
2020-01-24 01:44:08 +01:00
|
|
|
"github.com/navidrome/navidrome/log"
|
|
|
|
"github.com/navidrome/navidrome/model"
|
|
|
|
"github.com/navidrome/navidrome/server/subsonic/responses"
|
|
|
|
"github.com/navidrome/navidrome/utils"
|
2016-03-03 02:00:55 +01:00
|
|
|
)
|
|
|
|
|
2016-03-09 16:22:10 +01:00
|
|
|
type BrowsingController struct {
|
2020-08-14 04:07:50 +02:00
|
|
|
ds model.DataStore
|
2021-02-09 17:41:47 +01:00
|
|
|
em core.ExternalMetadata
|
2016-03-03 02:00:55 +01:00
|
|
|
}
|
|
|
|
|
2021-02-09 17:41:47 +01:00
|
|
|
func NewBrowsingController(ds model.DataStore, em core.ExternalMetadata) *BrowsingController {
|
|
|
|
return &BrowsingController{ds: ds, em: em}
|
2016-03-03 02:00:55 +01:00
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetMusicFolders(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-08-13 23:51:57 +02:00
|
|
|
mediaFolderList, _ := c.ds.MediaFolder(r.Context()).GetAll()
|
2016-03-20 18:14:04 +01:00
|
|
|
folders := make([]responses.MusicFolder, len(mediaFolderList))
|
|
|
|
for i, f := range mediaFolderList {
|
2020-05-10 04:29:02 +02:00
|
|
|
folders[i].Id = f.ID
|
2016-03-09 16:22:10 +01:00
|
|
|
folders[i].Name = f.Name
|
|
|
|
}
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2016-03-09 16:22:10 +01:00
|
|
|
response.MusicFolders = &responses.MusicFolders{Folders: folders}
|
2020-01-07 20:56:26 +01:00
|
|
|
return response, nil
|
2016-03-09 16:22:10 +01:00
|
|
|
}
|
|
|
|
|
2020-10-26 02:52:51 +01:00
|
|
|
func (c *BrowsingController) getArtistIndex(ctx context.Context, mediaFolderId int, ifModifiedSince time.Time) (*responses.Indexes, error) {
|
|
|
|
folder, err := c.ds.MediaFolder(ctx).Get(int32(mediaFolderId))
|
2016-03-09 16:22:10 +01:00
|
|
|
if err != nil {
|
2020-08-13 23:51:57 +02:00
|
|
|
log.Error(ctx, "Error retrieving MediaFolder", "id", mediaFolderId, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2016-03-09 16:22:10 +01:00
|
|
|
}
|
|
|
|
|
2020-08-13 23:51:57 +02:00
|
|
|
l, err := c.ds.Property(ctx).DefaultGet(model.PropLastScan+"-"+folder.Path, "-1")
|
|
|
|
if err != nil {
|
|
|
|
log.Error(ctx, "Error retrieving LastScan property", err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2020-08-13 23:51:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var indexes model.ArtistIndexes
|
|
|
|
ms, _ := strconv.ParseInt(l, 10, 64)
|
|
|
|
lastModified := utils.ToTime(ms)
|
|
|
|
if lastModified.After(ifModifiedSince) {
|
|
|
|
indexes, err = c.ds.Artist(ctx).GetIndex()
|
|
|
|
if err != nil {
|
|
|
|
log.Error(ctx, "Error retrieving Indexes", err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2020-08-13 23:51:57 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
res := &responses.Indexes{
|
2020-01-24 07:29:31 +01:00
|
|
|
IgnoredArticles: conf.Server.IgnoredArticles,
|
2020-05-10 03:00:38 +02:00
|
|
|
LastModified: utils.ToMillis(lastModified),
|
2016-03-09 16:22:10 +01:00
|
|
|
}
|
|
|
|
|
2016-03-20 18:08:24 +01:00
|
|
|
res.Index = make([]responses.Index, len(indexes))
|
|
|
|
for i, idx := range indexes {
|
2020-01-11 01:41:35 +01:00
|
|
|
res.Index[i].Name = idx.ID
|
2020-10-30 21:08:43 +01:00
|
|
|
res.Index[i].Artists = toArtists(ctx, idx.Artists)
|
2016-03-09 16:22:10 +01:00
|
|
|
}
|
2020-01-07 20:56:26 +01:00
|
|
|
return res, nil
|
2016-03-28 02:35:10 +02:00
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetIndexes(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-10-26 02:52:51 +01:00
|
|
|
musicFolderId := utils.ParamInt(r, "musicFolderId", 0)
|
2020-02-07 00:55:38 +01:00
|
|
|
ifModifiedSince := utils.ParamTime(r, "ifModifiedSince", time.Time{})
|
2016-03-28 02:35:10 +02:00
|
|
|
|
2020-08-13 23:51:57 +02:00
|
|
|
res, err := c.getArtistIndex(r.Context(), musicFolderId, ifModifiedSince)
|
2020-01-07 20:56:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-03-09 16:22:10 +01:00
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-01-07 20:56:26 +01:00
|
|
|
response.Indexes = res
|
|
|
|
return response, nil
|
2016-03-09 16:22:10 +01:00
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetArtists(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-10-26 02:52:51 +01:00
|
|
|
musicFolderId := utils.ParamInt(r, "musicFolderId", 0)
|
2020-08-13 23:51:57 +02:00
|
|
|
res, err := c.getArtistIndex(r.Context(), musicFolderId, time.Time{})
|
2020-01-07 20:56:26 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2016-03-28 02:35:10 +02:00
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-01-07 20:56:26 +01:00
|
|
|
response.Artist = res
|
|
|
|
return response, nil
|
2016-03-28 02:35:10 +02:00
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-02-07 00:55:38 +01:00
|
|
|
id := utils.ParamString(r, "id")
|
2020-08-14 03:52:44 +02:00
|
|
|
ctx := r.Context()
|
|
|
|
|
2020-10-20 19:38:44 +02:00
|
|
|
entity, err := core.GetEntityByID(ctx, c.ds, id)
|
2016-03-03 15:50:50 +01:00
|
|
|
switch {
|
2020-01-15 04:22:34 +01:00
|
|
|
case err == model.ErrNotFound:
|
2020-01-10 05:33:01 +01:00
|
|
|
log.Error(r, "Requested ID not found ", "id", id)
|
2020-08-14 04:11:18 +02:00
|
|
|
return nil, newError(responses.ErrorDataNotFound, "Directory not found")
|
2016-03-08 14:48:47 +01:00
|
|
|
case err != nil:
|
2020-01-09 02:45:07 +01:00
|
|
|
log.Error(err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2016-03-03 02:00:55 +01:00
|
|
|
}
|
|
|
|
|
2020-08-14 03:52:44 +02:00
|
|
|
var dir *responses.Directory
|
|
|
|
|
|
|
|
switch v := entity.(type) {
|
|
|
|
case *model.Artist:
|
|
|
|
dir, err = c.buildArtistDirectory(ctx, v)
|
|
|
|
case *model.Album:
|
|
|
|
dir, err = c.buildAlbumDirectory(ctx, v)
|
|
|
|
default:
|
|
|
|
log.Error(r, "Requested ID of invalid type", "id", id, "entity", v)
|
2020-08-14 04:11:18 +02:00
|
|
|
return nil, newError(responses.ErrorDataNotFound, "Directory not found")
|
2020-08-14 03:52:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
log.Error(err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2020-08-14 03:52:44 +02:00
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-08-14 03:52:44 +02:00
|
|
|
response.Directory = dir
|
2020-01-07 20:56:26 +01:00
|
|
|
return response, nil
|
2016-03-25 05:04:22 +01:00
|
|
|
}
|
2016-03-08 14:48:47 +01:00
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetArtist(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-02-07 00:55:38 +01:00
|
|
|
id := utils.ParamString(r, "id")
|
2020-08-14 00:37:54 +02:00
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
artist, err := c.ds.Artist(ctx).Get(id)
|
2016-03-28 03:27:45 +02:00
|
|
|
switch {
|
2020-01-15 04:22:34 +01:00
|
|
|
case err == model.ErrNotFound:
|
2020-08-14 00:37:54 +02:00
|
|
|
log.Error(ctx, "Requested ArtistID not found ", "id", id)
|
2020-08-14 04:11:18 +02:00
|
|
|
return nil, newError(responses.ErrorDataNotFound, "Artist not found")
|
2016-03-28 03:27:45 +02:00
|
|
|
case err != nil:
|
2020-08-14 00:37:54 +02:00
|
|
|
log.Error(ctx, "Error retrieving artist", "id", id, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2020-08-14 00:37:54 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
albums, err := c.ds.Album(ctx).FindByArtist(id)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(ctx, "Error retrieving albums by artist", "id", id, "name", artist.Name, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2016-03-28 03:27:45 +02:00
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-08-14 00:37:54 +02:00
|
|
|
response.ArtistWithAlbumsID3 = c.buildArtist(ctx, artist, albums)
|
2020-01-07 20:56:26 +01:00
|
|
|
return response, nil
|
2016-03-28 03:27:45 +02:00
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetAlbum(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-02-07 00:55:38 +01:00
|
|
|
id := utils.ParamString(r, "id")
|
2020-08-14 00:50:28 +02:00
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
album, err := c.ds.Album(ctx).Get(id)
|
2016-03-28 15:16:03 +02:00
|
|
|
switch {
|
2020-01-15 04:22:34 +01:00
|
|
|
case err == model.ErrNotFound:
|
2020-08-14 00:50:28 +02:00
|
|
|
log.Error(ctx, "Requested AlbumID not found ", "id", id)
|
2020-08-14 04:11:18 +02:00
|
|
|
return nil, newError(responses.ErrorDataNotFound, "Album not found")
|
2016-03-28 15:16:03 +02:00
|
|
|
case err != nil:
|
2020-08-14 00:50:28 +02:00
|
|
|
log.Error(ctx, "Error retrieving album", "id", id, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2020-08-14 00:50:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mfs, err := c.ds.MediaFile(ctx).FindByAlbum(id)
|
|
|
|
if err != nil {
|
|
|
|
log.Error(ctx, "Error retrieving tracks from album", "id", id, "name", album.Name, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2016-03-28 15:16:03 +02:00
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-08-14 00:50:28 +02:00
|
|
|
response.AlbumWithSongsID3 = c.buildAlbum(ctx, album, mfs)
|
2020-01-07 20:56:26 +01:00
|
|
|
return response, nil
|
2016-03-28 15:16:03 +02:00
|
|
|
}
|
|
|
|
|
2020-01-07 20:56:26 +01:00
|
|
|
func (c *BrowsingController) GetSong(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-02-07 00:55:38 +01:00
|
|
|
id := utils.ParamString(r, "id")
|
2020-08-14 03:57:35 +02:00
|
|
|
ctx := r.Context()
|
|
|
|
|
|
|
|
mf, err := c.ds.MediaFile(ctx).Get(id)
|
2016-03-25 05:04:22 +01:00
|
|
|
switch {
|
2020-01-15 04:22:34 +01:00
|
|
|
case err == model.ErrNotFound:
|
2020-08-14 03:57:35 +02:00
|
|
|
log.Error(r, "Requested MediaFileID not found ", "id", id)
|
2020-08-14 04:11:18 +02:00
|
|
|
return nil, newError(responses.ErrorDataNotFound, "Song not found")
|
2016-03-25 05:04:22 +01:00
|
|
|
case err != nil:
|
2020-08-14 03:57:35 +02:00
|
|
|
log.Error(r, "Error retrieving MediaFile", "id", id, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2016-03-25 05:04:22 +01:00
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
|
|
|
child := childFromMediaFile(ctx, *mf)
|
2016-03-25 05:04:22 +01:00
|
|
|
response.Song = &child
|
2020-01-07 20:56:26 +01:00
|
|
|
return response, nil
|
2016-03-03 02:00:55 +01:00
|
|
|
}
|
2016-03-03 02:50:16 +01:00
|
|
|
|
2020-01-15 23:49:09 +01:00
|
|
|
func (c *BrowsingController) GetGenres(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-08-14 04:07:50 +02:00
|
|
|
ctx := r.Context()
|
|
|
|
genres, err := c.ds.Genre(ctx).GetAll()
|
2020-01-15 23:49:09 +01:00
|
|
|
if err != nil {
|
|
|
|
log.Error(r, err)
|
2020-10-27 20:23:29 +01:00
|
|
|
return nil, err
|
2020-01-15 23:49:09 +01:00
|
|
|
}
|
2020-08-14 04:07:50 +02:00
|
|
|
for i, g := range genres {
|
|
|
|
if strings.TrimSpace(g.Name) == "" {
|
|
|
|
genres[i].Name = "<Empty>"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort.Slice(genres, func(i, j int) bool {
|
|
|
|
return genres[i].Name < genres[j].Name
|
|
|
|
})
|
2020-01-15 23:49:09 +01:00
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
|
|
|
response.Genres = toGenres(genres)
|
2020-01-15 23:49:09 +01:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2020-02-10 01:42:37 +01:00
|
|
|
func (c *BrowsingController) GetArtistInfo(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-10-19 01:10:11 +02:00
|
|
|
ctx := r.Context()
|
2020-10-27 20:23:29 +01:00
|
|
|
id, err := requiredParamString(r, "id")
|
2020-10-19 01:10:11 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
count := utils.ParamInt(r, "count", 20)
|
|
|
|
includeNotPresent := utils.ParamBool(r, "includeNotPresent", false)
|
|
|
|
|
2021-02-09 17:41:47 +01:00
|
|
|
artist, err := c.em.UpdateArtistInfo(ctx, id, count, includeNotPresent)
|
2020-10-19 01:10:11 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-02-10 01:42:37 +01:00
|
|
|
response.ArtistInfo = &responses.ArtistInfo{}
|
2020-10-30 21:08:43 +01:00
|
|
|
response.ArtistInfo.Biography = artist.Biography
|
|
|
|
response.ArtistInfo.SmallImageUrl = artist.SmallImageUrl
|
|
|
|
response.ArtistInfo.MediumImageUrl = artist.MediumImageUrl
|
|
|
|
response.ArtistInfo.LargeImageUrl = artist.LargeImageUrl
|
|
|
|
response.ArtistInfo.LastFmUrl = artist.ExternalUrl
|
|
|
|
response.ArtistInfo.MusicBrainzID = artist.MbzArtistID
|
|
|
|
for _, s := range artist.SimilarArtists {
|
|
|
|
similar := toArtist(ctx, s)
|
2020-10-19 01:10:11 +02:00
|
|
|
response.ArtistInfo.SimilarArtist = append(response.ArtistInfo.SimilarArtist, similar)
|
|
|
|
}
|
2020-02-10 01:42:37 +01:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *BrowsingController) GetArtistInfo2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-10-19 01:10:11 +02:00
|
|
|
info, err := c.GetArtistInfo(w, r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-02-10 01:42:37 +01:00
|
|
|
response.ArtistInfo2 = &responses.ArtistInfo2{}
|
2020-10-19 01:10:11 +02:00
|
|
|
response.ArtistInfo2.ArtistInfoBase = info.ArtistInfo.ArtistInfoBase
|
|
|
|
for _, s := range info.ArtistInfo.SimilarArtist {
|
|
|
|
similar := responses.ArtistID3{}
|
|
|
|
similar.Id = s.Id
|
|
|
|
similar.Name = s.Name
|
|
|
|
similar.AlbumCount = s.AlbumCount
|
|
|
|
similar.Starred = s.Starred
|
2020-10-30 21:08:43 +01:00
|
|
|
similar.ArtistImageUrl = s.ArtistImageUrl
|
2020-10-19 01:10:11 +02:00
|
|
|
response.ArtistInfo2.SimilarArtist = append(response.ArtistInfo2.SimilarArtist, similar)
|
|
|
|
}
|
2020-02-10 01:42:37 +01:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2020-10-20 19:38:44 +02:00
|
|
|
func (c *BrowsingController) GetSimilarSongs(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
|
|
|
ctx := r.Context()
|
2020-10-27 20:23:29 +01:00
|
|
|
id, err := requiredParamString(r, "id")
|
2020-10-20 19:38:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2020-10-21 04:53:52 +02:00
|
|
|
count := utils.ParamInt(r, "count", 50)
|
2020-10-20 19:38:44 +02:00
|
|
|
|
2021-02-09 17:41:47 +01:00
|
|
|
songs, err := c.em.SimilarSongs(ctx, id, count)
|
2020-10-20 19:38:44 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
response := newResponse()
|
|
|
|
response.SimilarSongs = &responses.SimilarSongs{
|
|
|
|
Song: childrenFromMediaFiles(ctx, songs),
|
|
|
|
}
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *BrowsingController) GetSimilarSongs2(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
|
|
|
res, err := c.GetSimilarSongs(w, r)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
response := newResponse()
|
|
|
|
response.SimilarSongs2 = &responses.SimilarSongs2{
|
2020-10-20 22:00:29 +02:00
|
|
|
Song: res.SimilarSongs.Song,
|
2020-10-20 19:38:44 +02:00
|
|
|
}
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2020-08-05 19:48:50 +02:00
|
|
|
func (c *BrowsingController) GetTopSongs(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
|
2020-10-21 04:53:52 +02:00
|
|
|
ctx := r.Context()
|
2020-10-27 20:23:29 +01:00
|
|
|
artist, err := requiredParamString(r, "artist")
|
2020-10-21 04:53:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
count := utils.ParamInt(r, "count", 50)
|
|
|
|
|
2021-02-09 17:41:47 +01:00
|
|
|
songs, err := c.em.TopSongs(ctx, artist, count)
|
2020-10-21 04:53:52 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
response := newResponse()
|
2020-10-21 04:53:52 +02:00
|
|
|
response.TopSongs = &responses.TopSongs{
|
|
|
|
Song: childrenFromMediaFiles(ctx, songs),
|
|
|
|
}
|
2020-08-05 19:48:50 +02:00
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
2020-08-14 03:52:44 +02:00
|
|
|
func (c *BrowsingController) buildArtistDirectory(ctx context.Context, artist *model.Artist) (*responses.Directory, error) {
|
|
|
|
dir := &responses.Directory{}
|
|
|
|
dir.Id = artist.ID
|
|
|
|
dir.Name = artist.Name
|
|
|
|
dir.PlayCount = artist.PlayCount
|
|
|
|
dir.AlbumCount = artist.AlbumCount
|
|
|
|
dir.UserRating = artist.Rating
|
|
|
|
if artist.Starred {
|
|
|
|
dir.Starred = &artist.StarredAt
|
2016-03-21 14:35:18 +01:00
|
|
|
}
|
2020-08-14 03:52:44 +02:00
|
|
|
|
|
|
|
albums, err := c.ds.Album(ctx).FindByArtist(artist.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-03-21 14:35:18 +01:00
|
|
|
}
|
2016-03-08 14:48:47 +01:00
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
dir.Child = childrenFromAlbums(ctx, albums)
|
2020-08-14 03:52:44 +02:00
|
|
|
return dir, nil
|
2016-03-03 15:50:50 +01:00
|
|
|
}
|
2016-03-28 03:27:45 +02:00
|
|
|
|
2020-08-14 00:37:54 +02:00
|
|
|
func (c *BrowsingController) buildArtist(ctx context.Context, artist *model.Artist, albums model.Albums) *responses.ArtistWithAlbumsID3 {
|
2020-10-30 21:08:43 +01:00
|
|
|
a := &responses.ArtistWithAlbumsID3{}
|
|
|
|
a.ArtistID3 = toArtistID3(ctx, *artist)
|
|
|
|
a.Album = childrenFromAlbums(ctx, albums)
|
|
|
|
return a
|
2016-03-28 03:27:45 +02:00
|
|
|
}
|
2016-03-28 15:16:03 +02:00
|
|
|
|
2020-08-14 03:52:44 +02:00
|
|
|
func (c *BrowsingController) buildAlbumDirectory(ctx context.Context, album *model.Album) (*responses.Directory, error) {
|
|
|
|
dir := &responses.Directory{}
|
|
|
|
dir.Id = album.ID
|
|
|
|
dir.Name = album.Name
|
|
|
|
dir.Parent = album.AlbumArtistID
|
|
|
|
dir.PlayCount = album.PlayCount
|
|
|
|
dir.UserRating = album.Rating
|
|
|
|
dir.SongCount = album.SongCount
|
|
|
|
dir.CoverArt = album.CoverArtId
|
|
|
|
if album.Starred {
|
|
|
|
dir.Starred = &album.StarredAt
|
|
|
|
}
|
|
|
|
|
|
|
|
mfs, err := c.ds.MediaFile(ctx).FindByAlbum(album.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
dir.Child = childrenFromMediaFiles(ctx, mfs)
|
2020-08-14 03:52:44 +02:00
|
|
|
return dir, nil
|
|
|
|
}
|
|
|
|
|
2020-08-14 00:50:28 +02:00
|
|
|
func (c *BrowsingController) buildAlbum(ctx context.Context, album *model.Album, mfs model.MediaFiles) *responses.AlbumWithSongsID3 {
|
2016-03-28 15:16:03 +02:00
|
|
|
dir := &responses.AlbumWithSongsID3{}
|
2020-08-14 00:50:28 +02:00
|
|
|
dir.Id = album.ID
|
|
|
|
dir.Name = album.Name
|
|
|
|
dir.Artist = album.AlbumArtist
|
|
|
|
dir.ArtistId = album.AlbumArtistID
|
|
|
|
dir.CoverArt = album.CoverArtId
|
|
|
|
dir.SongCount = album.SongCount
|
|
|
|
dir.Duration = int(album.Duration)
|
|
|
|
dir.PlayCount = album.PlayCount
|
|
|
|
dir.Year = album.MaxYear
|
|
|
|
dir.Genre = album.Genre
|
|
|
|
if !album.CreatedAt.IsZero() {
|
|
|
|
dir.Created = &album.CreatedAt
|
2016-03-28 15:16:03 +02:00
|
|
|
}
|
2020-08-14 00:50:28 +02:00
|
|
|
if album.Starred {
|
|
|
|
dir.Starred = &album.StarredAt
|
2016-03-28 15:16:03 +02:00
|
|
|
}
|
|
|
|
|
2020-08-14 04:11:18 +02:00
|
|
|
dir.Song = childrenFromMediaFiles(ctx, mfs)
|
2016-03-28 15:16:03 +02:00
|
|
|
return dir
|
|
|
|
}
|