Fixes Manual Import and DroneFactory

Automatic Import still doesn't work - waiting for answer from Sonarr
team.
Tim Turner 8 years ago
parent 0fa1509ca6
commit 9206258370

@ -0,0 +1,17 @@
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Messaging.Commands;
namespace NzbDrone.Core.MediaFiles.Commands
{
public class DownloadedMovieScanCommand : Command
{
public override bool SendUpdatesToClient => SendUpdates;
public bool SendUpdates { get; set; }
// Properties used by third-party apps, do not modify.
public string Path { get; set; }
public string DownloadClientId { get; set; }
public ImportMode ImportMode { get; set; }
}
}

@ -1,265 +1,107 @@
using System.Collections.Generic; using NLog;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
using NzbDrone.Core.DecisionEngine; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.MediaFiles.Commands;
using NzbDrone.Core.MediaFiles.EpisodeImport; using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Parser; using NzbDrone.Core.Messaging.Commands;
using NzbDrone.Core.Tv; using System;
using NzbDrone.Core.Download; using System.Collections.Generic;
using NzbDrone.Core.Parser.Model; using System.IO;
using System.Linq;
using System.Text;
namespace NzbDrone.Core.MediaFiles namespace NzbDrone.Core.MediaFiles
{ {
public interface IDownloadedMovieImportService public class DownloadedMovieCommandService : IExecute<DownloadedMovieScanCommand>
{
List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo);
List<ImportResult> ProcessPath(string path, ImportMode importMode = ImportMode.Auto, Movie movie = null, DownloadClientItem downloadClientItem = null);
bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Movie movie);
}
public class DownloadedMovieImportService : IDownloadedMovieImportService
{ {
private readonly IDownloadedMovieImportService _downloadedMovieImportService;
private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IDiskProvider _diskProvider; private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService; private readonly IConfigService _configService;
private readonly IMovieService _movieService;
private readonly IParsingService _parsingService;
private readonly IMakeImportDecision _importDecisionMaker;
private readonly IImportApprovedMovie _importApprovedMovie;
private readonly IDetectSample _detectSample;
private readonly Logger _logger; private readonly Logger _logger;
public DownloadedMovieImportService(IDiskProvider diskProvider, public DownloadedMovieCommandService(IDownloadedMovieImportService downloadedMovieImportService,
IDiskScanService diskScanService, ITrackedDownloadService trackedDownloadService,
IMovieService movieService, IDiskProvider diskProvider,
IParsingService parsingService, IConfigService configService,
IMakeImportDecision importDecisionMaker, Logger logger)
IImportApprovedMovie importApprovedMovie,
IDetectSample detectSample,
Logger logger)
{ {
_downloadedMovieImportService = downloadedMovieImportService;
_trackedDownloadService = trackedDownloadService;
_diskProvider = diskProvider; _diskProvider = diskProvider;
_diskScanService = diskScanService; _configService = configService;
_movieService = movieService;
_parsingService = parsingService;
_importDecisionMaker = importDecisionMaker;
_importApprovedMovie = importApprovedMovie;
_detectSample = detectSample;
_logger = logger; _logger = logger;
} }
public List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo) private List<ImportResult> ProcessDroneFactoryFolder()
{ {
var results = new List<ImportResult>(); var downloadedEpisodesFolder = _configService.DownloadedEpisodesFolder;
foreach (var subFolder in _diskProvider.GetDirectories(directoryInfo.FullName)) if (string.IsNullOrEmpty(downloadedEpisodesFolder))
{ {
var folderResults = ProcessFolder(new DirectoryInfo(subFolder), ImportMode.Auto, null); _logger.Trace("Drone Factory folder is not configured");
results.AddRange(folderResults); return new List<ImportResult>();
} }
foreach (var videoFile in _diskScanService.GetVideoFiles(directoryInfo.FullName, false)) if (!_diskProvider.FolderExists(downloadedEpisodesFolder))
{ {
var fileResults = ProcessFile(new FileInfo(videoFile), ImportMode.Auto, null); _logger.Warn("Drone Factory folder [{0}] doesn't exist.", downloadedEpisodesFolder);
results.AddRange(fileResults); return new List<ImportResult>();
} }
return results; return _downloadedMovieImportService.ProcessRootFolder(new DirectoryInfo(downloadedEpisodesFolder));
} }
public List<ImportResult> ProcessPath(string path, ImportMode importMode = ImportMode.Auto, Movie movie = null, DownloadClientItem downloadClientItem = null) private List<ImportResult> ProcessPath(DownloadedMovieScanCommand message)
{ {
if (_diskProvider.FolderExists(path)) if (!_diskProvider.FolderExists(message.Path) && !_diskProvider.FileExists(message.Path))
{ {
var directoryInfo = new DirectoryInfo(path); _logger.Warn("Folder/File specified for import scan [{0}] doesn't exist.", message.Path);
return new List<ImportResult>();
if (movie == null)
{
return ProcessFolder(directoryInfo, importMode, downloadClientItem);
}
return ProcessFolder(directoryInfo, importMode, movie, downloadClientItem);
} }
if (_diskProvider.FileExists(path)) if (message.DownloadClientId.IsNotNullOrWhiteSpace())
{ {
var fileInfo = new FileInfo(path); var trackedDownload = _trackedDownloadService.Find(message.DownloadClientId);
if (movie == null) if (trackedDownload != null)
{ {
return ProcessFile(fileInfo, importMode, downloadClientItem); _logger.Debug("External directory scan request for known download {0}. [{1}]", message.DownloadClientId, message.Path);
}
return ProcessFile(fileInfo, importMode, movie, downloadClientItem); return _downloadedMovieImportService.ProcessPath(message.Path, message.ImportMode, trackedDownload.RemoteMovie.Movie, trackedDownload.DownloadItem);
}
_logger.Error("Import failed, path does not exist or is not accessible by Sonarr: {0}", path);
return new List<ImportResult>();
}
public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Movie movie)
{
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f) == ".rar");
foreach (var videoFile in videoFiles)
{
var episodeParseResult = Parser.Parser.ParseTitle(Path.GetFileName(videoFile));
if (episodeParseResult == null)
{
_logger.Warn("Unable to parse file on import: [{0}]", videoFile);
return false;
} }
else
var size = _diskProvider.GetFileSize(videoFile);
var quality = QualityParser.ParseQuality(videoFile);
if (!_detectSample.IsSample(movie, quality, videoFile, size, episodeParseResult.IsPossibleSpecialEpisode))
{ {
_logger.Warn("Non-sample file detected: [{0}]", videoFile); _logger.Warn("External directory scan request for unknown download {0}, attempting normal import. [{1}]", message.DownloadClientId, message.Path);
return false;
}
}
if (rarFiles.Any(f => _diskProvider.GetFileSize(f) > 10.Megabytes()))
{
_logger.Warn("RAR file detected, will require manual cleanup");
return false;
}
return true;
}
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
{
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var movie = _parsingService.GetMovie(cleanedUpName);
if (movie == null)
{
_logger.Debug("Unknown Movie {0}", cleanedUpName);
return new List<ImportResult>
{
UnknownMovieResult("Unknown Movie")
};
}
return ProcessFolder(directoryInfo, importMode, movie, downloadClientItem); return _downloadedMovieImportService.ProcessPath(message.Path, message.ImportMode);
}
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Movie movie, DownloadClientItem downloadClientItem)
{
if (_movieService.MoviePathExists(directoryInfo.FullName))
{
_logger.Warn("Unable to process folder that is mapped to an existing show");
return new List<ImportResult>();
}
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name);
if (folderInfo != null)
{
_logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
}
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
if (downloadClientItem == null)
{
foreach (var videoFile in videoFiles)
{
if (_diskProvider.IsFileLocked(videoFile))
{
return new List<ImportResult>
{
FileIsLockedResult(videoFile)
};
}
} }
} }
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, folderInfo, true); return _downloadedMovieImportService.ProcessPath(message.Path, message.ImportMode);
var importResults = _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
importResults.Any(i => i.Result == ImportResultType.Imported) &&
ShouldDeleteFolder(directoryInfo, movie))
{
_logger.Debug("Deleting folder after importing valid files");
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
}
return importResults;
} }
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem) public void Execute(DownloadedMovieScanCommand message)
{ {
var movie = _parsingService.GetMovie(Path.GetFileNameWithoutExtension(fileInfo.Name)); List<ImportResult> importResults;
if (movie == null) if (message.Path.IsNotNullOrWhiteSpace())
{ {
_logger.Debug("Unknown Movie for file: {0}", fileInfo.Name); importResults = ProcessPath(message);
return new List<ImportResult>
{
UnknownMovieResult(string.Format("Unknown Movie for file: {0}", fileInfo.Name), fileInfo.FullName)
};
} }
else
return ProcessFile(fileInfo, importMode, movie, downloadClientItem);
}
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, Movie movie, DownloadClientItem downloadClientItem)
{
if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
{ {
_logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName); importResults = ProcessDroneFactoryFolder();
return new List<ImportResult>
{
new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName }, new Rejection("Invalid video file, filename starts with '._'")), "Invalid video file, filename starts with '._'")
};
} }
if (downloadClientItem == null) if (importResults == null || importResults.All(v => v.Result != ImportResultType.Imported))
{ {
if (_diskProvider.IsFileLocked(fileInfo.FullName)) // Atm we don't report it as a command failure, coz that would cause the download to be failed.
{ // Changing the message won't do a thing either, coz it will get set to 'Completed' a msec later.
return new List<ImportResult> //message.SetMessage("Failed to import");
{
FileIsLockedResult(fileInfo.FullName)
};
}
} }
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, movie, null, true);
return _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
}
private string GetCleanedUpFolderName(string folder)
{
folder = folder.Replace("_UNPACK_", "")
.Replace("_FAILED_", "");
return folder;
}
private ImportResult FileIsLockedResult(string videoFile)
{
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later");
}
private ImportResult UnknownMovieResult(string message, string videoFile = null)
{
var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile };
return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Movie")), message);
} }
} }
} }

