Implemented similar artists and fixed bug with deleting associated.

This commit is contained in:
Steven Hildreth 2019-07-01 18:11:10 -05:00
parent 1402cfbb72
commit 7295095460
11 changed files with 154 additions and 8 deletions

View file

@ -25,8 +25,8 @@ namespace Roadie.Library.Tests
Assert.True(secondHash > 0);
Assert.Equal(hash, secondHash);
var similiar = ImageHasher.Similarity(imageFilename, secondImagFilename);
Assert.Equal(100d, similiar);
var similar = ImageHasher.Similarity(imageFilename, secondImagFilename);
Assert.Equal(100d, similar);
Assert.True(ImageHasher.ImagesAreSame(imageFilename, secondImagFilename));

View file

@ -19,6 +19,9 @@ namespace Roadie.Library.Data
[InverseProperty("Artist")]
public ICollection<ArtistAssociation> AssociatedArtists { get; set; }
[InverseProperty("Artist")]
public ICollection<ArtistSimilar> SimilarArtists { get; set; }
[Column("bandStatus", TypeName = "enum")]
public BandStatus? BandStatus { get; set; }
@ -89,6 +92,7 @@ namespace Roadie.Library.Data
this.Releases = new HashSet<Release>();
this.Genres = new HashSet<ArtistGenre>();
this.AssociatedArtists = new HashSet<ArtistAssociation>();
this.SimilarArtists = new HashSet<ArtistSimilar>();
this.Comments = new HashSet<Comment>();
this.Rating = 0;
this.Status = Statuses.Ok;

View file

@ -0,0 +1,27 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Roadie.Library.Data
{
[Table("artistSimilar")]
public partial class ArtistSimilar
{
//[ForeignKey("artistId")]
public Artist Artist { get; set; }
[Column("artistId")]
[Required]
public int ArtistId { get; set; }
//[ForeignKey("associatedArtistId")]
public Artist SimilarArtist { get; set; }
[Column("similarArtistId")]
public int SimilarArtistId { get; set; }
[Key]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
}
}

View file

@ -13,6 +13,7 @@ namespace Roadie.Library.Data
public interface IRoadieDbContext : IDisposable, IInfrastructure<IServiceProvider>, IDbContextDependencies, IDbSetCache, IDbQueryCache, IDbContextPoolable
{
DbSet<ArtistAssociation> ArtistAssociations { get; set; }
DbSet<ArtistSimilar> ArtistSimilar { get; set; }
DbSet<ArtistGenre> ArtistGenres { get; set; }
DbSet<Artist> Artists { get; set; }
DbSet<Bookmark> Bookmarks { get; set; }

View file

@ -8,6 +8,7 @@ namespace Roadie.Library.Data
public class RoadieDbContext : DbContext, IRoadieDbContext
{
public DbSet<ArtistAssociation> ArtistAssociations { get; set; }
public DbSet<ArtistSimilar> ArtistSimilar { get; set; }
public DbSet<ArtistGenre> ArtistGenres { get; set; }
public DbSet<Artist> Artists { get; set; }
public DbSet<Bookmark> Bookmarks { get; set; }

View file

@ -375,6 +375,7 @@ namespace Roadie.Library.Factories
var artistGenreTables = Artist.Genres.Select(x => new ArtistGenre { ArtistId = Artist.Id, GenreId = x.GenreId }).ToList();
var artistAssociatedWith = Artist.AssociatedArtists.Select(x => new ArtistAssociation { ArtistId = Artist.Id, AssociatedArtistId = x.AssociatedArtistId }).ToList();
var similarArtists = Artist.SimilarArtists.Select(x => new ArtistSimilar { ArtistId = Artist.Id, SimilarArtistId = x.SimilarArtistId }).ToList();
var result = true;
var now = DateTime.UtcNow;
@ -393,6 +394,7 @@ namespace Roadie.Library.Factories
where at.ArtistId == Artist.Id
select at));
Artist.AssociatedArtists = artistAssociatedWith;
Artist.SimilarArtists = similarArtists;
await this.DbContext.SaveChangesAsync();
var existingImageIds = (from ai in ArtistImages

View file

@ -15,7 +15,7 @@ namespace Roadie.Library.Models
[Serializable]
public class Artist : EntityModelBase
{
public const string DefaultIncludes = "stats,images,associatedartists,comments,collections,playlists,contributions,labels";
public const string DefaultIncludes = "stats,images,associatedartists,similarartists,comments,collections,playlists,contributions,labels";
public IEnumerable<ReleaseList> ArtistContributionReleases;
public IEnumerable<LabelList> ArtistLabels;
@ -29,6 +29,10 @@ namespace Roadie.Library.Models
public IEnumerable<DataToken> AssociatedArtistsTokens { get; set; }
public IEnumerable<ArtistList> SimilarArtists { get; set; }
public IEnumerable<DataToken> SimilarArtistsTokens { get; set; }
public string BandStatus { get; set; }
[MaxLength(65535)]

View file

@ -667,8 +667,8 @@ namespace Roadie.Api.Services
{
CollectionId = collection.Id,
Position = csvRelease.Position,
Artist = csvRelease.Artist,
Release = searchName
Artist = searchName,
Release = csvRelease.Release.NormalizeName()
});
continue;
}

View file

