From 6d1bc335024cdf11a43b2ba0a7a83b40521d6b54 Mon Sep 17 00:00:00 2001 From: Jendrik Weise Date: Sun, 3 Sep 2023 04:38:02 +0200 Subject: [PATCH] Switch to using stdout for information Also fixes dependency loop --- .../UpdateMediaInfoServiceFixture.cs | 13 +-- .../Extras/ExistingExtraFileService.cs | 22 +---- .../MediaFiles/DiskScanService.cs | 11 ++- .../MediaFiles/Events/SeriesScannedEvent.cs | 7 +- .../MediaFiles/ScriptImportDecider.cs | 80 +++++++++---------- .../MediaFiles/ScriptImportInfo.cs | 16 ++++ 6 files changed, 76 insertions(+), 73 deletions(-) create mode 100644 src/NzbDrone.Core/MediaFiles/ScriptImportInfo.cs diff --git a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/UpdateMediaInfoServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/UpdateMediaInfoServiceFixture.cs index de3621fcd..72af3a7ca 100644 --- a/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/UpdateMediaInfoServiceFixture.cs +++ b/src/NzbDrone.Core.Test/MediaFiles/MediaInfo/UpdateMediaInfoServiceFixture.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using System.IO; using FizzWare.NBuilder; using FluentAssertions; @@ -71,7 +72,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo GivenFileExists(); GivenSuccessfulScan(); - Subject.Handle(new SeriesScannedEvent(_series)); + Subject.Handle(new SeriesScannedEvent(_series, new List())); Mocker.GetMock() .Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2)); @@ -97,7 +98,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo GivenFileExists(); GivenSuccessfulScan(); - Subject.Handle(new SeriesScannedEvent(_series)); + Subject.Handle(new SeriesScannedEvent(_series, new List())); Mocker.GetMock() .Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2)); @@ -123,7 +124,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo GivenFileExists(); GivenSuccessfulScan(); - Subject.Handle(new SeriesScannedEvent(_series)); + Subject.Handle(new SeriesScannedEvent(_series, new List())); Mocker.GetMock() .Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(3)); @@ -146,7 +147,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo GivenSuccessfulScan(); - Subject.Handle(new SeriesScannedEvent(_series)); + Subject.Handle(new SeriesScannedEvent(_series, new List())); Mocker.GetMock() .Verify(v => v.GetMediaInfo("media.mkv"), Times.Never()); @@ -173,7 +174,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo GivenSuccessfulScan(); GivenFailedScan(Path.Combine(_series.Path, "media2.mkv")); - Subject.Handle(new SeriesScannedEvent(_series)); + Subject.Handle(new SeriesScannedEvent(_series, new List())); Mocker.GetMock() .Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(1)); @@ -203,7 +204,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo GivenFileExists(); GivenSuccessfulScan(); - Subject.Handle(new SeriesScannedEvent(_series)); + Subject.Handle(new SeriesScannedEvent(_series, new List())); Mocker.GetMock() .Verify(v => v.GetMediaInfo(It.IsAny()), Times.Never()); diff --git a/src/NzbDrone.Core/Extras/ExistingExtraFileService.cs b/src/NzbDrone.Core/Extras/ExistingExtraFileService.cs index 1678cb0d6..b5e661de1 100644 --- a/src/NzbDrone.Core/Extras/ExistingExtraFileService.cs +++ b/src/NzbDrone.Core/Extras/ExistingExtraFileService.cs @@ -2,33 +2,25 @@ using System.Collections.Generic; using System.IO; using System.Linq; using NLog; -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 interface IExistingExtraFiles : IHandle + public interface IExistingExtraFiles { List ImportFileList(Series series, List possibleExtraFiles); } - public class ExistingExtraFileService : IExistingExtraFiles + public class ExistingExtraFileService : IExistingExtraFiles, IHandle { - private readonly IDiskProvider _diskProvider; - private readonly IDiskScanService _diskScanService; private readonly List _existingExtraFileImporters; private readonly Logger _logger; - public ExistingExtraFileService(IDiskProvider diskProvider, - IDiskScanService diskScanService, - IEnumerable existingExtraFileImporters, + public ExistingExtraFileService(IEnumerable existingExtraFileImporters, Logger logger) { - _diskProvider = diskProvider; - _diskScanService = diskScanService; _existingExtraFileImporters = existingExtraFileImporters.OrderBy(e => e.Order).ToList(); _logger = logger; } @@ -53,13 +45,7 @@ namespace NzbDrone.Core.Extras { var series = message.Series; - if (!_diskProvider.FolderExists(series.Path)) - { - return; - } - - var filesOnDisk = _diskScanService.GetNonVideoFiles(series.Path); - var possibleExtraFiles = _diskScanService.FilterPaths(series.Path, filesOnDisk); + var possibleExtraFiles = message.PossibleExtraFiles; var importedFiles = ImportFileList(series, possibleExtraFiles); diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs index 589a5c1c4..4c92b0d93 100644 --- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs +++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs @@ -121,7 +121,7 @@ namespace NzbDrone.Core.MediaFiles } CleanMediaFiles(series, new List()); - CompletedScanning(series); + CompletedScanning(series, new List()); return; } @@ -174,8 +174,11 @@ namespace NzbDrone.Core.MediaFiles fileInfoStopwatch.Stop(); _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); - CompletedScanning(series); + CompletedScanning(series, possibleExtraFiles); } private void CleanMediaFiles(Series series, List mediaFileList) @@ -184,10 +187,10 @@ namespace NzbDrone.Core.MediaFiles _mediaFileTableCleanupService.Clean(series, mediaFileList); } - private void CompletedScanning(Series series) + private void CompletedScanning(Series series, List possibleExtraFiles) { _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) diff --git a/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs b/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs index e07bbd75f..a76348b39 100644 --- a/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs +++ b/src/NzbDrone.Core/MediaFiles/Events/SeriesScannedEvent.cs @@ -1,4 +1,5 @@ -using NzbDrone.Common.Messaging; +using System.Collections.Generic; +using NzbDrone.Common.Messaging; using NzbDrone.Core.Tv; namespace NzbDrone.Core.MediaFiles.Events @@ -6,10 +7,12 @@ namespace NzbDrone.Core.MediaFiles.Events public class SeriesScannedEvent : IEvent { public Series Series { get; private set; } + public List PossibleExtraFiles { get; set; } - public SeriesScannedEvent(Series series) + public SeriesScannedEvent(Series series, List possibleExtraFiles) { Series = series; + PossibleExtraFiles = possibleExtraFiles; } } } diff --git a/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs b/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs index 1989f4f2c..705e1e3d6 100644 --- a/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs +++ b/src/NzbDrone.Core/MediaFiles/ScriptImportDecider.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using NLog; using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Processes; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Extras; +using NzbDrone.Core.Extras.Subtitles; using NzbDrone.Core.MediaFiles.MediaInfo; using NzbDrone.Core.Parser; using NzbDrone.Core.Parser.Model; @@ -27,7 +28,7 @@ namespace NzbDrone.Core.MediaFiles private readonly IProcessProvider _processProvider; private readonly IConfigService _configService; private readonly ITagRepository _tagRepository; - private readonly IExistingExtraFiles _existingExtraFiles; + private readonly IDiskProvider _diskProvider; private readonly Logger _logger; public ImportScriptService(IProcessProvider processProvider, @@ -35,7 +36,7 @@ namespace NzbDrone.Core.MediaFiles IConfigService configService, IConfigFileProvider configFileProvider, ITagRepository tagRepository, - IExistingExtraFiles existingExtraFiles, + IDiskProvider diskProvider, Logger logger) { _processProvider = processProvider; @@ -43,61 +44,57 @@ namespace NzbDrone.Core.MediaFiles _configService = configService; _configFileProvider = configFileProvider; _tagRepository = tagRepository; - _existingExtraFiles = existingExtraFiles; + _diskProvider = diskProvider; _logger = logger; } - private (List possibleMediaFiles, string mediaFile) ProcessTemporaryFile(string temporaryPath) + private static readonly Regex MediaFileLine = new Regex(@"^\[SonarrMediaFile\]\s*(?.*)$", RegexOptions.Compiled); + + private static readonly Regex ExtraFileLine = new Regex(@"^\[SonarrExtraFile\]\s*(?.*)$", RegexOptions.Compiled); + + private ScriptImportInfo ProcessStdout(List processOutputLines, string defaultMediaFile) { - var lines = File.ReadAllLines(temporaryPath); - - if (lines.Length == 0 || string.IsNullOrWhiteSpace(lines[0])) - { - return (new List(), null); - } - var possibleExtraFiles = new List(); string mediaFile = null; - foreach (var line in lines) + foreach (var line in processOutputLines) { - if (MediaFileExtensions.Extensions.Contains(Path.GetExtension(line))) + if (MediaFileLine.Match(line.Content) is var match && match.Success) { if (mediaFile is not null) { throw new ScriptImportException("Script output contains multiple media files. Only one media file can be returned."); } - else + + mediaFile = match.Groups["mediaFileName"].Value; + + if (!MediaFileExtensions.Extensions.Contains(Path.GetExtension(mediaFile))) { - if (File.Exists(line)) - { - mediaFile = line; - } - else - { - _logger.Warn("Script output contains invalid file: {0}", line); - } + 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 + else if (ExtraFileLine.Match(line.Content) is var match2 && match2.Success) { - if (File.Exists(line)) + possibleExtraFiles.Add(match2.Groups["extraFileName"].Value); + + var lastAdded = possibleExtraFiles.Last(); + + if (!SubtitleFileExtensions.Extensions.Contains(Path.GetExtension(lastAdded))) { - possibleExtraFiles.Add(line); + throw new ScriptImportException("Script output contains invalid extra file: {0}", lastAdded); } - else + else if (!_diskProvider.FileExists(lastAdded)) { - _logger.Warn("Script output contains invalid file: {0}", line); + throw new ScriptImportException("Script output contains non-existent extra file: {0}", lastAdded); } } } - if (mediaFile is not null) - { - throw new ScriptImportException("Script output does not contain a media file."); - } - - return (possibleExtraFiles, mediaFile); + return new ScriptImportInfo(possibleExtraFiles, mediaFile ?? defaultMediaFile); } public ScriptImportDecision TryImport(string sourcePath, string destinationFilePath, LocalEpisode localEpisode, EpisodeFile episodeFile, TransferMode mode) @@ -112,13 +109,10 @@ 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); @@ -179,13 +173,13 @@ 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); + var scriptImportInfo = ProcessStdout(processOutput.Lines, destinationFilePath); - localEpisode.PossibleExtraFiles = possibleExtraFiles; + var mediaFile = scriptImportInfo.MediaFile; + localEpisode.PossibleExtraFiles = scriptImportInfo.PossibleExtraFiles; - destinationFilePath = mediaFile ?? destinationFilePath; - episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilePath); - episodeFile.Path = destinationFilePath; + episodeFile.RelativePath = series.Path.GetRelativePath(mediaFile); + episodeFile.Path = mediaFile; if ((processOutput.ExitCode & 0x4) == 0x4) { @@ -199,7 +193,7 @@ namespace NzbDrone.Core.MediaFiles return ScriptImportDecision.MoveComplete; case 2: // Copy complete, file potentially changed, should try renaming again localEpisode.ScriptImported = true; - episodeFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(destinationFilePath); + episodeFile.MediaInfo = _videoFileInfoReader.GetMediaInfo(mediaFile); episodeFile.Path = null; return ScriptImportDecision.RenameRequested; case 3: // Let Sonarr handle it diff --git a/src/NzbDrone.Core/MediaFiles/ScriptImportInfo.cs b/src/NzbDrone.Core/MediaFiles/ScriptImportInfo.cs new file mode 100644 index 000000000..a44742fb5 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/ScriptImportInfo.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace NzbDrone.Core.MediaFiles +{ + public struct ScriptImportInfo + { + public List PossibleExtraFiles { get; set; } + public string MediaFile { get; set; } + + public ScriptImportInfo(List possibleExtraFiles, string mediaFile) + { + PossibleExtraFiles = possibleExtraFiles; + MediaFile = mediaFile; + } + } +}