Trigger fewer signalr broadcasts

(cherry picked from commit b05b7ec4ad9368c8c3ae5ff5316caf5d23e24191)
This commit is contained in:
ta264 2020-09-30 22:37:45 +01:00 committed by Qstick
commit 2982478dba
7 changed files with 53 additions and 31 deletions

View file

@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.MusicTests.AlbumMonitoredServiceTests
Subject.SetAlbumMonitoredStatus(_artist, null); Subject.SetAlbumMonitoredStatus(_artist, null);
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.IsAny<Artist>()), Times.Once()); .Verify(v => v.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()), Times.Once());
Mocker.GetMock<IAlbumService>() Mocker.GetMock<IAlbumService>()
.Verify(v => v.UpdateMany(It.IsAny<List<Album>>()), Times.Never()); .Verify(v => v.UpdateMany(It.IsAny<List<Album>>()), Times.Never());
@ -72,7 +72,7 @@ namespace NzbDrone.Core.Test.MusicTests.AlbumMonitoredServiceTests
Subject.SetAlbumMonitoredStatus(_artist, new MonitoringOptions { Monitored = true, AlbumsToMonitor = albumsToMonitor }); Subject.SetAlbumMonitoredStatus(_artist, new MonitoringOptions { Monitored = true, AlbumsToMonitor = albumsToMonitor });
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.IsAny<Artist>()), Times.Once()); .Verify(v => v.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()), Times.Once());
VerifyMonitored(e => e.ForeignAlbumId == _albums.First().ForeignAlbumId); VerifyMonitored(e => e.ForeignAlbumId == _albums.First().ForeignAlbumId);
VerifyNotMonitored(e => e.ForeignAlbumId != _albums.First().ForeignAlbumId); VerifyNotMonitored(e => e.ForeignAlbumId != _albums.First().ForeignAlbumId);

View file

@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.MusicTests
ExceptionVerification.ExpectedErrors(1); ExceptionVerification.ExpectedErrors(1);
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.IsAny<Artist>()), Times.Once()); .Verify(v => v.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()), Times.Once());
} }
[Test] [Test]

View file

@ -100,8 +100,8 @@ namespace NzbDrone.Core.Test.MusicTests
private void AllowArtistUpdate() private void AllowArtistUpdate()
{ {
Mocker.GetMock<IArtistService>(MockBehavior.Strict) Mocker.GetMock<IArtistService>(MockBehavior.Strict)
.Setup(x => x.UpdateArtist(It.IsAny<Artist>())) .Setup(x => x.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()))
.Returns((Artist a) => a); .Returns((Artist a, bool updated) => a);
} }
[Test] [Test]
@ -151,7 +151,7 @@ namespace NzbDrone.Core.Test.MusicTests
Subject.Execute(new RefreshArtistCommand(_artist.Id)); Subject.Execute(new RefreshArtistCommand(_artist.Id));
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.IsAny<Artist>()), Times.Never()); .Verify(v => v.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()), Times.Never());
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.DeleteArtist(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Once()); .Verify(v => v.DeleteArtist(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Once());
@ -169,7 +169,7 @@ namespace NzbDrone.Core.Test.MusicTests
Subject.Execute(new RefreshArtistCommand(_artist.Id)); Subject.Execute(new RefreshArtistCommand(_artist.Id));
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.IsAny<Artist>()), Times.Never()); .Verify(v => v.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()), Times.Never());
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.DeleteArtist(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never()); .Verify(v => v.DeleteArtist(It.IsAny<int>(), It.IsAny<bool>(), It.IsAny<bool>()), Times.Never());
@ -197,8 +197,8 @@ namespace NzbDrone.Core.Test.MusicTests
// Make sure that the artist is updated before we refresh the albums // Make sure that the artist is updated before we refresh the albums
Mocker.GetMock<IArtistService>(MockBehavior.Strict) Mocker.GetMock<IArtistService>(MockBehavior.Strict)
.InSequence(seq) .InSequence(seq)
.Setup(x => x.UpdateArtist(It.IsAny<Artist>())) .Setup(x => x.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()))
.Returns((Artist a) => a); .Returns((Artist a, bool updated) => a);
Mocker.GetMock<IAlbumService>(MockBehavior.Strict) Mocker.GetMock<IAlbumService>(MockBehavior.Strict)
.InSequence(seq) .InSequence(seq)
@ -208,13 +208,13 @@ namespace NzbDrone.Core.Test.MusicTests
// Update called twice for a move/merge // Update called twice for a move/merge
Mocker.GetMock<IArtistService>(MockBehavior.Strict) Mocker.GetMock<IArtistService>(MockBehavior.Strict)
.InSequence(seq) .InSequence(seq)
.Setup(x => x.UpdateArtist(It.IsAny<Artist>())) .Setup(x => x.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()))
.Returns((Artist a) => a); .Returns((Artist a, bool updated) => a);
Subject.Execute(new RefreshArtistCommand(_artist.Id)); Subject.Execute(new RefreshArtistCommand(_artist.Id));
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.Is<Artist>(s => s.ArtistMetadataId == 100 && s.ForeignArtistId == newArtistInfo.ForeignArtistId)), .Verify(v => v.UpdateArtist(It.Is<Artist>(s => s.ArtistMetadataId == 100 && s.ForeignArtistId == newArtistInfo.ForeignArtistId), It.IsAny<bool>()),
Times.Exactly(2)); Times.Exactly(2));
} }
@ -257,8 +257,8 @@ namespace NzbDrone.Core.Test.MusicTests
Mocker.GetMock<IArtistService>(MockBehavior.Strict) Mocker.GetMock<IArtistService>(MockBehavior.Strict)
.InSequence(seq) .InSequence(seq)
.Setup(x => x.UpdateArtist(It.Is<Artist>(a => a.Id == clash.Id))) .Setup(x => x.UpdateArtist(It.Is<Artist>(a => a.Id == clash.Id), It.IsAny<bool>()))
.Returns((Artist a) => a); .Returns((Artist a, bool updated) => a);
Mocker.GetMock<IAlbumService>(MockBehavior.Strict) Mocker.GetMock<IAlbumService>(MockBehavior.Strict)
.InSequence(seq) .InSequence(seq)
@ -268,14 +268,14 @@ namespace NzbDrone.Core.Test.MusicTests
// Update called twice for a move/merge // Update called twice for a move/merge
Mocker.GetMock<IArtistService>(MockBehavior.Strict) Mocker.GetMock<IArtistService>(MockBehavior.Strict)
.InSequence(seq) .InSequence(seq)
.Setup(x => x.UpdateArtist(It.IsAny<Artist>())) .Setup(x => x.UpdateArtist(It.IsAny<Artist>(), It.IsAny<bool>()))
.Returns((Artist a) => a); .Returns((Artist a, bool updated) => a);
Subject.Execute(new RefreshArtistCommand(_artist.Id)); Subject.Execute(new RefreshArtistCommand(_artist.Id));
// the retained artist gets updated // the retained artist gets updated
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()
.Verify(v => v.UpdateArtist(It.Is<Artist>(s => s.Id == clash.Id)), Times.Exactly(2)); .Verify(v => v.UpdateArtist(It.Is<Artist>(s => s.Id == clash.Id), It.IsAny<bool>()), Times.Exactly(2));
// the old one gets removed // the old one gets removed
Mocker.GetMock<IArtistService>() Mocker.GetMock<IArtistService>()

