From 978349e24135572889095c743d0e7fac734ba7e0 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Sun, 3 Nov 2024 14:43:50 -0800 Subject: [PATCH] New: Reject files during import that have no audio tracks Closes #7298 --- .../HasAudioTrackSpecificationFixture.cs | 70 +++++++++++++++++++ .../HasAudioTrackSpecification.cs | 35 ++++++++++ 2 files changed, 105 insertions(+) create mode 100644 src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecificationFixture.cs create mode 100644 src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecification.cs diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecificationFixture.cs new file mode 100644 index 000000000..eba293380 --- /dev/null +++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecificationFixture.cs @@ -0,0 +1,70 @@ +using System.IO; +using System.Linq; +using FizzWare.NBuilder; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications; +using NzbDrone.Core.MediaFiles.MediaInfo; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Tv; +using NzbDrone.Test.Common; + +namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications +{ + [TestFixture] + public class HasAudioTrackSpecificationFixture : CoreTest + { + private Series _series; + private LocalEpisode _localEpisode; + private string _rootFolder; + + [SetUp] + public void Setup() + { + _rootFolder = @"C:\Test\TV".AsOsAgnostic(); + + _series = Builder.CreateNew() + .With(s => s.SeriesType = SeriesTypes.Standard) + .With(s => s.Path = Path.Combine(_rootFolder, "30 Rock")) + .Build(); + + var episodes = Builder.CreateListOfSize(1) + .All() + .With(e => e.SeasonNumber = 1) + .Build() + .ToList(); + + _localEpisode = new LocalEpisode + { + Path = @"C:\Test\Unsorted\30 Rock\30.rock.s01e01.avi".AsOsAgnostic(), + Episodes = episodes, + Series = _series + }; + } + + [Test] + public void should_accept_if_media_info_is_null() + { + _localEpisode.MediaInfo = null; + + Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue(); + } + + [Test] + public void should_reject_if_audio_stream_count_is_0() + { + _localEpisode.MediaInfo = Builder.CreateNew().With(m => m.AudioStreamCount = 0).Build(); + + Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeFalse(); + } + + [Test] + public void should_accept_if_audio_stream_count_is_0() + { + _localEpisode.MediaInfo = Builder.CreateNew().With(m => m.AudioStreamCount = 1).Build(); + + Subject.IsSatisfiedBy(_localEpisode, null).Accepted.Should().BeTrue(); + } + } +} diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecification.cs new file mode 100644 index 000000000..4a66eeea1 --- /dev/null +++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/HasAudioTrackSpecification.cs @@ -0,0 +1,35 @@ +using NLog; +using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Download; +using NzbDrone.Core.Parser.Model; + +namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications +{ + public class HasAudioTrackSpecification : IImportDecisionEngineSpecification + { + private readonly Logger _logger; + + public HasAudioTrackSpecification(Logger logger) + { + _logger = logger; + } + + public Decision IsSatisfiedBy(LocalEpisode localEpisode, DownloadClientItem downloadClientItem) + { + if (localEpisode.MediaInfo == null) + { + _logger.Debug("Failed to get media info from the file, make sure ffprobe is available, skipping check"); + return Decision.Accept(); + } + + if (localEpisode.MediaInfo.AudioStreamCount == 0) + { + _logger.Debug("No audio tracks found in file"); + + return Decision.Reject("No audio tracks detected"); + } + + return Decision.Accept(); + } + } +}