2013-07-06 21:47:49 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using NLog;
|
2013-07-15 23:53:06 +00:00
|
|
|
|
using NzbDrone.Common;
|
2013-07-06 21:47:49 +00:00
|
|
|
|
using NzbDrone.Core.DecisionEngine;
|
|
|
|
|
using NzbDrone.Core.Parser;
|
|
|
|
|
using NzbDrone.Core.Parser.Model;
|
|
|
|
|
using NzbDrone.Core.Tv;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|
|
|
|
{
|
|
|
|
|
public interface IMakeImportDecision
|
|
|
|
|
{
|
2013-07-23 05:50:32 +00:00
|
|
|
|
List<ImportDecision> GetImportDecisions(IEnumerable<String> videoFiles, Series series, bool sceneSource);
|
2013-07-06 21:47:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public class ImportDecisionMaker : IMakeImportDecision
|
|
|
|
|
{
|
|
|
|
|
private readonly IEnumerable<IRejectWithReason> _specifications;
|
|
|
|
|
private readonly IParsingService _parsingService;
|
2013-07-19 05:05:07 +00:00
|
|
|
|
private readonly IMediaFileService _mediaFileService;
|
2013-07-15 23:53:06 +00:00
|
|
|
|
private readonly IDiskProvider _diskProvider;
|
2013-07-06 21:47:49 +00:00
|
|
|
|
private readonly Logger _logger;
|
|
|
|
|
|
2013-07-15 23:53:06 +00:00
|
|
|
|
public ImportDecisionMaker(IEnumerable<IRejectWithReason> specifications,
|
|
|
|
|
IParsingService parsingService,
|
2013-07-19 05:05:07 +00:00
|
|
|
|
IMediaFileService mediaFileService,
|
2013-07-15 23:53:06 +00:00
|
|
|
|
IDiskProvider diskProvider,
|
2013-07-19 05:05:07 +00:00
|
|
|
|
|
2013-07-15 23:53:06 +00:00
|
|
|
|
Logger logger)
|
2013-07-06 21:47:49 +00:00
|
|
|
|
{
|
|
|
|
|
_specifications = specifications;
|
|
|
|
|
_parsingService = parsingService;
|
2013-07-19 05:05:07 +00:00
|
|
|
|
_mediaFileService = mediaFileService;
|
2013-07-15 23:53:06 +00:00
|
|
|
|
_diskProvider = diskProvider;
|
2013-07-06 21:47:49 +00:00
|
|
|
|
_logger = logger;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-23 05:50:32 +00:00
|
|
|
|
public List<ImportDecision> GetImportDecisions(IEnumerable<string> videoFiles, Series series, bool sceneSource)
|
2013-07-06 21:47:49 +00:00
|
|
|
|
{
|
2013-07-19 05:05:07 +00:00
|
|
|
|
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series.Id);
|
|
|
|
|
|
|
|
|
|
_logger.Debug("Analysing {0}/{1} files.", newFiles.Count, videoFiles.Count());
|
|
|
|
|
|
2013-07-23 05:50:32 +00:00
|
|
|
|
return GetDecisions(newFiles, series, sceneSource).ToList();
|
2013-07-06 21:47:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2013-07-23 05:50:32 +00:00
|
|
|
|
private IEnumerable<ImportDecision> GetDecisions(IEnumerable<String> videoFiles, Series series, bool sceneSource)
|
2013-07-06 21:47:49 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var file in videoFiles)
|
|
|
|
|
{
|
|
|
|
|
ImportDecision decision = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
2013-07-23 05:50:32 +00:00
|
|
|
|
var parsedEpisode = _parsingService.GetEpisodes(file, series, sceneSource);
|
2013-07-15 23:53:06 +00:00
|
|
|
|
|
2013-07-06 21:47:49 +00:00
|
|
|
|
if (parsedEpisode != null)
|
|
|
|
|
{
|
2013-07-15 23:53:06 +00:00
|
|
|
|
parsedEpisode.Size = _diskProvider.GetFileSize(file);
|
2013-07-06 21:47:49 +00:00
|
|
|
|
decision = GetDecision(parsedEpisode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
parsedEpisode = new LocalEpisode();
|
|
|
|
|
parsedEpisode.Path = file;
|
|
|
|
|
|
|
|
|
|
decision = new ImportDecision(parsedEpisode, "Unable to parse file");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
2013-07-17 00:53:33 +00:00
|
|
|
|
_logger.ErrorException("Couldn't import file." + file, e);
|
2013-07-06 21:47:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (decision != null)
|
|
|
|
|
{
|
|
|
|
|
yield return decision;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private ImportDecision GetDecision(LocalEpisode localEpisode)
|
|
|
|
|
{
|
|
|
|
|
var reasons = _specifications.Select(c => EvaluateSpec(c, localEpisode))
|
|
|
|
|
.Where(c => !string.IsNullOrWhiteSpace(c));
|
|
|
|
|
|
|
|
|
|
return new ImportDecision(localEpisode, reasons.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private string EvaluateSpec(IRejectWithReason spec, LocalEpisode localEpisode)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(spec.RejectionReason))
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("[Need Rejection Text]");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var generalSpecification = spec as IImportDecisionEngineSpecification;
|
|
|
|
|
if (generalSpecification != null && !generalSpecification.IsSatisfiedBy(localEpisode))
|
|
|
|
|
{
|
|
|
|
|
return spec.RejectionReason;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
//e.Data.Add("report", remoteEpisode.Report.ToJson());
|
|
|
|
|
//e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
|
|
|
|
|
_logger.ErrorException("Couldn't evaluate decision on " + localEpisode.Path, e);
|
|
|
|
|
return string.Format("{0}: {1}", spec.GetType().Name, e.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|