@ -0,0 +1,266 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.MediaFiles.EpisodeImport;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Download;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.MediaFiles.Commands;
namespace NzbDrone.Core.MediaFiles
{
public interface IDownloadedMovieImportService
{
List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo);
List<ImportResult> ProcessPath(string path, ImportMode importMode = ImportMode.Auto, Movie movie = null, DownloadClientItem downloadClientItem = null);
bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Movie movie);
}
public class DownloadedMovieImportService : IDownloadedMovieImportService
{
private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService;
private readonly IMovieService _movieService;
private readonly IParsingService _parsingService;
private readonly IMakeImportDecision _importDecisionMaker;
private readonly IImportApprovedMovie _importApprovedMovie;
private readonly IDetectSample _detectSample;
private readonly Logger _logger;
public DownloadedMovieImportService(IDiskProvider diskProvider,
IDiskScanService diskScanService,
IMovieService movieService,
IParsingService parsingService,
IMakeImportDecision importDecisionMaker,
IImportApprovedMovie importApprovedMovie,
IDetectSample detectSample,
Logger logger)
{
_diskProvider = diskProvider;
_diskScanService = diskScanService;
_movieService = movieService;
_parsingService = parsingService;
_importDecisionMaker = importDecisionMaker;
_importApprovedMovie = importApprovedMovie;
_detectSample = detectSample;
_logger = logger;
}
public List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo)
{
var results = new List<ImportResult>();
foreach (var subFolder in _diskProvider.GetDirectories(directoryInfo.FullName))
{
var folderResults = ProcessFolder(new DirectoryInfo(subFolder), ImportMode.Auto, null);
results.AddRange(folderResults);
}
foreach (var videoFile in _diskScanService.GetVideoFiles(directoryInfo.FullName, false))
{
var fileResults = ProcessFile(new FileInfo(videoFile), ImportMode.Auto, null);
results.AddRange(fileResults);
}
return results;
}
public List<ImportResult> ProcessPath(string path, ImportMode importMode = ImportMode.Auto, Movie movie = null, DownloadClientItem downloadClientItem = null)
{
if (_diskProvider.FolderExists(path))
{
var directoryInfo = new DirectoryInfo(path);
if (movie == null)
{
return ProcessFolder(directoryInfo, importMode, downloadClientItem);
}
return ProcessFolder(directoryInfo, importMode, movie, downloadClientItem);
}
if (_diskProvider.FileExists(path))
{
var fileInfo = new FileInfo(path);
if (movie == null)
{
return ProcessFile(fileInfo, importMode, downloadClientItem);
}
return ProcessFile(fileInfo, importMode, movie, downloadClientItem);
}
_logger.Error("Import failed, path does not exist or is not accessible by Radarr: {0}", path);
return new List<ImportResult>();
}
public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Movie movie)
{
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f) == ".rar");
foreach (var videoFile in videoFiles)
{
var episodeParseResult = Parser.Parser.ParseTitle(Path.GetFileName(videoFile));
if (episodeParseResult == null)
{
_logger.Warn("Unable to parse file on import: [{0}]", videoFile);
return false;
}
var size = _diskProvider.GetFileSize(videoFile);
var quality = QualityParser.ParseQuality(videoFile);
if (!_detectSample.IsSample(movie, quality, videoFile, size, episodeParseResult.IsPossibleSpecialEpisode))
{
_logger.Warn("Non-sample file detected: [{0}]", videoFile);
return false;
}
}
if (rarFiles.Any(f => _diskProvider.GetFileSize(f) > 10.Megabytes()))
{
_logger.Warn("RAR file detected, will require manual cleanup");
return false;
}
return true;
}
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
{
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var movie = _parsingService.GetMovie(cleanedUpName);
if (movie == null)
{
_logger.Debug("Unknown Movie {0}", cleanedUpName);
return new List<ImportResult>
{
UnknownMovieResult("Unknown Movie")
};
}
return ProcessFolder(directoryInfo, importMode, movie, downloadClientItem);
}
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Movie movie, DownloadClientItem downloadClientItem)
{
if (_movieService.MoviePathExists(directoryInfo.FullName))
{
_logger.Warn("Unable to process folder that is mapped to an existing show");
return new List<ImportResult>();
}
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
var folderInfo = Parser.Parser.ParseMovieTitle(directoryInfo.Name);
if (folderInfo != null)
{
_logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
}
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
if (downloadClientItem == null)
{
foreach (var videoFile in videoFiles)
{
if (_diskProvider.IsFileLocked(videoFile))
{
return new List<ImportResult>
{
FileIsLockedResult(videoFile)
};
}
}
}
var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), movie, folderInfo, true);
var importResults = _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) &&
importResults.Any(i => i.Result == ImportResultType.Imported) &&
ShouldDeleteFolder(directoryInfo, movie))
{
_logger.Debug("Deleting folder after importing valid files");
_diskProvider.DeleteFolder(directoryInfo.FullName, true);
}
return importResults;
}
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
{
var movie = _parsingService.GetMovie(Path.GetFileNameWithoutExtension(fileInfo.Name));
if (movie == null)
{
_logger.Debug("Unknown Movie for file: {0}", fileInfo.Name);
return new List<ImportResult>
{
UnknownMovieResult(string.Format("Unknown Movie for file: {0}", fileInfo.Name), fileInfo.FullName)
};
}
return ProcessFile(fileInfo, importMode, movie, downloadClientItem);
}
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, Movie movie, DownloadClientItem downloadClientItem)
{
if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
{
_logger.Debug("[{0}] starts with '._', skipping", fileInfo.FullName);
return new List<ImportResult>
{
new ImportResult(new ImportDecision(new LocalEpisode { Path = fileInfo.FullName }, new Rejection("Invalid video file, filename starts with '._'")), "Invalid video file, filename starts with '._'")
};
}
if (downloadClientItem == null)
{
if (_diskProvider.IsFileLocked(fileInfo.FullName))
{
return new List<ImportResult>
{
FileIsLockedResult(fileInfo.FullName)
};
}
}
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, movie, null, true);
return _importApprovedMovie.Import(decisions, true, downloadClientItem, importMode);
}
private string GetCleanedUpFolderName(string folder)
{
folder = folder.Replace("_UNPACK_", "")
.Replace("_FAILED_", "");
return folder;
}
private ImportResult FileIsLockedResult(string videoFile)
{
_logger.Debug("[{0}] is currently locked by another process, skipping", videoFile);
return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later");
}
private ImportResult UnknownMovieResult(string message, string videoFile = null)
{
var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile };
return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Movie")), message);
}
}
}

