parent
f5c1858d4c
commit
0b7a42ee3b
@ -1,160 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using FluentValidation;
|
|
||||||
using FluentValidation.Results;
|
|
||||||
using NLog;
|
|
||||||
using NzbDrone.Common.EnsureThat;
|
|
||||||
using NzbDrone.Common.Extensions;
|
|
||||||
using NzbDrone.Common.Instrumentation.Extensions;
|
|
||||||
using NzbDrone.Core.Exceptions;
|
|
||||||
using NzbDrone.Core.MetadataSource;
|
|
||||||
|
|
||||||
namespace NzbDrone.Core.Music
|
|
||||||
{
|
|
||||||
public interface IAddAlbumService
|
|
||||||
{
|
|
||||||
Album AddAlbum(Album newAlbum);
|
|
||||||
List<Album> AddAlbums(List<Album> newAlbums);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AddAlbumService : IAddAlbumService
|
|
||||||
{
|
|
||||||
private readonly IAlbumService _albumService;
|
|
||||||
private readonly IReleaseService _releaseService;
|
|
||||||
private readonly IProvideAlbumInfo _albumInfo;
|
|
||||||
private readonly IArtistMetadataRepository _artistMetadataRepository;
|
|
||||||
private readonly IRefreshTrackService _refreshTrackService;
|
|
||||||
private readonly Logger _logger;
|
|
||||||
|
|
||||||
public AddAlbumService(IAlbumService albumService,
|
|
||||||
IReleaseService releaseService,
|
|
||||||
IProvideAlbumInfo albumInfo,
|
|
||||||
IArtistMetadataRepository artistMetadataRepository,
|
|
||||||
IRefreshTrackService refreshTrackService,
|
|
||||||
Logger logger)
|
|
||||||
{
|
|
||||||
_albumService = albumService;
|
|
||||||
_releaseService = releaseService;
|
|
||||||
_albumInfo = albumInfo;
|
|
||||||
_artistMetadataRepository = artistMetadataRepository;
|
|
||||||
_refreshTrackService = refreshTrackService;
|
|
||||||
_logger = logger;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<AlbumRelease> AddAlbumReleases(Album album)
|
|
||||||
{
|
|
||||||
var remoteReleases = album.AlbumReleases.Value.DistinctBy(m => m.ForeignReleaseId).ToList();
|
|
||||||
var existingReleases = _releaseService.GetReleasesForRefresh(album.Id, remoteReleases.Select(x => x.ForeignReleaseId));
|
|
||||||
var newReleaseList = new List<AlbumRelease>();
|
|
||||||
var updateReleaseList = new List<AlbumRelease>();
|
|
||||||
|
|
||||||
foreach (var release in remoteReleases)
|
|
||||||
{
|
|
||||||
release.AlbumId = album.Id;
|
|
||||||
release.Album = album;
|
|
||||||
var releaseToRefresh = existingReleases.SingleOrDefault(r => r.ForeignReleaseId == release.ForeignReleaseId);
|
|
||||||
|
|
||||||
if (releaseToRefresh != null)
|
|
||||||
{
|
|
||||||
existingReleases.Remove(releaseToRefresh);
|
|
||||||
|
|
||||||
// copy across the db keys and check for equality
|
|
||||||
release.Id = releaseToRefresh.Id;
|
|
||||||
release.AlbumId = releaseToRefresh.AlbumId;
|
|
||||||
|
|
||||||
updateReleaseList.Add(release);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newReleaseList.Add(release);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure only one release is monitored
|
|
||||||
remoteReleases.ForEach(x => x.Monitored = false);
|
|
||||||
remoteReleases.OrderByDescending(x => x.TrackCount).First().Monitored = true;
|
|
||||||
Ensure.That(remoteReleases.Count(x => x.Monitored) == 1).IsTrue();
|
|
||||||
|
|
||||||
// Since this is a new album, we can't be deleting any existing releases
|
|
||||||
_releaseService.UpdateMany(updateReleaseList);
|
|
||||||
_releaseService.InsertMany(newReleaseList);
|
|
||||||
|
|
||||||
return remoteReleases;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Album AddAlbum(Tuple<string, Album, List<ArtistMetadata>> skyHookData)
|
|
||||||
{
|
|
||||||
var newAlbum = skyHookData.Item2;
|
|
||||||
|
|
||||||
if (newAlbum.AlbumReleases.Value.Count == 0)
|
|
||||||
{
|
|
||||||
_logger.Debug($"Skipping album with no valid releases {newAlbum}");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.ProgressInfo("Adding Album {0}", newAlbum.Title);
|
|
||||||
|
|
||||||
_artistMetadataRepository.UpsertMany(skyHookData.Item3);
|
|
||||||
newAlbum.ArtistMetadata = _artistMetadataRepository.FindById(skyHookData.Item1);
|
|
||||||
newAlbum.ArtistMetadataId = newAlbum.ArtistMetadata.Value.Id;
|
|
||||||
|
|
||||||
_albumService.AddAlbum(newAlbum);
|
|
||||||
AddAlbumReleases(newAlbum);
|
|
||||||
|
|
||||||
_refreshTrackService.RefreshTrackInfo(newAlbum, false);
|
|
||||||
|
|
||||||
return newAlbum;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Album AddAlbum(Album newAlbum)
|
|
||||||
{
|
|
||||||
Ensure.That(newAlbum, () => newAlbum).IsNotNull();
|
|
||||||
|
|
||||||
var tuple = AddSkyhookData(newAlbum);
|
|
||||||
|
|
||||||
return AddAlbum(tuple);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<Album> AddAlbums(List<Album> newAlbums)
|
|
||||||
{
|
|
||||||
var added = DateTime.UtcNow;
|
|
||||||
var albumsToAdd = new List<Album>();
|
|
||||||
|
|
||||||
foreach (var newAlbum in newAlbums)
|
|
||||||
{
|
|
||||||
var tuple = AddSkyhookData(newAlbum);
|
|
||||||
tuple.Item2.Added = added;
|
|
||||||
tuple.Item2.LastInfoSync = added;
|
|
||||||
|
|
||||||
albumsToAdd.Add(AddAlbum(tuple));
|
|
||||||
}
|
|
||||||
|
|
||||||
return albumsToAdd;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Tuple<string, Album, List<ArtistMetadata>> AddSkyhookData(Album newAlbum)
|
|
||||||
{
|
|
||||||
Tuple<string, Album, List<ArtistMetadata>> tuple;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tuple = _albumInfo.GetAlbumInfo(newAlbum.ForeignAlbumId);
|
|
||||||
}
|
|
||||||
catch (AlbumNotFoundException)
|
|
||||||
{
|
|
||||||
_logger.Error("LidarrId {1} was not found, it may have been removed from Lidarr.", newAlbum.ForeignAlbumId);
|
|
||||||
|
|
||||||
throw new ValidationException(new List<ValidationFailure>
|
|
||||||
{
|
|
||||||
new ValidationFailure("MusicBrainzId", "An album with this ID was not found", newAlbum.ForeignAlbumId)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
tuple.Item2.Monitored = newAlbum.Monitored;
|
|
||||||
tuple.Item2.ProfileId = newAlbum.ProfileId;
|
|
||||||
|
|
||||||
return tuple;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,138 @@
|
|||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public interface IRefreshAlbumReleaseService
|
||||||
|
{
|
||||||
|
bool RefreshEntityInfo(AlbumRelease entity, List<AlbumRelease> remoteEntityList, bool forceChildRefresh, bool forceUpdateFileTags);
|
||||||
|
bool RefreshEntityInfo(List<AlbumRelease> releases, List<AlbumRelease> remoteEntityList, bool forceChildRefresh, bool forceUpdateFileTags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RefreshAlbumReleaseService : RefreshEntityServiceBase<AlbumRelease, Track>, IRefreshAlbumReleaseService
|
||||||
|
{
|
||||||
|
private readonly IReleaseService _releaseService;
|
||||||
|
private readonly IRefreshTrackService _refreshTrackService;
|
||||||
|
private readonly ITrackService _trackService;
|
||||||
|
private readonly IMediaFileService _mediaFileService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public RefreshAlbumReleaseService(IReleaseService releaseService,
|
||||||
|
IArtistMetadataRepository artistMetadataRepository,
|
||||||
|
IRefreshTrackService refreshTrackService,
|
||||||
|
ITrackService trackService,
|
||||||
|
IMediaFileService mediaFileService,
|
||||||
|
Logger logger)
|
||||||
|
: base(logger, artistMetadataRepository)
|
||||||
|
{
|
||||||
|
_releaseService = releaseService;
|
||||||
|
_trackService = trackService;
|
||||||
|
_refreshTrackService = refreshTrackService;
|
||||||
|
_mediaFileService = mediaFileService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override RemoteData GetRemoteData(AlbumRelease local, List<AlbumRelease> remote)
|
||||||
|
{
|
||||||
|
var result = new RemoteData();
|
||||||
|
result.Entity = remote.SingleOrDefault(x => x.ForeignReleaseId == local.ForeignReleaseId || x.OldForeignReleaseIds.Contains(local.ForeignReleaseId));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool IsMerge(AlbumRelease local, AlbumRelease remote)
|
||||||
|
{
|
||||||
|
return local.ForeignReleaseId != remote.ForeignReleaseId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override UpdateResult UpdateEntity(AlbumRelease local, AlbumRelease remote)
|
||||||
|
{
|
||||||
|
if (local.Equals(remote))
|
||||||
|
{
|
||||||
|
return UpdateResult.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
local.OldForeignReleaseIds = remote.OldForeignReleaseIds;
|
||||||
|
local.Title = remote.Title;
|
||||||
|
local.Status = remote.Status;
|
||||||
|
local.Duration = remote.Duration;
|
||||||
|
local.Label = remote.Label;
|
||||||
|
local.Disambiguation = remote.Disambiguation;
|
||||||
|
local.Country = remote.Country;
|
||||||
|
local.ReleaseDate = remote.ReleaseDate;
|
||||||
|
local.Media = remote.Media;
|
||||||
|
local.TrackCount = remote.TrackCount;
|
||||||
|
|
||||||
|
return UpdateResult.UpdateTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override AlbumRelease GetEntityByForeignId(AlbumRelease local)
|
||||||
|
{
|
||||||
|
return _releaseService.GetReleaseByForeignReleaseId(local.ForeignReleaseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SaveEntity(AlbumRelease local)
|
||||||
|
{
|
||||||
|
_releaseService.UpdateMany(new List<AlbumRelease> { local });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DeleteEntity(AlbumRelease local, bool deleteFiles)
|
||||||
|
{
|
||||||
|
_releaseService.DeleteMany(new List<AlbumRelease> { local });
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<Track> GetRemoteChildren(AlbumRelease remote)
|
||||||
|
{
|
||||||
|
return remote.Tracks.Value.DistinctBy(m => m.ForeignTrackId).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<Track> GetLocalChildren(AlbumRelease entity, List<Track> remoteChildren)
|
||||||
|
{
|
||||||
|
return _trackService.GetTracksForRefresh(entity.Id,
|
||||||
|
remoteChildren.Select(x => x.ForeignTrackId)
|
||||||
|
.Concat(remoteChildren.SelectMany(x => x.OldForeignTrackIds)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Tuple<Track, List<Track> > GetMatchingExistingChildren(List<Track> existingChildren, Track remote)
|
||||||
|
{
|
||||||
|
var existingChild = existingChildren.SingleOrDefault(x => x.ForeignTrackId == remote.ForeignTrackId);
|
||||||
|
var mergeChildren = existingChildren.Where(x => remote.OldForeignTrackIds.Contains(x.ForeignTrackId)).ToList();
|
||||||
|
return Tuple.Create(existingChild, mergeChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PrepareNewChild(Track child, AlbumRelease entity)
|
||||||
|
{
|
||||||
|
child.AlbumReleaseId = entity.Id;
|
||||||
|
child.AlbumRelease = entity;
|
||||||
|
child.ArtistMetadataId = child.ArtistMetadata.Value.Id;
|
||||||
|
|
||||||
|
// make sure title is not null
|
||||||
|
child.Title = child.Title ?? "Unknown";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void PrepareExistingChild(Track local, Track remote, AlbumRelease entity)
|
||||||
|
{
|
||||||
|
local.AlbumRelease = entity;
|
||||||
|
local.AlbumReleaseId = entity.Id;
|
||||||
|
local.ArtistMetadataId = remote.ArtistMetadata.Value.Id;
|
||||||
|
remote.Id = local.Id;
|
||||||
|
remote.TrackFileId = local.TrackFileId;
|
||||||
|
remote.AlbumReleaseId = local.AlbumReleaseId;
|
||||||
|
remote.ArtistMetadataId = local.ArtistMetadataId;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void AddChildren(List<Track> children)
|
||||||
|
{
|
||||||
|
_trackService.InsertMany(children);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool RefreshChildren(SortedChildren localChildren, List<Track> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||||
|
{
|
||||||
|
return _refreshTrackService.RefreshTrackInfo(localChildren.Added, localChildren.Updated, localChildren.Merged, localChildren.Deleted, localChildren.UpToDate, remoteChildren, forceUpdateFileTags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,277 @@
|
|||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Music
|
||||||
|
{
|
||||||
|
public abstract class RefreshEntityServiceBase<Entity, Child>
|
||||||
|
{
|
||||||
|
private readonly Logger _logger;
|
||||||
|
private readonly IArtistMetadataRepository _artistMetadataRepository;
|
||||||
|
|
||||||
|
public RefreshEntityServiceBase(Logger logger,
|
||||||
|
IArtistMetadataRepository artistMetadataRepository)
|
||||||
|
{
|
||||||
|
_logger = logger;
|
||||||
|
_artistMetadataRepository = artistMetadataRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UpdateResult
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Standard,
|
||||||
|
UpdateTags
|
||||||
|
};
|
||||||
|
|
||||||
|
public class SortedChildren
|
||||||
|
{
|
||||||
|
public SortedChildren()
|
||||||
|
{
|
||||||
|
UpToDate = new List<Child>();
|
||||||
|
Added = new List<Child>();
|
||||||
|
Updated = new List<Child>();
|
||||||
|
Merged = new List<Tuple<Child, Child> >();
|
||||||
|
Deleted = new List<Child>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Child> UpToDate { get; set; }
|
||||||
|
public List<Child> Added { get; set; }
|
||||||
|
public List<Child> Updated { get; set; }
|
||||||
|
public List<Tuple<Child, Child> > Merged { get; set; }
|
||||||
|
public List<Child> Deleted { get; set; }
|
||||||
|
|
||||||
|
public List<Child> All => UpToDate.Concat(Added).Concat(Updated).Concat(Merged.Select(x => x.Item1)).Concat(Deleted).ToList();
|
||||||
|
public List<Child> Future => UpToDate.Concat(Added).Concat(Updated).ToList();
|
||||||
|
public List<Child> Old => Merged.Select(x => x.Item1).Concat(Deleted).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class RemoteData
|
||||||
|
{
|
||||||
|
public Entity Entity { get; set; }
|
||||||
|
public List<ArtistMetadata> Metadata { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void LogProgress(Entity local)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract RemoteData GetRemoteData(Entity local, List<Entity> remote);
|
||||||
|
|
||||||
|
protected virtual void EnsureNewParent(Entity local, Entity remote)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract bool IsMerge(Entity local, Entity remote);
|
||||||
|
|
||||||
|
protected virtual bool ShouldDelete(Entity local)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract UpdateResult UpdateEntity(Entity local, Entity remote);
|
||||||
|
|
||||||
|
protected virtual UpdateResult MoveEntity(Entity local, Entity remote)
|
||||||
|
{
|
||||||
|
return UpdateEntity(local, remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual UpdateResult MergeEntity(Entity local, Entity target, Entity remote)
|
||||||
|
{
|
||||||
|
DeleteEntity(local, true);
|
||||||
|
return UpdateResult.UpdateTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Entity GetEntityByForeignId(Entity local);
|
||||||
|
protected abstract void SaveEntity(Entity local);
|
||||||
|
protected abstract void DeleteEntity(Entity local, bool deleteFiles);
|
||||||
|
|
||||||
|
protected abstract List<Child> GetRemoteChildren(Entity remote);
|
||||||
|
protected abstract List<Child> GetLocalChildren(Entity entity, List<Child> remoteChildren);
|
||||||
|
protected abstract Tuple<Child, List<Child> > GetMatchingExistingChildren(List<Child> existingChildren, Child remote);
|
||||||
|
|
||||||
|
protected abstract void PrepareNewChild(Child remoteChild, Entity entity);
|
||||||
|
protected abstract void PrepareExistingChild(Child existingChild, Child remoteChild, Entity entity);
|
||||||
|
protected abstract void AddChildren(List<Child> children);
|
||||||
|
protected abstract bool RefreshChildren(SortedChildren localChildren, List<Child> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags);
|
||||||
|
|
||||||
|
protected virtual void PublishEntityUpdatedEvent(Entity entity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void PublishChildrenUpdatedEvent(Entity entity, List<Child> newChildren, List<Child> updateChildren)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RefreshEntityInfo(Entity local, List<Entity> remoteList, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||||
|
{
|
||||||
|
bool updated = false;
|
||||||
|
|
||||||
|
LogProgress(local);
|
||||||
|
|
||||||
|
var data = GetRemoteData(local, remoteList);
|
||||||
|
var remote = data.Entity;
|
||||||
|
|
||||||
|
if (remote == null)
|
||||||
|
{
|
||||||
|
if (ShouldDelete(local))
|
||||||
|
{
|
||||||
|
_logger.Warn($"{typeof(Entity).Name} {local} not found in metadata and is being deleted");
|
||||||
|
DeleteEntity(local, true);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Error($"{typeof(Entity).Name} {local} was not found, it may have been removed from Metadata sources.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.Metadata != null)
|
||||||
|
{
|
||||||
|
var metadataResult = UpdateArtistMetadata(data.Metadata);
|
||||||
|
updated |= metadataResult >= UpdateResult.Standard;
|
||||||
|
forceUpdateFileTags |= metadataResult == UpdateResult.UpdateTags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate that the parent object exists (remote data might specify a different one)
|
||||||
|
EnsureNewParent(local, remote);
|
||||||
|
|
||||||
|
UpdateResult result;
|
||||||
|
if (IsMerge(local, remote))
|
||||||
|
{
|
||||||
|
// get entity we're merging into
|
||||||
|
var target = GetEntityByForeignId(remote);
|
||||||
|
|
||||||
|
if (target == null)
|
||||||
|
{
|
||||||
|
_logger.Trace($"Moving {typeof(Entity).Name} {local} to {remote}");
|
||||||
|
result = MoveEntity(local, remote);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Trace($"Merging {typeof(Entity).Name} {local} into {target}");
|
||||||
|
result = MergeEntity(local, target, remote);
|
||||||
|
|
||||||
|
// having merged local into target, do update for target using remote
|
||||||
|
local = target;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the entity early so that children see the updated ids
|
||||||
|
SaveEntity(local);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.Trace($"Updating {typeof(Entity).Name} {local}");
|
||||||
|
result = UpdateEntity(local, remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
updated |= result >= UpdateResult.Standard;
|
||||||
|
forceUpdateFileTags |= result == UpdateResult.UpdateTags;
|
||||||
|
|
||||||
|
_logger.Trace($"updated: {updated} forceUpdateFileTags: {forceUpdateFileTags}");
|
||||||
|
|
||||||
|
var remoteChildren = GetRemoteChildren(remote);
|
||||||
|
updated |= SortChildren(local, remoteChildren, forceChildRefresh, forceUpdateFileTags);
|
||||||
|
|
||||||
|
// Do this last so entity only marked as refreshed if refresh of children completed successfully
|
||||||
|
_logger.Trace($"Saving {typeof(Entity).Name} {local}");
|
||||||
|
SaveEntity(local);
|
||||||
|
|
||||||
|
if (updated)
|
||||||
|
{
|
||||||
|
PublishEntityUpdatedEvent(local);
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug($"Finished {typeof(Entity).Name} refresh for {local}");
|
||||||
|
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UpdateResult UpdateArtistMetadata(List<ArtistMetadata> data)
|
||||||
|
{
|
||||||
|
var remoteMetadata = data.DistinctBy(x => x.ForeignArtistId).ToList();
|
||||||
|
var updated = _artistMetadataRepository.UpsertMany(data);
|
||||||
|
return updated ? UpdateResult.UpdateTags : UpdateResult.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RefreshEntityInfo(List<Entity> localList, List<Entity> remoteList, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||||
|
{
|
||||||
|
bool updated = false;
|
||||||
|
foreach (var entity in localList)
|
||||||
|
{
|
||||||
|
updated |= RefreshEntityInfo(entity, remoteList, forceChildRefresh, forceUpdateFileTags);
|
||||||
|
}
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool SortChildren(Entity entity, List<Child> remoteChildren, bool forceChildRefresh, bool forceUpdateFileTags)
|
||||||
|
{
|
||||||
|
// Get existing children (and children to be) from the database
|
||||||
|
var localChildren = GetLocalChildren(entity, remoteChildren);
|
||||||
|
|
||||||
|
var sortedChildren = new SortedChildren();
|
||||||
|
sortedChildren.Deleted.AddRange(localChildren);
|
||||||
|
|
||||||
|
// Cycle through children
|
||||||
|
foreach (var remoteChild in remoteChildren)
|
||||||
|
{
|
||||||
|
// Check for child in existing children, if not set properties and add to new list
|
||||||
|
var tuple = GetMatchingExistingChildren(localChildren, remoteChild);
|
||||||
|
var existingChild = tuple.Item1;
|
||||||
|
var mergedChildren = tuple.Item2;
|
||||||
|
|
||||||
|
if (existingChild != null)
|
||||||
|
{
|
||||||
|
sortedChildren.Deleted.Remove(existingChild);
|
||||||
|
|
||||||
|
PrepareExistingChild(existingChild, remoteChild, entity);
|
||||||
|
|
||||||
|
if (existingChild.Equals(remoteChild))
|
||||||
|
{
|
||||||
|
sortedChildren.UpToDate.Add(existingChild);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sortedChildren.Updated.Add(existingChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note the children that are going to be merged into existingChild
|
||||||
|
foreach (var child in mergedChildren)
|
||||||
|
{
|
||||||
|
sortedChildren.Merged.Add(Tuple.Create(child, existingChild));
|
||||||
|
sortedChildren.Deleted.Remove(child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PrepareNewChild(remoteChild, entity);
|
||||||
|
sortedChildren.Added.Add(remoteChild);
|
||||||
|
|
||||||
|
// note the children that will be merged into remoteChild (once added)
|
||||||
|
foreach (var child in mergedChildren)
|
||||||
|
{
|
||||||
|
sortedChildren.Merged.Add(Tuple.Create(child, existingChild));
|
||||||
|
sortedChildren.Deleted.Remove(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_logger.Debug("{0} {1} {2}s up to date. Adding {3}, Updating {4}, Merging {5}, Deleting {6}.",
|
||||||
|
entity, sortedChildren.UpToDate.Count, typeof(Child).Name.ToLower(),
|
||||||
|
sortedChildren.Added.Count, sortedChildren.Updated.Count, sortedChildren.Merged.Count, sortedChildren.Deleted.Count);
|
||||||
|
|
||||||
|
// Add in the new children (we have checked that foreign IDs don't clash)
|
||||||
|
AddChildren(sortedChildren.Added);
|
||||||
|
|
||||||
|
// now trigger updates
|
||||||
|
var updated = RefreshChildren(sortedChildren, remoteChildren, forceChildRefresh, forceUpdateFileTags);
|
||||||
|
|
||||||
|
PublishChildrenUpdatedEvent(entity, sortedChildren.Added, sortedChildren.Updated);
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in new issue