mirror of
https://github.com/navidrome/navidrome.git
synced 2025-06-01 08:01:15 +03:00
refactor: remove annotation handling from engine
This commit is contained in:
parent
67ed830a68
commit
72d9ddf532
@ -81,8 +81,7 @@ func (b *browser) Artist(ctx context.Context, id string) (*DirectoryInfo, error)
|
|||||||
for _, al := range albums {
|
for _, al := range albums {
|
||||||
albumIds = append(albumIds, al.ID)
|
albumIds = append(albumIds, al.ID)
|
||||||
}
|
}
|
||||||
annMap, err := b.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
|
return b.buildArtistDir(a, albums), nil
|
||||||
return b.buildArtistDir(a, albums, annMap), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) {
|
func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error) {
|
||||||
@ -96,16 +95,7 @@ func (b *browser) Album(ctx context.Context, id string) (*DirectoryInfo, error)
|
|||||||
mfIds = append(mfIds, mf.ID)
|
mfIds = append(mfIds, mf.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
userID := getUserID(ctx)
|
return b.buildAlbumDir(al, tracks), nil
|
||||||
trackAnnMap, err := b.ds.Annotation(ctx).GetMap(userID, model.MediaItemType, mfIds)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
ann, err := b.ds.Annotation(ctx).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) {
|
func (b *browser) Directory(ctx context.Context, id string) (*DirectoryInfo, error) {
|
||||||
@ -126,13 +116,7 @@ func (b *browser) GetSong(ctx context.Context, id string) (*Entry, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
userId := getUserID(ctx)
|
entry := FromMediaFile(mf)
|
||||||
ann, err := b.ds.Annotation(ctx).Get(userId, model.MediaItemType, id)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
entry := FromMediaFile(mf, ann)
|
|
||||||
return &entry, nil
|
return &entry, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +133,7 @@ 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, albumAnnMap model.AnnotationMap) *DirectoryInfo {
|
func (b *browser) buildArtistDir(a *model.Artist, albums model.Albums) *DirectoryInfo {
|
||||||
dir := &DirectoryInfo{
|
dir := &DirectoryInfo{
|
||||||
Id: a.ID,
|
Id: a.ID,
|
||||||
Name: a.Name,
|
Name: a.Name,
|
||||||
@ -158,39 +142,31 @@ func (b *browser) buildArtistDir(a *model.Artist, albums model.Albums, albumAnnM
|
|||||||
|
|
||||||
dir.Entries = make(Entries, len(albums))
|
dir.Entries = make(Entries, len(albums))
|
||||||
for i, al := range albums {
|
for i, al := range albums {
|
||||||
ann := albumAnnMap[al.ID]
|
dir.Entries[i] = FromAlbum(&al)
|
||||||
dir.Entries[i] = FromAlbum(&al, &ann)
|
dir.PlayCount += int32(al.PlayCount)
|
||||||
dir.PlayCount += int32(ann.PlayCount)
|
|
||||||
}
|
}
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *browser) buildAlbumDir(al *model.Album, albumAnn *model.Annotation, tracks model.MediaFiles, trackAnnMap model.AnnotationMap) *DirectoryInfo {
|
func (b *browser) buildAlbumDir(al *model.Album, tracks model.MediaFiles) *DirectoryInfo {
|
||||||
dir := &DirectoryInfo{
|
dir := &DirectoryInfo{
|
||||||
Id: al.ID,
|
Id: al.ID,
|
||||||
Name: al.Name,
|
Name: al.Name,
|
||||||
Parent: al.ArtistID,
|
Parent: al.ArtistID,
|
||||||
Artist: al.Artist,
|
Artist: al.Artist,
|
||||||
ArtistId: al.ArtistID,
|
ArtistId: al.ArtistID,
|
||||||
SongCount: al.SongCount,
|
SongCount: al.SongCount,
|
||||||
Duration: al.Duration,
|
Duration: al.Duration,
|
||||||
Created: al.CreatedAt,
|
Created: al.CreatedAt,
|
||||||
Year: al.Year,
|
Year: al.Year,
|
||||||
Genre: al.Genre,
|
Genre: al.Genre,
|
||||||
CoverArt: al.CoverArtId,
|
CoverArt: al.CoverArtId,
|
||||||
}
|
PlayCount: int32(al.PlayCount),
|
||||||
if albumAnn != nil {
|
Starred: al.StarredAt,
|
||||||
dir.PlayCount = int32(albumAnn.PlayCount)
|
UserRating: al.Rating,
|
||||||
dir.Starred = albumAnn.StarredAt
|
|
||||||
dir.UserRating = albumAnn.Rating
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dir.Entries = make(Entries, len(tracks))
|
dir.Entries = FromMediaFiles(tracks)
|
||||||
for i, mf := range tracks {
|
|
||||||
mfId := mf.ID
|
|
||||||
ann := trackAnnMap[mfId]
|
|
||||||
dir.Entries[i] = FromMediaFile(&mf, &ann)
|
|
||||||
}
|
|
||||||
return dir
|
return dir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package engine
|
package engine
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -46,19 +45,17 @@ type Entry struct {
|
|||||||
|
|
||||||
type Entries []Entry
|
type Entries []Entry
|
||||||
|
|
||||||
func FromArtist(ar *model.Artist, ann *model.Annotation) Entry {
|
func FromArtist(ar *model.Artist) Entry {
|
||||||
e := Entry{}
|
e := Entry{}
|
||||||
e.Id = ar.ID
|
e.Id = ar.ID
|
||||||
e.Title = ar.Name
|
e.Title = ar.Name
|
||||||
e.AlbumCount = ar.AlbumCount
|
e.AlbumCount = ar.AlbumCount
|
||||||
e.IsDir = true
|
e.IsDir = true
|
||||||
//if ann != nil {
|
|
||||||
e.Starred = ar.StarredAt
|
e.Starred = ar.StarredAt
|
||||||
//}
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromAlbum(al *model.Album, ann *model.Annotation) Entry {
|
func FromAlbum(al *model.Album) Entry {
|
||||||
e := Entry{}
|
e := Entry{}
|
||||||
e.Id = al.ID
|
e.Id = al.ID
|
||||||
e.Title = al.Name
|
e.Title = al.Name
|
||||||
@ -74,15 +71,13 @@ func FromAlbum(al *model.Album, ann *model.Annotation) Entry {
|
|||||||
e.ArtistId = al.ArtistID
|
e.ArtistId = al.ArtistID
|
||||||
e.Duration = al.Duration
|
e.Duration = al.Duration
|
||||||
e.SongCount = al.SongCount
|
e.SongCount = al.SongCount
|
||||||
//if ann != nil {
|
|
||||||
e.Starred = al.StarredAt
|
e.Starred = al.StarredAt
|
||||||
e.PlayCount = int32(al.PlayCount)
|
e.PlayCount = int32(al.PlayCount)
|
||||||
e.UserRating = al.Rating
|
e.UserRating = al.Rating
|
||||||
//}
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromMediaFile(mf *model.MediaFile, ann *model.Annotation) Entry {
|
func FromMediaFile(mf *model.MediaFile) Entry {
|
||||||
e := Entry{}
|
e := Entry{}
|
||||||
e.Id = mf.ID
|
e.Id = mf.ID
|
||||||
e.Title = mf.Title
|
e.Title = mf.Title
|
||||||
@ -111,11 +106,9 @@ func FromMediaFile(mf *model.MediaFile, ann *model.Annotation) Entry {
|
|||||||
e.AlbumId = mf.AlbumID
|
e.AlbumId = mf.AlbumID
|
||||||
e.ArtistId = mf.ArtistID
|
e.ArtistId = mf.ArtistID
|
||||||
e.Type = "music" // TODO Hardcoded for now
|
e.Type = "music" // TODO Hardcoded for now
|
||||||
//if ann != nil {
|
|
||||||
e.PlayCount = int32(mf.PlayCount)
|
e.PlayCount = int32(mf.PlayCount)
|
||||||
e.Starred = mf.StarredAt
|
e.Starred = mf.StarredAt
|
||||||
e.UserRating = mf.Rating
|
e.UserRating = mf.Rating
|
||||||
//}
|
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,37 +123,26 @@ func realArtistName(mf *model.MediaFile) string {
|
|||||||
return mf.Artist
|
return mf.Artist
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromAlbums(albums model.Albums, annMap model.AnnotationMap) Entries {
|
func FromAlbums(albums model.Albums) Entries {
|
||||||
entries := make(Entries, len(albums))
|
entries := make(Entries, len(albums))
|
||||||
for i, al := range albums {
|
for i, al := range albums {
|
||||||
ann := annMap[al.ID]
|
entries[i] = FromAlbum(&al)
|
||||||
entries[i] = FromAlbum(&al, &ann)
|
|
||||||
}
|
}
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromMediaFiles(mfs model.MediaFiles, annMap model.AnnotationMap) Entries {
|
func FromMediaFiles(mfs model.MediaFiles) Entries {
|
||||||
entries := make(Entries, len(mfs))
|
entries := make(Entries, len(mfs))
|
||||||
for i, mf := range mfs {
|
for i, mf := range mfs {
|
||||||
ann := annMap[mf.ID]
|
entries[i] = FromMediaFile(&mf)
|
||||||
entries[i] = FromMediaFile(&mf, &ann)
|
|
||||||
}
|
}
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func FromArtists(ars model.Artists, annMap model.AnnotationMap) Entries {
|
func FromArtists(ars model.Artists) Entries {
|
||||||
entries := make(Entries, len(ars))
|
entries := make(Entries, len(ars))
|
||||||
for i, ar := range ars {
|
for i, ar := range ars {
|
||||||
ann := annMap[ar.ID]
|
entries[i] = FromArtist(&ar)
|
||||||
entries[i] = FromArtist(&ar, &ann)
|
|
||||||
}
|
}
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUserID(ctx context.Context) string {
|
|
||||||
user, ok := ctx.Value("user").(*model.User)
|
|
||||||
if ok {
|
|
||||||
return user.ID
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
@ -40,34 +40,7 @@ func (g *listGenerator) query(ctx context.Context, qo model.QueryOptions) (Entri
|
|||||||
for i, al := range albums {
|
for i, al := range albums {
|
||||||
albumIds[i] = al.ID
|
albumIds[i] = al.ID
|
||||||
}
|
}
|
||||||
annMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
|
return FromAlbums(albums), err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return FromAlbums(albums, annMap), err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *listGenerator) queryByAnnotation(ctx context.Context, qo model.QueryOptions) (Entries, error) {
|
|
||||||
annotations, err := g.ds.Annotation(ctx).GetAll(getUserID(ctx), model.AlbumItemType, qo)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
albumIds := make([]string, len(annotations))
|
|
||||||
for i, ann := range annotations {
|
|
||||||
albumIds[i] = ann.ItemID
|
|
||||||
}
|
|
||||||
|
|
||||||
albumMap, err := g.ds.Album(ctx).GetMap(albumIds)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var albums Entries
|
|
||||||
for _, ann := range annotations {
|
|
||||||
album := albumMap[ann.ItemID]
|
|
||||||
albums = append(albums, FromAlbum(&album, &ann))
|
|
||||||
}
|
|
||||||
return albums, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *listGenerator) GetNewest(ctx context.Context, offset int, size int) (Entries, error) {
|
func (g *listGenerator) GetNewest(ctx context.Context, offset int, size int) (Entries, error) {
|
||||||
@ -78,19 +51,19 @@ func (g *listGenerator) GetNewest(ctx context.Context, offset int, size int) (En
|
|||||||
func (g *listGenerator) GetRecent(ctx context.Context, 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", Offset: offset, Max: size,
|
qo := model.QueryOptions{Sort: "PlayDate", Order: "desc", Offset: offset, Max: size,
|
||||||
Filters: squirrel.Gt{"play_date": time.Time{}}}
|
Filters: squirrel.Gt{"play_date": time.Time{}}}
|
||||||
return g.queryByAnnotation(ctx, qo)
|
return g.query(ctx, qo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *listGenerator) GetFrequent(ctx context.Context, 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", Offset: offset, Max: size,
|
qo := model.QueryOptions{Sort: "PlayCount", Order: "desc", Offset: offset, Max: size,
|
||||||
Filters: squirrel.Gt{"play_count": 0}}
|
Filters: squirrel.Gt{"play_count": 0}}
|
||||||
return g.queryByAnnotation(ctx, qo)
|
return g.query(ctx, qo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *listGenerator) GetHighest(ctx context.Context, 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", Offset: offset, Max: size,
|
qo := model.QueryOptions{Sort: "Rating", Order: "desc", Offset: offset, Max: size,
|
||||||
Filters: squirrel.Gt{"rating__gt": 0}}
|
Filters: squirrel.Gt{"rating": 0}}
|
||||||
return g.queryByAnnotation(ctx, qo)
|
return g.query(ctx, qo)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *listGenerator) GetByName(ctx context.Context, offset int, size int) (Entries, error) {
|
func (g *listGenerator) GetByName(ctx context.Context, offset int, size int) (Entries, error) {
|
||||||
@ -109,19 +82,7 @@ func (g *listGenerator) GetRandom(ctx context.Context, offset int, size int) (En
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
annMap, err := g.getAnnotationsForAlbums(ctx, albums)
|
return FromAlbums(albums), nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return FromAlbums(albums, annMap), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
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(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre string) (Entries, error) {
|
func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre string) (Entries, error) {
|
||||||
@ -134,45 +95,33 @@ func (g *listGenerator) GetRandomSongs(ctx context.Context, size int, genre stri
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
r := make(Entries, len(mediaFiles))
|
return FromMediaFiles(mediaFiles), nil
|
||||||
for i, mf := range mediaFiles {
|
|
||||||
ann, err := g.ds.Annotation(ctx).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(ctx context.Context, 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"}
|
qo := model.QueryOptions{Offset: offset, Max: size, Sort: "starred_at", Order: "desc"}
|
||||||
albums, err := g.ds.Album(ctx).GetStarred(getUserID(ctx), qo)
|
albums, err := g.ds.Album(ctx).GetStarred(qo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
annMap, err := g.getAnnotationsForAlbums(ctx, albums)
|
return FromAlbums(albums), nil
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return FromAlbums(albums, annMap), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *listGenerator) GetAllStarred(ctx context.Context) (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"}
|
options := model.QueryOptions{Sort: "starred_at", Order: "desc"}
|
||||||
|
|
||||||
ars, err := g.ds.Artist(ctx).GetStarred(getUserID(ctx), options)
|
ars, err := g.ds.Artist(ctx).GetStarred(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
als, err := g.ds.Album(ctx).GetStarred(getUserID(ctx), options)
|
als, err := g.ds.Album(ctx).GetStarred(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mfs, err := g.ds.MediaFile(ctx).GetStarred(getUserID(ctx), options)
|
mfs, err := g.ds.MediaFile(ctx).GetStarred(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
@ -181,28 +130,15 @@ func (g *listGenerator) GetAllStarred(ctx context.Context) (artists Entries, alb
|
|||||||
for _, mf := range mfs {
|
for _, mf := range mfs {
|
||||||
mfIds = append(mfIds, mf.ID)
|
mfIds = append(mfIds, mf.ID)
|
||||||
}
|
}
|
||||||
trackAnnMap, err := g.ds.Annotation(ctx).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
|
var artistIds []string
|
||||||
for _, ar := range ars {
|
for _, ar := range ars {
|
||||||
artistIds = append(artistIds, ar.ID)
|
artistIds = append(artistIds, ar.ID)
|
||||||
}
|
}
|
||||||
artistAnnMap, err := g.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, artistIds)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
artists = FromArtists(ars, artistAnnMap)
|
artists = FromArtists(ars)
|
||||||
albums = FromAlbums(als, albumAnnMap)
|
albums = FromAlbums(als)
|
||||||
mediaFiles = FromMediaFiles(mfs, trackAnnMap)
|
mediaFiles = FromMediaFiles(mfs)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -218,8 +154,7 @@ func (g *listGenerator) GetNowPlaying(ctx context.Context) (Entries, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
ann, err := g.ds.Annotation(ctx).Get(getUserID(ctx), model.MediaItemType, mf.ID)
|
entries[i] = FromMediaFile(mf)
|
||||||
entries[i] = FromMediaFile(mf, ann)
|
|
||||||
entries[i].UserName = np.Username
|
entries[i].UserName = np.Username
|
||||||
entries[i].MinutesAgo = int(time.Now().Sub(np.Start).Minutes())
|
entries[i].MinutesAgo = int(time.Now().Sub(np.Start).Minutes())
|
||||||
entries[i].PlayerId = np.PlayerId
|
entries[i].PlayerId = np.PlayerId
|
||||||
|
@ -123,7 +123,7 @@ func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO Use model.Playlist when got rid of Entries
|
// TODO Use model.Playlist when got rid of Entries
|
||||||
pinfo := &PlaylistInfo{
|
plsInfo := &PlaylistInfo{
|
||||||
Id: pl.ID,
|
Id: pl.ID,
|
||||||
Name: pl.Name,
|
Name: pl.Name,
|
||||||
SongCount: len(pl.Tracks),
|
SongCount: len(pl.Tracks),
|
||||||
@ -132,19 +132,7 @@ func (p *playlists) Get(ctx context.Context, id string) (*PlaylistInfo, error) {
|
|||||||
Owner: pl.Owner,
|
Owner: pl.Owner,
|
||||||
Comment: pl.Comment,
|
Comment: pl.Comment,
|
||||||
}
|
}
|
||||||
pinfo.Entries = make(Entries, len(pl.Tracks))
|
|
||||||
|
|
||||||
var mfIds []string
|
plsInfo.Entries = FromMediaFiles(pl.Tracks)
|
||||||
for _, mf := range pl.Tracks {
|
return plsInfo, nil
|
||||||
mfIds = append(mfIds, mf.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
annMap, err := p.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, mfIds)
|
|
||||||
|
|
||||||
for i, mf := range pl.Tracks {
|
|
||||||
ann := annMap[mf.ID]
|
|
||||||
pinfo.Entries[i] = FromMediaFile(&mf, &ann)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pinfo, nil
|
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ func (r ratings) SetRating(ctx context.Context, id string, rating int) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
return r.ds.Annotation(ctx).SetRating(rating, getUserID(ctx), model.AlbumItemType, id)
|
return r.ds.Annotation(ctx).SetRating(rating, model.AlbumItemType, id)
|
||||||
}
|
}
|
||||||
return r.ds.Annotation(ctx).SetRating(rating, getUserID(ctx), model.MediaItemType, id)
|
return r.ds.Annotation(ctx).SetRating(rating, model.MediaItemType, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
|
func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
|
||||||
@ -36,7 +36,6 @@ func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
|
|||||||
log.Warn(ctx, "Cannot star/unstar an empty list of ids")
|
log.Warn(ctx, "Cannot star/unstar an empty list of ids")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
userId := getUserID(ctx)
|
|
||||||
|
|
||||||
return r.ds.WithTx(func(tx model.DataStore) error {
|
return r.ds.WithTx(func(tx model.DataStore) error {
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
@ -45,7 +44,7 @@ func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
err = tx.Annotation(ctx).SetStar(star, userId, model.AlbumItemType, ids...)
|
err = tx.Annotation(ctx).SetStar(star, model.AlbumItemType, ids...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -56,13 +55,13 @@ func (r ratings) SetStar(ctx context.Context, star bool, ids ...string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if exist {
|
if exist {
|
||||||
err = tx.Annotation(ctx).SetStar(star, userId, model.ArtistItemType, ids...)
|
err = tx.Annotation(ctx).SetStar(star, model.ArtistItemType, ids...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
err = tx.Annotation(ctx).SetStar(star, userId, model.MediaItemType, ids...)
|
err = tx.Annotation(ctx).SetStar(star, model.MediaItemType, ids...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,6 @@ type scrobbler struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string, playTime time.Time) (*model.MediaFile, error) {
|
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 mf *model.MediaFile
|
||||||
var err error
|
var err error
|
||||||
err = s.ds.WithTx(func(tx model.DataStore) error {
|
err = s.ds.WithTx(func(tx model.DataStore) error {
|
||||||
@ -33,11 +31,11 @@ func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = s.ds.Annotation(ctx).IncPlayCount(userId, model.MediaItemType, trackId, playTime)
|
err = s.ds.Annotation(ctx).IncPlayCount(model.MediaItemType, trackId, playTime)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
err = s.ds.Annotation(ctx).IncPlayCount(userId, model.AlbumItemType, mf.AlbumID, playTime)
|
err = s.ds.Annotation(ctx).IncPlayCount(model.AlbumItemType, mf.AlbumID, playTime)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
return mf, err
|
return mf, err
|
||||||
|
@ -34,12 +34,7 @@ func (s *search) SearchArtist(ctx context.Context, q string, offset int, size in
|
|||||||
for i, al := range artists {
|
for i, al := range artists {
|
||||||
artistIds[i] = al.ID
|
artistIds[i] = al.ID
|
||||||
}
|
}
|
||||||
annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.ArtistItemType, artistIds)
|
return FromArtists(artists), nil
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return FromArtists(artists, annMap), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int) (Entries, error) {
|
func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int) (Entries, error) {
|
||||||
@ -53,12 +48,8 @@ func (s *search) SearchAlbum(ctx context.Context, q string, offset int, size int
|
|||||||
for i, al := range albums {
|
for i, al := range albums {
|
||||||
albumIds[i] = al.ID
|
albumIds[i] = al.ID
|
||||||
}
|
}
|
||||||
annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.AlbumItemType, albumIds)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return FromAlbums(albums, annMap), nil
|
return FromAlbums(albums), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *search) SearchSong(ctx context.Context, q string, offset int, size int) (Entries, error) {
|
func (s *search) SearchSong(ctx context.Context, q string, offset int, size int) (Entries, error) {
|
||||||
@ -72,10 +63,6 @@ func (s *search) SearchSong(ctx context.Context, q string, offset int, size int)
|
|||||||
for i, mf := range mediaFiles {
|
for i, mf := range mediaFiles {
|
||||||
trackIds[i] = mf.ID
|
trackIds[i] = mf.ID
|
||||||
}
|
}
|
||||||
annMap, err := s.ds.Annotation(ctx).GetMap(getUserID(ctx), model.MediaItemType, trackIds)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return FromMediaFiles(mediaFiles, annMap), nil
|
return FromMediaFiles(mediaFiles), nil
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import "time"
|
|||||||
type Album struct {
|
type Album struct {
|
||||||
ID string `json:"id" orm:"column(id)"`
|
ID string `json:"id" orm:"column(id)"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
ArtistID string `json:"artistId"`
|
ArtistID string `json:"artistId" orm:"pk;column(artist_id)"`
|
||||||
CoverArtPath string `json:"-"`
|
CoverArtPath string `json:"-"`
|
||||||
CoverArtId string `json:"-"`
|
CoverArtId string `json:"-"`
|
||||||
Artist string `json:"artist"`
|
Artist string `json:"artist"`
|
||||||
@ -37,7 +37,7 @@ type AlbumRepository interface {
|
|||||||
GetAll(...QueryOptions) (Albums, error)
|
GetAll(...QueryOptions) (Albums, error)
|
||||||
GetMap(ids []string) (map[string]Album, error)
|
GetMap(ids []string) (map[string]Album, error)
|
||||||
GetRandom(...QueryOptions) (Albums, error)
|
GetRandom(...QueryOptions) (Albums, error)
|
||||||
GetStarred(userId string, options ...QueryOptions) (Albums, error)
|
GetStarred(options ...QueryOptions) (Albums, error)
|
||||||
Search(q string, offset int, size int) (Albums, error)
|
Search(q string, offset int, size int) (Albums, error)
|
||||||
Refresh(ids ...string) error
|
Refresh(ids ...string) error
|
||||||
PurgeEmpty() error
|
PurgeEmpty() error
|
||||||
|
@ -9,25 +9,22 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Annotation struct {
|
type Annotation struct {
|
||||||
AnnotationID string
|
AnnID string `json:"annID" orm:"pk;column(ann_id)"`
|
||||||
UserID string
|
UserID string `json:"userID" orm:"pk;column(user_id)"`
|
||||||
ItemID string
|
ItemID string `json:"itemID" orm:"pk;column(item_id)"`
|
||||||
ItemType string
|
ItemType string `json:"itemType"`
|
||||||
PlayCount int
|
PlayCount int `json:"playCount"`
|
||||||
PlayDate time.Time
|
PlayDate time.Time `json:"playDate"`
|
||||||
Rating int
|
Rating int `json:"rating"`
|
||||||
Starred bool
|
Starred bool `json:"starred"`
|
||||||
StarredAt time.Time
|
StarredAt time.Time `json:"starredAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnnotationMap map[string]Annotation
|
type AnnotationMap map[string]Annotation
|
||||||
|
|
||||||
type AnnotationRepository interface {
|
type AnnotationRepository interface {
|
||||||
Get(userID, itemType string, itemID string) (*Annotation, error)
|
Delete(itemType string, itemID ...string) error
|
||||||
GetAll(userID, itemType string, options ...QueryOptions) ([]Annotation, error)
|
IncPlayCount(itemType, itemID string, ts time.Time) error
|
||||||
GetMap(userID, itemType string, itemID []string) (AnnotationMap, error)
|
SetStar(starred bool, itemType string, ids ...string) error
|
||||||
Delete(userID, itemType string, itemID ...string) error
|
SetRating(rating int, itemType, itemID string) error
|
||||||
IncPlayCount(userID, itemType string, itemID string, ts time.Time) error
|
|
||||||
SetStar(starred bool, userID, itemType string, ids ...string) error
|
|
||||||
SetRating(rating int, userID, itemType string, itemID string) error
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ type ArtistRepository interface {
|
|||||||
Exists(id string) (bool, error)
|
Exists(id string) (bool, error)
|
||||||
Put(m *Artist) error
|
Put(m *Artist) error
|
||||||
Get(id string) (*Artist, error)
|
Get(id string) (*Artist, error)
|
||||||
GetStarred(userId string, options ...QueryOptions) (Artists, error)
|
GetStarred(options ...QueryOptions) (Artists, error)
|
||||||
Search(q string, offset int, size int) (Artists, error)
|
Search(q string, offset int, size int) (Artists, error)
|
||||||
Refresh(ids ...string) error
|
Refresh(ids ...string) error
|
||||||
GetIndex() (ArtistIndexes, error)
|
GetIndex() (ArtistIndexes, error)
|
||||||
|
@ -11,9 +11,9 @@ type MediaFile struct {
|
|||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Album string `json:"album"`
|
Album string `json:"album"`
|
||||||
Artist string `json:"artist"`
|
Artist string `json:"artist"`
|
||||||
ArtistID string `json:"artistId"`
|
ArtistID string `json:"artistId" orm:"pk;column(artist_id)"`
|
||||||
AlbumArtist string `json:"albumArtist"`
|
AlbumArtist string `json:"albumArtist"`
|
||||||
AlbumID string `json:"albumId"`
|
AlbumID string `json:"albumId" orm:"pk;column(album_id)"`
|
||||||
HasCoverArt bool `json:"hasCoverArt"`
|
HasCoverArt bool `json:"hasCoverArt"`
|
||||||
TrackNumber int `json:"trackNumber"`
|
TrackNumber int `json:"trackNumber"`
|
||||||
DiscNumber int `json:"discNumber"`
|
DiscNumber int `json:"discNumber"`
|
||||||
@ -48,8 +48,7 @@ type MediaFileRepository interface {
|
|||||||
Get(id string) (*MediaFile, error)
|
Get(id string) (*MediaFile, error)
|
||||||
FindByAlbum(albumId string) (MediaFiles, error)
|
FindByAlbum(albumId string) (MediaFiles, error)
|
||||||
FindByPath(path string) (MediaFiles, error)
|
FindByPath(path string) (MediaFiles, error)
|
||||||
// TODO Remove userId
|
GetStarred(options ...QueryOptions) (MediaFiles, error)
|
||||||
GetStarred(userId string, options ...QueryOptions) (MediaFiles, error)
|
|
||||||
GetRandom(options ...QueryOptions) (MediaFiles, error)
|
GetRandom(options ...QueryOptions) (MediaFiles, error)
|
||||||
Search(q string, offset int, size int) (MediaFiles, error)
|
Search(q string, offset int, size int) (MediaFiles, error)
|
||||||
Delete(id string) error
|
Delete(id string) error
|
||||||
|
@ -101,7 +101,7 @@ func (r *albumRepository) PurgeEmpty() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *albumRepository) GetStarred(userId string, options ...model.QueryOptions) (model.Albums, error) {
|
func (r *albumRepository) GetStarred(options ...model.QueryOptions) (model.Albums, error) {
|
||||||
sq := r.selectAlbum(options...).Where("starred = true")
|
sq := r.selectAlbum(options...).Where("starred = true")
|
||||||
var starred model.Albums
|
var starred model.Albums
|
||||||
err := r.queryAll(sq, &starred)
|
err := r.queryAll(sq, &starred)
|
||||||
|
@ -57,7 +57,7 @@ var _ = Describe("AlbumRepository", func() {
|
|||||||
|
|
||||||
Describe("GetStarred", func() {
|
Describe("GetStarred", func() {
|
||||||
It("returns all starred records", func() {
|
It("returns all starred records", func() {
|
||||||
Expect(repo.GetStarred("userid", model.QueryOptions{})).To(Equal(model.Albums{
|
Expect(repo.GetStarred(model.QueryOptions{})).To(Equal(model.Albums{
|
||||||
albumRadioactivity,
|
albumRadioactivity,
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
@ -10,24 +10,6 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
type annotation struct {
|
|
||||||
AnnotationID string `orm:"pk;column(ann_id)"`
|
|
||||||
UserID string `orm:"column(user_id)"`
|
|
||||||
ItemID string `orm:"column(item_id)"`
|
|
||||||
ItemType string `orm:"column(item_type)"`
|
|
||||||
PlayCount int `orm:"column(play_count);index;null"`
|
|
||||||
PlayDate time.Time `orm:"column(play_date);index;null"`
|
|
||||||
Rating int `orm:"null"`
|
|
||||||
Starred bool `orm:"index"`
|
|
||||||
StarredAt time.Time `orm:"column(starred_at);null"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (u *annotation) TableUnique() [][]string {
|
|
||||||
return [][]string{
|
|
||||||
{"UserID", "ItemID", "ItemType"},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type annotationRepository struct {
|
type annotationRepository struct {
|
||||||
sqlRepository
|
sqlRepository
|
||||||
}
|
}
|
||||||
@ -40,144 +22,70 @@ func NewAnnotationRepository(ctx context.Context, o orm.Ormer) model.AnnotationR
|
|||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *annotationRepository) Get(userID, itemType string, itemID string) (*model.Annotation, error) {
|
func (r *annotationRepository) upsert(values map[string]interface{}, itemType string, itemIDs ...string) error {
|
||||||
q := Select("*").From(r.tableName).Where(And{
|
upd := Update(r.tableName).Where(r.getId(itemType, itemIDs...))
|
||||||
Eq{"user_id": userId(r.ctx)},
|
for f, v := range values {
|
||||||
Eq{"item_type": itemType},
|
upd = upd.Set(f, v)
|
||||||
Eq{"item_id": itemID},
|
|
||||||
})
|
|
||||||
var ann annotation
|
|
||||||
err := r.queryOne(q, &ann)
|
|
||||||
if err == model.ErrNotFound {
|
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
resp := model.Annotation(ann)
|
c, err := r.executeSQL(upd)
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *annotationRepository) GetMap(userID, itemType string, itemIDs []string) (model.AnnotationMap, error) {
|
|
||||||
if len(itemIDs) == 0 {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
q := Select("*").From(r.tableName).Where(And{
|
|
||||||
Eq{"user_id": userId(r.ctx)},
|
|
||||||
Eq{"item_type": itemType},
|
|
||||||
Eq{"item_id": itemIDs},
|
|
||||||
})
|
|
||||||
var res []annotation
|
|
||||||
err := r.queryAll(q, &res)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
m := make(model.AnnotationMap)
|
|
||||||
for _, a := range res {
|
|
||||||
m[a.ItemID] = model.Annotation(a)
|
|
||||||
}
|
|
||||||
return m, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *annotationRepository) GetAll(userID, itemType string, options ...model.QueryOptions) ([]model.Annotation, error) {
|
|
||||||
q := Select("*").From(r.tableName).Where(And{
|
|
||||||
Eq{"user_id": userId(r.ctx)},
|
|
||||||
Eq{"item_type": itemType},
|
|
||||||
})
|
|
||||||
var res []annotation
|
|
||||||
err := r.queryAll(q, &res)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
all := make([]model.Annotation, len(res))
|
|
||||||
for i, a := range res {
|
|
||||||
all[i] = model.Annotation(a)
|
|
||||||
}
|
|
||||||
return all, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *annotationRepository) new(userID, itemType string, itemID string) *annotation {
|
|
||||||
id, _ := uuid.NewRandom()
|
|
||||||
return &annotation{
|
|
||||||
AnnotationID: id.String(),
|
|
||||||
UserID: userID,
|
|
||||||
ItemID: itemID,
|
|
||||||
ItemType: itemType,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *annotationRepository) IncPlayCount(userID, itemType string, itemID string, ts time.Time) error {
|
|
||||||
uid := userId(r.ctx)
|
|
||||||
q := Update(r.tableName).
|
|
||||||
Set("play_count", Expr("play_count + 1")).
|
|
||||||
Set("play_date", ts).
|
|
||||||
Where(And{
|
|
||||||
Eq{"user_id": uid},
|
|
||||||
Eq{"item_type": itemType},
|
|
||||||
Eq{"item_id": itemID},
|
|
||||||
})
|
|
||||||
c, err := r.executeSQL(q)
|
|
||||||
if c == 0 || err == orm.ErrNoRows {
|
if c == 0 || err == orm.ErrNoRows {
|
||||||
ann := r.new(uid, itemType, itemID)
|
for _, itemID := range itemIDs {
|
||||||
ann.PlayCount = 1
|
id, _ := uuid.NewRandom()
|
||||||
ann.PlayDate = ts
|
values["ann_id"] = id.String()
|
||||||
_, err = r.ormer.Insert(ann)
|
values["user_id"] = userId(r.ctx)
|
||||||
}
|
values["item_type"] = itemType
|
||||||
return err
|
values["item_id"] = itemID
|
||||||
}
|
ins := Insert(r.tableName).SetMap(values)
|
||||||
|
_, err = r.executeSQL(ins)
|
||||||
func (r *annotationRepository) SetStar(starred bool, userID, itemType string, ids ...string) error {
|
|
||||||
uid := userId(r.ctx)
|
|
||||||
var starredAt time.Time
|
|
||||||
if starred {
|
|
||||||
starredAt = time.Now()
|
|
||||||
}
|
|
||||||
q := Update(r.tableName).
|
|
||||||
Set("starred", starred).
|
|
||||||
Set("starred_at", starredAt).
|
|
||||||
Where(And{
|
|
||||||
Eq{"user_id": uid},
|
|
||||||
Eq{"item_type": itemType},
|
|
||||||
Eq{"item_id": ids},
|
|
||||||
})
|
|
||||||
c, err := r.executeSQL(q)
|
|
||||||
if c == 0 || err == orm.ErrNoRows {
|
|
||||||
for _, id := range ids {
|
|
||||||
ann := r.new(uid, itemType, id)
|
|
||||||
ann.Starred = starred
|
|
||||||
ann.StarredAt = starredAt
|
|
||||||
_, err = r.ormer.Insert(ann)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err.Error() != "LastInsertId is not supported by this driver" {
|
return err
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *annotationRepository) SetRating(rating int, userID, itemType string, itemID string) error {
|
func (r *annotationRepository) IncPlayCount(itemType, itemID string, ts time.Time) error {
|
||||||
uid := userId(r.ctx)
|
upd := Update(r.tableName).Where(r.getId(itemType, itemID)).
|
||||||
q := Update(r.tableName).
|
Set("play_count", Expr("play_count+1")).
|
||||||
Set("rating", rating).
|
Set("play_date", ts)
|
||||||
Where(And{
|
c, err := r.executeSQL(upd)
|
||||||
Eq{"user_id": uid},
|
|
||||||
Eq{"item_type": itemType},
|
|
||||||
Eq{"item_id": itemID},
|
|
||||||
})
|
|
||||||
c, err := r.executeSQL(q)
|
|
||||||
if c == 0 || err == orm.ErrNoRows {
|
if c == 0 || err == orm.ErrNoRows {
|
||||||
ann := r.new(uid, itemType, itemID)
|
id, _ := uuid.NewRandom()
|
||||||
ann.Rating = rating
|
values := map[string]interface{}{}
|
||||||
_, err = r.ormer.Insert(ann)
|
values["ann_id"] = id.String()
|
||||||
|
values["user_id"] = userId(r.ctx)
|
||||||
|
values["item_type"] = itemType
|
||||||
|
values["item_id"] = itemID
|
||||||
|
values["play_count"] = 1
|
||||||
|
values["play_date"] = ts
|
||||||
|
ins := Insert(r.tableName).SetMap(values)
|
||||||
|
_, err = r.executeSQL(ins)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *annotationRepository) Delete(userID, itemType string, ids ...string) error {
|
func (r *annotationRepository) getId(itemType string, itemID ...string) And {
|
||||||
return r.delete(And{
|
return And{
|
||||||
Eq{"user_id": userId(r.ctx)},
|
Eq{"user_id": userId(r.ctx)},
|
||||||
Eq{"item_type": itemType},
|
Eq{"item_type": itemType},
|
||||||
Eq{"item_id": ids},
|
Eq{"item_id": itemID},
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *annotationRepository) SetStar(starred bool, itemType string, ids ...string) error {
|
||||||
|
starredAt := time.Now()
|
||||||
|
return r.upsert(map[string]interface{}{"starred": starred, "starred_at": starredAt}, itemType, ids...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *annotationRepository) SetRating(rating int, itemType, itemID string) error {
|
||||||
|
return r.upsert(map[string]interface{}{"rating": rating}, itemType, itemID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *annotationRepository) Delete(itemType string, itemIDs ...string) error {
|
||||||
|
return r.delete(r.getId(itemType, itemIDs...))
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ func (r *artistRepository) Refresh(ids ...string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *artistRepository) GetStarred(userId string, options ...model.QueryOptions) (model.Artists, error) {
|
func (r *artistRepository) GetStarred(options ...model.QueryOptions) (model.Artists, error) {
|
||||||
return nil, nil // TODO
|
return nil, nil // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ func (r *artistRepository) Search(q string, offset int, size int) (model.Artists
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *artistRepository) Count(options ...rest.QueryOptions) (int64, error) {
|
func (r *artistRepository) Count(options ...rest.QueryOptions) (int64, error) {
|
||||||
return r.CountAll(r.parseRestOptions(options...))
|
return r.CountAll(r.parseRestOptions(options...)) // TODO Don't apply pagination!
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *artistRepository) Read(id string) (interface{}, error) {
|
func (r *artistRepository) Read(id string) (interface{}, error) {
|
||||||
|
@ -78,7 +78,7 @@ func (r mediaFileRepository) FindByPath(path string) (model.MediaFiles, error) {
|
|||||||
return res, err
|
return res, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r mediaFileRepository) GetStarred(userId string, options ...model.QueryOptions) (model.MediaFiles, error) {
|
func (r mediaFileRepository) GetStarred(options ...model.QueryOptions) (model.MediaFiles, error) {
|
||||||
sq := r.selectMediaFile(options...).Where("starred = true")
|
sq := r.selectMediaFile(options...).Where("starred = true")
|
||||||
var starred model.MediaFiles
|
var starred model.MediaFiles
|
||||||
err := r.queryAll(sq, &starred)
|
err := r.queryAll(sq, &starred)
|
||||||
|
@ -44,7 +44,7 @@ var _ = Describe("MediaRepository", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("returns empty array when no tracks are found", func() {
|
It("returns empty array when no tracks are found", func() {
|
||||||
Expect(mr.FindByAlbum("67")).To(Equal(model.MediaFiles{}))
|
Expect(mr.FindByAlbum("67")).To(Equal(model.MediaFiles(nil)))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("finds tracks by path", func() {
|
It("finds tracks by path", func() {
|
||||||
@ -54,7 +54,7 @@ var _ = Describe("MediaRepository", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("returns starred tracks", func() {
|
It("returns starred tracks", func() {
|
||||||
Expect(mr.GetStarred("userid")).To(Equal(model.MediaFiles{
|
Expect(mr.GetStarred()).To(Equal(model.MediaFiles{
|
||||||
songComeTogether,
|
songComeTogether,
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
@ -125,17 +125,8 @@ func (db *NewSQLStore) getOrmer() orm.Ormer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func initORM(dbPath string) error {
|
func initORM(dbPath string) error {
|
||||||
//verbose := conf.Server.LogLevel == "trace"
|
|
||||||
//orm.Debug = verbose
|
|
||||||
if strings.Contains(dbPath, "postgres") {
|
if strings.Contains(dbPath, "postgres") {
|
||||||
driver = "postgres"
|
driver = "postgres"
|
||||||
}
|
}
|
||||||
err := orm.RegisterDataBase("default", driver, dbPath)
|
return orm.RegisterDataBase("default", driver, dbPath)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// TODO Remove all RegisterModels (i.e. don't use orm.Insert/Update)
|
|
||||||
orm.RegisterModel(new(annotation))
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/Masterminds/squirrel"
|
||||||
"github.com/astaxie/beego/orm"
|
"github.com/astaxie/beego/orm"
|
||||||
"github.com/deluan/navidrome/conf"
|
"github.com/deluan/navidrome/conf"
|
||||||
"github.com/deluan/navidrome/db"
|
"github.com/deluan/navidrome/db"
|
||||||
@ -52,8 +53,8 @@ var testSongs = model.MediaFiles{
|
|||||||
songAntenna,
|
songAntenna,
|
||||||
}
|
}
|
||||||
|
|
||||||
var annAlbumRadioactivity = model.Annotation{AnnotationID: "1", UserID: "userid", ItemType: model.AlbumItemType, ItemID: "3", Starred: true}
|
var annAlbumRadioactivity = model.Annotation{AnnID: "1", UserID: "userid", ItemType: model.AlbumItemType, ItemID: "3", Starred: true}
|
||||||
var annSongComeTogether = model.Annotation{AnnotationID: "2", UserID: "userid", ItemType: model.MediaItemType, ItemID: "2", Starred: true}
|
var annSongComeTogether = model.Annotation{AnnID: "2", UserID: "userid", ItemType: model.MediaItemType, ItemID: "2", Starred: true}
|
||||||
var testAnnotations = []model.Annotation{
|
var testAnnotations = []model.Annotation{
|
||||||
annAlbumRadioactivity,
|
annAlbumRadioactivity,
|
||||||
annSongComeTogether,
|
annSongComeTogether,
|
||||||
@ -81,7 +82,6 @@ var _ = Describe("Initialize test DB", func() {
|
|||||||
BeforeSuite(func() {
|
BeforeSuite(func() {
|
||||||
o := orm.NewOrm()
|
o := orm.NewOrm()
|
||||||
mr := NewMediaFileRepository(nil, o)
|
mr := NewMediaFileRepository(nil, o)
|
||||||
|
|
||||||
for _, s := range testSongs {
|
for _, s := range testSongs {
|
||||||
err := mr.Put(&s)
|
err := mr.Put(&s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -90,8 +90,13 @@ var _ = Describe("Initialize test DB", func() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, a := range testAnnotations {
|
for _, a := range testAnnotations {
|
||||||
ann := annotation(a)
|
values, _ := toSqlArgs(a)
|
||||||
_, err := o.Insert(&ann)
|
ins := squirrel.Insert("annotation").SetMap(values)
|
||||||
|
query, args, err := ins.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
_, err = o.Raw(query, args...).Exec()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,9 @@ func (r *sqlRepository) applyOptions(sq SelectBuilder, options ...model.QueryOpt
|
|||||||
}
|
}
|
||||||
if options[0].Sort != "" {
|
if options[0].Sort != "" {
|
||||||
if options[0].Order == "desc" {
|
if options[0].Order == "desc" {
|
||||||
sq = sq.OrderBy(options[0].Sort + " desc")
|
sq = sq.OrderBy(toSnakeCase(options[0].Sort + " desc"))
|
||||||
} else {
|
} else {
|
||||||
sq = sq.OrderBy(options[0].Sort)
|
sq = sq.OrderBy(toSnakeCase(options[0].Sort))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if options[0].Filters != nil {
|
if options[0].Filters != nil {
|
||||||
@ -151,7 +151,7 @@ func (r sqlRepository) toSql(sq Sqlizer) (string, []interface{}, error) {
|
|||||||
func (r sqlRepository) parseRestOptions(options ...rest.QueryOptions) model.QueryOptions {
|
func (r sqlRepository) parseRestOptions(options ...rest.QueryOptions) model.QueryOptions {
|
||||||
qo := model.QueryOptions{}
|
qo := model.QueryOptions{}
|
||||||
if len(options) > 0 {
|
if len(options) > 0 {
|
||||||
qo.Sort = toSnakeCase(options[0].Sort)
|
qo.Sort = options[0].Sort
|
||||||
qo.Order = options[0].Order
|
qo.Order = options[0].Order
|
||||||
qo.Max = options[0].Max
|
qo.Max = options[0].Max
|
||||||
qo.Offset = options[0].Offset
|
qo.Offset = options[0].Offset
|
||||||
|
Loading…
x
Reference in New Issue
Block a user