WIP: communication back from custom import script

This commit is contained in:
Jendrik Weise 2023-08-22 14:42:00 +02:00
parent 7986488c6d
commit 6d0f73e641
6 changed files with 127 additions and 13 deletions

View File

@ -6,10 +6,16 @@ using NzbDrone.Common.Disk;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.Events;
using NzbDrone.Core.Messaging.Events;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Extras
{
public class ExistingExtraFileService : IHandle<SeriesScannedEvent>
public interface IExistingExtraFiles : IHandle<SeriesScannedEvent>
{
List<string> ImportFileList(Series series, List<string> possibleExtraFiles);
}
public class ExistingExtraFileService : IExistingExtraFiles
{
private readonly IDiskProvider _diskProvider;
private readonly IDiskScanService _diskScanService;
@ -27,20 +33,10 @@ namespace NzbDrone.Core.Extras
_logger = logger;
}
public void Handle(SeriesScannedEvent message)
public List<string> ImportFileList(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);
var filesOnDisk = _diskScanService.GetNonVideoFiles(series.Path);
var possibleExtraFiles = _diskScanService.FilterPaths(series.Path, filesOnDisk);
var importedFiles = new List<string>();
foreach (var existingExtraFileImporter in _existingExtraFileImporters)
@ -50,6 +46,23 @@ namespace NzbDrone.Core.Extras
importedFiles.AddRange(imported.Select(f => Path.Combine(series.Path, f.RelativePath)));
}
return importedFiles;
}
public void Handle(SeriesScannedEvent message)
{
var series = message.Series;
if (!_diskProvider.FolderExists(series.Path))
{
return;
}
var filesOnDisk = _diskScanService.GetNonVideoFiles(series.Path);
var possibleExtraFiles = _diskScanService.FilterPaths(series.Path, filesOnDisk);
var importedFiles = ImportFileList(series, possibleExtraFiles);
_logger.Info("Found {0} possible extra files, imported {1} files.", possibleExtraFiles.Count, importedFiles.Count);
}
}

View File

