Lidarr/src/NzbDrone.Core/DecisionEngine/DownloadDecisionComparer.cs

174 lines
6.5 KiB
C#
Raw Normal View History

2017-09-04 02:20:56 +00:00
using System;
2016-04-08 20:23:09 +00:00
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Core.Configuration;
2016-04-08 20:23:09 +00:00
using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles.Delay;
using NzbDrone.Core.Qualities;
2016-04-08 20:23:09 +00:00
namespace NzbDrone.Core.DecisionEngine
{
public class DownloadDecisionComparer : IComparer<DownloadDecision>
{
private readonly IConfigService _configService;
2016-04-08 20:23:09 +00:00
private readonly IDelayProfileService _delayProfileService;
2016-04-08 20:23:09 +00:00
public delegate int CompareDelegate(DownloadDecision x, DownloadDecision y);
public delegate int CompareDelegate<TSubject, TValue>(DownloadDecision x, DownloadDecision y);
public DownloadDecisionComparer(IConfigService configService, IDelayProfileService delayProfileService)
2016-04-08 20:23:09 +00:00
{
_configService = configService;
2016-04-08 20:23:09 +00:00
_delayProfileService = delayProfileService;
}
public int Compare(DownloadDecision x, DownloadDecision y)
{
var comparers = new List<CompareDelegate>
{
CompareQuality,
ComparePreferredWordScore,
2016-04-08 20:23:09 +00:00
CompareProtocol,
2020-09-10 22:04:53 +00:00
CompareIndexerPriority,
2016-04-08 20:23:09 +00:00
ComparePeersIfTorrent,
CompareAlbumCount,
2016-04-08 20:23:09 +00:00
CompareAgeIfUsenet,
CompareSize
};
return comparers.Select(comparer => comparer(x, y)).FirstOrDefault(result => result != 0);
}
private int CompareBy<TSubject, TValue>(TSubject left, TSubject right, Func<TSubject, TValue> funcValue)
where TValue : IComparable<TValue>
{
var leftValue = funcValue(left);
var rightValue = funcValue(right);
return leftValue.CompareTo(rightValue);
}
private int CompareByReverse<TSubject, TValue>(TSubject left, TSubject right, Func<TSubject, TValue> funcValue)
where TValue : IComparable<TValue>
{
2017-09-04 02:20:56 +00:00
return CompareBy(left, right, funcValue) * -1;
2016-04-08 20:23:09 +00:00
}
private int CompareAll(params int[] comparers)
{
return comparers.Select(comparer => comparer).FirstOrDefault(result => result != 0);
}
2020-09-10 22:04:53 +00:00
private int CompareIndexerPriority(DownloadDecision x, DownloadDecision y)
{
return CompareByReverse(x.RemoteAlbum.Release, y.RemoteAlbum.Release, release => release.IndexerPriority);
}
2016-04-08 20:23:09 +00:00
private int CompareQuality(DownloadDecision x, DownloadDecision y)
{
if (_configService.DownloadPropersAndRepacks == ProperDownloadTypes.DoNotPrefer)
{
return CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Artist.QualityProfile.Value.GetIndex(remoteAlbum.ParsedAlbumInfo.Quality.Quality));
}
return CompareAll(CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Artist.QualityProfile.Value.GetIndex(remoteAlbum.ParsedAlbumInfo.Quality.Quality)),
CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.ParsedAlbumInfo.Quality.Revision));
2016-04-08 20:23:09 +00:00
}
private int ComparePreferredWordScore(DownloadDecision x, DownloadDecision y)
{
return CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.PreferredWordScore);
}
2016-04-08 20:23:09 +00:00
private int CompareProtocol(DownloadDecision x, DownloadDecision y)
{
var result = CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
2016-04-08 20:23:09 +00:00
{
var delayProfile = _delayProfileService.BestForTags(remoteAlbum.Artist.Tags);
var downloadProtocol = remoteAlbum.Release.DownloadProtocol;
2016-04-08 20:23:09 +00:00
return downloadProtocol == delayProfile.PreferredProtocol;
});
return result;
}
private int CompareAlbumCount(DownloadDecision x, DownloadDecision y)
2016-04-08 20:23:09 +00:00
{
var discographyCompare = CompareBy(x.RemoteAlbum,
y.RemoteAlbum,
remoteAlbum => remoteAlbum.ParsedAlbumInfo.Discography);
if (discographyCompare != 0)
{
return discographyCompare;
}
return CompareByReverse(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Albums.Count);
2016-04-08 20:23:09 +00:00
}
private int ComparePeersIfTorrent(DownloadDecision x, DownloadDecision y)
{
// Different protocols should get caught when checking the preferred protocol,
// since we're dealing with the same series in our comparisons
if (x.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Torrent ||
y.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Torrent)
2016-04-08 20:23:09 +00:00
{
return 0;
}
return CompareAll(
CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
2016-04-08 20:23:09 +00:00
{
var seeders = TorrentInfo.GetSeeders(remoteAlbum.Release);
2016-04-08 20:23:09 +00:00
return seeders.HasValue && seeders.Value > 0 ? Math.Round(Math.Log10(seeders.Value)) : 0;
}),
CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
2016-04-08 20:23:09 +00:00
{
var peers = TorrentInfo.GetPeers(remoteAlbum.Release);
2016-04-08 20:23:09 +00:00
return peers.HasValue && peers.Value > 0 ? Math.Round(Math.Log10(peers.Value)) : 0;
}));
}
private int CompareAgeIfUsenet(DownloadDecision x, DownloadDecision y)
{
if (x.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Usenet ||
y.RemoteAlbum.Release.DownloadProtocol != DownloadProtocol.Usenet)
2016-04-08 20:23:09 +00:00
{
return 0;
}
return CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum =>
2016-04-08 20:23:09 +00:00
{
var ageHours = remoteAlbum.Release.AgeHours;
var age = remoteAlbum.Release.Age;
2016-04-08 20:23:09 +00:00
if (ageHours < 1)
{
return 1000;
}
if (ageHours <= 24)
{
return 100;
}
if (age <= 7)
{
return 10;
}
return 1;
});
}
private int CompareSize(DownloadDecision x, DownloadDecision y)
{
// TODO: Is smaller better? Smaller for usenet could mean no par2 files.
return CompareBy(x.RemoteAlbum, y.RemoteAlbum, remoteAlbum => remoteAlbum.Release.Size.Round(200.Megabytes()));
2016-04-08 20:23:09 +00:00
}
}
}