@ -30,11 +30,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
private readonly IDiskScanService _diskScanService; private readonly IDiskScanService _diskScanService;
private readonly IMakeImportDecision _importDecisionMaker; private readonly IMakeImportDecision _importDecisionMaker;
private readonly ISeriesService _seriesService; private readonly ISeriesService _seriesService;
private readonly IMovieService _movieService;
private readonly IEpisodeService _episodeService; private readonly IEpisodeService _episodeService;
private readonly IVideoFileInfoReader _videoFileInfoReader; private readonly IVideoFileInfoReader _videoFileInfoReader;
private readonly IImportApprovedEpisodes _importApprovedEpisodes; private readonly IImportApprovedEpisodes _importApprovedEpisodes;
private readonly IImportApprovedMovie _importApprovedMovie;
private readonly ITrackedDownloadService _trackedDownloadService; private readonly ITrackedDownloadService _trackedDownloadService;
private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService; private readonly IDownloadedEpisodesImportService _downloadedEpisodesImportService;
private readonly IDownloadedMovieImportService _downloadedMovieImportService;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly Logger _logger; private readonly Logger _logger;
@ -43,11 +46,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
IDiskScanService diskScanService, IDiskScanService diskScanService,
IMakeImportDecision importDecisionMaker, IMakeImportDecision importDecisionMaker,
ISeriesService seriesService, ISeriesService seriesService,
IMovieService movieService,
IEpisodeService episodeService, IEpisodeService episodeService,
IVideoFileInfoReader videoFileInfoReader, IVideoFileInfoReader videoFileInfoReader,
IImportApprovedEpisodes importApprovedEpisodes, IImportApprovedEpisodes importApprovedEpisodes,
IImportApprovedMovie importApprovedMovie,
ITrackedDownloadService trackedDownloadService, ITrackedDownloadService trackedDownloadService,
IDownloadedEpisodesImportService downloadedEpisodesImportService, IDownloadedEpisodesImportService downloadedEpisodesImportService,
IDownloadedMovieImportService downloadedMovieImportService,
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
Logger logger) Logger logger)
{ {
@ -56,11 +62,14 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
_diskScanService = diskScanService; _diskScanService = diskScanService;
_importDecisionMaker = importDecisionMaker; _importDecisionMaker = importDecisionMaker;
_seriesService = seriesService; _seriesService = seriesService;
_movieService = movieService;
_episodeService = episodeService; _episodeService = episodeService;
_videoFileInfoReader = videoFileInfoReader; _videoFileInfoReader = videoFileInfoReader;
_importApprovedEpisodes = importApprovedEpisodes; _importApprovedEpisodes = importApprovedEpisodes;
_importApprovedMovie = importApprovedMovie;
_trackedDownloadService = trackedDownloadService; _trackedDownloadService = trackedDownloadService;
_downloadedEpisodesImportService = downloadedEpisodesImportService; _downloadedEpisodesImportService = downloadedEpisodesImportService;
_downloadedMovieImportService = downloadedMovieImportService;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_logger = logger; _logger = logger;
} }
@ -126,62 +135,128 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
var relativeFile = folder.GetRelativePath(file); var relativeFile = folder.GetRelativePath(file);
var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]); var movie = _parsingService.GetMovie(relativeFile.Split('\\', '/')[0]);
if (series == null) if (movie == null)
{ {
series = _parsingService.GetSeries(relativeFile); movie = _parsingService.GetMovie(relativeFile);
} }
if (series == null && downloadId.IsNotNullOrWhiteSpace()) if (movie == null && downloadId.IsNotNullOrWhiteSpace())
{ {
var trackedDownload = _trackedDownloadService.Find(downloadId); var trackedDownload = _trackedDownloadService.Find(downloadId);
series = trackedDownload.RemoteEpisode.Series; movie = trackedDownload.RemoteMovie.Movie;
} }
if (series == null) if (movie == null)
{ {
var localEpisode = new LocalEpisode(); var localMovie = new LocalMovie()
localEpisode.Path = file; {
localEpisode.Quality = QualityParser.ParseQuality(file); Path = file,
localEpisode.Size = _diskProvider.GetFileSize(file); Quality = QualityParser.ParseQuality(file),
Size = _diskProvider.GetFileSize(file)
};
return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId); return MapItem(new ImportDecision(localMovie, new Rejection("Unknown Movie")), folder, downloadId);
} }
var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> {file}, var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> { file },
series, null, SceneSource(series, folder)); movie, null, SceneSource(movie, folder));
return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null; return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null;
} }
//private ManualImportItem ProcessFile(string file, string downloadId, string folder = null)
//{
// if (folder.IsNullOrWhiteSpace())
// {
// folder = new FileInfo(file).Directory.FullName;
// }
// var relativeFile = folder.GetRelativePath(file);
// var series = _parsingService.GetSeries(relativeFile.Split('\\', '/')[0]);
// if (series == null)
// {
// series = _parsingService.GetSeries(relativeFile);
// }
// if (series == null && downloadId.IsNotNullOrWhiteSpace())
// {
// var trackedDownload = _trackedDownloadService.Find(downloadId);
// series = trackedDownload.RemoteEpisode.Series;
// }
// if (series == null)
// {
// var localEpisode = new LocalEpisode();
// localEpisode.Path = file;
// localEpisode.Quality = QualityParser.ParseQuality(file);
// localEpisode.Size = _diskProvider.GetFileSize(file);
// return MapItem(new ImportDecision(localEpisode, new Rejection("Unknown Series")), folder, downloadId);
// }
// var importDecisions = _importDecisionMaker.GetImportDecisions(new List<string> {file},
// series, null, SceneSource(series, folder));
// return importDecisions.Any() ? MapItem(importDecisions.First(), folder, downloadId) : null;
//}
private bool SceneSource(Series series, string folder) private bool SceneSource(Series series, string folder)
{ {
return !(series.Path.PathEquals(folder) || series.Path.IsParentPath(folder)); return !(series.Path.PathEquals(folder) || series.Path.IsParentPath(folder));
} }
private bool SceneSource(Movie movie, string folder)
{
return !(movie.Path.PathEquals(folder) || movie.Path.IsParentPath(folder));
}
//private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId)
//{
// var item = new ManualImportItem();
// item.Path = decision.LocalEpisode.Path;
// item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path);
// item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path);
// item.DownloadId = downloadId;
// if (decision.LocalEpisode.Series != null)
// {
// item.Series = decision.LocalEpisode.Series;
// }
// if (decision.LocalEpisode.Episodes.Any())
// {
// item.SeasonNumber = decision.LocalEpisode.SeasonNumber;
// item.Episodes = decision.LocalEpisode.Episodes;
// }
// item.Quality = decision.LocalEpisode.Quality;
// item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path);
// item.Rejections = decision.Rejections;
// return item;
//}
private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId) private ManualImportItem MapItem(ImportDecision decision, string folder, string downloadId)
{ {
var item = new ManualImportItem(); var item = new ManualImportItem();
item.Path = decision.LocalEpisode.Path; item.Path = decision.LocalMovie.Path;
item.RelativePath = folder.GetRelativePath(decision.LocalEpisode.Path); item.RelativePath = folder.GetRelativePath(decision.LocalMovie.Path);
item.Name = Path.GetFileNameWithoutExtension(decision.LocalEpisode.Path); item.Name = Path.GetFileNameWithoutExtension(decision.LocalMovie.Path);
item.DownloadId = downloadId; item.DownloadId = downloadId;
if (decision.LocalEpisode.Series != null) if (decision.LocalMovie.Movie != null)
{ {
item.Series = decision.LocalEpisode.Series; item.Movie = decision.LocalMovie.Movie;
} }
if (decision.LocalEpisode.Episodes.Any()) item.Quality = decision.LocalMovie.Quality;
{ item.Size = _diskProvider.GetFileSize(decision.LocalMovie.Path);
item.SeasonNumber = decision.LocalEpisode.SeasonNumber;
item.Episodes = decision.LocalEpisode.Episodes;
}
item.Quality = decision.LocalEpisode.Quality;
item.Size = _diskProvider.GetFileSize(decision.LocalEpisode.Path);
item.Rejections = decision.Rejections; item.Rejections = decision.Rejections;
return item; return item;
@ -199,45 +274,43 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
_logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count); _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count);
var file = message.Files[i]; var file = message.Files[i];
var series = _seriesService.GetSeries(file.SeriesId); var movie = _movieService.GetMovie(file.MovieId);
var episodes = _episodeService.GetEpisodes(file.EpisodeIds); var parsedMovieInfo = Parser.Parser.ParseMoviePath(file.Path) ?? new ParsedMovieInfo();
var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path); var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
var existingFile = series.Path.IsParentPath(file.Path); var existingFile = movie.Path.IsParentPath(file.Path);
var localEpisode = new LocalEpisode var localMovie = new LocalMovie
{ {
ExistingFile = false, ExistingFile = false,
Episodes = episodes,
MediaInfo = mediaInfo, MediaInfo = mediaInfo,
ParsedEpisodeInfo = parsedEpisodeInfo, ParsedMovieInfo = parsedMovieInfo,
Path = file.Path, Path = file.Path,
Quality = file.Quality, Quality = file.Quality,
Series = series, Movie = movie,
Size = 0 Size = 0
}; };
//TODO: Cleanup non-tracked downloads //TODO: Cleanup non-tracked downloads
var importDecision = new ImportDecision(localEpisode); var importDecision = new ImportDecision(localMovie);
if (file.DownloadId.IsNullOrWhiteSpace()) if (file.DownloadId.IsNullOrWhiteSpace())
{ {
imported.AddRange(_importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode)); imported.AddRange(_importApprovedMovie.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode));
} }
else else
{ {
var trackedDownload = _trackedDownloadService.Find(file.DownloadId); var trackedDownload = _trackedDownloadService.Find(file.DownloadId);
var importResult = _importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); var importResult = _importApprovedMovie.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First();
imported.Add(importResult); imported.Add(importResult);
importedTrackedDownload.Add(new ManuallyImportedFile importedTrackedDownload.Add(new ManuallyImportedFile
{ {
TrackedDownload = trackedDownload, TrackedDownload = trackedDownload,
ImportResult = importResult ImportResult = importResult
}); });
} }
} }
@ -249,20 +322,98 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Manual
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath)) if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
{ {
if (_downloadedEpisodesImportService.ShouldDeleteFolder( if (_downloadedMovieImportService.ShouldDeleteFolder(
new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath), new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly) trackedDownload.RemoteMovie.Movie) && !trackedDownload.DownloadItem.IsReadOnly)
{ {
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true); _diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
} }
} }
if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count)) if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, 1)) //TODO: trackedDownload.RemoteMovie.Movie.Count is always 1?
{ {
trackedDownload.State = TrackedDownloadStage.Imported; trackedDownload.State = TrackedDownloadStage.Imported;
_eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload)); _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
} }
} }
} }
//public void Execute(ManualImportCommand message)
//{
// _logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode);
// var imported = new List<ImportResult>();
// var importedTrackedDownload = new List<ManuallyImportedFile>();
// for (int i = 0; i < message.Files.Count; i++)
// {
// _logger.ProgressTrace("Processing file {0} of {1}", i + 1, message.Files.Count);
// var file = message.Files[i];
// var series = _seriesService.GetSeries(file.SeriesId);
// var episodes = _episodeService.GetEpisodes(file.EpisodeIds);
// var parsedEpisodeInfo = Parser.Parser.ParsePath(file.Path) ?? new ParsedEpisodeInfo();
// var mediaInfo = _videoFileInfoReader.GetMediaInfo(file.Path);
// var existingFile = series.Path.IsParentPath(file.Path);
// var localEpisode = new LocalEpisode
// {
// ExistingFile = false,
// Episodes = episodes,
// MediaInfo = mediaInfo,
// ParsedEpisodeInfo = parsedEpisodeInfo,
// Path = file.Path,
// Quality = file.Quality,
// Series = series,
// Size = 0
// };
// //TODO: Cleanup non-tracked downloads
// var importDecision = new ImportDecision(localEpisode);
// if (file.DownloadId.IsNullOrWhiteSpace())
// {
// imported.AddRange(_importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, !existingFile, null, message.ImportMode));
// }
// else
// {
// var trackedDownload = _trackedDownloadService.Find(file.DownloadId);
// var importResult = _importApprovedEpisodes.Import(new List<ImportDecision> { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First();
// imported.Add(importResult);
// importedTrackedDownload.Add(new ManuallyImportedFile
// {
// TrackedDownload = trackedDownload,
// ImportResult = importResult
// });
// }
// }
// _logger.ProgressTrace("Manually imported {0} files", imported.Count);
// foreach (var groupedTrackedDownload in importedTrackedDownload.GroupBy(i => i.TrackedDownload.DownloadItem.DownloadId).ToList())
// {
// var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
// if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
// {
// if (_downloadedEpisodesImportService.ShouldDeleteFolder(
// new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
// trackedDownload.RemoteEpisode.Series) && !trackedDownload.DownloadItem.IsReadOnly)
// {
// _diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
// }
// }
// if (groupedTrackedDownload.Select(c => c.ImportResult).Count(c => c.Result == ImportResultType.Imported) >= Math.Max(1, trackedDownload.RemoteEpisode.Episodes.Count))
// {
// trackedDownload.State = TrackedDownloadStage.Imported;
// _eventAggregator.PublishEvent(new DownloadCompletedEvent(trackedDownload));
// }
// }
//}
} }
} }