View file

@ -20,7 +20,7 @@ namespace NzbDrone.Core.MediaCover
{ {
void ConvertToLocalUrls(int entityId, MediaCoverEntity coverEntity, IEnumerable<MediaCover> covers); void ConvertToLocalUrls(int entityId, MediaCoverEntity coverEntity, IEnumerable<MediaCover> covers);
string GetCoverPath(int entityId, MediaCoverEntity coverEntity, MediaCoverTypes mediaCoverTypes, string extension, int? height = null); string GetCoverPath(int entityId, MediaCoverEntity coverEntity, MediaCoverTypes mediaCoverTypes, string extension, int? height = null);
void EnsureAlbumCovers(Album album); bool EnsureAlbumCovers(Album album);
} }
public class MediaCoverService : public class MediaCoverService :
@ -114,8 +114,9 @@ namespace NzbDrone.Core.MediaCover
return Path.Combine(_coverRootFolder, "Albums", albumId.ToString()); return Path.Combine(_coverRootFolder, "Albums", albumId.ToString());
} }
private void EnsureArtistCovers(Artist artist) private bool EnsureArtistCovers(Artist artist)
{ {
bool updated = false;
var toResize = new List<Tuple<MediaCover, bool>>(); var toResize = new List<Tuple<MediaCover, bool>>();
foreach (var cover in artist.Metadata.Value.Images) foreach (var cover in artist.Metadata.Value.Images)
@ -132,6 +133,7 @@ namespace NzbDrone.Core.MediaCover
if (!alreadyExists) if (!alreadyExists)
{ {
DownloadCover(artist, cover, serverFileHeaders.LastModified ?? DateTime.Now); DownloadCover(artist, cover, serverFileHeaders.LastModified ?? DateTime.Now);
updated = true;
} }
} }
catch (WebException e) catch (WebException e)
@ -159,10 +161,14 @@ namespace NzbDrone.Core.MediaCover
{ {
_semaphore.Release(); _semaphore.Release();
} }
return updated;
} }
public void EnsureAlbumCovers(Album album) public bool EnsureAlbumCovers(Album album)
{ {
bool updated = false;
foreach (var cover in album.Images.Where(e => e.CoverType == MediaCoverTypes.Cover)) foreach (var cover in album.Images.Where(e => e.CoverType == MediaCoverTypes.Cover))
{ {
var fileName = GetCoverPath(album.Id, MediaCoverEntity.Album, cover.CoverType, cover.Extension, null); var fileName = GetCoverPath(album.Id, MediaCoverEntity.Album, cover.CoverType, cover.Extension, null);
@ -176,6 +182,7 @@ namespace NzbDrone.Core.MediaCover
if (!alreadyExists) if (!alreadyExists)
{ {
DownloadAlbumCover(album, cover, serverFileHeaders.LastModified ?? DateTime.Now); DownloadAlbumCover(album, cover, serverFileHeaders.LastModified ?? DateTime.Now);
updated = true;
} }
} }
catch (WebException e) catch (WebException e)
@ -187,6 +194,8 @@ namespace NzbDrone.Core.MediaCover
_logger.Error(e, "Couldn't download media cover for {0}", album); _logger.Error(e, "Couldn't download media cover for {0}", album);
} }
} }
return updated;
} }
private void DownloadCover(Artist artist, MediaCover cover, DateTime lastModified) private void DownloadCover(Artist artist, MediaCover cover, DateTime lastModified)
@ -273,16 +282,19 @@ namespace NzbDrone.Core.MediaCover
public void HandleAsync(ArtistRefreshCompleteEvent message) public void HandleAsync(ArtistRefreshCompleteEvent message)
{ {
EnsureArtistCovers(message.Artist); var updated = EnsureArtistCovers(message.Artist);
var albums = _albumService.GetAlbumsByArtist(message.Artist.Id); var albums = _albumService.GetAlbumsByArtist(message.Artist.Id);
foreach (Album album in albums) foreach (var album in albums)
{ {
EnsureAlbumCovers(album); updated |= EnsureAlbumCovers(album);
} }
if (updated)
{
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Artist)); _eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Artist));
} }
}
public void HandleAsync(ArtistDeletedEvent message) public void HandleAsync(ArtistDeletedEvent message)
{ {
@ -297,7 +309,11 @@ namespace NzbDrone.Core.MediaCover
{ {
if (message.DoRefresh) if (message.DoRefresh)
{ {
EnsureAlbumCovers(message.Album); var updated = EnsureAlbumCovers(message.Album);
if (updated)
{
_eventAggregator.PublishEvent(new MediaCoversUpdatedEvent(message.Album));
}
} }
} }

View file

@ -24,7 +24,7 @@ namespace NzbDrone.Core.Music
void DeleteArtist(int artistId, bool deleteFiles, bool addImportListExclusion = false); void DeleteArtist(int artistId, bool deleteFiles, bool addImportListExclusion = false);
List<Artist> GetAllArtists(); List<Artist> GetAllArtists();
List<Artist> AllForTag(int tagId); List<Artist> AllForTag(int tagId);
Artist UpdateArtist(Artist artist); Artist UpdateArtist(Artist artist, bool publishUpdatedEvent = true);
List<Artist> UpdateArtists(List<Artist> artist, bool useExistingRelativeFolder); List<Artist> UpdateArtists(List<Artist> artist, bool useExistingRelativeFolder);
bool ArtistPathExists(string folder); bool ArtistPathExists(string folder);
void RemoveAddOptions(Artist artist); void RemoveAddOptions(Artist artist);
@ -194,12 +194,16 @@ namespace NzbDrone.Core.Music
_artistRepository.SetFields(artist, s => s.AddOptions); _artistRepository.SetFields(artist, s => s.AddOptions);
} }
public Artist UpdateArtist(Artist artist) public Artist UpdateArtist(Artist artist, bool publishUpdatedEvent = true)
{ {
_cache.Clear(); _cache.Clear();
var storedArtist = GetArtist(artist.Id); var storedArtist = GetArtist(artist.Id);
var updatedArtist = _artistRepository.Update(artist); var updatedArtist = _artistRepository.Update(artist);
if (publishUpdatedEvent)
{
_eventAggregator.PublishEvent(new ArtistEditedEvent(updatedArtist, storedArtist)); _eventAggregator.PublishEvent(new ArtistEditedEvent(updatedArtist, storedArtist));
}
return updatedArtist; return updatedArtist;
} }

View file

@ -174,9 +174,11 @@ namespace NzbDrone.Core.Music
// Force update and fetch covers if images have changed so that we can write them into tags // Force update and fetch covers if images have changed so that we can write them into tags
if (remote.Images.Any() && !local.Images.SequenceEqual(remote.Images)) if (remote.Images.Any() && !local.Images.SequenceEqual(remote.Images))
{ {
_mediaCoverService.EnsureAlbumCovers(remote); if (_mediaCoverService.EnsureAlbumCovers(remote))
{
result = UpdateResult.UpdateTags; result = UpdateResult.UpdateTags;
} }
}
local.UseMetadataFrom(remote); local.UseMetadataFrom(remote);

View file

@ -190,7 +190,7 @@ namespace NzbDrone.Core.Music
protected override void SaveEntity(Artist local) protected override void SaveEntity(Artist local)
{ {
_artistService.UpdateArtist(local); _artistService.UpdateArtist(local, publishUpdatedEvent: false);
} }
protected override void DeleteEntity(Artist local, bool deleteFiles) protected override void DeleteEntity(Artist local, bool deleteFiles)