Implement annotations per user

This commit is contained in:
Deluan
2020-01-21 23:01:43 -05:00
parent e03304650d
commit d7116eebd4
26 changed files with 572 additions and 262 deletions
+54 -24
View File
@@ -19,7 +19,7 @@ type Browser interface {
Directory(ctx context.Context, id string) (*DirectoryInfo, error)
Artist(ctx context.Context, id string) (*DirectoryInfo, error)
Album(ctx context.Context, id string) (*DirectoryInfo, error)
GetSong(id string) (*Entry, error)
GetSong(ctx context.Context, id string) (*Entry, error)
GetGenres() (model.Genres, error)
}
@@ -77,7 +77,12 @@ func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error)
return nil, err
}
log.Debug(ctx, "Found Artist", "id", id, "name", a.Name)
return b.buildArtistDir(a, albums), nil
var albumIds []string
for _, al := range albums {
albumIds = append(albumIds, al.ID)
}
annMap, err := b.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
return b.buildArtistDir(a, albums, annMap), nil
}
func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) {
@@ -86,7 +91,21 @@ func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error)
return nil, err
}
log.Debug(ctx, "Found Album", "id", id, "name", al.Name)
return b.buildAlbumDir(al, tracks), nil
var mfIds []string
for _, mf := range tracks {
mfIds = append(mfIds, mf.ID)
}
userID := getUserID(ctx)
trackAnnMap, err := b.ds.Annotation().GetMap(userID, model.MediaItemType, mfIds)
if err != nil {
return nil, err
}
ann, err := b.ds.Annotation().Get(userID, model.AlbumItemType, al.ID)
if err != nil {
return nil, err
}
return b.buildAlbumDir(al, ann, tracks, trackAnnMap), nil
}
func (b *browser) Directory(ctx context.Context, id string) (*DirectoryInfo, error) {
@@ -101,13 +120,19 @@ func (b *browser) Directory(ctx context.Context, id string) (*DirectoryInfo, err
}
}
func (b *browser) GetSong(id string) (*Entry, error) {
func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) {
mf, err := b.ds.MediaFile().Get(id)
if err != nil {
return nil, err
}
entry := FromMediaFile(mf)
userId := getUserID(ctx)
ann, err := b.ds.Annotation().Get(userId, model.MediaItemType, id)
if err != nil {
return nil, err
}
entry := FromMediaFile(mf, ann)
return &entry, nil
}
@@ -124,7 +149,7 @@ func (b *browser) GetGenres() (model.Genres, error) {
return genres, err
}
func (b *browser) buildArtistDir(a *model.Artist, albums model.Albums) *DirectoryInfo {
func (b *browser) buildArtistDir(a *model.Artist, albums model.Albums, albumAnnMap model.AnnotationMap) *DirectoryInfo {
dir := &DirectoryInfo{
Id: a.ID,
Name: a.Name,
@@ -133,33 +158,38 @@ func (b *browser) buildArtistDir(a *model.Artist, albums model.Albums) *Director
dir.Entries = make(Entries, len(albums))
for i, al := range albums {
dir.Entries[i] = FromAlbum(&al)
dir.PlayCount += int32(al.PlayCount)
ann := albumAnnMap[al.ID]
dir.Entries[i] = FromAlbum(&al, &ann)
dir.PlayCount += int32(ann.PlayCount)
}
return dir
}
func (b *browser) buildAlbumDir(al *model.Album, tracks model.MediaFiles) *DirectoryInfo {
func (b *browser) buildAlbumDir(al *model.Album, albumAnn *model.Annotation, tracks model.MediaFiles, trackAnnMap model.AnnotationMap) *DirectoryInfo {
dir := &DirectoryInfo{
Id: al.ID,
Name: al.Name,
Parent: al.ArtistID,
PlayCount: int32(al.PlayCount),
UserRating: al.Rating,
Starred: al.StarredAt,
Artist: al.Artist,
ArtistId: al.ArtistID,
SongCount: al.SongCount,
Duration: al.Duration,
Created: al.CreatedAt,
Year: al.Year,
Genre: al.Genre,
CoverArt: al.CoverArtId,
Id: al.ID,
Name: al.Name,
Parent: al.ArtistID,
Artist: al.Artist,
ArtistId: al.ArtistID,
SongCount: al.SongCount,
Duration: al.Duration,
Created: al.CreatedAt,
Year: al.Year,
Genre: al.Genre,
CoverArt: al.CoverArtId,
}
if albumAnn != nil {
dir.PlayCount = int32(albumAnn.PlayCount)
dir.Starred = albumAnn.StarredAt
dir.UserRating = albumAnn.Rating
}
dir.Entries = make(Entries, len(tracks))
for i, mf := range tracks {
dir.Entries[i] = FromMediaFile(&mf)
mfId := mf.ID
ann := trackAnnMap[mfId]
dir.Entries[i] = FromMediaFile(&mf, &ann)
}
return dir
}
+34 -16
View File
@@ -1,6 +1,7 @@
package engine
import (
"context"
"fmt"
"time"
@@ -45,17 +46,19 @@ type Entry struct {
type Entries []Entry
func FromArtist(ar *model.Artist) Entry {
func FromArtist(ar *model.Artist, ann *model.Annotation) Entry {
e := Entry{}
e.Id = ar.ID
e.Title = ar.Name
e.AlbumCount = ar.AlbumCount
e.Starred = ar.StarredAt
e.IsDir = true
if ann != nil {
e.Starred = ann.StarredAt
}
return e
}
func FromAlbum(al *model.Album) Entry {
func FromAlbum(al *model.Album, ann *model.Annotation) Entry {
e := Entry{}
e.Id = al.ID
e.Title = al.Name
@@ -66,18 +69,20 @@ func FromAlbum(al *model.Album) Entry {
e.Artist = al.AlbumArtist
e.Genre = al.Genre
e.CoverArt = al.CoverArtId
e.Starred = al.StarredAt
e.PlayCount = int32(al.PlayCount)
e.Created = al.CreatedAt
e.AlbumId = al.ID
e.ArtistId = al.ArtistID
e.UserRating = al.Rating
e.Duration = al.Duration
e.SongCount = al.SongCount
if ann != nil {
e.Starred = ann.StarredAt
e.PlayCount = int32(ann.PlayCount)
e.UserRating = ann.Rating
}
return e
}
func FromMediaFile(mf *model.MediaFile) Entry {
func FromMediaFile(mf *model.MediaFile, ann *model.Annotation) Entry {
e := Entry{}
e.Id = mf.ID
e.Title = mf.Title
@@ -92,7 +97,6 @@ func FromMediaFile(mf *model.MediaFile) Entry {
e.Size = mf.Size
e.Suffix = mf.Suffix
e.BitRate = mf.BitRate
e.Starred = mf.StarredAt
if mf.HasCoverArt {
e.CoverArt = mf.ID
}
@@ -102,13 +106,16 @@ func FromMediaFile(mf *model.MediaFile) Entry {
if mf.Path != "" {
e.Path = fmt.Sprintf("%s/%s/%s.%s", realArtistName(mf), mf.Album, mf.Title, mf.Suffix)
}
e.PlayCount = int32(mf.PlayCount)
e.DiscNumber = mf.DiscNumber
e.Created = mf.CreatedAt
e.AlbumId = mf.AlbumID
e.ArtistId = mf.ArtistID
e.Type = "music" // TODO Hardcoded for now
e.UserRating = mf.Rating
if ann != nil {
e.PlayCount = int32(ann.PlayCount)
e.Starred = ann.StarredAt
e.UserRating = ann.Rating
}
return e
}
@@ -123,26 +130,37 @@ func realArtistName(mf *model.MediaFile) string {
return mf.Artist
}
func FromAlbums(albums model.Albums) Entries {
func FromAlbums(albums model.Albums, annMap model.AnnotationMap) Entries {
entries := make(Entries, len(albums))
for i, al := range albums {
entries[i] = FromAlbum(&al)
ann := annMap[al.ID]
entries[i] = FromAlbum(&al, &ann)
}
return entries
}
func FromMediaFiles(mfs model.MediaFiles) Entries {
func FromMediaFiles(mfs model.MediaFiles, annMap model.AnnotationMap) Entries {
entries := make(Entries, len(mfs))
for i, mf := range mfs {
entries[i] = FromMediaFile(&mf)
ann := annMap[mf.ID]
entries[i] = FromMediaFile(&mf, &ann)
}
return entries
}
func FromArtists(ars model.Artists) Entries {
func FromArtists(ars model.Artists, annMap model.AnnotationMap) Entries {
entries := make(Entries, len(ars))
for i, ar := range ars {
entries[i] = FromArtist(&ar)
ann := annMap[ar.ID]
entries[i] = FromArtist(&ar, &ann)
}
return entries
}
func getUserID(ctx context.Context) string {
user, ok := ctx.Value("user").(*model.User)
if ok {
return user.ID
}
return ""
}
+96 -45
View File
@@ -1,23 +1,24 @@
package engine
import (
"context"
"time"
"github.com/cloudsonic/sonic-server/model"
)
type ListGenerator interface {
GetNewest(offset int, size int) (Entries, error)
GetRecent(offset int, size int) (Entries, error)
GetFrequent(offset int, size int) (Entries, error)
GetHighest(offset int, size int) (Entries, error)
GetRandom(offset int, size int) (Entries, error)
GetByName(offset int, size int) (Entries, error)
GetByArtist(offset int, size int) (Entries, error)
GetStarred(offset int, size int) (Entries, error)
GetAllStarred() (artists Entries, albums Entries, mediaFiles Entries, err error)
GetNowPlaying() (Entries, error)
GetRandomSongs(size int, genre string) (Entries, error)
GetNewest(ctx context.Context, offset int, size int) (Entries, error)
GetRecent(ctx context.Context, offset int, size int) (Entries, error)
GetFrequent(ctx context.Context, offset int, size int) (Entries, error)
GetHighest(ctx context.Context, offset int, size int) (Entries, error)
GetRandom(ctx context.Context, offset int, size int) (Entries, error)
GetByName(ctx context.Context, offset int, size int) (Entries, error)
GetByArtist(ctx context.Context, offset int, size int) (Entries, error)
GetStarred(ctx context.Context, offset int, size int) (Entries, error)
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)
}
func NewListGenerator(ds model.DataStore, npRepo NowPlayingRepository) ListGenerator {
@@ -30,58 +31,76 @@ type listGenerator struct {
}
// TODO: Only return albums that have the Sort field != empty
func (g *listGenerator) query(qo model.QueryOptions, offset int, size int) (Entries, error) {
func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions, offset int, size int) (Entries, error) {
qo.Offset = offset
qo.Max = size
albums, err := g.ds.Album().GetAll(qo)
return FromAlbums(albums), err
if err != nil {
return nil, err
}
albumIds := make([]string, len(albums))
for i, al := range albums {
albumIds[i] = al.ID
}
annMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
if err != nil {
return nil, err
}
return FromAlbums(albums, annMap), err
}
func (g *listGenerator) GetNewest(offset int, size int) (Entries, error) {
func (g *listGenerator) GetNewest(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Sort: "CreatedAt", Order: "desc"}
return g.query(qo, offset, size)
return g.query(ctx, qo, offset, size)
}
func (g *listGenerator) GetRecent(offset int, size int) (Entries, error) {
func (g *listGenerator) GetRecent(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Sort: "PlayDate", Order: "desc"}
return g.query(qo, offset, size)
return g.query(ctx, qo, offset, size)
}
func (g *listGenerator) GetFrequent(offset int, size int) (Entries, error) {
func (g *listGenerator) GetFrequent(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Sort: "PlayCount", Order: "desc"}
return g.query(qo, offset, size)
return g.query(ctx, qo, offset, size)
}
func (g *listGenerator) GetHighest(offset int, size int) (Entries, error) {
func (g *listGenerator) GetHighest(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Sort: "Rating", Order: "desc"}
return g.query(qo, offset, size)
return g.query(ctx, qo, offset, size)
}
func (g *listGenerator) GetByName(offset int, size int) (Entries, error) {
func (g *listGenerator) GetByName(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Sort: "Name"}
return g.query(qo, offset, size)
return g.query(ctx, qo, offset, size)
}
func (g *listGenerator) GetByArtist(offset int, size int) (Entries, error) {
func (g *listGenerator) GetByArtist(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Sort: "Artist"}
return g.query(qo, offset, size)
return g.query(ctx, qo, offset, size)
}
func (g *listGenerator) GetRandom(offset int, size int) (Entries, error) {
func (g *listGenerator) GetRandom(ctx context.Context, offset int, size int) (Entries, error) {
albums, err := g.ds.Album().GetRandom(model.QueryOptions{Max: size, Offset: offset})
if err != nil {
return nil, err
}
r := make(Entries, len(albums))
for i, al := range albums {
r[i] = FromAlbum(&al)
annMap, err := g.getAnnotationsForAlbums(ctx, albums)
if err != nil {
return nil, err
}
return r, nil
return FromAlbums(albums, annMap), nil
}
func (g *listGenerator) GetRandomSongs(size int, genre string) (Entries, error) {
func (g *listGenerator) getAnnotationsForAlbums(ctx context.Context, albums model.Albums) (model.AnnotationMap, error) {
albumIds := make([]string, len(albums))
for i, al := range albums {
albumIds[i] = al.ID
}
return g.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
}
func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre string) (Entries, error) {
options := model.QueryOptions{Max: size}
if genre != "" {
options.Filters = map[string]interface{}{"genre": genre}
@@ -93,47 +112,78 @@ func (g *listGenerator) GetRandomSongs(size int, genre string) (Entries, error)
r := make(Entries, len(mediaFiles))
for i, mf := range mediaFiles {
r[i] = FromMediaFile(&mf)
ann, err := g.ds.Annotation().Get(getUserID(ctx), model.MediaItemType, mf.ID)
if err != nil {
return nil, err
}
r[i] = FromMediaFile(&mf, ann)
}
return r, nil
}
func (g *listGenerator) GetStarred(offset int, size int) (Entries, error) {
func (g *listGenerator) GetStarred(ctx context.Context, offset int, size int) (Entries, error) {
qo := model.QueryOptions{Offset: offset, Max: size, Sort: "starred_at", Order: "desc"}
albums, err := g.ds.Album().GetStarred(qo)
albums, err := g.ds.Album().GetStarred(getUserID(ctx), qo)
if err != nil {
return nil, err
}
return FromAlbums(albums), nil
annMap, err := g.getAnnotationsForAlbums(ctx, albums)
if err != nil {
return nil, err
}
return FromAlbums(albums, annMap), nil
}
func (g *listGenerator) GetAllStarred() (artists Entries, albums Entries, mediaFiles Entries, err error) {
func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, albums Entries, mediaFiles Entries, err error) {
options := model.QueryOptions{Sort: "starred_at", Order: "desc"}
ars, err := g.ds.Artist().GetStarred(options)
ars, err := g.ds.Artist().GetStarred(getUserID(ctx), options)
if err != nil {
return nil, nil, nil, err
}
als, err := g.ds.Album().GetStarred(options)
als, err := g.ds.Album().GetStarred(getUserID(ctx), options)
if err != nil {
return nil, nil, nil, err
}
mfs, err := g.ds.MediaFile().GetStarred(options)
mfs, err := g.ds.MediaFile().GetStarred(getUserID(ctx), options)
if err != nil {
return nil, nil, nil, err
}
artists = FromArtists(ars)
albums = FromAlbums(als)
mediaFiles = FromMediaFiles(mfs)
var mfIds []string
for _, mf := range mfs {
mfIds = append(mfIds, mf.ID)
}
trackAnnMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, mfIds)
if err != nil {
return nil, nil, nil, err
}
albumAnnMap, err := g.getAnnotationsForAlbums(ctx, als)
if err != nil {
return nil, nil, nil, err
}
var artistIds []string
for _, ar := range ars {
artistIds = append(artistIds, ar.ID)
}
artistAnnMap, err := g.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, artistIds)
if err != nil {
return nil, nil, nil, err
}
artists = FromArtists(ars, artistAnnMap)
albums = FromAlbums(als, albumAnnMap)
mediaFiles = FromMediaFiles(mfs, trackAnnMap)
return
}
func (g *listGenerator) GetNowPlaying() (Entries, error) {
func (g *listGenerator) GetNowPlaying(ctx context.Context) (Entries, error) {
npInfo, err := g.npRepo.GetAll()
if err != nil {
return nil, err
@@ -144,7 +194,8 @@ func (g *listGenerator) GetNowPlaying() (Entries, error) {
if err != nil {
return nil, err
}
entries[i] = FromMediaFile(mf)
ann, err := g.ds.Annotation().Get(getUserID(ctx), model.MediaItemType, mf.ID)
entries[i] = FromMediaFile(mf, ann)
entries[i].UserName = np.Username
entries[i].MinutesAgo = int(time.Now().Sub(np.Start).Minutes())
entries[i].PlayerId = np.PlayerId
+11 -3
View File
@@ -10,7 +10,7 @@ import (
type Playlists interface {
GetAll() (model.Playlists, error)
Get(id string) (*PlaylistInfo, error)
Get(ctx context.Context, id string) (*PlaylistInfo, error)
Create(ctx context.Context, playlistId, name string, ids []string) error
Delete(ctx context.Context, playlistId string) error
Update(ctx context.Context, playlistId string, name *string, idsToAdd []string, idxToRemove []int) error
@@ -118,7 +118,7 @@ type PlaylistInfo struct {
Comment string
}
func (p *playlists) Get(id string) (*PlaylistInfo, error) {
func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) {
pl, err := p.ds.Playlist().GetWithTracks(id)
if err != nil {
return nil, err
@@ -136,8 +136,16 @@ func (p *playlists) Get(id string) (*PlaylistInfo, error) {
}
pinfo.Entries = make(Entries, len(pl.Tracks))
var mfIds []string
for _, mf := range pl.Tracks {
mfIds = append(mfIds, mf.ID)
}
annMap, err := p.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, mfIds)
for i, mf := range pl.Tracks {
pinfo.Entries[i] = FromMediaFile(&mf)
ann := annMap[mf.ID]
pinfo.Entries[i] = FromMediaFile(&mf, &ann)
}
return pinfo, nil
+43 -11
View File
@@ -3,6 +3,7 @@ package engine
import (
"context"
"github.com/cloudsonic/sonic-server/log"
"github.com/cloudsonic/sonic-server/model"
)
@@ -20,21 +21,52 @@ type ratings struct {
}
func (r ratings) SetRating(ctx context.Context, id string, rating int) error {
// TODO
return model.ErrNotFound
exist, err := r.ds.Album().Exists(id)
if err != nil {
return err
}
if exist {
return r.ds.Annotation().SetRating(rating, getUserID(ctx), model.AlbumItemType, id)
}
return r.ds.Annotation().SetRating(rating, getUserID(ctx), model.MediaItemType, id)
}
func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
if len(ids) == 0 {
log.Warn(ctx, "Cannot star/unstar an empty list of ids")
return nil
}
userId := getUserID(ctx)
return r.ds.WithTx(func(tx model.DataStore) error {
err := tx.MediaFile().SetStar(star, ids...)
if err != nil {
return err
for _, id := range ids {
exist, err := r.ds.Album().Exists(id)
if err != nil {
return err
}
if exist {
err = tx.Annotation().SetStar(star, userId, model.AlbumItemType, ids...)
if err != nil {
return err
}
continue
}
exist, err = r.ds.Artist().Exists(id)
if err != nil {
return err
}
if exist {
err = tx.Annotation().SetStar(star, userId, model.ArtistItemType, ids...)
if err != nil {
return err
}
continue
}
err = tx.Annotation().SetStar(star, userId, model.MediaItemType, ids...)
if err != nil {
return err
}
}
err = tx.Album().SetStar(star, ids...)
if err != nil {
return err
}
err = tx.Artist().SetStar(star, ids...)
return err
return nil
})
}
+4 -2
View File
@@ -24,6 +24,8 @@ type scrobbler struct {
}
func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string, playTime time.Time) (*model.MediaFile, error) {
userId := getUserID(ctx)
var mf *model.MediaFile
var err error
err = s.ds.WithTx(func(tx model.DataStore) error {
@@ -31,11 +33,11 @@ func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string,
if err != nil {
return err
}
err = s.ds.MediaFile().MarkAsPlayed(trackId, playTime)
err = s.ds.Annotation().IncPlayCount(userId, model.MediaItemType, trackId, playTime)
if err != nil {
return err
}
err = s.ds.Album().MarkAsPlayed(mf.AlbumID, playTime)
err = s.ds.Annotation().IncPlayCount(userId, model.AlbumItemType, mf.AlbumID, playTime)
return err
})
return mf, err
+36 -18
View File
@@ -25,39 +25,57 @@ func NewSearch(ds model.DataStore) Search {
func (s *search) SearchArtist(ctx context.Context, q string, offset int, size int) (Entries, error) {
q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
resp, err := s.ds.Artist().Search(q, offset, size)
artists, err := s.ds.Artist().Search(q, offset, size)
if len(artists) == 0 || err != nil {
return nil, nil
}
artistIds := make([]string, len(artists))
for i, al := range artists {
artistIds[i] = al.ID
}
annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.ArtistItemType, artistIds)
if err != nil {
return nil, nil
}
res := make(Entries, 0, len(resp))
for _, ar := range resp {
res = append(res, FromArtist(&ar))
}
return res, nil
return FromArtists(artists, annMap), nil
}
func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int) (Entries, error) {
q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
resp, err := s.ds.Album().Search(q, offset, size)
albums, err := s.ds.Album().Search(q, offset, size)
if len(albums) == 0 || err != nil {
return nil, nil
}
albumIds := make([]string, len(albums))
for i, al := range albums {
albumIds[i] = al.ID
}
annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
if err != nil {
return nil, nil
}
res := make(Entries, 0, len(resp))
for _, al := range resp {
res = append(res, FromAlbum(&al))
}
return res, nil
return FromAlbums(albums, annMap), nil
}
func (s *search) SearchSong(ctx context.Context, q string, offset int, size int) (Entries, error) {
q = sanitize.Accents(strings.ToLower(strings.TrimSuffix(q, "*")))
resp, err := s.ds.MediaFile().Search(q, offset, size)
mediaFiles, err := s.ds.MediaFile().Search(q, offset, size)
if len(mediaFiles) == 0 || err != nil {
return nil, nil
}
trackIds := make([]string, len(mediaFiles))
for i, mf := range mediaFiles {
trackIds[i] = mf.ID
}
annMap, err := s.ds.Annotation().GetMap(getUserID(ctx), model.MediaItemType, trackIds)
if err != nil {
return nil, nil
}
res := make(Entries, 0, len(resp))
for _, mf := range resp {
res = append(res, FromMediaFile(&mf))
}
return res, nil
return FromMediaFiles(mediaFiles, annMap), nil
}