@ -707,10 +707,12 @@
<Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" /> <Compile Include="MediaFiles\Commands\BackendCommandAttribute.cs" />
<Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" /> <Compile Include="MediaFiles\Commands\CleanUpRecycleBinCommand.cs" />
<Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" /> <Compile Include="MediaFiles\Commands\DownloadedEpisodesScanCommand.cs" />
<Compile Include="MediaFiles\Commands\DownloadedMovieScanCommand.cs" />
<Compile Include="MediaFiles\Commands\RenameMovieCommand.cs" /> <Compile Include="MediaFiles\Commands\RenameMovieCommand.cs" />
<Compile Include="MediaFiles\Commands\RenameMovieFilesCommand.cs" /> <Compile Include="MediaFiles\Commands\RenameMovieFilesCommand.cs" />
<Compile Include="MediaFiles\Commands\RescanMovieCommand.cs" /> <Compile Include="MediaFiles\Commands\RescanMovieCommand.cs" />
<Compile Include="MediaFiles\DownloadedMovieCommandService.cs" /> <Compile Include="MediaFiles\DownloadedMovieCommandService.cs" />
<Compile Include="MediaFiles\DownloadedMovieImportService.cs" />
<Compile Include="MediaFiles\MovieFileMovingService.cs" /> <Compile Include="MediaFiles\MovieFileMovingService.cs" />
<Compile Include="MediaFiles\Events\MovieDownloadedEvent.cs" /> <Compile Include="MediaFiles\Events\MovieDownloadedEvent.cs" />
<Compile Include="MediaFiles\Events\MovieFileAddedEvent.cs" /> <Compile Include="MediaFiles\Events\MovieFileAddedEvent.cs" />

@ -168,8 +168,8 @@ module.exports = Marionette.Layout.extend({
}, },
_automaticImport : function (e) { _automaticImport : function (e) {
CommandController.Execute('downloadedEpisodesScan', { CommandController.Execute('downloadedMovieScan', {
name : 'downloadedEpisodesScan', name : 'downloadedMovieScan',
path : e.folder path : e.folder
}); });

@ -23,7 +23,7 @@
</div> </div>
<div class="col-sm-2 col-sm-pull-1"> <div class="col-sm-2 col-sm-pull-1">
<input type="number" name="downloadedEpisodesScanInterval" class="form-control" /> <input type="number" name="downloadedMovieScanInterval" class="form-control" />
</div> </div>
</div> </div>
</fieldset> </fieldset>

@ -133,7 +133,7 @@ module.exports = Marionette.Layout.extend({
{ {
title : 'Rescan Drone Factory Folder', title : 'Rescan Drone Factory Folder',
icon : 'icon-sonarr-refresh', icon : 'icon-sonarr-refresh',
command : 'downloadedepisodesscan', command : 'downloadedMovieScan',
properties : { sendUpdates : true } properties : { sendUpdates : true }
}, },
{ {

Loading…
Cancel
Save