|
|
|
@ -15,6 +15,7 @@ using NzbDrone.Core.Music.Events;
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Marr.Data;
|
|
|
|
|
|
|
|
|
|
namespace NzbDrone.Core.Download.Pending
|
|
|
|
|
{
|
|
|
|
@ -69,66 +70,72 @@ namespace NzbDrone.Core.Download.Pending
|
|
|
|
|
|
|
|
|
|
public void Add(DownloadDecision decision, PendingReleaseReason reason)
|
|
|
|
|
{
|
|
|
|
|
var alreadyPending = _repository.AllByArtistId(decision.RemoteAlbum.Artist.Id);
|
|
|
|
|
|
|
|
|
|
alreadyPending = IncludeRemoteAlbums(alreadyPending);
|
|
|
|
|
|
|
|
|
|
Add(alreadyPending, decision, reason);
|
|
|
|
|
AddMany(new List<Tuple<DownloadDecision, PendingReleaseReason>> { Tuple.Create(decision, reason) });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void AddMany(List<Tuple<DownloadDecision, PendingReleaseReason>> decisions)
|
|
|
|
|
{
|
|
|
|
|
var alreadyPending = decisions.Select(v => v.Item1.RemoteAlbum.Artist.Id).Distinct().SelectMany(_repository.AllByArtistId).ToList();
|
|
|
|
|
|
|
|
|
|
alreadyPending = IncludeRemoteAlbums(alreadyPending);
|
|
|
|
|
|
|
|
|
|
foreach (var pair in decisions)
|
|
|
|
|
foreach (var artistDecisions in decisions.GroupBy(v => v.Item1.RemoteAlbum.Artist.Id))
|
|
|
|
|
{
|
|
|
|
|
Add(alreadyPending, pair.Item1, pair.Item2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var artist = artistDecisions.First().Item1.RemoteAlbum.Artist;
|
|
|
|
|
var alreadyPending = _repository.AllByArtistId(artist.Id);
|
|
|
|
|
|
|
|
|
|
private void Add(List<PendingRelease> alreadyPending, DownloadDecision decision, PendingReleaseReason reason)
|
|
|
|
|
{
|
|
|
|
|
var albumIds = decision.RemoteAlbum.Albums.Select(e => e.Id);
|
|
|
|
|
|
|
|
|
|
var existingReports = alreadyPending.Where(r => r.RemoteAlbum.Albums.Select(e => e.Id)
|
|
|
|
|
.Intersect(albumIds)
|
|
|
|
|
.Any());
|
|
|
|
|
alreadyPending = IncludeRemoteAlbums(alreadyPending, artistDecisions.ToDictionaryIgnoreDuplicates(v => v.Item1.RemoteAlbum.Release.Title, v => v.Item1.RemoteAlbum));
|
|
|
|
|
var alreadyPendingByAlbum = CreateAlbumLookup(alreadyPending);
|
|
|
|
|
|
|
|
|
|
var matchingReports = existingReports.Where(MatchingReleasePredicate(decision.RemoteAlbum.Release)).ToList();
|
|
|
|
|
|
|
|
|
|
if (matchingReports.Any())
|
|
|
|
|
{
|
|
|
|
|
var matchingReport = matchingReports.First();
|
|
|
|
|
|
|
|
|
|
if (matchingReport.Reason != reason)
|
|
|
|
|
foreach (var pair in artistDecisions)
|
|
|
|
|
{
|
|
|
|
|
_logger.Debug("The release {0} is already pending with reason {1}, changing to {2}", decision.RemoteAlbum, matchingReport.Reason, reason);
|
|
|
|
|
matchingReport.Reason = reason;
|
|
|
|
|
_repository.Update(matchingReport);
|
|
|
|
|
}
|
|
|
|
|
var decision = pair.Item1;
|
|
|
|
|
var reason = pair.Item2;
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.Debug("The release {0} is already pending with reason {1}, not adding again", decision.RemoteAlbum, reason); return;
|
|
|
|
|
}
|
|
|
|
|
var albumIds = decision.RemoteAlbum.Albums.Select(e => e.Id);
|
|
|
|
|
|
|
|
|
|
if (matchingReports.Count() > 1)
|
|
|
|
|
{
|
|
|
|
|
_logger.Debug("The release {0} had {1} duplicate pending, removing duplicates.", decision.RemoteAlbum, matchingReports.Count() - 1);
|
|
|
|
|
var existingReports = albumIds.SelectMany(v => alreadyPendingByAlbum[v] ?? Enumerable.Empty<PendingRelease>())
|
|
|
|
|
.Distinct().ToList();
|
|
|
|
|
|
|
|
|
|
var matchingReports = existingReports.Where(MatchingReleasePredicate(decision.RemoteAlbum.Release)).ToList();
|
|
|
|
|
|
|
|
|
|
foreach (var duplicate in matchingReports.Skip(1))
|
|
|
|
|
if (matchingReports.Any())
|
|
|
|
|
{
|
|
|
|
|
_repository.Delete(duplicate.Id);
|
|
|
|
|
alreadyPending.Remove(duplicate);
|
|
|
|
|
var matchingReport = matchingReports.First();
|
|
|
|
|
|
|
|
|
|
if (matchingReport.Reason != reason)
|
|
|
|
|
{
|
|
|
|
|
_logger.Debug("The release {0} is already pending with reason {1}, changing to {2}", decision.RemoteAlbum, matchingReport.Reason, reason);
|
|
|
|
|
matchingReport.Reason = reason;
|
|
|
|
|
_repository.Update(matchingReport);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_logger.Debug("The release {0} is already pending with reason {1}, not adding again", decision.RemoteAlbum, reason);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (matchingReports.Count() > 1)
|
|
|
|
|
{
|
|
|
|
|
_logger.Debug("The release {0} had {1} duplicate pending, removing duplicates.", decision.RemoteAlbum, matchingReports.Count() - 1);
|
|
|
|
|
|
|
|
|
|
foreach (var duplicate in matchingReports.Skip(1))
|
|
|
|
|
{
|
|
|
|
|
_repository.Delete(duplicate.Id);
|
|
|
|
|
alreadyPending.Remove(duplicate);
|
|
|
|
|
alreadyPendingByAlbum = CreateAlbumLookup(alreadyPending);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
_logger.Debug("Adding release {0} to pending releases with reason {1}", decision.RemoteAlbum, reason);
|
|
|
|
|
Insert(decision, reason);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_logger.Debug("Adding release {0} to pending releases with reason {1}", decision.RemoteAlbum, reason); Insert(decision, reason);
|
|
|
|
|
private ILookup<int, PendingRelease> CreateAlbumLookup(IEnumerable<PendingRelease> alreadyPending)
|
|
|
|
|
{
|
|
|
|
|
return alreadyPending.SelectMany(v => v.RemoteAlbum.Albums
|
|
|
|
|
.Select(d => new { Album = d, PendingRelease = v }))
|
|
|
|
|
.ToLookup(v => v.Album.Id, v => v.PendingRelease);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public List<ReleaseInfo> GetPending()
|
|
|
|
@ -185,20 +192,20 @@ namespace NzbDrone.Core.Download.Pending
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var queue = new Queue.Queue
|
|
|
|
|
{
|
|
|
|
|
Id = GetQueueId(pendingRelease, album),
|
|
|
|
|
Artist = pendingRelease.RemoteAlbum.Artist,
|
|
|
|
|
Album = album,
|
|
|
|
|
Quality = pendingRelease.RemoteAlbum.ParsedAlbumInfo.Quality,
|
|
|
|
|
Title = pendingRelease.Title,
|
|
|
|
|
Size = pendingRelease.RemoteAlbum.Release.Size,
|
|
|
|
|
Sizeleft = pendingRelease.RemoteAlbum.Release.Size,
|
|
|
|
|
RemoteAlbum = pendingRelease.RemoteAlbum,
|
|
|
|
|
Timeleft = timeleft,
|
|
|
|
|
EstimatedCompletionTime = ect,
|
|
|
|
|
Status = pendingRelease.Reason.ToString(),
|
|
|
|
|
Protocol = pendingRelease.RemoteAlbum.Release.DownloadProtocol,
|
|
|
|
|
Indexer = pendingRelease.RemoteAlbum.Release.Indexer
|
|
|
|
|
{
|
|
|
|
|
Id = GetQueueId(pendingRelease, album),
|
|
|
|
|
Artist = pendingRelease.RemoteAlbum.Artist,
|
|
|
|
|
Album = album,
|
|
|
|
|
Quality = pendingRelease.RemoteAlbum.ParsedAlbumInfo.Quality,
|
|
|
|
|
Title = pendingRelease.Title,
|
|
|
|
|
Size = pendingRelease.RemoteAlbum.Release.Size,
|
|
|
|
|
Sizeleft = pendingRelease.RemoteAlbum.Release.Size,
|
|
|
|
|
RemoteAlbum = pendingRelease.RemoteAlbum,
|
|
|
|
|
Timeleft = timeleft,
|
|
|
|
|
EstimatedCompletionTime = ect,
|
|
|
|
|
Status = pendingRelease.Reason.ToString(),
|
|
|
|
|
Protocol = pendingRelease.RemoteAlbum.Release.DownloadProtocol,
|
|
|
|
|
Indexer = pendingRelease.RemoteAlbum.Release.Indexer
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
queued.Add(queue);
|
|
|
|
@ -254,11 +261,27 @@ namespace NzbDrone.Core.Download.Pending
|
|
|
|
|
return IncludeRemoteAlbums(_repository.AllByArtistId(artistId).ToList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private List<PendingRelease> IncludeRemoteAlbums(List<PendingRelease> releases)
|
|
|
|
|
private List<PendingRelease> IncludeRemoteAlbums(List<PendingRelease> releases, Dictionary<string, RemoteAlbum> knownRemoteAlbums = null)
|
|
|
|
|
{
|
|
|
|
|
var result = new List<PendingRelease>();
|
|
|
|
|
var artistMap = _artistService.GetArtists(releases.Select(v => v.ArtistId).Distinct())
|
|
|
|
|
.ToDictionary(v => v.Id);
|
|
|
|
|
|
|
|
|
|
var artistMap = new Dictionary<int, Artist>();
|
|
|
|
|
|
|
|
|
|
if (knownRemoteAlbums != null)
|
|
|
|
|
{
|
|
|
|
|
foreach (var artist in knownRemoteAlbums.Values.Select(v => v.Artist))
|
|
|
|
|
{
|
|
|
|
|
if (!artistMap.ContainsKey(artist.Id))
|
|
|
|
|
{
|
|
|
|
|
artistMap[artist.Id] = artist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var artist in _artistService.GetArtists(releases.Select(v => v.ArtistId).Distinct().Where(v => !artistMap.ContainsKey(v))))
|
|
|
|
|
{
|
|
|
|
|
artistMap[artist.Id] = artist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var release in releases)
|
|
|
|
|
{
|
|
|
|
@ -267,7 +290,17 @@ namespace NzbDrone.Core.Download.Pending
|
|
|
|
|
// Just in case the artist was removed, but wasn't cleaned up yet (housekeeper will clean it up)
|
|
|
|
|
if (artist == null) return null;
|
|
|
|
|
|
|
|
|
|
var albums = _parsingService.GetAlbums(release.ParsedAlbumInfo, artist);
|
|
|
|
|
List<Album> albums;
|
|
|
|
|
|
|
|
|
|
RemoteAlbum knownRemoteAlbum;
|
|
|
|
|
if (knownRemoteAlbums != null && knownRemoteAlbums.TryGetValue(release.Release.Title, out knownRemoteAlbum))
|
|
|
|
|
{
|
|
|
|
|
albums = knownRemoteAlbum.Albums;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
albums = _parsingService.GetAlbums(release.ParsedAlbumInfo, artist);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
release.RemoteAlbum = new RemoteAlbum
|
|
|
|
|
{
|
|
|
|
|