diff --git a/engine/list_generator.go b/engine/list_generator.go index 95c4df04b..0ffe6f3ce 100644 --- a/engine/list_generator.go +++ b/engine/list_generator.go @@ -12,6 +12,7 @@ type ListGenerator interface { GetAllStarred(ctx context.Context) (artists Entries, albums Entries, mediaFiles Entries, err error) GetNowPlaying(ctx context.Context) (Entries, error) GetRandomSongs(ctx context.Context, size int, genre string) (Entries, error) + GetSongsByGenre(ctx context.Context, offset int, count int, genre string) (Entries, error) GetAlbums(ctx context.Context, offset, size int, filter AlbumFilter) (Entries, error) } @@ -106,6 +107,19 @@ func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre stri return FromMediaFiles(mediaFiles), nil } +func (g *listGenerator) GetSongsByGenre(ctx context.Context, offset int, count int, genre string) (Entries, error) { + options := model.QueryOptions{Offset: offset, Max: count} + if genre != "" { + options.Filters = squirrel.Eq{"genre": genre} + } + mediaFiles, err := g.ds.MediaFile(ctx).GetAll(options) + if err != nil { + return nil, err + } + + return FromMediaFiles(mediaFiles), nil +} + func (g *listGenerator) GetAlbums(ctx context.Context, offset, size int, filter AlbumFilter) (Entries, error) { qo := model.QueryOptions(filter) qo.Offset = offset diff --git a/model/mediafile.go b/model/mediafile.go index cbed33b8b..14115a49d 100644 --- a/model/mediafile.go +++ b/model/mediafile.go @@ -48,6 +48,7 @@ type MediaFileRepository interface { Exists(id string) (bool, error) Put(m *MediaFile) error Get(id string) (*MediaFile, error) + GetAll(options ...QueryOptions) (MediaFiles, error) FindByAlbum(albumId string) (MediaFiles, error) FindByPath(path string) (MediaFiles, error) GetStarred(options ...QueryOptions) (MediaFiles, error) diff --git a/server/subsonic/album_lists.go b/server/subsonic/album_lists.go index cb67ad550..780e61fde 100644 --- a/server/subsonic/album_lists.go +++ b/server/subsonic/album_lists.go @@ -153,3 +153,20 @@ func (c *AlbumListController) GetRandomSongs(w http.ResponseWriter, r *http.Requ response.RandomSongs.Songs = ToChildren(r.Context(), songs) return response, nil } + +func (c *AlbumListController) GetSongsByGenre(w http.ResponseWriter, r *http.Request) (*responses.Subsonic, error) { + count := utils.MinInt(utils.ParamInt(r, "count", 10), 500) + offset := utils.MinInt(utils.ParamInt(r, "offset", 0), 500) + genre := utils.ParamString(r, "genre") + + songs, err := c.listGen.GetSongsByGenre(r.Context(), offset, count, genre) + if err != nil { + log.Error(r, "Error retrieving random songs", "error", err) + return nil, NewError(responses.ErrorGeneric, "Internal Error") + } + + response := NewResponse() + response.RandomSongs = &responses.Songs{} + response.RandomSongs.Songs = ToChildren(r.Context(), songs) + return response, nil +} diff --git a/server/subsonic/api.go b/server/subsonic/api.go index 833aca891..b36e20295 100644 --- a/server/subsonic/api.go +++ b/server/subsonic/api.go @@ -86,6 +86,7 @@ func (api *Router) routes() http.Handler { H(withPlayer, "getStarred2", c.GetStarred2) H(withPlayer, "getNowPlaying", c.GetNowPlaying) H(withPlayer, "getRandomSongs", c.GetRandomSongs) + H(withPlayer, "getSongsByGenre", c.GetSongsByGenre) }) r.Group(func(r chi.Router) { c := initMediaAnnotationController(api) diff --git a/server/subsonic/responses/responses.go b/server/subsonic/responses/responses.go index 3db71b97d..c7fcec656 100644 --- a/server/subsonic/responses/responses.go +++ b/server/subsonic/responses/responses.go @@ -28,6 +28,7 @@ type Subsonic struct { NowPlaying *NowPlaying `xml:"nowPlaying,omitempty" json:"nowPlaying,omitempty"` Song *Child `xml:"song,omitempty" json:"song,omitempty"` RandomSongs *Songs `xml:"randomSongs,omitempty" json:"randomSongs,omitempty"` + SongsByGenre *Songs `xml:"songsByGenre,omitempty" json:"songsByGenre,omitempty"` Genres *Genres `xml:"genres,omitempty" json:"genres,omitempty"` // ID3