@ -557,10 +557,48 @@ namespace Roadie.Api.Services
});
}
}
}
else if (model.AssociatedArtistsTokens == null || !model.AssociatedArtistsTokens.Any())
{
artist.AssociatedArtists.Clear();
var associatedArtists = DbContext.ArtistAssociations.Include(x => x.AssociatedArtist).Where(x => x.ArtistId == artist.Id || x.AssociatedArtistId == artist.Id).ToList();
DbContext.ArtistAssociations.RemoveRange(associatedArtists);
}
if(model.SimilarArtistsTokens != null && model.SimilarArtistsTokens.Any())
{
var similarArtists = DbContext.ArtistSimilar.Include(x => x.SimilarArtist)
.Where(x => x.ArtistId == artist.Id).ToList();
// Remove existing AssociatedArtists not in model list
foreach (var similarArtist in similarArtists)
{
var doesExistInModel = model.SimilarArtistsTokens.Any(x =>
SafeParser.ToGuid(x.Value) == similarArtist.SimilarArtist.RoadieId);
if (!doesExistInModel) DbContext.ArtistSimilar.Remove(similarArtist);
}
// Add new SimilarArtists in model not in data
foreach (var similarArtist in model.SimilarArtistsTokens)
{
var similarArtistId = SafeParser.ToGuid(similarArtist.Value);
var doesExistInData = similarArtists.Any(x => x.SimilarArtist.RoadieId == similarArtistId);
if (!doesExistInData)
{
var a = DbContext.Artists.FirstOrDefault(x => x.RoadieId == similarArtistId);
if (a != null)
DbContext.ArtistSimilar.Add(new data.ArtistSimilar
{
ArtistId = artist.Id,
SimilarArtistId = a.Id
});
}
}
}
else if (model.SimilarArtistsTokens == null || !model.SimilarArtistsTokens.Any())
{
var similarArtists = DbContext.ArtistSimilar.Include(x => x.SimilarArtist).Where(x => x.ArtistId == artist.Id || x.SimilarArtistId == artist.Id).ToList();
DbContext.ArtistSimilar.RemoveRange(similarArtists);
}
if (model.Images != null && model.Images.Any())
@ -816,6 +854,63 @@ namespace Roadie.Api.Services
timings.Add("associatedartists", tsw.ElapsedMilliseconds);
}
if (includes.Contains("similarartists"))
{
tsw.Restart();
var similarWithArtists = (from aa in DbContext.ArtistSimilar
join a in DbContext.Artists on aa.SimilarArtistId equals a.Id
where aa.ArtistId == artist.Id
select new ArtistList
{
DatabaseId = a.Id,
Id = a.RoadieId,
Artist = new DataToken
{
Text = a.Name,
Value = a.RoadieId.ToString()
},
Thumbnail = MakeArtistThumbnailImage(a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
PlayedCount = a.PlayedCount,
ReleaseCount = a.ReleaseCount,
TrackCount = a.TrackCount,
SortName = a.SortName
}).ToArray();
var similarArtists = (from aa in DbContext.ArtistSimilar
join a in DbContext.Artists on aa.ArtistId equals a.Id
where aa.SimilarArtistId == artist.Id
select new ArtistList
{
DatabaseId = a.Id,
Id = a.RoadieId,
Artist = new DataToken
{
Text = a.Name,
Value = a.RoadieId.ToString()
},
Thumbnail = MakeArtistThumbnailImage(a.RoadieId),
Rating = a.Rating,
Rank = a.Rank,
CreatedDate = a.CreatedDate,
LastUpdated = a.LastUpdated,
LastPlayed = a.LastPlayed,
PlayedCount = a.PlayedCount,
ReleaseCount = a.ReleaseCount,
TrackCount = a.TrackCount,
SortName = a.SortName
}).ToArray();
result.SimilarArtists = similarWithArtists.Union(similarArtists, new ArtistListComparer())
.OrderBy(x => x.SortName);
result.SimilarArtistsTokens = result.SimilarArtists.Select(x => x.Artist).ToArray();
tsw.Stop();
timings.Add("similarartists", tsw.ElapsedMilliseconds);
}
if (includes.Contains("collections"))
{
tsw.Restart();

View file

@ -1269,7 +1269,7 @@ namespace Roadie.Api.Services
public Task<subsonic.SubsonicOperationResult<subsonic.Response>> GetSimliarSongs(subsonic.Request request,
User roadieUser, subsonic.SimilarSongsVersion version, int? count = 50)
{
// TODO How to determine similiar songs? Perhaps by genre?
// TODO How to determine similar songs? Perhaps by genre?
switch (version)
{

View file

@ -8,4 +8,16 @@ CREATE TABLE `collectionMissing` (
`release` varchar(1000) COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`),
KEY `ix_collection_collectionId` (`collectionId`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Create artistSimilar table for < 1.0.2.0 database
CREATE TABLE `artistSimilar` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`artistId` int(11) NOT NULL,
`similarArtistId` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `similarArtistId` (`similarArtistId`),
KEY `idx_artistSimilar` (`artistId`,`similarArtistId`),
CONSTRAINT `artistSimilar_ibfk_1` FOREIGN KEY (`artistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE,
CONSTRAINT `artistSimilar_ibfk_2` FOREIGN KEY (`similarArtistId`) REFERENCES `artist` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci