mirror of
https://github.com/Readarr/Readarr.git
synced 2026-04-23 22:25:09 -04:00
New: Readarr 0.1
This commit is contained in:
@@ -70,29 +70,23 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
var parsedAlbumInfo = Parser.Parser.ParseAlbumTitle(report.Title);
|
||||
|
||||
if (parsedAlbumInfo == null && searchCriteria != null)
|
||||
if (parsedAlbumInfo == null)
|
||||
{
|
||||
parsedAlbumInfo = Parser.Parser.ParseAlbumTitleWithSearchCriteria(report.Title,
|
||||
searchCriteria.Artist,
|
||||
searchCriteria.Albums);
|
||||
if (searchCriteria != null)
|
||||
{
|
||||
parsedAlbumInfo = Parser.Parser.ParseAlbumTitleWithSearchCriteria(report.Title,
|
||||
searchCriteria.Artist,
|
||||
searchCriteria.Albums);
|
||||
}
|
||||
else
|
||||
{
|
||||
// try parsing fuzzy
|
||||
parsedAlbumInfo = _parsingService.ParseAlbumTitleFuzzy(report.Title);
|
||||
}
|
||||
}
|
||||
|
||||
if (parsedAlbumInfo != null)
|
||||
{
|
||||
// TODO: Artist Data Augment without calling to parse title again
|
||||
//if (!report.Artist.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// if (parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace() || _parsingService.GetArtist(parsedAlbumInfo.ArtistName) == null)
|
||||
// {
|
||||
// parsedAlbumInfo.ArtistName = report.Artist;
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO: Replace Parsed AlbumTitle with metadata Title if Parsed AlbumTitle not a valid match
|
||||
//if (!report.Album.IsNullOrWhiteSpace())
|
||||
//{
|
||||
// parsedAlbumInfo.AlbumTitle = report.Album;
|
||||
//}
|
||||
if (!parsedAlbumInfo.ArtistName.IsNullOrWhiteSpace())
|
||||
{
|
||||
var remoteAlbum = _parsingService.Map(parsedAlbumInfo, searchCriteria);
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace NzbDrone.Core.DecisionEngine
|
||||
public List<DownloadDecision> PrioritizeDecisions(List<DownloadDecision> decisions)
|
||||
{
|
||||
return decisions.Where(c => c.RemoteAlbum.DownloadAllowed)
|
||||
.GroupBy(c => c.RemoteAlbum.Artist.Id, (artistId, downloadDecisions) =>
|
||||
.GroupBy(c => c.RemoteAlbum.Artist.Id, (authorId, downloadDecisions) =>
|
||||
{
|
||||
return downloadDecisions.OrderByDescending(decision => decision, new DownloadDecisionComparer(_configService, _delayProfileService));
|
||||
})
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
_logger.Debug("size restriction not implemented");
|
||||
return Decision.Accept();
|
||||
|
||||
/*
|
||||
_logger.Debug("Beginning size check for: {0}", subject);
|
||||
|
||||
var quality = subject.ParsedAlbumInfo.Quality.Quality;
|
||||
@@ -38,17 +42,11 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
if (qualityDefinition.MinSize.HasValue)
|
||||
{
|
||||
var minSize = qualityDefinition.MinSize.Value.Kilobits();
|
||||
var minReleaseDuration = subject.Albums.Select(a => a.AlbumReleases.Value.Where(r => r.Monitored || a.AnyReleaseOk).Select(r => r.Duration).Min()).Sum() / 1000;
|
||||
|
||||
//Multiply minSize by smallest release duration
|
||||
minSize = minSize * minReleaseDuration;
|
||||
|
||||
//If the parsed size is smaller than minSize we don't want it
|
||||
if (subject.Release.Size < minSize)
|
||||
{
|
||||
var runtimeMessage = $"{minReleaseDuration}sec";
|
||||
|
||||
_logger.Debug("Item: {0}, Size: {1} is smaller than minimum allowed size ({2} bytes for {3}), rejecting.", subject, subject.Release.Size, minSize, runtimeMessage);
|
||||
_logger.Debug("Item: {0}, Size: {1} is smaller than minimum allowed size ({2} bytes), rejecting.", subject, subject.Release.Size, minSize);
|
||||
return Decision.Reject("{0} is smaller than minimum allowed {1}", subject.Release.Size.SizeSuffix(), minSize.SizeSuffix());
|
||||
}
|
||||
}
|
||||
@@ -60,23 +58,18 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
else
|
||||
{
|
||||
var maxSize = qualityDefinition.MaxSize.Value.Kilobits();
|
||||
var maxReleaseDuration = subject.Albums.Select(a => a.AlbumReleases.Value.Where(r => r.Monitored || a.AnyReleaseOk).Select(r => r.Duration).Max()).Sum() / 1000;
|
||||
|
||||
//Multiply maxSize by Album.Duration
|
||||
maxSize = maxSize * maxReleaseDuration;
|
||||
|
||||
//If the parsed size is greater than maxSize we don't want it
|
||||
if (subject.Release.Size > maxSize)
|
||||
{
|
||||
var runtimeMessage = $"{maxReleaseDuration}sec";
|
||||
|
||||
_logger.Debug("Item: {0}, Size: {1} is greater than maximum allowed size ({2} bytes for {3}), rejecting.", subject, subject.Release.Size, maxSize, runtimeMessage);
|
||||
_logger.Debug("Item: {0}, Size: {1} is greater than maximum allowed size ({2} bytes), rejecting.", subject, subject.Release.Size, maxSize);
|
||||
return Decision.Reject("{0} is larger than maximum allowed {1}", subject.Release.Size.SizeSuffix(), maxSize.SizeSuffix());
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug("Item: {0}, meets size constraints.", subject);
|
||||
return Decision.Accept();
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class CutoffSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly ITrackService _trackService;
|
||||
private readonly Logger _logger;
|
||||
private readonly ICached<bool> _missingFilesCache;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
|
||||
public CutoffSpecification(UpgradableSpecification upgradableSpecification,
|
||||
Logger logger,
|
||||
ICacheManager cacheManager,
|
||||
IMediaFileService mediaFileService,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
ITrackService trackService)
|
||||
Logger logger)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_mediaFileService = mediaFileService;
|
||||
_trackService = trackService;
|
||||
_missingFilesCache = cacheManager.GetCache<bool>(GetType());
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
}
|
||||
@@ -42,33 +31,25 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
var qualityProfile = subject.Artist.QualityProfile.Value;
|
||||
|
||||
foreach (var album in subject.Albums)
|
||||
foreach (var file in subject.Albums.SelectMany(b => b.BookFiles.Value))
|
||||
{
|
||||
var tracksMissing = _missingFilesCache.Get(album.Id.ToString(),
|
||||
() => _trackService.TracksWithoutFiles(album.Id).Any(),
|
||||
TimeSpan.FromSeconds(30));
|
||||
var trackFiles = _mediaFileService.GetFilesByAlbum(album.Id);
|
||||
// Get a distinct list of all current track qualities for a given album
|
||||
var currentQualities = new List<QualityModel> { file.Quality };
|
||||
|
||||
if (!tracksMissing && trackFiles.Any())
|
||||
_logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
currentQualities,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, file.GetSceneOrFileName()),
|
||||
subject.ParsedAlbumInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
// Get a distinct list of all current track qualities for a given album
|
||||
var currentQualities = trackFiles.Select(c => c.Quality).Distinct().ToList();
|
||||
_logger.Debug("Cutoff already met by existing files, rejecting.");
|
||||
|
||||
_logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());
|
||||
var qualityCutoffIndex = qualityProfile.GetIndex(qualityProfile.Cutoff);
|
||||
var qualityCutoff = qualityProfile.Items[qualityCutoffIndex.Index];
|
||||
|
||||
if (!_upgradableSpecification.CutoffNotMet(qualityProfile,
|
||||
currentQualities,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName()),
|
||||
subject.ParsedAlbumInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
_logger.Debug("Cutoff already met by existing files, rejecting.");
|
||||
|
||||
var qualityCutoffIndex = qualityProfile.GetIndex(qualityProfile.Cutoff);
|
||||
var qualityCutoff = qualityProfile.Items[qualityCutoffIndex.Index];
|
||||
|
||||
return Decision.Reject("Existing files meets cutoff: {0}", qualityCutoff);
|
||||
}
|
||||
return Decision.Reject("Existing files meets cutoff: {0}", qualityCutoff);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
var albumIds = subject.Albums.Select(e => e.Id);
|
||||
var bookIds = subject.Albums.Select(e => e.Id);
|
||||
|
||||
var oldest = _pendingReleaseService.OldestPendingRelease(subject.Artist.Id, albumIds.ToArray());
|
||||
var oldest = _pendingReleaseService.OldestPendingRelease(subject.Artist.Id, bookIds.ToArray());
|
||||
|
||||
if (oldest != null && oldest.Release.AgeMinutes > delay)
|
||||
{
|
||||
|
||||
+1
-1
@@ -64,7 +64,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
||||
return Decision.Accept();
|
||||
}
|
||||
|
||||
private bool IsTrackFileMissing(Artist artist, TrackFile trackFile)
|
||||
private bool IsTrackFileMissing(Author artist, BookFile trackFile)
|
||||
{
|
||||
return !_diskProvider.FileExists(trackFile.Path);
|
||||
}
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class SameTracksGrabSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly SameTracksSpecification _sameTracksSpecification;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public SameTracksGrabSpecification(SameTracksSpecification sameTracksSpecification, Logger logger)
|
||||
{
|
||||
_sameTracksSpecification = sameTracksSpecification;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public SpecificationPriority Priority => SpecificationPriority.Default;
|
||||
public RejectionType Type => RejectionType.Permanent;
|
||||
|
||||
public Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
// TODO: Rework for Tracks if we can parse from release details.
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Music;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class SameTracksSpecification
|
||||
{
|
||||
private readonly ITrackService _trackService;
|
||||
|
||||
public SameTracksSpecification(ITrackService trackService)
|
||||
{
|
||||
_trackService = trackService;
|
||||
}
|
||||
|
||||
public bool IsSatisfiedBy(List<Track> tracks)
|
||||
{
|
||||
var trackIds = tracks.SelectList(e => e.Id);
|
||||
var trackFileIds = tracks.Where(c => c.TrackFileId != 0).Select(c => c.TrackFileId).Distinct();
|
||||
|
||||
foreach (var trackFileId in trackFileIds)
|
||||
{
|
||||
var tracksInFile = _trackService.GetTracksByFileId(trackFileId);
|
||||
|
||||
if (tracksInFile.Select(e => e.Id).Except(trackIds).Any())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class UpgradeAllowedSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly ITrackService _trackService;
|
||||
private readonly Logger _logger;
|
||||
private readonly ICached<bool> _missingFilesCache;
|
||||
|
||||
public UpgradeAllowedSpecification(UpgradableSpecification upgradableSpecification,
|
||||
Logger logger,
|
||||
ICacheManager cacheManager,
|
||||
IMediaFileService mediaFileService,
|
||||
ITrackService trackService)
|
||||
Logger logger)
|
||||
{
|
||||
_upgradableSpecification = upgradableSpecification;
|
||||
_mediaFileService = mediaFileService;
|
||||
_trackService = trackService;
|
||||
_missingFilesCache = cacheManager.GetCache<bool>(GetType());
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
@@ -38,29 +27,26 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
var qualityProfile = subject.Artist.QualityProfile.Value;
|
||||
|
||||
foreach (var album in subject.Albums)
|
||||
foreach (var file in subject.Albums.SelectMany(b => b.BookFiles.Value))
|
||||
{
|
||||
var tracksMissing = _missingFilesCache.Get(album.Id.ToString(),
|
||||
() => _trackService.TracksWithoutFiles(album.Id).Any(),
|
||||
TimeSpan.FromSeconds(30));
|
||||
|
||||
var trackFiles = _mediaFileService.GetFilesByAlbum(album.Id);
|
||||
|
||||
if (!tracksMissing && trackFiles.Any())
|
||||
if (file == null)
|
||||
{
|
||||
// Get a distinct list of all current track qualities for a given album
|
||||
var currentQualities = trackFiles.Select(c => c.Quality).Distinct().ToList();
|
||||
_logger.Debug("File is no longer available, skipping this file.");
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());
|
||||
// Get a distinct list of all current track qualities for a given album
|
||||
var currentQualities = new List<QualityModel> { file.Quality };
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
|
||||
_logger.Debug("Comparing file quality with report. Existing files contain {0}", currentQualities.ConcatToString());
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradeAllowed(qualityProfile,
|
||||
currentQualities,
|
||||
subject.ParsedAlbumInfo.Quality))
|
||||
{
|
||||
_logger.Debug("Upgrading is not allowed by the quality profile");
|
||||
{
|
||||
_logger.Debug("Upgrading is not allowed by the quality profile");
|
||||
|
||||
return Decision.Reject("Existing files and the Quality profile does not allow upgrades");
|
||||
}
|
||||
return Decision.Reject("Existing files and the Quality profile does not allow upgrades");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,38 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles.Releases;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
{
|
||||
public class UpgradeDiskSpecification : IDecisionEngineSpecification
|
||||
{
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly ITrackService _trackService;
|
||||
private readonly UpgradableSpecification _upgradableSpecification;
|
||||
private readonly IPreferredWordService _preferredWordServiceCalculator;
|
||||
private readonly Logger _logger;
|
||||
private readonly ICached<bool> _missingFilesCache;
|
||||
|
||||
public UpgradeDiskSpecification(UpgradableSpecification qualityUpgradableSpecification,
|
||||
IMediaFileService mediaFileService,
|
||||
ITrackService trackService,
|
||||
ICacheManager cacheManager,
|
||||
IPreferredWordService preferredWordServiceCalculator,
|
||||
Logger logger)
|
||||
{
|
||||
_upgradableSpecification = qualityUpgradableSpecification;
|
||||
_mediaFileService = mediaFileService;
|
||||
_trackService = trackService;
|
||||
_preferredWordServiceCalculator = preferredWordServiceCalculator;
|
||||
_logger = logger;
|
||||
_missingFilesCache = cacheManager.GetCache<bool>(GetType());
|
||||
}
|
||||
|
||||
public SpecificationPriority Priority => SpecificationPriority.Default;
|
||||
@@ -40,25 +28,23 @@ namespace NzbDrone.Core.DecisionEngine.Specifications
|
||||
|
||||
public virtual Decision IsSatisfiedBy(RemoteAlbum subject, SearchCriteriaBase searchCriteria)
|
||||
{
|
||||
foreach (var album in subject.Albums)
|
||||
foreach (var file in subject.Albums.SelectMany(c => c.BookFiles.Value))
|
||||
{
|
||||
var tracksMissing = _missingFilesCache.Get(album.Id.ToString(),
|
||||
() => _trackService.TracksWithoutFiles(album.Id).Any(),
|
||||
TimeSpan.FromSeconds(30));
|
||||
var trackFiles = _mediaFileService.GetFilesByAlbum(album.Id);
|
||||
|
||||
if (!tracksMissing && trackFiles.Any())
|
||||
if (file == null)
|
||||
{
|
||||
var currentQualities = trackFiles.Select(c => c.Quality).Distinct().ToList();
|
||||
_logger.Debug("File is no longer available, skipping this file.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradable(subject.Artist.QualityProfile,
|
||||
currentQualities,
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, trackFiles[0].GetSceneOrFileName()),
|
||||
subject.ParsedAlbumInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
return Decision.Reject("Existing files on disk is of equal or higher preference: {0}", currentQualities.ConcatToString());
|
||||
}
|
||||
_logger.Debug("Comparing file quality and language with report. Existing file is {0}", file.Quality);
|
||||
|
||||
if (!_upgradableSpecification.IsUpgradable(subject.Artist.QualityProfile,
|
||||
new List<QualityModel> { file.Quality },
|
||||
_preferredWordServiceCalculator.Calculate(subject.Artist, file.GetSceneOrFileName()),
|
||||
subject.ParsedAlbumInfo.Quality,
|
||||
subject.PreferredWordScore))
|
||||
{
|
||||
return Decision.Reject("Existing file on disk is of equal or higher preference: {0}", file.Quality);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user