2018-03-14 20:41:36 +00:00
|
|
|
using System;
|
2013-07-06 21:47:49 +00:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
|
|
|
using NLog;
|
2014-01-06 06:20:08 +00:00
|
|
|
using NzbDrone.Common.Disk;
|
2015-01-27 05:57:07 +00:00
|
|
|
using NzbDrone.Common.Extensions;
|
2013-07-06 21:47:49 +00:00
|
|
|
using NzbDrone.Core.DecisionEngine;
|
2018-01-31 19:09:04 +00:00
|
|
|
using NzbDrone.Core.Download;
|
2019-12-22 22:08:53 +00:00
|
|
|
using NzbDrone.Core.MediaFiles.MovieImport.Aggregation;
|
|
|
|
using NzbDrone.Core.Movies;
|
2013-07-06 21:47:49 +00:00
|
|
|
using NzbDrone.Core.Parser;
|
|
|
|
using NzbDrone.Core.Parser.Model;
|
|
|
|
|
2018-03-14 20:41:36 +00:00
|
|
|
namespace NzbDrone.Core.MediaFiles.MovieImport
|
2013-07-06 21:47:49 +00:00
|
|
|
{
|
|
|
|
public interface IMakeImportDecision
|
|
|
|
{
|
2017-01-02 17:05:55 +00:00
|
|
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie);
|
2021-11-28 21:42:44 +00:00
|
|
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, bool filterExistingFiles);
|
2018-01-31 19:09:04 +00:00
|
|
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource);
|
2019-12-07 04:06:58 +00:00
|
|
|
List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool filterExistingFiles);
|
2021-01-31 06:02:51 +00:00
|
|
|
ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem);
|
2013-07-06 21:47:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public class ImportDecisionMaker : IMakeImportDecision
|
|
|
|
{
|
2015-01-27 05:57:07 +00:00
|
|
|
private readonly IEnumerable<IImportDecisionEngineSpecification> _specifications;
|
2013-07-19 05:05:07 +00:00
|
|
|
private readonly IMediaFileService _mediaFileService;
|
2019-07-16 02:27:35 +00:00
|
|
|
private readonly IAggregationService _aggregationService;
|
2013-07-15 23:53:06 +00:00
|
|
|
private readonly IDiskProvider _diskProvider;
|
2015-01-27 05:57:07 +00:00
|
|
|
private readonly IDetectSample _detectSample;
|
2019-10-31 03:46:40 +00:00
|
|
|
private readonly IParsingService _parsingService;
|
2013-07-06 21:47:49 +00:00
|
|
|
private readonly Logger _logger;
|
|
|
|
|
2015-01-27 05:57:07 +00:00
|
|
|
public ImportDecisionMaker(IEnumerable<IImportDecisionEngineSpecification> specifications,
|
2013-07-19 05:05:07 +00:00
|
|
|
IMediaFileService mediaFileService,
|
2019-07-16 02:27:35 +00:00
|
|
|
IAggregationService aggregationService,
|
2013-07-15 23:53:06 +00:00
|
|
|
IDiskProvider diskProvider,
|
2015-01-27 05:57:07 +00:00
|
|
|
IDetectSample detectSample,
|
2019-10-31 03:46:40 +00:00
|
|
|
IParsingService parsingService,
|
2013-07-15 23:53:06 +00:00
|
|
|
Logger logger)
|
2013-07-06 21:47:49 +00:00
|
|
|
{
|
|
|
|
_specifications = specifications;
|
2013-07-19 05:05:07 +00:00
|
|
|
_mediaFileService = mediaFileService;
|
2019-07-16 02:27:35 +00:00
|
|
|
_aggregationService = aggregationService;
|
2013-07-15 23:53:06 +00:00
|
|
|
_diskProvider = diskProvider;
|
2015-01-27 05:57:07 +00:00
|
|
|
_detectSample = detectSample;
|
2019-10-31 03:46:40 +00:00
|
|
|
_parsingService = parsingService;
|
2013-07-06 21:47:49 +00:00
|
|
|
_logger = logger;
|
|
|
|
}
|
|
|
|
|
2017-01-02 17:05:55 +00:00
|
|
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie)
|
|
|
|
{
|
2019-12-07 04:06:58 +00:00
|
|
|
return GetImportDecisions(videoFiles, movie, null, null, false);
|
2017-01-02 17:05:55 +00:00
|
|
|
}
|
|
|
|
|
2021-11-28 21:42:44 +00:00
|
|
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, bool filterExistingFiles)
|
|
|
|
{
|
|
|
|
return GetImportDecisions(videoFiles, movie, null, null, false, filterExistingFiles);
|
|
|
|
}
|
|
|
|
|
2018-01-31 19:09:04 +00:00
|
|
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource)
|
2017-03-08 21:07:51 +00:00
|
|
|
{
|
2019-12-07 04:06:58 +00:00
|
|
|
return GetImportDecisions(videoFiles, movie, downloadClientItem, folderInfo, sceneSource, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Movie movie, DownloadClientItem downloadClientItem, ParsedMovieInfo folderInfo, bool sceneSource, bool filterExistingFiles)
|
|
|
|
{
|
|
|
|
var newFiles = filterExistingFiles ? _mediaFileService.FilterExistingFiles(videoFiles.ToList(), movie) : videoFiles.ToList();
|
2017-03-08 21:07:51 +00:00
|
|
|
|
2020-10-02 18:05:34 +00:00
|
|
|
_logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count);
|
2017-03-08 21:07:51 +00:00
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
ParsedMovieInfo downloadClientItemInfo = null;
|
2017-03-08 21:07:51 +00:00
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
if (downloadClientItem != null)
|
2017-03-08 21:07:51 +00:00
|
|
|
{
|
2020-04-08 16:54:05 +00:00
|
|
|
downloadClientItemInfo = Parser.Parser.ParseMovieTitle(downloadClientItem.Title);
|
2019-10-31 03:46:40 +00:00
|
|
|
downloadClientItemInfo = _parsingService.EnhanceMovieInfo(downloadClientItemInfo);
|
2017-03-08 21:07:51 +00:00
|
|
|
}
|
|
|
|
|
2020-07-19 05:45:23 +00:00
|
|
|
var nonSampleVideoFileCount = GetNonSampleVideoFileCount(newFiles, movie);
|
2017-01-02 17:05:55 +00:00
|
|
|
|
|
|
|
var decisions = new List<ImportDecision>();
|
|
|
|
|
|
|
|
foreach (var file in newFiles)
|
|
|
|
{
|
2019-07-16 02:27:35 +00:00
|
|
|
var localMovie = new LocalMovie
|
|
|
|
{
|
|
|
|
Movie = movie,
|
|
|
|
DownloadClientMovieInfo = downloadClientItemInfo,
|
|
|
|
FolderMovieInfo = folderInfo,
|
|
|
|
Path = file,
|
2019-12-07 04:06:58 +00:00
|
|
|
SceneSource = sceneSource,
|
|
|
|
ExistingFile = movie.Path.IsParentPath(file)
|
2019-07-16 02:27:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
decisions.AddIfNotNull(GetDecision(localMovie, downloadClientItem, nonSampleVideoFileCount > 1));
|
2017-01-02 17:05:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return decisions;
|
|
|
|
}
|
|
|
|
|
2021-01-31 06:02:51 +00:00
|
|
|
public ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
|
|
|
{
|
|
|
|
var reasons = _specifications.Select(c => EvaluateSpec(c, localMovie, downloadClientItem))
|
|
|
|
.Where(c => c != null);
|
|
|
|
|
|
|
|
return new ImportDecision(localMovie, reasons.ToArray());
|
|
|
|
}
|
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
private ImportDecision GetDecision(LocalMovie localMovie, DownloadClientItem downloadClientItem, bool otherFiles)
|
2017-01-02 17:05:55 +00:00
|
|
|
{
|
|
|
|
ImportDecision decision = null;
|
|
|
|
|
2020-04-08 16:54:05 +00:00
|
|
|
var fileMovieInfo = Parser.Parser.ParseMoviePath(localMovie.Path);
|
2018-09-10 19:25:10 +00:00
|
|
|
|
2019-10-31 03:46:40 +00:00
|
|
|
if (fileMovieInfo != null)
|
|
|
|
{
|
|
|
|
fileMovieInfo = _parsingService.EnhanceMovieInfo(fileMovieInfo);
|
2019-12-22 21:24:11 +00:00
|
|
|
}
|
2019-10-31 03:46:40 +00:00
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
localMovie.FileMovieInfo = fileMovieInfo;
|
|
|
|
localMovie.Size = _diskProvider.GetFileSize(localMovie.Path);
|
2017-01-02 17:05:55 +00:00
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
try
|
|
|
|
{
|
2020-08-16 01:54:20 +00:00
|
|
|
_aggregationService.Augment(localMovie, downloadClientItem, otherFiles);
|
2018-08-05 14:28:05 +00:00
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
if (localMovie.Movie == null)
|
2017-01-02 17:05:55 +00:00
|
|
|
{
|
2019-07-16 02:27:35 +00:00
|
|
|
decision = new ImportDecision(localMovie, new Rejection("Invalid movie"));
|
2017-01-02 17:05:55 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-07-16 02:27:35 +00:00
|
|
|
decision = GetDecision(localMovie, downloadClientItem);
|
2017-01-02 17:05:55 +00:00
|
|
|
}
|
|
|
|
}
|
2019-07-16 02:27:35 +00:00
|
|
|
catch (AugmentingFailedException)
|
|
|
|
{
|
|
|
|
decision = new ImportDecision(localMovie, new Rejection("Unable to parse file"));
|
|
|
|
}
|
|
|
|
catch (Exception ex)
|
2017-01-02 17:05:55 +00:00
|
|
|
{
|
2019-07-16 02:27:35 +00:00
|
|
|
_logger.Error(ex, "Couldn't import file. {0}", localMovie.Path);
|
2017-01-02 17:05:55 +00:00
|
|
|
|
2017-01-09 03:16:14 +00:00
|
|
|
decision = new ImportDecision(localMovie, new Rejection("Unexpected error processing file"));
|
2017-01-03 19:24:55 +00:00
|
|
|
}
|
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
if (decision == null)
|
|
|
|
{
|
|
|
|
_logger.Error("Unable to make a decision on {0}", localMovie.Path);
|
|
|
|
}
|
|
|
|
else if (decision.Rejections.Any())
|
|
|
|
{
|
|
|
|
_logger.Debug("File rejected for the following reasons: {0}", string.Join(", ", decision.Rejections));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_logger.Debug("File accepted");
|
|
|
|
}
|
2017-01-02 17:05:55 +00:00
|
|
|
|
|
|
|
return decision;
|
|
|
|
}
|
|
|
|
|
2018-01-31 19:09:04 +00:00
|
|
|
private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalMovie localMovie, DownloadClientItem downloadClientItem)
|
2017-01-03 19:24:55 +00:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2018-01-31 19:09:04 +00:00
|
|
|
var result = spec.IsSatisfiedBy(localMovie, downloadClientItem);
|
2017-01-03 19:24:55 +00:00
|
|
|
|
|
|
|
if (!result.Accepted)
|
|
|
|
{
|
|
|
|
return new Rejection(result.Reason);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (NotImplementedException e)
|
|
|
|
{
|
|
|
|
_logger.Warn(e, "Spec " + spec.ToString() + " currently does not implement evaluation for movies.");
|
|
|
|
return null;
|
|
|
|
}
|
2019-08-31 03:37:05 +00:00
|
|
|
catch (Exception ex)
|
2017-01-03 19:24:55 +00:00
|
|
|
{
|
2019-08-31 03:37:05 +00:00
|
|
|
_logger.Error(ex, "Couldn't evaluate decision on {0}", localMovie.Path);
|
|
|
|
return new Rejection($"{spec.GetType().Name}: {ex.Message}");
|
2017-01-03 19:24:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2020-07-19 05:45:23 +00:00
|
|
|
private int GetNonSampleVideoFileCount(List<string> videoFiles, Movie movie)
|
2017-01-03 19:24:55 +00:00
|
|
|
{
|
2019-07-16 02:27:35 +00:00
|
|
|
return videoFiles.Count(file =>
|
2017-01-03 19:24:55 +00:00
|
|
|
{
|
2020-07-19 05:45:23 +00:00
|
|
|
var sample = _detectSample.IsSample(movie, file);
|
2017-01-03 19:24:55 +00:00
|
|
|
|
2019-07-16 02:27:35 +00:00
|
|
|
if (sample == DetectSampleResult.Sample)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-05 14:28:05 +00:00
|
|
|
|
2017-01-03 19:24:55 +00:00
|
|
|
return true;
|
2019-07-16 02:27:35 +00:00
|
|
|
});
|
2016-01-05 07:11:06 +00:00
|
|
|
}
|
2013-07-06 21:47:49 +00:00
|
|
|
}
|
|
|
|
}
|