New: Custom import scripts can communicate information back
This commit is contained in:
parent
3541cd7ba8
commit
b4ac495983
|
@ -267,7 +267,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
||||||
Subject.Scan(_series);
|
Subject.Scan(_series);
|
||||||
|
|
||||||
Mocker.GetMock<IDiskProvider>()
|
Mocker.GetMock<IDiskProvider>()
|
||||||
.Verify(v => v.GetFiles(It.IsAny<string>(), It.IsAny<bool>()), Times.Once());
|
.Verify(v => v.GetFiles(It.IsAny<string>(), It.IsAny<bool>()), Times.Exactly(2));
|
||||||
|
|
||||||
Mocker.GetMock<IMakeImportDecision>()
|
Mocker.GetMock<IMakeImportDecision>()
|
||||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series, false), Times.Once());
|
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _series, false), Times.Once());
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using FizzWare.NBuilder;
|
using FizzWare.NBuilder;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
@ -71,7 +72,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
GivenFileExists();
|
GivenFileExists();
|
||||||
GivenSuccessfulScan();
|
GivenSuccessfulScan();
|
||||||
|
|
||||||
Subject.Handle(new SeriesScannedEvent(_series));
|
Subject.Handle(new SeriesScannedEvent(_series, new List<string>()));
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>()
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2));
|
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2));
|
||||||
|
@ -97,7 +98,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
GivenFileExists();
|
GivenFileExists();
|
||||||
GivenSuccessfulScan();
|
GivenSuccessfulScan();
|
||||||
|
|
||||||
Subject.Handle(new SeriesScannedEvent(_series));
|
Subject.Handle(new SeriesScannedEvent(_series, new List<string>()));
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>()
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2));
|
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2));
|
||||||
|
@ -123,7 +124,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
GivenFileExists();
|
GivenFileExists();
|
||||||
GivenSuccessfulScan();
|
GivenSuccessfulScan();
|
||||||
|
|
||||||
Subject.Handle(new SeriesScannedEvent(_series));
|
Subject.Handle(new SeriesScannedEvent(_series, new List<string>()));
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>()
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(3));
|
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(3));
|
||||||
|
@ -146,7 +147,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
|
|
||||||
GivenSuccessfulScan();
|
GivenSuccessfulScan();
|
||||||
|
|
||||||
Subject.Handle(new SeriesScannedEvent(_series));
|
Subject.Handle(new SeriesScannedEvent(_series, new List<string>()));
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>()
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
.Verify(v => v.GetMediaInfo("media.mkv"), Times.Never());
|
.Verify(v => v.GetMediaInfo("media.mkv"), Times.Never());
|
||||||
|
@ -173,7 +174,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
GivenSuccessfulScan();
|
GivenSuccessfulScan();
|
||||||
GivenFailedScan(Path.Combine(_series.Path, "media2.mkv"));
|
GivenFailedScan(Path.Combine(_series.Path, "media2.mkv"));
|
||||||
|
|
||||||
Subject.Handle(new SeriesScannedEvent(_series));
|
Subject.Handle(new SeriesScannedEvent(_series, new List<string>()));
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>()
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(1));
|
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(1));
|
||||||
|
@ -203,7 +204,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||||
GivenFileExists();
|
GivenFileExists();
|
||||||
GivenSuccessfulScan();
|
GivenSuccessfulScan();
|
||||||
|
|
||||||
Subject.Handle(new SeriesScannedEvent(_series));
|
Subject.Handle(new SeriesScannedEvent(_series, new List<string>()));
|
||||||
|
|
||||||
Mocker.GetMock<IVideoFileInfoReader>()
|
Mocker.GetMock<IVideoFileInfoReader>()
|
||||||
.Verify(v => v.GetMediaInfo(It.IsAny<string>()), Times.Never());
|
.Verify(v => v.GetMediaInfo(It.IsAny<string>()), Times.Never());
|
||||||
|
|
|
@ -2,45 +2,33 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
|
||||||
using NzbDrone.Core.MediaFiles;
|
|
||||||
using NzbDrone.Core.MediaFiles.Events;
|
using NzbDrone.Core.MediaFiles.Events;
|
||||||
using NzbDrone.Core.Messaging.Events;
|
using NzbDrone.Core.Messaging.Events;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.Extras
|
namespace NzbDrone.Core.Extras
|
||||||
{
|
{
|
||||||
public class ExistingExtraFileService : IHandle<SeriesScannedEvent>
|
public interface IExistingExtraFiles
|
||||||
|
{
|
||||||
|
List<string> ImportExtraFiles(Series series, List<string> possibleExtraFiles);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ExistingExtraFileService : IExistingExtraFiles, IHandle<SeriesScannedEvent>
|
||||||
{
|
{
|
||||||
private readonly IDiskProvider _diskProvider;
|
|
||||||
private readonly IDiskScanService _diskScanService;
|
|
||||||
private readonly List<IImportExistingExtraFiles> _existingExtraFileImporters;
|
private readonly List<IImportExistingExtraFiles> _existingExtraFileImporters;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ExistingExtraFileService(IDiskProvider diskProvider,
|
public ExistingExtraFileService(IEnumerable<IImportExistingExtraFiles> existingExtraFileImporters,
|
||||||
IDiskScanService diskScanService,
|
|
||||||
IEnumerable<IImportExistingExtraFiles> existingExtraFileImporters,
|
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_diskProvider = diskProvider;
|
|
||||||
_diskScanService = diskScanService;
|
|
||||||
_existingExtraFileImporters = existingExtraFileImporters.OrderBy(e => e.Order).ToList();
|
_existingExtraFileImporters = existingExtraFileImporters.OrderBy(e => e.Order).ToList();
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(SeriesScannedEvent message)
|
public List<string> ImportExtraFiles(Series series, List<string> possibleExtraFiles)
|
||||||
{
|
{
|
||||||
var series = message.Series;
|
|
||||||
|
|
||||||
if (!_diskProvider.FolderExists(series.Path))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_logger.Debug("Looking for existing extra files in {0}", series.Path);
|
_logger.Debug("Looking for existing extra files in {0}", series.Path);
|
||||||
|
|
||||||
var filesOnDisk = _diskScanService.GetNonVideoFiles(series.Path);
|
|
||||||
var possibleExtraFiles = _diskScanService.FilterPaths(series.Path, filesOnDisk);
|
|
||||||
|
|
||||||
var importedFiles = new List<string>();
|
var importedFiles = new List<string>();
|
||||||
|
|
||||||
foreach (var existingExtraFileImporter in _existingExtraFileImporters)
|
foreach (var existingExtraFileImporter in _existingExtraFileImporters)
|
||||||
|
@ -50,6 +38,15 @@ namespace NzbDrone.Core.Extras
|
||||||
importedFiles.AddRange(imported.Select(f => Path.Combine(series.Path, f.RelativePath)));
|
importedFiles.AddRange(imported.Select(f => Path.Combine(series.Path, f.RelativePath)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return importedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Handle(SeriesScannedEvent message)
|
||||||
|
{
|
||||||
|
var series = message.Series;
|
||||||
|
var possibleExtraFiles = message.PossibleExtraFiles;
|
||||||
|
var importedFiles = ImportExtraFiles(series, possibleExtraFiles);
|
||||||
|
|
||||||
_logger.Info("Found {0} possible extra files, imported {1} files.", possibleExtraFiles.Count, importedFiles.Count);
|
_logger.Info("Found {0} possible extra files, imported {1} files.", possibleExtraFiles.Count, importedFiles.Count);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace NzbDrone.Core.Extras
|
||||||
{
|
{
|
||||||
public interface IExtraService
|
public interface IExtraService
|
||||||
{
|
{
|
||||||
|
void MoveFilesAfterRename(Series series, EpisodeFile episodeFile);
|
||||||
void ImportEpisode(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly);
|
void ImportEpisode(LocalEpisode localEpisode, EpisodeFile episodeFile, bool isReadOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,6 +140,16 @@ namespace NzbDrone.Core.Extras
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void MoveFilesAfterRename(Series series, EpisodeFile episodeFile)
|
||||||
|
{
|
||||||
|
var episodeFiles = new List<EpisodeFile> { episodeFile };
|
||||||
|
|
||||||
|
foreach (var extraFileManager in _extraFileManagers)
|
||||||
|
{
|
||||||
|
extraFileManager.MoveFilesAfterRename(series, episodeFiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Handle(SeriesRenamedEvent message)
|
public void Handle(SeriesRenamedEvent message)
|
||||||
{
|
{
|
||||||
var series = message.Series;
|
var series = message.Series;
|
||||||
|
|
|
@ -121,7 +121,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
}
|
}
|
||||||
|
|
||||||
CleanMediaFiles(series, new List<string>());
|
CleanMediaFiles(series, new List<string>());
|
||||||
CompletedScanning(series);
|
CompletedScanning(series, new List<string>());
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -174,8 +174,11 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
fileInfoStopwatch.Stop();
|
fileInfoStopwatch.Stop();
|
||||||
_logger.Trace("Reprocessing existing files complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
|
_logger.Trace("Reprocessing existing files complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
|
||||||
|
|
||||||
|
var filesOnDisk = GetNonVideoFiles(series.Path);
|
||||||
|
var possibleExtraFiles = FilterPaths(series.Path, filesOnDisk);
|
||||||
|
|
||||||
RemoveEmptySeriesFolder(series.Path);
|
RemoveEmptySeriesFolder(series.Path);
|
||||||
CompletedScanning(series);
|
CompletedScanning(series, possibleExtraFiles);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CleanMediaFiles(Series series, List<string> mediaFileList)
|
private void CleanMediaFiles(Series series, List<string> mediaFileList)
|
||||||
|
@ -184,10 +187,10 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
_mediaFileTableCleanupService.Clean(series, mediaFileList);
|
_mediaFileTableCleanupService.Clean(series, mediaFileList);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CompletedScanning(Series series)
|
private void CompletedScanning(Series series, List<string> possibleExtraFiles)
|
||||||
{
|
{
|
||||||
_logger.Info("Completed scanning disk for {0}", series.Title);
|
_logger.Info("Completed scanning disk for {0}", series.Title);
|
||||||
_eventAggregator.PublishEvent(new SeriesScannedEvent(series));
|
_eventAggregator.PublishEvent(new SeriesScannedEvent(series, possibleExtraFiles));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string[] GetVideoFiles(string path, bool allDirectories = true)
|
public string[] GetVideoFiles(string path, bool allDirectories = true)
|
||||||
|
|
|
@ -130,6 +130,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
MoveEpisodeFile(episodeFile, series, episodeFile.Episodes);
|
MoveEpisodeFile(episodeFile, series, episodeFile.Episodes);
|
||||||
|
localEpisode.FileRenamedAfterScriptImport = true;
|
||||||
}
|
}
|
||||||
catch (SameFilenameException)
|
catch (SameFilenameException)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||||
private readonly IUpgradeMediaFiles _episodeFileUpgrader;
|
private readonly IUpgradeMediaFiles _episodeFileUpgrader;
|
||||||
private readonly IMediaFileService _mediaFileService;
|
private readonly IMediaFileService _mediaFileService;
|
||||||
private readonly IExtraService _extraService;
|
private readonly IExtraService _extraService;
|
||||||
|
private readonly IExistingExtraFiles _existingExtraFiles;
|
||||||
private readonly IDiskProvider _diskProvider;
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IManageCommandQueue _commandQueueManager;
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
|
@ -34,6 +35,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||||
public ImportApprovedEpisodes(IUpgradeMediaFiles episodeFileUpgrader,
|
public ImportApprovedEpisodes(IUpgradeMediaFiles episodeFileUpgrader,
|
||||||
IMediaFileService mediaFileService,
|
IMediaFileService mediaFileService,
|
||||||
IExtraService extraService,
|
IExtraService extraService,
|
||||||
|
IExistingExtraFiles existingExtraFiles,
|
||||||
IDiskProvider diskProvider,
|
IDiskProvider diskProvider,
|
||||||
IEventAggregator eventAggregator,
|
IEventAggregator eventAggregator,
|
||||||
IManageCommandQueue commandQueueManager,
|
IManageCommandQueue commandQueueManager,
|
||||||
|
@ -42,6 +44,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||||
_episodeFileUpgrader = episodeFileUpgrader;
|
_episodeFileUpgrader = episodeFileUpgrader;
|
||||||
_mediaFileService = mediaFileService;
|
_mediaFileService = mediaFileService;
|
||||||
_extraService = extraService;
|
_extraService = extraService;
|
||||||
|
_existingExtraFiles = existingExtraFiles;
|
||||||
_diskProvider = diskProvider;
|
_diskProvider = diskProvider;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_commandQueueManager = commandQueueManager;
|
_commandQueueManager = commandQueueManager;
|
||||||
|
@ -129,9 +132,22 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
||||||
importResults.Add(new ImportResult(importDecision));
|
importResults.Add(new ImportResult(importDecision));
|
||||||
|
|
||||||
if (newDownload)
|
if (newDownload)
|
||||||
|
{
|
||||||
|
if (localEpisode.ScriptImported)
|
||||||
|
{
|
||||||
|
_existingExtraFiles.ImportExtraFiles(localEpisode.Series, localEpisode.PossibleExtraFiles);
|
||||||
|
|
||||||
|
if (localEpisode.FileRenamedAfterScriptImport)
|
||||||
|
{
|
||||||
|
_extraService.MoveFilesAfterRename(localEpisode.Series, episodeFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!localEpisode.ScriptImported || localEpisode.ShouldImportExtras)
|
||||||
{
|
{
|
||||||
_extraService.ImportEpisode(localEpisode, episodeFile, copyOnly);
|
_extraService.ImportEpisode(localEpisode, episodeFile, copyOnly);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, oldFiles, newDownload, downloadClientItem));
|
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, oldFiles, newDownload, downloadClientItem));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using NzbDrone.Common.Messaging;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Messaging;
|
||||||
using NzbDrone.Core.Tv;
|
using NzbDrone.Core.Tv;
|
||||||
|
|
||||||
namespace NzbDrone.Core.MediaFiles.Events
|
namespace NzbDrone.Core.MediaFiles.Events
|
||||||
|
@ -6,10 +7,12 @@ namespace NzbDrone.Core.MediaFiles.Events
|
||||||
public class SeriesScannedEvent : IEvent
|
public class SeriesScannedEvent : IEvent
|
||||||
{
|
{
|
||||||
public Series Series { get; private set; }
|
public Series Series { get; private set; }
|
||||||
|
public List<string> PossibleExtraFiles { get; set; }
|
||||||
|
|
||||||
public SeriesScannedEvent(Series series)
|
public SeriesScannedEvent(Series series, List<string> possibleExtraFiles)
|
||||||
{
|
{
|
||||||
Series = series;
|
Series = series;
|
||||||
|
PossibleExtraFiles = possibleExtraFiles;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Disk;
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Extensions;
|
using NzbDrone.Common.Extensions;
|
||||||
|
@ -25,6 +27,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
private readonly IProcessProvider _processProvider;
|
private readonly IProcessProvider _processProvider;
|
||||||
private readonly IConfigService _configService;
|
private readonly IConfigService _configService;
|
||||||
private readonly ITagRepository _tagRepository;
|
private readonly ITagRepository _tagRepository;
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
private readonly Logger _logger;
|
private readonly Logger _logger;
|
||||||
|
|
||||||
public ImportScriptService(IProcessProvider processProvider,
|
public ImportScriptService(IProcessProvider processProvider,
|
||||||
|
@ -32,6 +35,7 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
IConfigService configService,
|
IConfigService configService,
|
||||||
IConfigFileProvider configFileProvider,
|
IConfigFileProvider configFileProvider,
|
||||||
ITagRepository tagRepository,
|
ITagRepository tagRepository,
|
||||||
|
IDiskProvider diskProvider,
|
||||||
Logger logger)
|
Logger logger)
|
||||||
{
|
{
|
||||||
_processProvider = processProvider;
|
_processProvider = processProvider;
|
||||||
|
@ -39,9 +43,73 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
_configService = configService;
|
_configService = configService;
|
||||||
_configFileProvider = configFileProvider;
|
_configFileProvider = configFileProvider;
|
||||||
_tagRepository = tagRepository;
|
_tagRepository = tagRepository;
|
||||||
|
_diskProvider = diskProvider;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly Regex OutputRegex = new Regex(@"^(?:\[(?:(?<mediaFile>MediaFile)|(?<extraFile>ExtraFile))\]\s?(?<fileName>.+)|(?<preventExtraImport>\[PreventExtraImport\])|\[MoveStatus\]\s?(?:(?<deferMove>DeferMove)|(?<moveComplete>MoveComplete)|(?<renameRequested>RenameRequested)))$", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
private ScriptImportInfo ProcessOutput(List<ProcessOutputLine> processOutputLines)
|
||||||
|
{
|
||||||
|
var possibleExtraFiles = new List<string>();
|
||||||
|
string mediaFile = null;
|
||||||
|
var decision = ScriptImportDecision.MoveComplete;
|
||||||
|
var importExtraFiles = true;
|
||||||
|
|
||||||
|
foreach (var line in processOutputLines)
|
||||||
|
{
|
||||||
|
var match = OutputRegex.Match(line.Content);
|
||||||
|
|
||||||
|
if (match.Groups["mediaFile"].Success)
|
||||||
|
{
|
||||||
|
if (mediaFile is not null)
|
||||||
|
{
|
||||||
|
throw new ScriptImportException("Script output contains multiple media files. Only one media file can be returned.");
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaFile = match.Groups["fileName"].Value;
|
||||||
|
|
||||||
|
if (!MediaFileExtensions.Extensions.Contains(Path.GetExtension(mediaFile)))
|
||||||
|
{
|
||||||
|
throw new ScriptImportException("Script output contains invalid media file: {0}", mediaFile);
|
||||||
|
}
|
||||||
|
else if (!_diskProvider.FileExists(mediaFile))
|
||||||
|
{
|
||||||
|
throw new ScriptImportException("Script output contains non-existent media file: {0}", mediaFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (match.Groups["extraFile"].Success)
|
||||||
|
{
|
||||||
|
var fileName = match.Groups["fileName"].Value;
|
||||||
|
|
||||||
|
if (!_diskProvider.FileExists(fileName))
|
||||||
|
{
|
||||||
|
_logger.Warn("Script output contains non-existent possible extra file: {0}", fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
possibleExtraFiles.Add(fileName);
|
||||||
|
}
|
||||||
|
else if (match.Groups["moveComplete"].Success)
|
||||||
|
{
|
||||||
|
decision = ScriptImportDecision.MoveComplete;
|
||||||
|
}
|
||||||
|
else if (match.Groups["renameRequested"].Success)
|
||||||
|
{
|
||||||
|
decision = ScriptImportDecision.RenameRequested;
|
||||||
|
}
|
||||||
|
else if (match.Groups["deferMove"].Success)
|
||||||
|
{
|
||||||
|
decision = ScriptImportDecision.DeferMove;
|
||||||
|
}
|
||||||
|
else if (match.Groups["preventExtraImport"].Success)
|
||||||
|
{
|
||||||
|
importExtraFiles = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ScriptImportInfo(possibleExtraFiles, mediaFile, decision, importExtraFiles);
|
||||||
|
}
|
||||||
|
|
||||||
public ScriptImportDecision TryImport(string sourcePath, string destinationFilePath, LocalEpisode localEpisode, EpisodeFile episodeFile, TransferMode mode)
|
public ScriptImportDecision TryImport(string sourcePath, string destinationFilePath, LocalEpisode localEpisode, EpisodeFile episodeFile, TransferMode mode)
|
||||||
{
|
{
|
||||||
var series = localEpisode.Series;
|
var series = localEpisode.Series;
|
||||||
|
@ -115,22 +183,37 @@ namespace NzbDrone.Core.MediaFiles
|
||||||
|
|
||||||
var processOutput = _processProvider.StartAndCapture(_configService.ScriptImportPath, $"\"{sourcePath}\" \"{destinationFilePath}\"", environmentVariables);
|
var processOutput = _processProvider.StartAndCapture(_configService.ScriptImportPath, $"\"{sourcePath}\" \"{destinationFilePath}\"", environmentVariables);
|
||||||
|
|
||||||
_logger.Debug("Executed external script: {0} - Status: {1}", _configService.ScriptImportPath, processOutput.ExitCode);
|
|
||||||
_logger.Debug("Script Output: \r\n{0}", string.Join("\r\n", processOutput.Lines));
|
_logger.Debug("Script Output: \r\n{0}", string.Join("\r\n", processOutput.Lines));
|
||||||
|
|
||||||
switch (processOutput.ExitCode)
|
if (processOutput.ExitCode != 0)
|
||||||
{
|
{
|
||||||
case 0: // Copy complete
|
throw new ScriptImportException("Script exited with non-zero exit code: {0}", processOutput.ExitCode);
|
||||||
return ScriptImportDecision.MoveComplete;
|
|
||||||
case 2: // Copy complete, file potentially changed, should try renaming again
|
|
||||||
episodeFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(destinationFilePath);
|
|
||||||
episodeFile.Path = null;
|
|
||||||
return ScriptImportDecision.RenameRequested;
|
|
||||||
case 3: // Let Sonarr handle it
|
|
||||||
return ScriptImportDecision.DeferMove;
|
|
||||||
default: // Error, fail to import
|
|
||||||
throw new ScriptImportException("Moving with script failed! Exit code {0}", processOutput.ExitCode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var scriptImportInfo = ProcessOutput(processOutput.Lines);
|
||||||
|
|
||||||
|
var mediaFile = scriptImportInfo.MediaFile ?? destinationFilePath;
|
||||||
|
localEpisode.PossibleExtraFiles = scriptImportInfo.PossibleExtraFiles;
|
||||||
|
|
||||||
|
episodeFile.RelativePath = series.Path.GetRelativePath(mediaFile);
|
||||||
|
episodeFile.Path = mediaFile;
|
||||||
|
|
||||||
|
var exitCode = processOutput.ExitCode;
|
||||||
|
|
||||||
|
localEpisode.ShouldImportExtras = scriptImportInfo.ImportExtraFiles;
|
||||||
|
|
||||||
|
if (scriptImportInfo.Decision != ScriptImportDecision.DeferMove)
|
||||||
|
{
|
||||||
|
localEpisode.ScriptImported = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scriptImportInfo.Decision == ScriptImportDecision.RenameRequested)
|
||||||
|
{
|
||||||
|
episodeFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(mediaFile);
|
||||||
|
episodeFile.Path = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return scriptImportInfo.Decision;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles
|
||||||
|
{
|
||||||
|
public struct ScriptImportInfo
|
||||||
|
{
|
||||||
|
public List<string> PossibleExtraFiles { get; set; }
|
||||||
|
public string MediaFile { get; set; }
|
||||||
|
public ScriptImportDecision Decision { get; set; }
|
||||||
|
public bool ImportExtraFiles { get; set; }
|
||||||
|
|
||||||
|
public ScriptImportInfo(List<string> possibleExtraFiles, string mediaFile, ScriptImportDecision decision, bool importExtraFiles)
|
||||||
|
{
|
||||||
|
PossibleExtraFiles = possibleExtraFiles;
|
||||||
|
MediaFile = mediaFile;
|
||||||
|
Decision = decision;
|
||||||
|
ImportExtraFiles = importExtraFiles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,6 +40,10 @@ namespace NzbDrone.Core.Parser.Model
|
||||||
public List<CustomFormat> CustomFormats { get; set; }
|
public List<CustomFormat> CustomFormats { get; set; }
|
||||||
public int CustomFormatScore { get; set; }
|
public int CustomFormatScore { get; set; }
|
||||||
public GrabbedReleaseInfo Release { get; set; }
|
public GrabbedReleaseInfo Release { get; set; }
|
||||||
|
public bool ScriptImported { get; set; }
|
||||||
|
public bool FileRenamedAfterScriptImport { get; set; }
|
||||||
|
public bool ShouldImportExtras { get; set; }
|
||||||
|
public List<string> PossibleExtraFiles { get; set; }
|
||||||
|
|
||||||
public int SeasonNumber
|
public int SeasonNumber
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue