Implement annotations per user
This commit is contained in:
+54
-24
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user