Load SmartPlaylists rules from DB

This commit is contained in:
Deluan 2021-10-14 18:39:17 -04:00 committed by Deluan Quintão
parent 7221b49b98
commit 815623715e
4 changed files with 84 additions and 38 deletions

View File

@ -20,8 +20,8 @@ type Playlist struct {
UpdatedAt time.Time `structs:"updated_at" json:"updatedAt"` UpdatedAt time.Time `structs:"updated_at" json:"updatedAt"`
// SmartPlaylist attributes // SmartPlaylist attributes
//Rules *SmartPlaylist `structs:"rules" json:"rules"` Rules *SmartPlaylist `structs:"-" json:"rules"`
//EvaluatedAt time.Time `structs:"evaluated_at" json:"evaluatedAt"` EvaluatedAt time.Time `structs:"evaluated_at" json:"evaluatedAt"`
} }
type Playlists []Playlist type Playlists []Playlist
@ -33,6 +33,7 @@ type PlaylistRepository interface {
Get(id string) (*Playlist, error) Get(id string) (*Playlist, error)
GetAll(options ...QueryOptions) (Playlists, error) GetAll(options ...QueryOptions) (Playlists, error)
FindByPath(path string) (*Playlist, error) FindByPath(path string) (*Playlist, error)
FindByID(id string) (*Playlist, error)
Delete(id string) error Delete(id string) error
Tracks(playlistId string) PlaylistTrackRepository Tracks(playlistId string) PlaylistTrackRepository
} }

View File

