Refactor getMusicDirectory

This commit is contained in:
Deluan 2020-08-13 21:52:44 -04:00 committed by Deluan Quintão
parent 15c8f4c0ef
commit f16dc5f8f8
3 changed files with 76 additions and 154 deletions

View File

@ -105,7 +105,9 @@ func (c *BrowsingController) GetArtists(w http.ResponseWriter, r *http.Request)
func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) { func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) {
id := utils.ParamString(r, "id") id := utils.ParamString(r, "id")
dir, err := c.browser.Directory(r.Context(), id) ctx := r.Context()
entity, err := getEntityByID(ctx, c.ds, id)
switch { switch {
case err == model.ErrNotFound: case err == model.ErrNotFound:
log.Error(r, "Requested ID not found ", "id", id) log.Error(r, "Requested ID not found ", "id", id)
@ -115,8 +117,25 @@ func (c *BrowsingController) GetMusicDirectory(w http.ResponseWriter, r *http.Re
return nil, NewError(responses.ErrorGeneric, "Internal Error") return nil, NewError(responses.ErrorGeneric, "Internal Error")
} }
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)
return nil, NewError(responses.ErrorDataNotFound, "Directory not found")
}
if err != nil {
log.Error(err)
return nil, NewError(responses.ErrorGeneric, "Internal Error")
}
response := NewResponse() response := NewResponse()
response.Directory = c.buildDirectory(r.Context(), dir) response.Directory = dir
return response, nil return response, nil
} }
@ -233,21 +252,24 @@ func (c *BrowsingController) GetTopSongs(w http.ResponseWriter, r *http.Request)
return response, nil return response, nil
} }
func (c *BrowsingController) buildDirectory(ctx context.Context, d *engine.DirectoryInfo) *responses.Directory { func (c *BrowsingController) buildArtistDirectory(ctx context.Context, artist *model.Artist) (*responses.Directory, error) {
dir := &responses.Directory{ dir := &responses.Directory{}
Id: d.Id, dir.Id = artist.ID
Name: d.Name, dir.Name = artist.Name
Parent: d.Parent, dir.PlayCount = artist.PlayCount
PlayCount: d.PlayCount, dir.AlbumCount = artist.AlbumCount
AlbumCount: d.AlbumCount, dir.UserRating = artist.Rating
UserRating: d.UserRating, if artist.Starred {
} dir.Starred = &artist.StarredAt
if !d.Starred.IsZero() {
dir.Starred = &d.Starred
} }
dir.Child = ToChildren(ctx, d.Entries) albums, err := c.ds.Album(ctx).FindByArtist(artist.ID)
return dir if err != nil {
return nil, err
}
dir.Child = ChildrenFromAlbums(ctx, albums)
return dir, nil
} }
func (c *BrowsingController) buildArtist(ctx context.Context, artist *model.Artist, albums model.Albums) *responses.ArtistWithAlbumsID3 { func (c *BrowsingController) buildArtist(ctx context.Context, artist *model.Artist, albums model.Albums) *responses.ArtistWithAlbumsID3 {
@ -263,6 +285,28 @@ func (c *BrowsingController) buildArtist(ctx context.Context, artist *model.Arti
return dir return dir
} }
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
}
dir.Child = ChildrenFromMediaFiles(ctx, mfs)
return dir, nil
}
func (c *BrowsingController) buildAlbum(ctx context.Context, album *model.Album, mfs model.MediaFiles) *responses.AlbumWithSongsID3 { func (c *BrowsingController) buildAlbum(ctx context.Context, album *model.Album, mfs model.MediaFiles) *responses.AlbumWithSongsID3 {
dir := &responses.AlbumWithSongsID3{} dir := &responses.AlbumWithSongsID3{}
dir.Id = album.ID dir.Id = album.ID

View File

@ -2,18 +2,13 @@ package engine
import ( import (
"context" "context"
"fmt"
"sort" "sort"
"strings" "strings"
"time"
"github.com/deluan/navidrome/log"
"github.com/deluan/navidrome/model" "github.com/deluan/navidrome/model"
) )
type Browser interface { type Browser interface {
Directory(ctx context.Context, id string) (*DirectoryInfo, error)
Album(ctx context.Context, id string) (*DirectoryInfo, error)
GetSong(ctx context.Context, id string) (*Entry, error) GetSong(ctx context.Context, id string) (*Entry, error)
GetGenres(ctx context.Context) (model.Genres, error) GetGenres(ctx context.Context) (model.Genres, error)
} }
@ -26,55 +21,6 @@ type browser struct {
ds model.DataStore ds model.DataStore
} }
type DirectoryInfo struct {
Id string
Name string
Entries Entries
Parent string
Starred time.Time
PlayCount int64
UserRating int
AlbumCount int
CoverArt string
Artist string
ArtistId string
SongCount int
Duration int
Created time.Time
Year int
Genre string
}
func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error) {
a, albums, err := b.retrieveArtist(ctx, id)
if err != nil {
return nil, err
}
log.Debug(ctx, "Found Artist", "id", id, "name", a.Name)
return b.buildArtistDir(a, albums), nil
}
func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) {
al, tracks, err := b.retrieveAlbum(ctx, id)
if err != nil {
return nil, err
}
log.Debug(ctx, "Found Album", "id", id, "name", al.Name)
return b.buildAlbumDir(al, tracks), nil
}
func (b *browser) Directory(ctx context.Context, id string) (*DirectoryInfo, error) {
switch {
case b.isArtist(ctx, id):
return b.Artist(ctx, id)
case b.isAlbum(ctx, id):
return b.Album(ctx, id)
default:
log.Debug(ctx, "Directory not found", "id", id)
return nil, model.ErrNotFound
}
}
func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) { func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) {
mf, err := b.ds.MediaFile(ctx).Get(id) mf, err := b.ds.MediaFile(ctx).Get(id)
if err != nil { if err != nil {
@ -97,88 +43,3 @@ func (b *browser) GetGenres(ctx context.Context) (model.Genres, error) {
}) })
return genres, err return genres, err
} }
func (b *browser) buildArtistDir(a *model.Artist, albums model.Albums) *DirectoryInfo {
dir := &DirectoryInfo{
Id: a.ID,
Name: a.Name,
AlbumCount: a.AlbumCount,
}
dir.Entries = make(Entries, len(albums))
for i := range albums {
al := albums[i]
dir.Entries[i] = FromAlbum(&al)
dir.PlayCount += al.PlayCount
}
return dir
}
func (b *browser) buildAlbumDir(al *model.Album, tracks model.MediaFiles) *DirectoryInfo {
dir := &DirectoryInfo{
Id: al.ID,
Name: al.Name,
Parent: al.AlbumArtistID,
Artist: al.AlbumArtist,
ArtistId: al.AlbumArtistID,
SongCount: al.SongCount,
Duration: int(al.Duration),
Created: al.CreatedAt,
Year: al.MaxYear,
Genre: al.Genre,
CoverArt: al.CoverArtId,
PlayCount: al.PlayCount,
UserRating: al.Rating,
}
if al.Starred {
dir.Starred = al.StarredAt
}
dir.Entries = FromMediaFiles(tracks)
return dir
}
func (b *browser) isArtist(ctx context.Context, id string) bool {
found, err := b.ds.Artist(ctx).Exists(id)
if err != nil {
log.Debug(ctx, "Error searching for Artist", "id", id, err)
return false
}
return found
}
func (b *browser) isAlbum(ctx context.Context, id string) bool {
found, err := b.ds.Album(ctx).Exists(id)
if err != nil {
log.Debug(ctx, "Error searching for Album", "id", id, err)
return false
}
return found
}
func (b *browser) retrieveArtist(ctx context.Context, id string) (a *model.Artist, as model.Albums, err error) {
a, err = b.ds.Artist(ctx).Get(id)
if err != nil {
err = fmt.Errorf("Error reading Artist %s from DB: %v", id, err)
return
}
if as, err = b.ds.Album(ctx).FindByArtist(id); err != nil {
err = fmt.Errorf("Error reading %s's albums from DB: %v", a.Name, err)
}
return
}
func (b *browser) retrieveAlbum(ctx context.Context, id string) (al *model.Album, mfs model.MediaFiles, err error) {
al, err = b.ds.Album(ctx).Get(id)
if err != nil {
err = fmt.Errorf("Error reading Album %s from DB: %v", id, err)
return
}
if mfs, err = b.ds.MediaFile(ctx).FindByAlbum(id); err != nil {
err = fmt.Errorf("Error reading %s's tracks from DB: %v", al.Name, err)
}
return
}

View File

@ -255,3 +255,20 @@ func ChildrenFromAlbums(ctx context.Context, als model.Albums) []responses.Child
} }
return children return children
} }
// TODO: Should the type be encoded in the ID?
func getEntityByID(ctx context.Context, ds model.DataStore, id string) (interface{}, error) {
ar, err := ds.Artist(ctx).Get(id)
if err == nil {
return ar, nil
}
al, err := ds.Album(ctx).Get(id)
if err == nil {
return al, nil
}
mf, err := ds.MediaFile(ctx).Get(id)
if err == nil {
return mf, nil
}
return nil, err
}