diff --git a/src/NzbDrone.Core.Test/Lidarr.Core.Test.csproj b/src/NzbDrone.Core.Test/Lidarr.Core.Test.csproj
index 16efb130f..e314a2c58 100644
--- a/src/NzbDrone.Core.Test/Lidarr.Core.Test.csproj
+++ b/src/NzbDrone.Core.Test/Lidarr.Core.Test.csproj
@@ -6,6 +6,7 @@
+
diff --git a/src/NzbDrone.Core.Test/MusicTests/EntityFixture.cs b/src/NzbDrone.Core.Test/MusicTests/EntityFixture.cs
new file mode 100644
index 000000000..ba5fb83b5
--- /dev/null
+++ b/src/NzbDrone.Core.Test/MusicTests/EntityFixture.cs
@@ -0,0 +1,298 @@
+using NUnit.Framework;
+using NzbDrone.Common.Extensions;
+using NzbDrone.Core.Music;
+using NzbDrone.Test.Common;
+using FluentAssertions;
+using System.Collections;
+using System.Reflection;
+using AutoFixture;
+using System.Linq;
+using Equ;
+using Marr.Data;
+
+namespace NzbDrone.Core.Test.MusicTests
+{
+ [TestFixture]
+ public class EntityFixture : LoggingTest
+ {
+
+ Fixture fixture = new Fixture();
+
+ private static bool IsNotMarkedAsIgnore(PropertyInfo propertyInfo)
+ {
+ return !propertyInfo.GetCustomAttributes(typeof(MemberwiseEqualityIgnoreAttribute), true).Any();
+ }
+
+ public class EqualityPropertySource
+ {
+ public static IEnumerable TestCases
+ {
+ get
+ {
+ foreach (var property in typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite && IsNotMarkedAsIgnore(x)))
+ {
+ yield return new TestCaseData(property).SetName($"{{m}}_{property.Name}");
+ }
+ }
+ }
+ }
+
+ public class IgnoredPropertySource
+ {
+ public static IEnumerable TestCases
+ {
+ get
+ {
+ foreach (var property in typeof(T).GetProperties().Where(x => x.CanRead && x.CanWrite && !IsNotMarkedAsIgnore(x)))
+ {
+ yield return new TestCaseData(property).SetName($"{{m}}_{property.Name}");
+ }
+ }
+ }
+ }
+
+ [Test]
+ public void two_equivalent_artist_metadata_should_be_equal()
+ {
+ var item1 = fixture.Create();
+ var item2 = item1.JsonClone();
+
+ item1.Should().NotBeSameAs(item2);
+ item1.Should().Be(item2);
+ }
+
+ [Test, TestCaseSource(typeof(EqualityPropertySource), "TestCases")]
+ public void two_different_artist_metadata_should_not_be_equal(PropertyInfo prop)
+ {
+ var item1 = fixture.Create();
+ var item2 = item1.JsonClone();
+ var different = fixture.Create();
+
+ // make item2 different in the property under consideration
+ var differentEntry = prop.GetValue(different);
+ prop.SetValue(item2, differentEntry);
+
+ item1.Should().NotBeSameAs(item2);
+ item1.Should().NotBe(item2);
+ }
+
+ [Test]
+ public void metadata_and_db_fields_should_replicate_artist_metadata()
+ {
+ var item1 = fixture.Create();
+ var item2 = fixture.Create();
+
+ item1.Should().NotBe(item2);
+
+ item1.UseMetadataFrom(item2);
+ item1.UseDbFieldsFrom(item2);
+ item1.Should().Be(item2);
+ }
+
+ private Track GivenTrack()
+ {
+ return fixture.Build
diff --git a/src/NzbDrone.Core/MediaCover/MediaCover.cs b/src/NzbDrone.Core/MediaCover/MediaCover.cs
index bdca37a68..4e5c42b7d 100644
--- a/src/NzbDrone.Core/MediaCover/MediaCover.cs
+++ b/src/NzbDrone.Core/MediaCover/MediaCover.cs
@@ -1,5 +1,6 @@
using System.IO;
using NzbDrone.Common.Extensions;
+using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.MediaCover
@@ -24,7 +25,7 @@ namespace NzbDrone.Core.MediaCover
Album = 1
}
- public class MediaCover : IEmbeddedDocument
+ public class MediaCover : MemberwiseEquatable, IEmbeddedDocument
{
private string _url;
public string Url
diff --git a/src/NzbDrone.Core/Music/Album.cs b/src/NzbDrone.Core/Music/Album.cs
index 6eec0f258..2ece54b34 100644
--- a/src/NzbDrone.Core/Music/Album.cs
+++ b/src/NzbDrone.Core/Music/Album.cs
@@ -1,26 +1,26 @@
using NzbDrone.Common.Extensions;
-using NzbDrone.Core.Datastore;
using System;
using System.Collections.Generic;
using Marr.Data;
+using Equ;
using System.Linq;
-using NzbDrone.Common.Serializer;
namespace NzbDrone.Core.Music
{
- public class Album : ModelBase, IEquatable
+ public class Album : Entity
{
public Album()
{
- Genres = new List();
+ OldForeignAlbumIds = new List();
+
Images = new List();
Links = new List();
+ Genres = new List();
+ SecondaryTypes = new List();
Ratings = new Ratings();
Artist = new Artist();
- OldForeignAlbumIds = new List();
- }
- public const string RELEASE_DATE_FORMAT = "yyyy-MM-dd";
+ }
// These correspond to columns in the Albums table
// These are metadata entries
@@ -45,14 +45,19 @@ namespace NzbDrone.Core.Music
public bool AnyReleaseOk { get; set; }
public DateTime? LastInfoSync { get; set; }
public DateTime Added { get; set; }
+ [MemberwiseEqualityIgnore]
public AddArtistOptions AddOptions { get; set; }
// These are dynamically queried from other tables
+ [MemberwiseEqualityIgnore]
public LazyLoaded ArtistMetadata { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded> AlbumReleases { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded Artist { get; set; }
//compatibility properties with old version of Album
+ [MemberwiseEqualityIgnore]
public int ArtistId { get { return Artist?.Value?.Id ?? 0; } set { Artist.Value.Id = value; } }
public override string ToString()
@@ -60,80 +65,42 @@ namespace NzbDrone.Core.Music
return string.Format("[{0}][{1}]", ForeignAlbumId, Title.NullSafe());
}
- public void ApplyChanges(Album otherAlbum)
+ public override void UseMetadataFrom(Album other)
{
- ForeignAlbumId = otherAlbum.ForeignAlbumId;
- ProfileId = otherAlbum.ProfileId;
- AddOptions = otherAlbum.AddOptions;
- Monitored = otherAlbum.Monitored;
- AnyReleaseOk = otherAlbum.AnyReleaseOk;
+ ForeignAlbumId = other.ForeignAlbumId;
+ OldForeignAlbumIds = other.OldForeignAlbumIds;
+ Title = other.Title;
+ Overview = other.Overview.IsNullOrWhiteSpace() ? Overview : other.Overview;
+ Disambiguation = other.Disambiguation;
+ ReleaseDate = other.ReleaseDate;
+ Images = other.Images.Any() ? other.Images : Images;
+ Links = other.Links;
+ Genres = other.Genres;
+ AlbumType = other.AlbumType;
+ SecondaryTypes = other.SecondaryTypes;
+ Ratings = other.Ratings;
+ CleanTitle = other.CleanTitle;
}
- public bool Equals(Album other)
+ public override void UseDbFieldsFrom(Album other)
{
- if (other == null)
- {
- return false;
- }
-
- if (Id == other.Id &&
- ForeignAlbumId == other.ForeignAlbumId &&
- (OldForeignAlbumIds?.SequenceEqual(other.OldForeignAlbumIds) ?? true) &&
- Title == other.Title &&
- Overview == other.Overview &&
- Disambiguation == other.Disambiguation &&
- ReleaseDate == other.ReleaseDate &&
- Images?.ToJson() == other.Images?.ToJson() &&
- Links?.ToJson() == other.Links?.ToJson() &&
- (Genres?.SequenceEqual(other.Genres) ?? true) &&
- AlbumType == other.AlbumType &&
- (SecondaryTypes?.SequenceEqual(other.SecondaryTypes) ?? true) &&
- Ratings?.ToJson() == other.Ratings?.ToJson())
- {
- return true;
- }
-
- return false;
- }
-
- public override bool Equals(object obj)
- {
- if (obj == null)
- {
- return false;
- }
-
- var other = obj as Album;
- if (other == null)
- {
- return false;
- }
- else
- {
- return Equals(other);
- }
+ Id = other.Id;
+ ArtistMetadataId = other.ArtistMetadataId;
+ ProfileId = other.ProfileId;
+ Monitored = other.Monitored;
+ AnyReleaseOk = other.AnyReleaseOk;
+ LastInfoSync = other.LastInfoSync;
+ Added = other.Added;
+ AddOptions = other.AddOptions;
}
- public override int GetHashCode()
+ public override void ApplyChanges(Album otherAlbum)
{
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + Id;
- hash = hash * 23 + ForeignAlbumId.GetHashCode();
- hash = hash * 23 + OldForeignAlbumIds?.GetHashCode() ?? 0;
- hash = hash * 23 + Title?.GetHashCode() ?? 0;
- hash = hash * 23 + Overview?.GetHashCode() ?? 0;
- hash = hash * 23 + Disambiguation?.GetHashCode() ?? 0;
- hash = hash * 23 + ReleaseDate?.GetHashCode() ?? 0;
- hash = hash * 23 + Images?.GetHashCode() ?? 0;
- hash = hash * 23 + Links?.GetHashCode() ?? 0;
- hash = hash * 23 + Genres?.GetHashCode() ?? 0;
- hash = hash * 23 + AlbumType?.GetHashCode() ?? 0;
- hash = hash * 23 + SecondaryTypes?.GetHashCode() ?? 0;
- hash = hash * 23 + Ratings?.GetHashCode() ?? 0;
- return hash;
- }
+ ForeignAlbumId = otherAlbum.ForeignAlbumId;
+ ProfileId = otherAlbum.ProfileId;
+ AddOptions = otherAlbum.AddOptions;
+ Monitored = otherAlbum.Monitored;
+ AnyReleaseOk = otherAlbum.AnyReleaseOk;
}
}
}
diff --git a/src/NzbDrone.Core/Music/Artist.cs b/src/NzbDrone.Core/Music/Artist.cs
index 75d57df9f..77636b27e 100644
--- a/src/NzbDrone.Core/Music/Artist.cs
+++ b/src/NzbDrone.Core/Music/Artist.cs
@@ -1,16 +1,14 @@
using Marr.Data;
using NzbDrone.Common.Extensions;
-using NzbDrone.Core.Datastore;
using NzbDrone.Core.Profiles.Qualities;
using NzbDrone.Core.Profiles.Metadata;
using System;
using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using Equ;
namespace NzbDrone.Core.Music
{
- public class Artist : ModelBase
+ public class Artist : Entity
{
public Artist()
{
@@ -18,8 +16,8 @@ namespace NzbDrone.Core.Music
Metadata = new ArtistMetadata();
}
+ // These correspond to columns in the Artists table
public int ArtistMetadataId { get; set; }
- public LazyLoaded Metadata { get; set; }
public string CleanName { get; set; }
public string SortName { get; set; }
public bool Monitored { get; set; }
@@ -29,25 +27,62 @@ namespace NzbDrone.Core.Music
public string RootFolderPath { get; set; }
public DateTime Added { get; set; }
public int QualityProfileId { get; set; }
+ public int MetadataProfileId { get; set; }
+ public HashSet Tags { get; set; }
+ [MemberwiseEqualityIgnore]
+ public AddArtistOptions AddOptions { get; set; }
+
+ // Dynamically loaded from DB
+ [MemberwiseEqualityIgnore]
+ public LazyLoaded Metadata { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded QualityProfile { get; set; }
- public int MetadataProfileId { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded MetadataProfile { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded> Albums { get; set; }
- public HashSet Tags { get; set; }
- public AddArtistOptions AddOptions { get; set; }
+
+ //compatibility properties
+ [MemberwiseEqualityIgnore]
+ public string Name { get { return Metadata.Value.Name; } set { Metadata.Value.Name = value; } }
+ [MemberwiseEqualityIgnore]
+ public string ForeignArtistId { get { return Metadata.Value.ForeignArtistId; } set { Metadata.Value.ForeignArtistId = value; } }
public override string ToString()
{
- return string.Format("[{0}][{1}]", Metadata.Value.ForeignArtistId, Metadata.Value.Name.NullSafe());
+ return string.Format("[{0}][{1}]", Metadata.Value.ForeignArtistId.NullSafe(), Metadata.Value.Name.NullSafe());
}
- public void ApplyChanges(Artist otherArtist)
+ public override void UseMetadataFrom(Artist other)
+ {
+ CleanName = other.CleanName;
+ SortName = other.SortName;
+ }
+
+ public override void UseDbFieldsFrom(Artist other)
+ {
+ Id = other.Id;
+ ArtistMetadataId = other.ArtistMetadataId;
+ Monitored = other.Monitored;
+ AlbumFolder = other.AlbumFolder;
+ LastInfoSync = other.LastInfoSync;
+ Path = other.Path;
+ RootFolderPath = other.RootFolderPath;
+ Added = other.Added;
+ QualityProfileId = other.QualityProfileId;
+ MetadataProfileId = other.MetadataProfileId;
+ Tags = other.Tags;
+ AddOptions = other.AddOptions;
+ }
+
+ public override void ApplyChanges(Artist otherArtist)
{
Path = otherArtist.Path;
QualityProfileId = otherArtist.QualityProfileId;
QualityProfile = otherArtist.QualityProfile;
MetadataProfileId = otherArtist.MetadataProfileId;
+ MetadataProfile = otherArtist.MetadataProfile;
Albums = otherArtist.Albums;
Tags = otherArtist.Tags;
@@ -57,10 +92,5 @@ namespace NzbDrone.Core.Music
AlbumFolder = otherArtist.AlbumFolder;
}
-
- //compatibility properties
- public string Name { get { return Metadata.Value.Name; } set { Metadata.Value.Name = value; } }
- public string ForeignArtistId { get { return Metadata.Value.ForeignArtistId; } set { Metadata.Value.ForeignArtistId = value; } }
-
}
}
diff --git a/src/NzbDrone.Core/Music/ArtistMetadata.cs b/src/NzbDrone.Core/Music/ArtistMetadata.cs
index 45732c7c4..bb56bf7c9 100644
--- a/src/NzbDrone.Core/Music/ArtistMetadata.cs
+++ b/src/NzbDrone.Core/Music/ArtistMetadata.cs
@@ -1,13 +1,10 @@
using NzbDrone.Common.Extensions;
-using NzbDrone.Common.Serializer;
-using NzbDrone.Core.Datastore;
-using System;
using System.Collections.Generic;
using System.Linq;
namespace NzbDrone.Core.Music
{
- public class ArtistMetadata : ModelBase, IEquatable
+ public class ArtistMetadata : Entity
{
public ArtistMetadata()
{
@@ -38,90 +35,21 @@ namespace NzbDrone.Core.Music
return string.Format("[{0}][{1}]", ForeignArtistId, Name.NullSafe());
}
- public void ApplyChanges(ArtistMetadata otherArtist)
+ public override void UseMetadataFrom(ArtistMetadata other)
{
- ForeignArtistId = otherArtist.ForeignArtistId;
- OldForeignArtistIds = otherArtist.OldForeignArtistIds;
- Name = otherArtist.Name;
- Aliases = otherArtist.Aliases;
- Overview = otherArtist.Overview.IsNullOrWhiteSpace() ? Overview : otherArtist.Overview;
- Disambiguation = otherArtist.Disambiguation;
- Type = otherArtist.Type;
- Status = otherArtist.Status;
- Images = otherArtist.Images.Any() ? otherArtist.Images : Images;
- Links = otherArtist.Links;
- Genres = otherArtist.Genres;
- Ratings = otherArtist.Ratings;
- Members = otherArtist.Members;
- }
-
- public bool Equals(ArtistMetadata other)
- {
- if (other == null)
- {
- return false;
- }
-
- if (Id == other.Id &&
- ForeignArtistId == other.ForeignArtistId &&
- (OldForeignArtistIds?.SequenceEqual(other.OldForeignArtistIds) ?? true) &&
- Name == other.Name &&
- (Aliases?.SequenceEqual(other.Aliases) ?? true) &&
- Overview == other.Overview &&
- Disambiguation == other.Disambiguation &&
- Type == other.Type &&
- Status == other.Status &&
- Images?.ToJson() == other.Images?.ToJson() &&
- Links?.ToJson() == other.Links?.ToJson() &&
- (Genres?.SequenceEqual(other.Genres) ?? true) &&
- Ratings?.ToJson() == other.Ratings?.ToJson() &&
- Members?.ToJson() == other.Members?.ToJson())
- {
- return true;
- }
-
- return false;
- }
-
- public override bool Equals(object obj)
- {
- if (obj == null)
- {
- return false;
- }
-
- var other = obj as ArtistMetadata;
- if (other == null)
- {
- return false;
- }
- else
- {
- return Equals(other);
- }
- }
-
- public override int GetHashCode()
- {
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + Id;
- hash = hash * 23 + ForeignArtistId.GetHashCode();
- hash = hash * 23 + OldForeignArtistIds.GetHashCode();
- hash = hash * 23 + Name?.GetHashCode() ?? 0;
- hash = hash * 23 + Aliases?.GetHashCode() ?? 0;
- hash = hash * 23 + Overview?.GetHashCode() ?? 0;
- hash = hash * 23 + Disambiguation?.GetHashCode() ?? 0;
- hash = hash * 23 + Type?.GetHashCode() ?? 0;
- hash = hash * 23 + (int)Status;
- hash = hash * 23 + Images?.GetHashCode() ?? 0;
- hash = hash * 23 + Links?.GetHashCode() ?? 0;
- hash = hash * 23 + Genres?.GetHashCode() ?? 0;
- hash = hash * 23 + Ratings?.GetHashCode() ?? 0;
- hash = hash * 23 + Members?.GetHashCode() ?? 0;
- return hash;
- }
+ ForeignArtistId = other.ForeignArtistId;
+ OldForeignArtistIds = other.OldForeignArtistIds;
+ Name = other.Name;
+ Aliases = other.Aliases;
+ Overview = other.Overview.IsNullOrWhiteSpace() ? Overview : other.Overview;
+ Disambiguation = other.Disambiguation;
+ Type = other.Type;
+ Status = other.Status;
+ Images = other.Images.Any() ? other.Images : Images;
+ Links = other.Links;
+ Genres = other.Genres;
+ Ratings = other.Ratings;
+ Members = other.Members;
}
}
}
diff --git a/src/NzbDrone.Core/Music/ArtistMetadataRepository.cs b/src/NzbDrone.Core/Music/ArtistMetadataRepository.cs
index 2890f4dee..8ef16f41a 100644
--- a/src/NzbDrone.Core/Music/ArtistMetadataRepository.cs
+++ b/src/NzbDrone.Core/Music/ArtistMetadataRepository.cs
@@ -39,7 +39,7 @@ namespace NzbDrone.Core.Music
var existing = existingMetadata.SingleOrDefault(x => x.ForeignArtistId == meta.ForeignArtistId);
if (existing != null)
{
- meta.Id = existing.Id;
+ meta.UseDbFieldsFrom(existing);
if (!meta.Equals(existing))
{
updateMetadataList.Add(meta);
diff --git a/src/NzbDrone.Core/Music/Entity.cs b/src/NzbDrone.Core/Music/Entity.cs
new file mode 100644
index 000000000..b0dc4d822
--- /dev/null
+++ b/src/NzbDrone.Core/Music/Entity.cs
@@ -0,0 +1,37 @@
+using NzbDrone.Core.Datastore;
+using System;
+using Equ;
+
+namespace NzbDrone.Core.Music
+{
+ public abstract class Entity : ModelBase, IEquatable
+ where T : Entity
+ {
+ private static readonly MemberwiseEqualityComparer _comparer =
+ MemberwiseEqualityComparer.ByProperties;
+
+ public virtual void UseDbFieldsFrom(T other)
+ {
+ Id = other.Id;
+ }
+
+ public virtual void UseMetadataFrom(T other) { }
+
+ public virtual void ApplyChanges(T other) { }
+
+ public bool Equals(T other)
+ {
+ return _comparer.Equals(this as T, other);
+ }
+
+ public override bool Equals(object obj)
+ {
+ return Equals(obj as T);
+ }
+
+ public override int GetHashCode()
+ {
+ return _comparer.GetHashCode(this as T);
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/Music/Links.cs b/src/NzbDrone.Core/Music/Links.cs
index abf47eafc..19df7f5fd 100644
--- a/src/NzbDrone.Core/Music/Links.cs
+++ b/src/NzbDrone.Core/Music/Links.cs
@@ -1,8 +1,9 @@
+using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Music
{
- public class Links : IEmbeddedDocument
+ public class Links : MemberwiseEquatable, IEmbeddedDocument
{
public string Url { get; set; }
public string Name { get; set; }
diff --git a/src/NzbDrone.Core/Music/Medium.cs b/src/NzbDrone.Core/Music/Medium.cs
index 02ada9896..63a9a72c4 100644
--- a/src/NzbDrone.Core/Music/Medium.cs
+++ b/src/NzbDrone.Core/Music/Medium.cs
@@ -1,9 +1,9 @@
-using System.Collections.Generic;
+using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Music
{
- public class Medium : IEmbeddedDocument
+ public class Medium : MemberwiseEquatable, IEmbeddedDocument
{
public int Number { get; set; }
public string Name { get; set; }
diff --git a/src/NzbDrone.Core/Music/Member.cs b/src/NzbDrone.Core/Music/Member.cs
index e948c9936..34f3bcbc2 100644
--- a/src/NzbDrone.Core/Music/Member.cs
+++ b/src/NzbDrone.Core/Music/Member.cs
@@ -1,9 +1,10 @@
using System.Collections.Generic;
+using Equ;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Music
{
- public class Member : IEmbeddedDocument
+ public class Member : MemberwiseEquatable, IEmbeddedDocument
{
public Member()
{
diff --git a/src/NzbDrone.Core/Music/Ratings.cs b/src/NzbDrone.Core/Music/Ratings.cs
index 530e5a168..ae3a0526a 100644
--- a/src/NzbDrone.Core/Music/Ratings.cs
+++ b/src/NzbDrone.Core/Music/Ratings.cs
@@ -1,8 +1,9 @@
-using NzbDrone.Core.Datastore;
+using Equ;
+using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.Music
{
- public class Ratings : IEmbeddedDocument
+ public class Ratings : MemberwiseEquatable, IEmbeddedDocument
{
public int Votes { get; set; }
public decimal Value { get; set; }
diff --git a/src/NzbDrone.Core/Music/RefreshAlbumReleaseService.cs b/src/NzbDrone.Core/Music/RefreshAlbumReleaseService.cs
index ce96500c1..ef8cec763 100644
--- a/src/NzbDrone.Core/Music/RefreshAlbumReleaseService.cs
+++ b/src/NzbDrone.Core/Music/RefreshAlbumReleaseService.cs
@@ -54,18 +54,9 @@ namespace NzbDrone.Core.Music
{
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;
-
+
+ local.UseMetadataFrom(remote);
+
return UpdateResult.UpdateTags;
}
diff --git a/src/NzbDrone.Core/Music/RefreshAlbumService.cs b/src/NzbDrone.Core/Music/RefreshAlbumService.cs
index bcc214d45..8aa740d07 100644
--- a/src/NzbDrone.Core/Music/RefreshAlbumService.cs
+++ b/src/NzbDrone.Core/Music/RefreshAlbumService.cs
@@ -120,7 +120,8 @@ namespace NzbDrone.Core.Music
QualityProfileId = oldArtist.QualityProfileId,
RootFolderPath = oldArtist.RootFolderPath,
Monitored = oldArtist.Monitored,
- AlbumFolder = oldArtist.AlbumFolder
+ AlbumFolder = oldArtist.AlbumFolder,
+ Tags = oldArtist.Tags
};
_logger.Debug($"Adding missing parent artist {addArtist}");
_addArtistService.AddArtist(addArtist);
@@ -162,27 +163,16 @@ namespace NzbDrone.Core.Music
}
// Force update and fetch covers if images have changed so that we can write them into tags
- if (remote.Images.Any() && !local.Images.Select(x => x.Url).SequenceEqual(remote.Images.Select(x => x.Url)))
+ if (remote.Images.Any() && !local.Images.SequenceEqual(remote.Images))
{
_mediaCoverService.EnsureAlbumCovers(remote);
result = UpdateResult.UpdateTags;
}
-
+
+ local.UseMetadataFrom(remote);
+
local.ArtistMetadataId = remote.ArtistMetadata.Value.Id;
- local.ForeignAlbumId = remote.ForeignAlbumId;
- local.OldForeignAlbumIds = remote.OldForeignAlbumIds;
local.LastInfoSync = DateTime.UtcNow;
- local.CleanTitle = remote.CleanTitle;
- local.Title = remote.Title ?? "Unknown";
- local.Overview = remote.Overview.IsNullOrWhiteSpace() ? local.Overview : remote.Overview;
- local.Disambiguation = remote.Disambiguation;
- local.AlbumType = remote.AlbumType;
- local.SecondaryTypes = remote.SecondaryTypes;
- local.Genres = remote.Genres;
- local.Images = remote.Images.Any() ? remote.Images : local.Images;
- local.Links = remote.Links;
- local.ReleaseDate = remote.ReleaseDate;
- local.Ratings = remote.Ratings;
local.AlbumReleases = new List();
return result;
@@ -274,10 +264,8 @@ namespace NzbDrone.Core.Music
{
local.AlbumId = entity.Id;
local.Album = entity;
- remote.Id = local.Id;
- remote.Album = entity;
- remote.AlbumId = entity.Id;
- remote.Monitored = local.Monitored;
+
+ remote.UseDbFieldsFrom(local);
}
protected override void AddChildren(List children)
diff --git a/src/NzbDrone.Core/Music/RefreshArtistService.cs b/src/NzbDrone.Core/Music/RefreshArtistService.cs
index 154162aec..5d3dd2fda 100644
--- a/src/NzbDrone.Core/Music/RefreshArtistService.cs
+++ b/src/NzbDrone.Core/Music/RefreshArtistService.cs
@@ -103,8 +103,8 @@ namespace NzbDrone.Core.Music
result = UpdateResult.UpdateTags;
}
- local.CleanName = remote.CleanName;
- local.SortName = remote.SortName;
+ local.UseMetadataFrom(remote);
+ local.Metadata = remote.Metadata;
local.LastInfoSync = DateTime.UtcNow;
try
diff --git a/src/NzbDrone.Core/Music/RefreshEntityServiceBase.cs b/src/NzbDrone.Core/Music/RefreshEntityServiceBase.cs
index b802bc3bf..574f9140c 100644
--- a/src/NzbDrone.Core/Music/RefreshEntityServiceBase.cs
+++ b/src/NzbDrone.Core/Music/RefreshEntityServiceBase.cs
@@ -259,7 +259,7 @@ namespace NzbDrone.Core.Music
// note the children that will be merged into remoteChild (once added)
foreach (var child in mergedChildren)
{
- sortedChildren.Merged.Add(Tuple.Create(child, existingChild));
+ sortedChildren.Merged.Add(Tuple.Create(child, remoteChild));
sortedChildren.Deleted.Remove(child);
}
diff --git a/src/NzbDrone.Core/Music/RefreshTrackService.cs b/src/NzbDrone.Core/Music/RefreshTrackService.cs
index 5e3a3b5b4..cb4ad38f8 100644
--- a/src/NzbDrone.Core/Music/RefreshTrackService.cs
+++ b/src/NzbDrone.Core/Music/RefreshTrackService.cs
@@ -31,13 +31,11 @@ namespace NzbDrone.Core.Music
var updateList = new List();
// for tracks that need updating, just grab the remote track and set db ids
- foreach (var trackToUpdate in update)
+ foreach (var track in update)
{
- var track = remoteTracks.Single(e => e.ForeignTrackId == trackToUpdate.ForeignTrackId);
+ var remoteTrack = remoteTracks.Single(e => e.ForeignTrackId == track.ForeignTrackId);
+ track.UseMetadataFrom(remoteTrack);
- // copy across the db keys to the remote track and check if we need to update
- track.Id = trackToUpdate.Id;
- track.TrackFileId = trackToUpdate.TrackFileId;
// make sure title is not null
track.Title = track.Title ?? "Unknown";
updateList.Add(track);
@@ -60,6 +58,9 @@ namespace NzbDrone.Core.Music
}
}
+ _trackService.DeleteMany(delete.Concat(merge.Select(x => x.Item1)).ToList());
+ _trackService.UpdateMany(updateList);
+
var tagsToUpdate = updateList;
if (forceUpdateFileTags)
{
@@ -67,9 +68,6 @@ namespace NzbDrone.Core.Music
tagsToUpdate = updateList.Concat(upToDate).ToList();
}
_audioTagService.SyncTags(tagsToUpdate);
-
- _trackService.DeleteMany(delete.Concat(merge.Select(x => x.Item1)).ToList());
- _trackService.UpdateMany(updateList);
return delete.Any() || updateList.Any() || merge.Any();
}
diff --git a/src/NzbDrone.Core/Music/Release.cs b/src/NzbDrone.Core/Music/Release.cs
index 54ece47f6..2ad6936af 100644
--- a/src/NzbDrone.Core/Music/Release.cs
+++ b/src/NzbDrone.Core/Music/Release.cs
@@ -1,18 +1,19 @@
using NzbDrone.Common.Extensions;
-using NzbDrone.Core.Datastore;
using System;
using System.Collections.Generic;
-using System.Linq;
using Marr.Data;
-using NzbDrone.Common.Serializer;
+using Equ;
namespace NzbDrone.Core.Music
{
- public class AlbumRelease : ModelBase, IEquatable
+ public class AlbumRelease : Entity
{
public AlbumRelease()
{
OldForeignReleaseIds = new List();
+ Label = new List();
+ Country = new List();
+ Media = new List();
}
// These correspond to columns in the AlbumReleases table
@@ -31,7 +32,9 @@ namespace NzbDrone.Core.Music
public bool Monitored { get; set; }
// These are dynamically queried from other tables
+ [MemberwiseEqualityIgnore]
public LazyLoaded Album { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded> Tracks { get; set; }
public override string ToString()
@@ -39,73 +42,27 @@ namespace NzbDrone.Core.Music
return string.Format("[{0}][{1}]", ForeignReleaseId, Title.NullSafe());
}
- public bool Equals (AlbumRelease other)
+ public override void UseMetadataFrom(AlbumRelease other)
{
- if (other == null)
- {
- return false;
- }
-
- if (Id == other.Id &&
- AlbumId == other.AlbumId &&
- ForeignReleaseId == other.ForeignReleaseId &&
- (OldForeignReleaseIds?.SequenceEqual(other.OldForeignReleaseIds) ?? true) &&
- Title == other.Title &&
- Status == other.Status &&
- Duration == other.Duration &&
- (Label?.SequenceEqual(other.Label) ?? true) &&
- Disambiguation == other.Disambiguation &&
- (Country?.SequenceEqual(other.Country) ?? true) &&
- ReleaseDate == other.ReleaseDate &&
- ((Media == null && other.Media == null) || (Media?.ToJson() == other.Media?.ToJson())) &&
- TrackCount == other.TrackCount &&
- Monitored == other.Monitored)
- {
- return true;
- }
-
- return false;
- }
-
- public override bool Equals(object obj)
- {
- if (obj == null)
- {
- return false;
- }
-
- var other = obj as AlbumRelease;
- if (other == null)
- {
- return false;
- }
- else
- {
- return Equals(other);
- }
+ ForeignReleaseId = other.ForeignReleaseId;
+ OldForeignReleaseIds = other.OldForeignReleaseIds;
+ Title = other.Title;
+ Status = other.Status;
+ Duration = other.Duration;
+ Label = other.Label;
+ Disambiguation = other.Disambiguation;
+ Country = other.Country;
+ ReleaseDate = other.ReleaseDate;
+ Media = other.Media;
+ TrackCount = other.TrackCount;
}
- public override int GetHashCode()
+ public override void UseDbFieldsFrom(AlbumRelease other)
{
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + Id;
- hash = hash * 23 + AlbumId;
- hash = hash * 23 + ForeignReleaseId.GetHashCode();
- hash = hash * 23 + OldForeignReleaseIds?.GetHashCode() ?? 0;
- hash = hash * 23 + Title?.GetHashCode() ?? 0;
- hash = hash * 23 + Status?.GetHashCode() ?? 0;
- hash = hash * 23 + Duration;
- hash = hash * 23 + Label?.GetHashCode() ?? 0;
- hash = hash * 23 + Disambiguation?.GetHashCode() ?? 0;
- hash = hash * 23 + Country?.GetHashCode() ?? 0;
- hash = hash * 23 + ReleaseDate.GetHashCode();
- hash = hash * 23 + Media?.GetHashCode() ?? 0;
- hash = hash * 23 + TrackCount;
- hash = hash * 23 + Monitored.GetHashCode();
- return hash;
- }
+ Id = other.Id;
+ AlbumId = other.AlbumId;
+ Album = other.Album;
+ Monitored = other.Monitored;
}
}
}
diff --git a/src/NzbDrone.Core/Music/Track.cs b/src/NzbDrone.Core/Music/Track.cs
index d0a1bae23..ceaabc3d9 100644
--- a/src/NzbDrone.Core/Music/Track.cs
+++ b/src/NzbDrone.Core/Music/Track.cs
@@ -1,20 +1,18 @@
-using NzbDrone.Core.Datastore;
using NzbDrone.Core.MediaFiles;
using Marr.Data;
using NzbDrone.Common.Extensions;
-using System;
-using NzbDrone.Common.Serializer;
using System.Collections.Generic;
-using System.Linq;
+using Equ;
namespace NzbDrone.Core.Music
{
- public class Track : ModelBase, IEquatable
+ public class Track : Entity
{
public Track()
{
OldForeignTrackIds = new List();
OldForeignRecordingIds = new List();
+ Ratings = new Ratings();
}
// These are model fields
@@ -32,17 +30,25 @@ namespace NzbDrone.Core.Music
public Ratings Ratings { get; set; }
public int MediumNumber { get; set; }
public int TrackFileId { get; set; }
+
+ [MemberwiseEqualityIgnore]
public bool HasFile => TrackFileId > 0;
// These are dynamically queried from the DB
+ [MemberwiseEqualityIgnore]
public LazyLoaded AlbumRelease { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded ArtistMetadata { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded TrackFile { get; set; }
+ [MemberwiseEqualityIgnore]
public LazyLoaded Artist { get; set; }
// These are retained for compatibility
// TODO: Remove set, bodged in because tests expect this to be writable
+ [MemberwiseEqualityIgnore]
public int AlbumId { get { return AlbumRelease?.Value?.Album?.Value?.Id ?? 0; } set { /* empty */ } }
+ [MemberwiseEqualityIgnore]
public Album Album { get; set; }
public override string ToString()
@@ -50,75 +56,27 @@ namespace NzbDrone.Core.Music
return string.Format("[{0}]{1}", ForeignTrackId, Title.NullSafe());
}
- public bool Equals(Track other)
+ public override void UseMetadataFrom(Track other)
{
- if (other == null)
- {
- return false;
- }
-
- if (Id == other.Id &&
- ForeignTrackId == other.ForeignTrackId &&
- (OldForeignTrackIds?.SequenceEqual(other.OldForeignTrackIds) ?? true) &&
- ForeignRecordingId == other.ForeignRecordingId &&
- (OldForeignRecordingIds?.SequenceEqual(other.OldForeignRecordingIds) ?? true) &&
- AlbumReleaseId == other.AlbumReleaseId &&
- ArtistMetadataId == other.ArtistMetadataId &&
- TrackNumber == other.TrackNumber &&
- AbsoluteTrackNumber == other.AbsoluteTrackNumber &&
- Title == other.Title &&
- Duration == other.Duration &&
- Explicit == other.Explicit &&
- Ratings?.ToJson() == other.Ratings?.ToJson() &&
- MediumNumber == other.MediumNumber &&
- TrackFileId == other.TrackFileId)
- {
- return true;
- }
-
- return false;
- }
-
- public override bool Equals(object obj)
- {
- if (obj == null)
- {
- return false;
- }
-
- var other = obj as Track;
- if (other == null)
- {
- return false;
- }
- else
- {
- return Equals(other);
- }
+ ForeignTrackId = other.ForeignTrackId;
+ OldForeignTrackIds = other.OldForeignTrackIds;
+ ForeignRecordingId = other.ForeignRecordingId;
+ OldForeignRecordingIds = other.OldForeignRecordingIds;
+ TrackNumber = other.TrackNumber;
+ AbsoluteTrackNumber = other.AbsoluteTrackNumber;
+ Title = other.Title;
+ Duration = other.Duration;
+ Explicit = other.Explicit;
+ Ratings = other.Ratings;
+ MediumNumber = other.MediumNumber;
}
- public override int GetHashCode()
+ public override void UseDbFieldsFrom(Track other)
{
- unchecked
- {
- int hash = 17;
- hash = hash * 23 + Id;
- hash = hash * 23 + ForeignTrackId.GetHashCode();
- hash = hash * 23 + OldForeignTrackIds?.GetHashCode() ?? 0;
- hash = hash * 23 + ForeignRecordingId.GetHashCode();
- hash = hash * 23 + OldForeignRecordingIds?.GetHashCode() ?? 0;
- hash = hash * 23 + AlbumReleaseId;
- hash = hash * 23 + ArtistMetadataId;
- hash = hash * 23 + TrackNumber?.GetHashCode() ?? 0;
- hash = hash * 23 + AbsoluteTrackNumber;
- hash = hash * 23 + Title?.GetHashCode() ?? 0;
- hash = hash * 23 + Duration;
- hash = hash * 23 + Explicit.GetHashCode();
- hash = hash * 23 + Ratings?.GetHashCode() ?? 0;
- hash = hash * 23 + MediumNumber;
- hash = hash * 23 + TrackFileId;
- return hash;
- }
+ Id = other.Id;
+ AlbumReleaseId = other.AlbumReleaseId;
+ ArtistMetadataId = other.ArtistMetadataId;
+ TrackFileId = other.TrackFileId;
}
}
}