@ -2,6 +2,8 @@ package persistence
import ( import (
"context" "context"
"encoding/json"
"strings"
"time" "time"
. "github.com/Masterminds/squirrel" . "github.com/Masterminds/squirrel"
@ -16,6 +18,11 @@ type playlistRepository struct {
sqlRestful sqlRestful
} }
type dbPlaylist struct {
model.Playlist `structs:",flatten"`
RawRules string `structs:"rules"`
}
func NewPlaylistRepository(ctx context.Context, o orm.Ormer) model.PlaylistRepository { func NewPlaylistRepository(ctx context.Context, o orm.Ormer) model.PlaylistRepository {
r := &playlistRepository{} r := &playlistRepository{}
r.ctx = ctx r.ctx = ctx
@ -59,10 +66,18 @@ func (r *playlistRepository) Delete(id string) error {
} }
func (r *playlistRepository) Put(p *model.Playlist) error { func (r *playlistRepository) Put(p *model.Playlist) error {
if p.ID == "" { pls := dbPlaylist{Playlist: *p}
p.CreatedAt = time.Now() if p.Rules != nil {
j, err := json.Marshal(p.Rules)
if err != nil {
return err
}
pls.RawRules = string(j)
}
if pls.ID == "" {
pls.CreatedAt = time.Now()
} else { } else {
ok, err := r.Exists(p.ID) ok, err := r.Exists(pls.ID)
if err != nil { if err != nil {
return err return err
} }
@ -70,54 +85,85 @@ func (r *playlistRepository) Put(p *model.Playlist) error {
return model.ErrNotAuthorized return model.ErrNotAuthorized
} }
} }
p.UpdatedAt = time.Now() pls.UpdatedAt = time.Now()
// Save tracks for later and set it to nil, to avoid trying to save it to the DB // Save tracks for later and set it to nil, to avoid trying to save it to the DB
tracks := p.Tracks tracks := pls.Tracks
p.Tracks = nil pls.Tracks = nil
id, err := r.put(p.ID, p) id, err := r.put(pls.ID, pls)
if err != nil { if err != nil {
return err return err
} }
p.ID = id p.ID = id
// Only update tracks if they are specified // Only update tracks if they are specified
if tracks != nil { if tracks == nil {
err = r.updateTracks(id, tracks) return nil
if err != nil {
return err
}
} }
return r.loadTracks(p) return r.updateTracks(id, tracks)
} }
func (r *playlistRepository) Get(id string) (*model.Playlist, error) { func (r *playlistRepository) Get(id string) (*model.Playlist, error) {
sel := r.newSelect().Columns("*").Where(And{Eq{"id": id}, r.userFilter()}) return r.findBy(And{Eq{"id": id}, r.userFilter()}, true)
var pls model.Playlist
err := r.queryOne(sel, &pls)
if err != nil {
return nil, err
}
err = r.loadTracks(&pls)
return &pls, err
} }
func (r *playlistRepository) FindByPath(path string) (*model.Playlist, error) { func (r *playlistRepository) FindByPath(path string) (*model.Playlist, error) {
sel := r.newSelect().Columns("*").Where(Eq{"path": path}) return r.findBy(Eq{"path": path}, false)
var pls model.Playlist }
err := r.queryOne(sel, &pls)
func (r *playlistRepository) FindByID(id string) (*model.Playlist, error) {
return r.findBy(And{Eq{"id": id}, r.userFilter()}, false)
}
func (r *playlistRepository) findBy(sql Sqlizer, includeTracks bool) (*model.Playlist, error) {
sel := r.newSelect().Columns("*").Where(sql)
var pls []dbPlaylist
err := r.queryAll(sel, &pls)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &pls, err if len(pls) == 0 {
return nil, model.ErrNotFound
}
return r.toModel(pls[0], includeTracks)
}
func (r *playlistRepository) toModel(pls dbPlaylist, includeTracks bool) (*model.Playlist, error) {
var err error
if strings.TrimSpace(pls.RawRules) != "" {
r := model.SmartPlaylist{}
err = json.Unmarshal([]byte(pls.RawRules), &r)
if err != nil {
return nil, err
}
pls.Playlist.Rules = &r
} else {
pls.Playlist.Rules = nil
}
if includeTracks {
err = r.loadTracks(&pls)
}
return &pls.Playlist, err
} }
func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playlists, error) { func (r *playlistRepository) GetAll(options ...model.QueryOptions) (model.Playlists, error) {
sel := r.newSelect(options...).Columns("*").Where(r.userFilter()) sel := r.newSelect(options...).Columns("*").Where(r.userFilter())
res := model.Playlists{} var res []dbPlaylist
err := r.queryAll(sel, &res) err := r.queryAll(sel, &res)
return res, err if err != nil {
return nil, err
}
playlists := make(model.Playlists, len(res))
for i, p := range res {
pls, err := r.toModel(p, false)
if err != nil {
return nil, err
}
playlists[i] = *pls
}
return playlists, err
} }
func (r *playlistRepository) updateTracks(id string, tracks model.MediaFiles) error { func (r *playlistRepository) updateTracks(id string, tracks model.MediaFiles) error {
@ -128,7 +174,7 @@ func (r *playlistRepository) updateTracks(id string, tracks model.MediaFiles) er
return r.Tracks(id).Update(ids) return r.Tracks(id).Update(ids)
} }
func (r *playlistRepository) loadTracks(pls *model.Playlist) error { func (r *playlistRepository) loadTracks(pls *dbPlaylist) error {
tracksQuery := Select().From("playlist_tracks"). tracksQuery := Select().From("playlist_tracks").
LeftJoin("annotation on ("+ LeftJoin("annotation on ("+
"annotation.item_id = media_file_id"+ "annotation.item_id = media_file_id"+

View File

@ -231,7 +231,7 @@ func (r *playlistTrackRepository) isWritable() bool {
if usr.IsAdmin { if usr.IsAdmin {
return true return true
} }
pls, err := r.playlistRepo.Get(r.playlistId) pls, err := r.playlistRepo.FindByID(r.playlistId)
return err == nil && pls.Owner == usr.UserName return err == nil && pls.Owner == usr.UserName
} }

View File

@ -13,13 +13,12 @@ import (
) )
//{ //{
// "combinator": "and", //"combinator": "and",
// "rules": [ //"rules": [
// {"field": "loved", "operator": "is true"}, // {"field": "lastPlayed", "operator": "in the last", "value": "30"}
// {"field": "lastPlayed", "operator": "in the last", "value": "90"} //],
// ], //"order": "lastPlayed desc",
// "order": "artist asc", //"limit": 10
// "limit": 100
//} //}
type SmartPlaylist model.SmartPlaylist type SmartPlaylist model.SmartPlaylist