From c2d1e9df9ffea300e73049124f9a1b41ed5d2026 Mon Sep 17 00:00:00 2001 From: Deluan Date: Mon, 18 May 2020 20:32:01 -0400 Subject: [PATCH] Remove orphan tracks from playlists after they are removed from library --- model/album.go | 1 - model/artist.go | 1 - persistence/album_repository.go | 2 +- persistence/artist_repository.go | 2 +- persistence/persistence.go | 10 ++++--- persistence/playlist_repository.go | 34 ++++++++++++++++++++++++ persistence/playlist_track_repository.go | 4 ++- 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/model/album.go b/model/album.go index 3028bf02..f429a924 100644 --- a/model/album.go +++ b/model/album.go @@ -46,6 +46,5 @@ type AlbumRepository interface { GetStarred(options ...QueryOptions) (Albums, error) Search(q string, offset int, size int) (Albums, error) Refresh(ids ...string) error - PurgeEmpty() error AnnotatedRepository } diff --git a/model/artist.go b/model/artist.go index 76f13490..299d0d81 100644 --- a/model/artist.go +++ b/model/artist.go @@ -36,6 +36,5 @@ type ArtistRepository interface { Search(q string, offset int, size int) (Artists, error) Refresh(ids ...string) error GetIndex() (ArtistIndexes, error) - PurgeEmpty() error AnnotatedRepository } diff --git a/persistence/album_repository.go b/persistence/album_repository.go index 9fe15c01..339c0e70 100644 --- a/persistence/album_repository.go +++ b/persistence/album_repository.go @@ -180,7 +180,7 @@ func getMinYear(years string) int { return 0 } -func (r *albumRepository) PurgeEmpty() error { +func (r *albumRepository) purgeEmpty() error { del := Delete(r.tableName).Where("id not in (select distinct(album_id) from media_file)") c, err := r.executeSQL(del) if err == nil { diff --git a/persistence/artist_repository.go b/persistence/artist_repository.go index 2d346faa..4c191ba1 100644 --- a/persistence/artist_repository.go +++ b/persistence/artist_repository.go @@ -155,7 +155,7 @@ func (r *artistRepository) GetStarred(options ...model.QueryOptions) (model.Arti return starred, err } -func (r *artistRepository) PurgeEmpty() error { +func (r *artistRepository) purgeEmpty() error { del := Delete(r.tableName).Where("id not in (select distinct(album_artist_id) from album)") c, err := r.executeSQL(del) if err == nil { diff --git a/persistence/persistence.go b/persistence/persistence.go index 11987aae..daaf2bfd 100644 --- a/persistence/persistence.go +++ b/persistence/persistence.go @@ -108,11 +108,11 @@ func (s *SQLStore) WithTx(block func(tx model.DataStore) error) error { } func (s *SQLStore) GC(ctx context.Context) error { - err := s.Album(ctx).PurgeEmpty() + err := s.Album(ctx).(*albumRepository).purgeEmpty() if err != nil { return err } - err = s.Artist(ctx).PurgeEmpty() + err = s.Artist(ctx).(*artistRepository).purgeEmpty() if err != nil { return err } @@ -124,7 +124,11 @@ func (s *SQLStore) GC(ctx context.Context) error { if err != nil { return err } - return s.Artist(ctx).(*artistRepository).cleanAnnotations() + err = s.Artist(ctx).(*artistRepository).cleanAnnotations() + if err != nil { + return err + } + return s.Playlist(ctx).(*playlistRepository).removeOrphans() } func (s *SQLStore) getOrmer() orm.Ormer { diff --git a/persistence/playlist_repository.go b/persistence/playlist_repository.go index acc0dfcf..a7ccbd28 100644 --- a/persistence/playlist_repository.go +++ b/persistence/playlist_repository.go @@ -165,6 +165,40 @@ func (r *playlistRepository) Update(entity interface{}, cols ...string) error { return err } +func (r *playlistRepository) removeOrphans() error { + sel := Select("playlist_tracks.playlist_id as id", "p.name").From("playlist_tracks"). + Join("playlist p on playlist_tracks.playlist_id = p.id"). + LeftJoin("media_file mf on playlist_tracks.media_file_id = mf.id"). + Where(Eq{"mf.id": nil}). + GroupBy("playlist_tracks.playlist_id") + + var pls []struct{ Id, Name string } + err := r.queryAll(sel, &pls) + if err != nil { + return err + } + + for _, pl := range pls { + log.Debug(r.ctx, "Cleaning-up orphan tracks from playlist", "id", pl.Id, "name", pl.Name) + del := Delete("playlist_tracks").Where(And{ + ConcatExpr("media_file_id not in (select id from media_file)"), + Eq{"playlist_id": pl.Id}, + }) + n, err := r.executeSQL(del) + if n == 0 || err != nil { + return err + } + log.Debug(r.ctx, "Deleted tracks, now reordering", "id", pl.Id, "name", pl.Name, "deleted", n) + + // To reorganize the playlist, just add an empty list of new tracks + trks := r.Tracks(pl.Id) + if err := trks.Add(nil); err != nil { + return err + } + } + return nil +} + var _ model.PlaylistRepository = (*playlistRepository)(nil) var _ rest.Repository = (*playlistRepository)(nil) var _ rest.Persistable = (*playlistRepository)(nil) diff --git a/persistence/playlist_track_repository.go b/persistence/playlist_track_repository.go index 09f12df0..52817bef 100644 --- a/persistence/playlist_track_repository.go +++ b/persistence/playlist_track_repository.go @@ -66,7 +66,9 @@ func (r *playlistTrackRepository) NewInstance() interface{} { } func (r *playlistTrackRepository) Add(mediaFileIds []string) error { - log.Debug(r.ctx, "Adding songs to playlist", "playlistId", r.playlistId, "mediaFileIds", mediaFileIds) + if len(mediaFileIds) > 0 { + log.Debug(r.ctx, "Adding songs to playlist", "playlistId", r.playlistId, "mediaFileIds", mediaFileIds) + } // Get all current tracks all := r.newSelect().Columns("media_file_id").Where(Eq{"playlist_id": r.playlistId}).OrderBy("id")