mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-05 10:32:35 +01:00
209 lines
7.8 KiB
C#
209 lines
7.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Ninject;
|
|
using NLog;
|
|
using NzbDrone.Core.Helpers;
|
|
using NzbDrone.Core.Model;
|
|
using NzbDrone.Core.Repository;
|
|
using NzbDrone.Core.Repository.Quality;
|
|
|
|
namespace NzbDrone.Core.Providers
|
|
{
|
|
public class InventoryProvider
|
|
{
|
|
private readonly SeriesProvider _seriesProvider;
|
|
private readonly EpisodeProvider _episodeProvider;
|
|
private readonly HistoryProvider _historyProvider;
|
|
private readonly QualityTypeProvider _qualityTypeProvider;
|
|
private readonly QualityProvider _qualityProvider;
|
|
|
|
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
|
|
|
|
[Inject]
|
|
public InventoryProvider(SeriesProvider seriesProvider, EpisodeProvider episodeProvider,
|
|
HistoryProvider historyProvider, QualityTypeProvider qualityTypeProvider,
|
|
QualityProvider qualityProvider)
|
|
{
|
|
_seriesProvider = seriesProvider;
|
|
_episodeProvider = episodeProvider;
|
|
_historyProvider = historyProvider;
|
|
_qualityTypeProvider = qualityTypeProvider;
|
|
_qualityProvider = qualityProvider;
|
|
}
|
|
|
|
public InventoryProvider()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
public virtual bool IsMonitored(EpisodeParseResult parseResult)
|
|
{
|
|
var series = _seriesProvider.FindSeries(parseResult.CleanTitle);
|
|
|
|
if (series == null)
|
|
{
|
|
Logger.Trace("{0} is not mapped to any series in DB. skipping", parseResult.CleanTitle);
|
|
return false;
|
|
}
|
|
|
|
parseResult.Series = series;
|
|
|
|
if (!series.Monitored)
|
|
{
|
|
Logger.Debug("{0} is present in the DB but not tracked. skipping.", parseResult.CleanTitle);
|
|
return false;
|
|
}
|
|
|
|
var episodes = _episodeProvider.GetEpisodesByParseResult(parseResult, true);
|
|
|
|
//return monitored if any of the episodes are monitored
|
|
if (episodes.Any(episode => !episode.Ignored))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
Logger.Debug("All episodes are ignored. skipping.");
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Comprehensive check on whether or not this episode is needed.
|
|
/// </summary>
|
|
/// <param name = "parsedReport">Episode that needs to be checked</param>
|
|
/// <param name="skipHistory">False unless called by a manual search job</param>
|
|
/// <returns>Whether or not the file quality meets the requirements </returns>
|
|
/// <remarks>for multi episode files, all episodes need to meet the requirement
|
|
/// before the report is downloaded</remarks>
|
|
public virtual bool IsQualityNeeded(EpisodeParseResult parsedReport, bool skipHistory = false)
|
|
{
|
|
Logger.Trace("Checking if report meets quality requirements. {0}", parsedReport.Quality);
|
|
if (!parsedReport.Series.QualityProfile.Allowed.Contains(parsedReport.Quality.QualityType))
|
|
{
|
|
Logger.Trace("Quality {0} rejected by Series' quality profile", parsedReport.Quality);
|
|
return false;
|
|
}
|
|
|
|
var cutoff = parsedReport.Series.QualityProfile.Cutoff;
|
|
|
|
if (!IsAcceptableSize(parsedReport))
|
|
{
|
|
Logger.Info("Size: {0} is not acceptable for Quality: {1}", FileSizeFormatHelper.Format(parsedReport.Size, 2), parsedReport.Quality);
|
|
return false;
|
|
}
|
|
|
|
foreach (var episode in _episodeProvider.GetEpisodesByParseResult(parsedReport, true))
|
|
{
|
|
//Checking File
|
|
var file = episode.EpisodeFile;
|
|
if (file != null)
|
|
{
|
|
Logger.Trace("Comparing file quality with report. Existing file is {0} proper:{1}", file.Quality, file.Proper);
|
|
if (!IsUpgrade(new Quality { QualityType = file.Quality, Proper = file.Proper }, parsedReport.Quality, cutoff))
|
|
return false;
|
|
}
|
|
|
|
//Checking History (If not a manual search)
|
|
if (!skipHistory)
|
|
{
|
|
var bestQualityInHistory = _historyProvider.GetBestQualityInHistory(episode.EpisodeId);
|
|
if(bestQualityInHistory != null)
|
|
{
|
|
Logger.Trace("Comparing history quality with report. History is {0}", bestQualityInHistory);
|
|
if(!IsUpgrade(bestQualityInHistory, parsedReport.Quality, cutoff))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
Logger.Debug("Episode {0} is needed", parsedReport);
|
|
return true; //If we get to this point and the file has not yet been rejected then accept it
|
|
}
|
|
|
|
public static bool IsUpgrade(Quality currentQuality, Quality newQuality, QualityTypes cutOff)
|
|
{
|
|
if (currentQuality.QualityType >= cutOff)
|
|
{
|
|
if (newQuality.QualityType > currentQuality.QualityType ||
|
|
(newQuality.QualityType == currentQuality.QualityType && newQuality.Proper == currentQuality.Proper))
|
|
{
|
|
Logger.Trace("Existing item meets cut-off. skipping.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (newQuality > currentQuality)
|
|
return true;
|
|
|
|
if (currentQuality > newQuality)
|
|
{
|
|
Logger.Trace("existing item has better quality. skipping");
|
|
return false;
|
|
}
|
|
|
|
if (currentQuality == newQuality && !newQuality.Proper)
|
|
{
|
|
Logger.Trace("Same quality, not proper skipping");
|
|
return false;
|
|
}
|
|
|
|
Logger.Debug("New item has better quality than existing item");
|
|
return true;
|
|
}
|
|
|
|
public virtual bool IsAcceptableSize(EpisodeParseResult parseResult)
|
|
{
|
|
var qualityType = _qualityTypeProvider.Get((int) parseResult.Quality.QualityType);
|
|
|
|
//Need to determine if this is a 30 or 60 minute episode
|
|
//Is it a multi-episode release?
|
|
//Is it the first or last series of a season?
|
|
|
|
//0 will be treated as unlimited
|
|
if (qualityType.MaxSize == 0)
|
|
return true;
|
|
|
|
var maxSize = qualityType.MaxSize.Megabytes();
|
|
var series = parseResult.Series;
|
|
|
|
//Multiply maxSize by Series.Runtime
|
|
maxSize = maxSize * series.Runtime;
|
|
|
|
//Multiply maxSize by the number of episodes parsed (if EpisodeNumbers is null it will be treated as a single episode)
|
|
if (parseResult.EpisodeNumbers != null)
|
|
maxSize = maxSize * parseResult.EpisodeNumbers.Count;
|
|
|
|
//Check if there was only one episode parsed
|
|
//and it is the first or last episode of the season
|
|
if (parseResult.EpisodeNumbers != null && parseResult.EpisodeNumbers.Count == 1 &&
|
|
_episodeProvider.IsFirstOrLastEpisodeOfSeason(series.SeriesId,
|
|
parseResult.SeasonNumber, parseResult.EpisodeNumbers[0]))
|
|
{
|
|
maxSize = maxSize * 2;
|
|
}
|
|
|
|
//If the parsed size is greater than maxSize we don't want it
|
|
if (parseResult.Size > maxSize)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public virtual bool IsUpgradePossible(Episode episode)
|
|
{
|
|
//Used to check if the existing episode can be upgraded by searching (Before we search)
|
|
|
|
if (episode.EpisodeFileId == 0)
|
|
return true;
|
|
|
|
var profile = _qualityProvider.Get(episode.Series.QualityProfileId);
|
|
|
|
if (episode.EpisodeFile.Quality >= profile.Cutoff)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
}
|
|
} |