diff --git a/engine/list_generator.go b/engine/list_generator.go index 1123598ed..d4b81f0b4 100644 --- a/engine/list_generator.go +++ b/engine/list_generator.go @@ -33,6 +33,7 @@ type listGenerator struct { npRepo NowPlayingRepository } +// TODO: Only return albums that have the SortBy field != empty func (g *listGenerator) query(qo model.QueryOptions, offset int, size int) (Entries, error) { qo.Offset = offset qo.Size = size diff --git a/engine/scrobbler.go b/engine/scrobbler.go index 7a237c185..db3d165e3 100644 --- a/engine/scrobbler.go +++ b/engine/scrobbler.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/cloudsonic/sonic-server/conf" "github.com/cloudsonic/sonic-server/itunesbridge" "github.com/cloudsonic/sonic-server/log" "github.com/cloudsonic/sonic-server/model" @@ -21,13 +22,14 @@ type Scrobbler interface { NowPlaying(ctx context.Context, playerId int, playerName, trackId, username string) (*model.MediaFile, error) } -func NewScrobbler(itunes itunesbridge.ItunesControl, mr model.MediaFileRepository, npr NowPlayingRepository) Scrobbler { - return &scrobbler{itunes, mr, npr} +func NewScrobbler(itunes itunesbridge.ItunesControl, mr model.MediaFileRepository, alr model.AlbumRepository, npr NowPlayingRepository) Scrobbler { + return &scrobbler{itunes: itunes, mfRepo: mr, alRepo: alr, npRepo: npr} } type scrobbler struct { itunes itunesbridge.ItunesControl mfRepo model.MediaFileRepository + alRepo model.AlbumRepository npRepo NowPlayingRepository } @@ -71,6 +73,16 @@ func (s *scrobbler) detectSkipped(ctx context.Context, playerId int, trackId str func (s *scrobbler) Register(ctx context.Context, playerId int, trackId string, playTime time.Time) (*model.MediaFile, error) { s.detectSkipped(ctx, playerId, trackId) + if conf.Sonic.DevUseFileScanner { + mf, err := s.mfRepo.Get(trackId) + if err != nil { + err = s.mfRepo.MarkAsPlayed(trackId, playTime) + return nil, err + } + err = s.alRepo.MarkAsPlayed(mf.AlbumID, playTime) + return mf, err + } + mf, err := s.mfRepo.Get(trackId) if err != nil { return nil, err diff --git a/engine/scrobbler_test.go b/engine/scrobbler_test.go index ef96fd550..eb000e3bf 100644 --- a/engine/scrobbler_test.go +++ b/engine/scrobbler_test.go @@ -17,10 +17,11 @@ func TestScrobbler(t *testing.T) { Init(t, false) mfRepo := persistence.CreateMockMediaFileRepo() + alRepo := persistence.CreateMockAlbumRepo() npRepo := engine.CreateMockNowPlayingRepo() itCtrl := &mockItunesControl{} - scrobbler := engine.NewScrobbler(itCtrl, mfRepo, npRepo) + scrobbler := engine.NewScrobbler(itCtrl, mfRepo, alRepo, npRepo) Convey("Given a DB with one song", t, func() { mfRepo.SetData(`[{"ID":"2","Title":"Hands Of Time"}]`, 1) @@ -89,10 +90,11 @@ func TestSkipping(t *testing.T) { Init(t, false) mfRepo := persistence.CreateMockMediaFileRepo() + alRepo := persistence.CreateMockAlbumRepo() npRepo := engine.CreateMockNowPlayingRepo() itCtrl := &mockItunesControl{} - scrobbler := engine.NewScrobbler(itCtrl, mfRepo, npRepo) + scrobbler := engine.NewScrobbler(itCtrl, mfRepo, alRepo, npRepo) Convey("Given a DB with three songs", t, func() { mfRepo.SetData(`[{"ID":"1","Title":"Femme Fatale"},{"ID":"2","Title":"Here She Comes Now"},{"ID":"3","Title":"Lady Godiva's Operation"}]`, 3) diff --git a/model/album.go b/model/album.go index b96cd0091..3b4345c63 100644 --- a/model/album.go +++ b/model/album.go @@ -36,8 +36,9 @@ type AlbumRepository interface { PurgeInactive(active Albums) error GetAllIds() ([]string, error) GetStarred(...QueryOptions) (Albums, error) - SetStar(star bool, ids ...string) error Search(q string, offset int, size int) (Albums, error) Refresh(ids ...string) error PurgeEmpty() error + SetStar(star bool, ids ...string) error + MarkAsPlayed(id string, playDate time.Time) error } diff --git a/model/mediafile.go b/model/mediafile.go index ea2a7a533..9ecc07bad 100644 --- a/model/mediafile.go +++ b/model/mediafile.go @@ -54,4 +54,5 @@ type MediaFileRepository interface { DeleteByPath(path string) error SetStar(star bool, ids ...string) error SetRating(rating int, ids ...string) error + MarkAsPlayed(id string, playTime time.Time) error } diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 50fd12c7b..36ba89c76 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -190,6 +190,14 @@ func (r *albumRepository) SetStar(starred bool, ids ...string) error { return err } +func (r *albumRepository) MarkAsPlayed(id string, playDate time.Time) error { + _, err := r.newQuery(Db()).Filter("id", id).Update(orm.Params{ + "play_count": orm.ColValue(orm.ColAdd, 1), + "play_date": playDate, + }) + return err +} + func (r *albumRepository) Search(q string, offset int, size int) (model.Albums, error) { if len(q) <= 2 { return nil, nil diff --git a/persistence/mediafile_repository.go b/persistence/mediafile_repository.go index d342be95d..b04f4071d 100644 --- a/persistence/mediafile_repository.go +++ b/persistence/mediafile_repository.go @@ -158,6 +158,14 @@ func (r *mediaFileRepository) SetRating(rating int, ids ...string) error { return err } +func (r *mediaFileRepository) MarkAsPlayed(id string, playDate time.Time) error { + _, err := r.newQuery(Db()).Filter("id", id).Update(orm.Params{ + "play_count": orm.ColValue(orm.ColAdd, 1), + "play_date": playDate, + }) + return err +} + func (r *mediaFileRepository) PurgeInactive(activeList model.MediaFiles) error { return withTx(func(o orm.Ormer) error { _, err := r.purgeInactive(o, activeList, func(item interface{}) string { diff --git a/wire_gen.go b/wire_gen.go index 582c9e4fa..982aeac23 100644 --- a/wire_gen.go +++ b/wire_gen.go @@ -48,7 +48,7 @@ func CreateSubsonicAPIRouter() *api.Router { playlistRepository := persistence.NewPlaylistRepository() playlists := engine.NewPlaylists(itunesControl, playlistRepository, mediaFileRepository) ratings := engine.NewRatings(itunesControl, mediaFileRepository, albumRepository, artistRepository) - scrobbler := engine.NewScrobbler(itunesControl, mediaFileRepository, nowPlayingRepository) + scrobbler := engine.NewScrobbler(itunesControl, mediaFileRepository, albumRepository, nowPlayingRepository) search := engine.NewSearch(artistRepository, albumRepository, mediaFileRepository) router := api.NewRouter(browser, cover, listGenerator, playlists, ratings, scrobbler, search) return router