2017-09-23 04:30:52 +00:00
|
|
|
using NLog;
|
2017-04-28 22:05:35 +00:00
|
|
|
using NzbDrone.Core.Messaging.Events;
|
2017-04-30 21:54:01 +00:00
|
|
|
using NzbDrone.Core.Music.Events;
|
2017-04-28 22:05:35 +00:00
|
|
|
using NzbDrone.Core.Organizer;
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2017-04-30 21:54:01 +00:00
|
|
|
using NzbDrone.Core.Parser;
|
2017-04-28 22:05:35 +00:00
|
|
|
using System.Text;
|
2017-04-30 21:54:01 +00:00
|
|
|
using System.IO;
|
|
|
|
using NzbDrone.Common.Extensions;
|
2017-04-28 22:05:35 +00:00
|
|
|
|
|
|
|
namespace NzbDrone.Core.Music
|
|
|
|
{
|
|
|
|
public interface IArtistService
|
|
|
|
{
|
|
|
|
Artist GetArtist(int artistId);
|
2018-12-15 00:02:43 +00:00
|
|
|
Artist GetArtistByMetadataId(int artistMetadataId);
|
2017-04-28 22:05:35 +00:00
|
|
|
List<Artist> GetArtists(IEnumerable<int> artistIds);
|
|
|
|
Artist AddArtist(Artist newArtist);
|
2017-12-30 06:09:10 +00:00
|
|
|
List<Artist> AddArtists(List<Artist> newArtists);
|
2017-05-07 19:32:13 +00:00
|
|
|
Artist FindById(string spotifyId);
|
2017-04-30 21:54:01 +00:00
|
|
|
Artist FindByName(string title);
|
2018-11-16 17:46:46 +00:00
|
|
|
Artist FindByNameInexact(string title);
|
2017-04-28 22:05:35 +00:00
|
|
|
void DeleteArtist(int artistId, bool deleteFiles);
|
|
|
|
List<Artist> GetAllArtists();
|
2017-09-23 04:30:52 +00:00
|
|
|
List<Artist> AllForTag(int tagId);
|
2017-04-28 22:05:35 +00:00
|
|
|
Artist UpdateArtist(Artist artist);
|
2018-08-08 00:57:15 +00:00
|
|
|
List<Artist> UpdateArtists(List<Artist> artist, bool useExistingRelativeFolder);
|
2017-04-28 22:05:35 +00:00
|
|
|
bool ArtistPathExists(string folder);
|
|
|
|
void RemoveAddOptions(Artist artist);
|
|
|
|
}
|
|
|
|
|
|
|
|
public class ArtistService : IArtistService
|
|
|
|
{
|
|
|
|
private readonly IArtistRepository _artistRepository;
|
2018-12-15 00:02:43 +00:00
|
|
|
private readonly IArtistMetadataRepository _artistMetadataRepository;
|
2017-04-28 22:05:35 +00:00
|
|
|
private readonly IEventAggregator _eventAggregator;
|
|
|
|
private readonly ITrackService _trackService;
|
2018-08-08 00:57:15 +00:00
|
|
|
private readonly IBuildArtistPaths _artistPathBuilder;
|
2017-04-28 22:05:35 +00:00
|
|
|
private readonly Logger _logger;
|
|
|
|
|
2017-04-30 21:54:01 +00:00
|
|
|
public ArtistService(IArtistRepository artistRepository,
|
2018-12-15 00:02:43 +00:00
|
|
|
IArtistMetadataRepository artistMetadataRepository,
|
|
|
|
IEventAggregator eventAggregator,
|
|
|
|
ITrackService trackService,
|
|
|
|
IBuildArtistPaths artistPathBuilder,
|
|
|
|
Logger logger)
|
2017-04-30 21:54:01 +00:00
|
|
|
{
|
|
|
|
_artistRepository = artistRepository;
|
2018-12-15 00:02:43 +00:00
|
|
|
_artistMetadataRepository = artistMetadataRepository;
|
2017-04-30 21:54:01 +00:00
|
|
|
_eventAggregator = eventAggregator;
|
|
|
|
_trackService = trackService;
|
2018-08-08 00:57:15 +00:00
|
|
|
_artistPathBuilder = artistPathBuilder;
|
2017-04-30 21:54:01 +00:00
|
|
|
_logger = logger;
|
|
|
|
}
|
|
|
|
|
2017-04-28 22:05:35 +00:00
|
|
|
public Artist AddArtist(Artist newArtist)
|
|
|
|
{
|
2018-12-15 00:02:43 +00:00
|
|
|
_artistMetadataRepository.Upsert(newArtist);
|
2017-04-30 21:54:01 +00:00
|
|
|
_artistRepository.Insert(newArtist);
|
|
|
|
_eventAggregator.PublishEvent(new ArtistAddedEvent(GetArtist(newArtist.Id)));
|
|
|
|
|
|
|
|
return newArtist;
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2017-12-30 06:09:10 +00:00
|
|
|
public List<Artist> AddArtists(List<Artist> newArtists)
|
|
|
|
{
|
2018-12-15 00:02:43 +00:00
|
|
|
_artistMetadataRepository.UpsertMany(newArtists);
|
2017-12-30 06:09:10 +00:00
|
|
|
_artistRepository.InsertMany(newArtists);
|
|
|
|
_eventAggregator.PublishEvent(new ArtistsImportedEvent(newArtists.Select(s => s.Id).ToList()));
|
|
|
|
|
|
|
|
return newArtists;
|
|
|
|
}
|
|
|
|
|
2017-04-28 22:05:35 +00:00
|
|
|
public bool ArtistPathExists(string folder)
|
|
|
|
{
|
2017-04-30 21:54:01 +00:00
|
|
|
return _artistRepository.ArtistPathExists(folder);
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void DeleteArtist(int artistId, bool deleteFiles)
|
|
|
|
{
|
2017-04-30 21:54:01 +00:00
|
|
|
var artist = _artistRepository.Get(artistId);
|
|
|
|
_artistRepository.Delete(artistId);
|
|
|
|
_eventAggregator.PublishEvent(new ArtistDeletedEvent(artist, deleteFiles));
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2017-05-07 19:32:13 +00:00
|
|
|
public Artist FindById(string spotifyId)
|
2017-04-28 22:05:35 +00:00
|
|
|
{
|
2017-05-07 19:32:13 +00:00
|
|
|
return _artistRepository.FindById(spotifyId);
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2017-04-30 21:54:01 +00:00
|
|
|
public Artist FindByName(string title)
|
2017-04-28 22:05:35 +00:00
|
|
|
{
|
2017-10-08 20:07:54 +00:00
|
|
|
return _artistRepository.FindByName(title.CleanArtistName());
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2018-11-16 17:46:46 +00:00
|
|
|
public Artist FindByNameInexact(string title)
|
2017-04-28 22:05:35 +00:00
|
|
|
{
|
2018-11-16 17:46:46 +00:00
|
|
|
const double fuzzThreshold = 0.8;
|
|
|
|
const double fuzzGap = 0.2;
|
|
|
|
var cleanTitle = Parser.Parser.CleanArtistName(title);
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(cleanTitle))
|
|
|
|
{
|
|
|
|
cleanTitle = title;
|
|
|
|
}
|
|
|
|
|
|
|
|
var sortedArtists = GetAllArtists()
|
|
|
|
.Select(s => new
|
|
|
|
{
|
|
|
|
MatchProb = s.CleanName.FuzzyMatch(cleanTitle),
|
|
|
|
Artist = s
|
|
|
|
})
|
|
|
|
.ToList()
|
|
|
|
.OrderByDescending(s => s.MatchProb)
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
if (!sortedArtists.Any())
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
_logger.Trace("\nFuzzy artist match on '{0}':\n{1}",
|
|
|
|
cleanTitle,
|
|
|
|
string.Join("\n", sortedArtists.Select(x => $"{x.Artist.CleanName}: {x.MatchProb}")));
|
|
|
|
|
|
|
|
if (sortedArtists[0].MatchProb > fuzzThreshold
|
|
|
|
&& (sortedArtists.Count == 1 || sortedArtists[0].MatchProb - sortedArtists[1].MatchProb > fuzzGap))
|
|
|
|
{
|
|
|
|
return sortedArtists[0].Artist;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public List<Artist> GetAllArtists()
|
|
|
|
{
|
2017-05-04 13:00:19 +00:00
|
|
|
return _artistRepository.All().ToList();
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2017-09-23 04:30:52 +00:00
|
|
|
public List<Artist> AllForTag(int tagId)
|
|
|
|
{
|
|
|
|
return GetAllArtists().Where(s => s.Tags.Contains(tagId))
|
|
|
|
.ToList();
|
|
|
|
}
|
|
|
|
|
2017-05-11 18:43:05 +00:00
|
|
|
public Artist GetArtist(int artistDBId)
|
2017-04-28 22:05:35 +00:00
|
|
|
{
|
2017-05-11 18:43:05 +00:00
|
|
|
return _artistRepository.Get(artistDBId);
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2018-12-15 00:02:43 +00:00
|
|
|
public Artist GetArtistByMetadataId(int artistMetadataId)
|
|
|
|
{
|
|
|
|
return _artistRepository.GetArtistByMetadataId(artistMetadataId);
|
|
|
|
}
|
|
|
|
|
2017-04-28 22:05:35 +00:00
|
|
|
public List<Artist> GetArtists(IEnumerable<int> artistIds)
|
|
|
|
{
|
2017-04-30 21:54:01 +00:00
|
|
|
return _artistRepository.Get(artistIds).ToList();
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void RemoveAddOptions(Artist artist)
|
|
|
|
{
|
2017-04-30 21:54:01 +00:00
|
|
|
_artistRepository.SetFields(artist, s => s.AddOptions);
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public Artist UpdateArtist(Artist artist)
|
|
|
|
{
|
2018-12-15 00:02:43 +00:00
|
|
|
var storedArtist = GetArtist(artist.Id); // Is it Id or iTunesId?
|
|
|
|
var updatedArtist = _artistMetadataRepository.Update(artist);
|
|
|
|
updatedArtist = _artistRepository.Update(updatedArtist);
|
2017-04-30 21:54:01 +00:00
|
|
|
_eventAggregator.PublishEvent(new ArtistEditedEvent(updatedArtist, storedArtist));
|
|
|
|
|
|
|
|
return updatedArtist;
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
|
2018-08-08 00:57:15 +00:00
|
|
|
public List<Artist> UpdateArtists(List<Artist> artist, bool useExistingRelativeFolder)
|
2017-04-28 22:05:35 +00:00
|
|
|
{
|
2017-04-30 21:54:01 +00:00
|
|
|
_logger.Debug("Updating {0} artist", artist.Count);
|
2018-08-08 00:57:15 +00:00
|
|
|
|
2017-04-30 21:54:01 +00:00
|
|
|
foreach (var s in artist)
|
|
|
|
{
|
2017-06-13 02:02:17 +00:00
|
|
|
_logger.Trace("Updating: {0}", s.Name);
|
2018-08-08 00:57:15 +00:00
|
|
|
|
2017-04-30 21:54:01 +00:00
|
|
|
if (!s.RootFolderPath.IsNullOrWhiteSpace())
|
|
|
|
{
|
2018-08-08 00:57:15 +00:00
|
|
|
s.Path = _artistPathBuilder.BuildPath(s, useExistingRelativeFolder);
|
2017-12-30 03:23:04 +00:00
|
|
|
|
2018-08-08 00:57:15 +00:00
|
|
|
//s.Path = Path.Combine(s.RootFolderPath, _fileNameBuilder.GetArtistFolder(s));
|
2017-12-30 03:23:04 +00:00
|
|
|
|
2017-06-13 02:02:17 +00:00
|
|
|
_logger.Trace("Changing path for {0} to {1}", s.Name, s.Path);
|
2017-04-30 21:54:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-06-13 02:02:17 +00:00
|
|
|
_logger.Trace("Not changing path for: {0}", s.Name);
|
2017-04-30 21:54:01 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-15 00:02:43 +00:00
|
|
|
_artistMetadataRepository.UpdateMany(artist);
|
2017-04-30 21:54:01 +00:00
|
|
|
_artistRepository.UpdateMany(artist);
|
|
|
|
_logger.Debug("{0} artists updated", artist.Count);
|
|
|
|
|
|
|
|
return artist;
|
2017-04-28 22:05:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|