@ -17,6 +17,7 @@ namespace NzbDrone.Core.Extras
{
public interface IExtraService
{
void MoveFilesAfterRename(Series series, EpisodeFile episodeFile);
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)
{
var series = message.Series;

View File

@ -130,6 +130,7 @@ namespace NzbDrone.Core.MediaFiles
try
{
MoveEpisodeFile(episodeFile, series, episodeFile.Episodes);
localEpisode.ImportRenamed = true;
}
catch (SameFilenameException)
{

View File

@ -26,6 +26,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
private readonly IUpgradeMediaFiles _episodeFileUpgrader;
private readonly IMediaFileService _mediaFileService;
private readonly IExtraService _extraService;
private readonly IExistingExtraFiles _existingExtraFiles;
private readonly IDiskProvider _diskProvider;
private readonly IEventAggregator _eventAggregator;
private readonly IManageCommandQueue _commandQueueManager;
@ -34,6 +35,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public ImportApprovedEpisodes(IUpgradeMediaFiles episodeFileUpgrader,
IMediaFileService mediaFileService,
IExtraService extraService,
IExistingExtraFiles existingExtraFiles,
IDiskProvider diskProvider,
IEventAggregator eventAggregator,
IManageCommandQueue commandQueueManager,
@ -42,6 +44,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_episodeFileUpgrader = episodeFileUpgrader;
_mediaFileService = mediaFileService;
_extraService = extraService;
_existingExtraFiles = existingExtraFiles;
_diskProvider = diskProvider;
_eventAggregator = eventAggregator;
_commandQueueManager = commandQueueManager;
@ -130,7 +133,19 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
if (newDownload)
{
_extraService.ImportEpisode(localEpisode, episodeFile, copyOnly);
if (localEpisode.ScriptImported)
{
_existingExtraFiles.ImportFileList(localEpisode.Series, localEpisode.PossibleExtraFiles);
if (localEpisode.ImportRenamed)
{
_extraService.MoveFilesAfterRename(localEpisode.Series, episodeFile);
}
}
else
{
_extraService.ImportEpisode(localEpisode, episodeFile, copyOnly);
}
}
_eventAggregator.PublishEvent(new EpisodeImportedEvent(localEpisode, episodeFile, oldFiles, newDownload, downloadClientItem));

View File

@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
@ -6,6 +7,7 @@ using NzbDrone.Common.Disk;
using NzbDrone.Common.Extensions;
using NzbDrone.Common.Processes;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Extras;
using NzbDrone.Core.MediaFiles.MediaInfo;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@ -25,6 +27,7 @@ namespace NzbDrone.Core.MediaFiles
private readonly IProcessProvider _processProvider;
private readonly IConfigService _configService;
private readonly ITagRepository _tagRepository;
private readonly IExistingExtraFiles _existingExtraFiles;
private readonly Logger _logger;
public ImportScriptService(IProcessProvider processProvider,
@ -32,6 +35,7 @@ namespace NzbDrone.Core.MediaFiles
IConfigService configService,
IConfigFileProvider configFileProvider,
ITagRepository tagRepository,
IExistingExtraFiles existingExtraFiles,
Logger logger)
{
_processProvider = processProvider;
@ -39,9 +43,63 @@ namespace NzbDrone.Core.MediaFiles
_configService = configService;
_configFileProvider = configFileProvider;
_tagRepository = tagRepository;
_existingExtraFiles = existingExtraFiles;
_logger = logger;
}
private (List<string> possibleMediaFiles, string mediaFile) ProcessTemporaryFile(string temporaryPath)
{
var lines = File.ReadAllLines(temporaryPath);
if (lines.Length == 0 || string.IsNullOrWhiteSpace(lines[0]))
{
return (new List<string>(), null);
}
var possibleExtraFiles = new List<string>();
string mediaFile = null;
foreach (var line in lines)
{
if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(line)))
{
if (mediaFile is not null)
{
throw new ScriptImportException("Script output contains multiple media files. Only one media file can be returned.");
}
else
{
if (File.Exists(line))
{
mediaFile = line;
}
else
{
_logger.Warn("Script output contains invalid file: {0}", line);
}
}
}
else
{
if (File.Exists(line))
{
possibleExtraFiles.Add(line);
}
else
{
_logger.Warn("Script output contains invalid file: {0}", line);
}
}
}
if (mediaFile is not null)
{
throw new ScriptImportException("Script output does not contain a media file.");
}
return (possibleExtraFiles, mediaFile);
}
public ScriptImportDecision TryImport(string sourcePath, string destinationFilePath, LocalEpisode localEpisode, EpisodeFile episodeFile, TransferMode mode)
{
var series = localEpisode.Series;
@ -54,10 +112,13 @@ namespace NzbDrone.Core.MediaFiles
return ScriptImportDecision.DeferMove;
}
var temporaryPath = Path.GetTempFileName();
var environmentVariables = new StringDictionary();
environmentVariables.Add("Sonarr_SourcePath", sourcePath);
environmentVariables.Add("Sonarr_DestinationPath", destinationFilePath);
environmentVariables.Add("Sonarr_InfoFilePath", temporaryPath);
environmentVariables.Add("Sonarr_InstanceName", _configFileProvider.InstanceName);
environmentVariables.Add("Sonarr_ApplicationUrl", _configService.ApplicationUrl);
@ -118,11 +179,21 @@ namespace NzbDrone.Core.MediaFiles
_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));
var (possibleExtraFiles, mediaFile) = ProcessTemporaryFile(temporaryPath);
localEpisode.PossibleExtraFiles = possibleExtraFiles;
destinationFilePath = mediaFile ?? destinationFilePath;
episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilePath);
episodeFile.Path = destinationFilePath;
switch (processOutput.ExitCode)
{
case 0: // Copy complete
localEpisode.ScriptImported = true;
return ScriptImportDecision.MoveComplete;
case 2: // Copy complete, file potentially changed, should try renaming again
localEpisode.ScriptImported = true;
episodeFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(destinationFilePath);
episodeFile.Path = null;
return ScriptImportDecision.RenameRequested;

View File

@ -40,6 +40,9 @@ namespace NzbDrone.Core.Parser.Model
public List<CustomFormat> CustomFormats { get; set; }
public int CustomFormatScore { get; set; }
public GrabbedReleaseInfo Release { get; set; }
public bool ScriptImported { get; set; }
public bool ImportRenamed { get; set; }
public List<string> PossibleExtraFiles { get; set; }
public int SeasonNumber
{