diff --git a/src/NzbDrone.Test.Common/ObjectExtensions.cs b/src/NzbDrone.Common/Extensions/ObjectExtensions.cs
similarity index 87%
rename from src/NzbDrone.Test.Common/ObjectExtensions.cs
rename to src/NzbDrone.Common/Extensions/ObjectExtensions.cs
index 702797269..98f694090 100644
--- a/src/NzbDrone.Test.Common/ObjectExtensions.cs
+++ b/src/NzbDrone.Common/Extensions/ObjectExtensions.cs
@@ -1,6 +1,6 @@
using NzbDrone.Common.Serializer;
-namespace NzbDrone.Test.Common
+namespace NzbDrone.Common.Extensions
{
public static class ObjectExtensions
{
diff --git a/src/NzbDrone.Common/NzbDrone.Common.csproj b/src/NzbDrone.Common/NzbDrone.Common.csproj
index d7966efc0..8db2ba470 100644
--- a/src/NzbDrone.Common/NzbDrone.Common.csproj
+++ b/src/NzbDrone.Common/NzbDrone.Common.csproj
@@ -134,6 +134,7 @@
+
diff --git a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs
index 17a3bb655..9bd22d81e 100644
--- a/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/CompletedDownloadServiceFixture.cs
@@ -5,6 +5,7 @@ using Moq;
using NUnit.Framework;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.TrackedDownloads;
using NzbDrone.Core.History;
@@ -153,8 +154,13 @@ namespace NzbDrone.Core.Test.Download
.Setup(v => v.ProcessPath(It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(new List
{
- new ImportResult(new ImportDecision(new LocalEpisode {Path = @"C:\TestPath\Droned.S01E01.mkv"}, "Rejected!"),"Test Failure"),
- new ImportResult(new ImportDecision(new LocalEpisode {Path = @"C:\TestPath\Droned.S01E02.mkv"}, "Rejected!"),"Test Failure")
+ new ImportResult(
+ new ImportDecision(
+ new LocalEpisode {Path = @"C:\TestPath\Droned.S01E01.mkv"}, new Rejection("Rejected!")), "Test Failure"),
+
+ new ImportResult(
+ new ImportDecision(
+ new LocalEpisode {Path = @"C:\TestPath\Droned.S01E02.mkv"},new Rejection("Rejected!")), "Test Failure")
});
Subject.Process(_trackedDownload);
diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs
index 6dac469ab..6ec615982 100644
--- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/AddFixture.cs
@@ -4,6 +4,7 @@ using FizzWare.NBuilder;
using Marr.Data;
using Moq;
using NUnit.Framework;
+using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download.Pending;
using NzbDrone.Core.Parser;
@@ -12,7 +13,6 @@ using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
-using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{
diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs
index 89776300a..323394532 100644
--- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveGrabbedFixture.cs
@@ -4,17 +4,16 @@ using FizzWare.NBuilder;
using Marr.Data;
using Moq;
using NUnit.Framework;
+using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Pending;
-using NzbDrone.Core.Indexers;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
-using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{
diff --git a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs
index 36e520a2d..9d9aac486 100644
--- a/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs
+++ b/src/NzbDrone.Core.Test/Download/Pending/PendingReleaseServiceTests/RemoveRejectedFixture.cs
@@ -4,6 +4,7 @@ using FizzWare.NBuilder;
using Marr.Data;
using Moq;
using NUnit.Framework;
+using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.Download.Pending;
@@ -14,7 +15,6 @@ using NzbDrone.Core.Profiles;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
-using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.Download.Pending.PendingReleaseServiceTests
{
diff --git a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs
index 8982e441d..4e3a41f30 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/DiskScanServiceTests/ScanFixture.cs
@@ -101,7 +101,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
Subject.Scan(_series);
Mocker.GetMock()
- .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 1), _series, false, (QualityModel)null), Times.Once());
+ .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 1), _series), Times.Once());
}
[Test]
@@ -119,7 +119,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
Subject.Scan(_series);
Mocker.GetMock()
- .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 1), _series, false, (QualityModel)null), Times.Once());
+ .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 1), _series), Times.Once());
}
[Test]
@@ -141,7 +141,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
Subject.Scan(_series);
Mocker.GetMock()
- .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 4), _series, false, (QualityModel)null), Times.Once());
+ .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 4), _series), Times.Once());
}
[Test]
@@ -160,7 +160,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
Subject.Scan(_series);
Mocker.GetMock()
- .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 1), _series, false, (QualityModel)null), Times.Once());
+ .Verify(v => v.GetImportDecisions(It.Is>(l => l.Count == 1), _series), Times.Once());
}
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs
index f32cb519a..89f00416c 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/DownloadedEpisodesImportServiceFixture.cs
@@ -78,7 +78,7 @@ namespace NzbDrone.Core.Test.MediaFiles
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
Mocker.GetMock()
- .Verify(c => c.GetImportDecisions(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny()),
+ .Verify(c => c.GetImportDecisions(It.IsAny>(), It.IsAny(), It.IsAny(), It.IsAny()),
Times.Never());
VerifyNoImport();
@@ -129,7 +129,7 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), true, null))
+ .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
.Returns(imported);
Mocker.GetMock()
@@ -155,14 +155,14 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), true, null))
+ .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
.Returns(imported);
Mocker.GetMock()
.Setup(s => s.Import(It.IsAny>(), true, null))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
- Mocker.GetMock()
+ Mocker.GetMock()
.Setup(s => s.IsSample(It.IsAny(),
It.IsAny(),
It.IsAny(),
@@ -224,14 +224,14 @@ namespace NzbDrone.Core.Test.MediaFiles
imported.Add(new ImportDecision(localEpisode));
Mocker.GetMock()
- .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), true, null))
+ .Setup(s => s.GetImportDecisions(It.IsAny>(), It.IsAny(), null, true))
.Returns(imported);
Mocker.GetMock()
.Setup(s => s.Import(It.IsAny>(), true, null))
.Returns(imported.Select(i => new ImportResult(i)).ToList());
- Mocker.GetMock()
+ Mocker.GetMock()
.Setup(s => s.IsSample(It.IsAny(),
It.IsAny(),
It.IsAny(),
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs
index 6f887ad37..e5e3e0985 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/ImportDecisionMakerFixture.cs
@@ -45,31 +45,20 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
_fail2 = new Mock();
_fail3 = new Mock();
- _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true);
- _pass1.Setup(c => c.RejectionReason).Returns("_pass1");
+ _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Accept());
+ _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Accept());
+ _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Accept());
- _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true);
- _pass2.Setup(c => c.RejectionReason).Returns("_pass2");
+ _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Reject("_fail1"));
+ _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Reject("_fail2"));
+ _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(Decision.Reject("_fail3"));
- _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true);
- _pass3.Setup(c => c.RejectionReason).Returns("_pass3");
-
-
- _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false);
- _fail1.Setup(c => c.RejectionReason).Returns("_fail1");
-
- _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false);
- _fail2.Setup(c => c.RejectionReason).Returns("_fail2");
-
- _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false);
- _fail3.Setup(c => c.RejectionReason).Returns("_fail3");
-
- _videoFiles = new List { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi" };
_series = Builder.CreateNew()
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
.Build();
_quality = new QualityModel(Quality.DVD);
+
_localEpisode = new LocalEpisode
{
Series = _series,
@@ -78,17 +67,24 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
};
Mocker.GetMock()
- .Setup(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Setup(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Returns(_localEpisode);
- Mocker.GetMock()
- .Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny()))
- .Returns(_videoFiles);
+ GivenVideoFiles(new List { @"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV.avi".AsOsAgnostic() });
}
private void GivenSpecifications(params Mock[] mocks)
{
- Mocker.SetConstant>(mocks.Select(c => c.Object));
+ Mocker.SetConstant(mocks.Select(c => c.Object));
+ }
+
+ private void GivenVideoFiles(IEnumerable videoFiles)
+ {
+ _videoFiles = videoFiles.ToList();
+
+ Mocker.GetMock()
+ .Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny()))
+ .Returns(_videoFiles);
}
[Test]
@@ -96,7 +92,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
- Subject.GetImportDecisions(_videoFiles, new Series(), false);
+ Subject.GetImportDecisions(_videoFiles, new Series(), null, false);
_fail1.Verify(c => c.IsSatisfiedBy(_localEpisode), Times.Once());
_fail2.Verify(c => c.IsSatisfiedBy(_localEpisode), Times.Once());
@@ -111,7 +107,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
GivenSpecifications(_fail1);
- var result = Subject.GetImportDecisions(_videoFiles, new Series(), false);
+ var result = Subject.GetImportDecisions(_videoFiles, new Series());
result.Single().Approved.Should().BeFalse();
}
@@ -121,7 +117,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
GivenSpecifications(_pass1, _fail1, _pass2, _pass3);
- var result = Subject.GetImportDecisions(_videoFiles, new Series(), false);
+ var result = Subject.GetImportDecisions(_videoFiles, new Series());
result.Single().Approved.Should().BeFalse();
}
@@ -131,7 +127,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
GivenSpecifications(_pass1, _pass2, _pass3);
- var result = Subject.GetImportDecisions(_videoFiles, new Series(), false);
+ var result = Subject.GetImportDecisions(_videoFiles, new Series());
result.Single().Approved.Should().BeTrue();
}
@@ -141,7 +137,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
- var result = Subject.GetImportDecisions(_videoFiles, new Series(), false);
+ var result = Subject.GetImportDecisions(_videoFiles, new Series());
result.Single().Rejections.Should().HaveCount(3);
}
@@ -151,7 +147,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
GivenSpecifications(_pass1);
Mocker.GetMock()
- .Setup(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Setup(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Throws();
_videoFiles = new List
@@ -161,14 +157,12 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
"The.Office.S03E115.DVDRip.XviD-OSiTV"
};
- Mocker.GetMock()
- .Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny()))
- .Returns(_videoFiles);
+ GivenVideoFiles(_videoFiles);
- Subject.GetImportDecisions(_videoFiles, _series, false);
+ Subject.GetImportDecisions(_videoFiles, _series);
Mocker.GetMock()
- .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_videoFiles.Count));
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_videoFiles.Count));
ExceptionVerification.ExpectedErrors(3);
}
@@ -179,7 +173,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
GivenSpecifications(_pass1, _pass2, _pass3);
var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());
- var result = Subject.GetImportDecisions(_videoFiles, _series, false, null);
+ var result = Subject.GetImportDecisions(_videoFiles, _series);
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
}
@@ -190,7 +184,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
GivenSpecifications(_pass1, _pass2, _pass3);
var expectedQuality = QualityParser.ParseQuality(_videoFiles.Single());
- var result = Subject.GetImportDecisions(_videoFiles, _series, false, new QualityModel(Quality.SDTV));
+ var result = Subject.GetImportDecisions(_videoFiles, _series, new ParsedEpisodeInfo{Quality = new QualityModel(Quality.SDTV)}, true);
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
}
@@ -201,7 +195,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
GivenSpecifications(_pass1, _pass2, _pass3);
var expectedQuality = new QualityModel(Quality.Bluray1080p);
- var result = Subject.GetImportDecisions(_videoFiles, _series, false, expectedQuality);
+ var result = Subject.GetImportDecisions(_videoFiles, _series, new ParsedEpisodeInfo { Quality = expectedQuality }, true);
result.Single().LocalEpisode.Quality.Should().Be(expectedQuality);
}
@@ -212,7 +206,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
GivenSpecifications(_pass1);
Mocker.GetMock()
- .Setup(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny()))
+ .Setup(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()))
.Throws(new EpisodeNotFoundException("Episode not found"));
_videoFiles = new List
@@ -222,14 +216,130 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
"The.Office.S03E115.DVDRip.XviD-OSiTV"
};
- Mocker.GetMock()
- .Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny()))
- .Returns(_videoFiles);
+ GivenVideoFiles(_videoFiles);
+
+ Subject.GetImportDecisions(_videoFiles, _series);
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_videoFiles.Count));
+ }
+
+ [Test]
+ public void should_not_use_folder_for_full_season()
+ {
+ var videoFiles = new[]
+ {
+ @"C:\Test\Unsorted\Series.Title.S01\S01E01.mkv".AsOsAgnostic(),
+ @"C:\Test\Unsorted\Series.Title.S01\S01E02.mkv".AsOsAgnostic(),
+ @"C:\Test\Unsorted\Series.Title.S01\S01E03.mkv".AsOsAgnostic()
+ };
+
+ GivenSpecifications(_pass1);
+ GivenVideoFiles(videoFiles);
+
+ var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01");
- Subject.GetImportDecisions(_videoFiles, _series, false);
+ Subject.GetImportDecisions(_videoFiles, _series, folderInfo, true);
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), null, true), Times.Exactly(3));
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.Is(p => p != null), true), Times.Never());
+ }
+
+ [Test]
+ public void should_not_use_folder_when_it_contains_more_than_one_valid_video_file()
+ {
+ var videoFiles = new[]
+ {
+ @"C:\Test\Unsorted\Series.Title.S01E01\S01E01.mkv".AsOsAgnostic(),
+ @"C:\Test\Unsorted\Series.Title.S01E01\1x01.mkv".AsOsAgnostic()
+ };
+
+ GivenSpecifications(_pass1);
+ GivenVideoFiles(videoFiles);
+
+ var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
+
+ Subject.GetImportDecisions(_videoFiles, _series, folderInfo, true);
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), null, true), Times.Exactly(2));
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.Is(p => p != null), true), Times.Never());
+ }
+
+ [Test]
+ public void should_use_folder_when_only_one_video_file()
+ {
+ var videoFiles = new[]
+ {
+ @"C:\Test\Unsorted\Series.Title.S01E01\S01E01.mkv".AsOsAgnostic()
+ };
+
+ GivenSpecifications(_pass1);
+ GivenVideoFiles(videoFiles);
+
+ var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
+
+ Subject.GetImportDecisions(_videoFiles, _series, folderInfo, true);
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), true), Times.Exactly(1));
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), null, true), Times.Never());
+ }
+
+ [Test]
+ public void should_use_folder_when_only_one_video_file_and_a_sample()
+ {
+ var videoFiles = new[]
+ {
+ @"C:\Test\Unsorted\Series.Title.S01E01\S01E01.mkv".AsOsAgnostic(),
+ @"C:\Test\Unsorted\Series.Title.S01E01\S01E01.sample.mkv".AsOsAgnostic()
+ };
+
+ GivenSpecifications(_pass1);
+ GivenVideoFiles(videoFiles.ToList());
+
+ Mocker.GetMock()
+ .Setup(s => s.IsSample(_series, It.IsAny(), It.Is(c => c.Contains("sample")), It.IsAny(), It.IsAny()))
+ .Returns(true);
+
+ var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01");
+
+ Subject.GetImportDecisions(_videoFiles, _series, folderInfo, true);
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny(), true), Times.Exactly(2));
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), null, true), Times.Never());
+ }
+
+ [Test]
+ public void should_not_use_folder_name_if_file_name_is_scene_name()
+ {
+ var videoFiles = new[]
+ {
+ @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-LOL\Series.Title.S01E01.720p.HDTV-LOL.mkv".AsOsAgnostic()
+ };
+
+ GivenSpecifications(_pass1);
+ GivenVideoFiles(videoFiles);
+
+ var folderInfo = Parser.Parser.ParseTitle("Series.Title.S01E01.720p.HDTV-LOL");
+
+ Subject.GetImportDecisions(_videoFiles, _series, folderInfo, true);
+
+ Mocker.GetMock()
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), null, true), Times.Exactly(1));
Mocker.GetMock()
- .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(_videoFiles.Count));
+ .Verify(c => c.GetLocalEpisode(It.IsAny(), It.IsAny(), It.Is(p => p != null), true), Times.Never());
}
}
-}
\ No newline at end of file
+}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/SampleServiceFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/SampleServiceFixture.cs
index dbb860d8e..813ef747b 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/SampleServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/SampleServiceFixture.cs
@@ -14,7 +14,7 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
{
[TestFixture]
- public class SampleServiceFixture : CoreTest
+ public class SampleServiceFixture : CoreTest
{
private Series _series;
private LocalEpisode _localEpisode;
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecificationFixture.cs
index 007a52976..5cdaa8590 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecificationFixture.cs
@@ -64,7 +64,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenFileSize(100.Megabytes());
GivenFreeSpace(80.Megabytes());
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
ExceptionVerification.ExpectedWarns(1);
}
@@ -74,7 +74,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenFileSize(100.Megabytes());
GivenFreeSpace(150.Megabytes());
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
ExceptionVerification.ExpectedWarns(1);
}
@@ -84,7 +84,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenFileSize(100.Megabytes());
GivenFreeSpace(1.Gigabytes());
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -93,7 +93,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenFileSize(100.Megabytes());
GivenFreeSpace(1.Gigabytes());
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
Mocker.GetMock()
.Verify(v => v.GetAvailableSpace(_rootFolder), Times.Once());
@@ -105,7 +105,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenFileSize(100.Megabytes());
GivenFreeSpace(null);
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -117,7 +117,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Setup(s => s.GetAvailableSpace(It.IsAny()))
.Throws(new TestException());
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
ExceptionVerification.ExpectedErrors(1);
}
@@ -126,7 +126,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
{
_localEpisode.ExistingFile = true;
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
Mocker.GetMock()
.Verify(s => s.GetAvailableSpace(It.IsAny()), Times.Never());
@@ -141,7 +141,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Setup(s => s.GetAvailableSpace(It.IsAny()))
.Returns(freeSpace);
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -151,7 +151,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Setup(s => s.SkipFreeSpaceCheckWhenImporting)
.Returns(true);
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs
index cb657d47e..d8dced788 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecificationFixture.cs
@@ -34,13 +34,13 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
{
_localEpisode.ParsedEpisodeInfo.FullSeason = true;
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
}
[Test]
public void should_return_true_when_file_does_not_contain_the_full_season()
{
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecificationFixture.cs
new file mode 100644
index 000000000..71ff631a1
--- /dev/null
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecificationFixture.cs
@@ -0,0 +1,84 @@
+using FizzWare.NBuilder;
+using FluentAssertions;
+using NUnit.Framework;
+using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
+using NzbDrone.Core.Parser.Model;
+using NzbDrone.Core.Test.Framework;
+using NzbDrone.Test.Common;
+
+namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
+{
+ [TestFixture]
+ public class MatchesFolderSpecificationFixture : CoreTest
+ {
+ private LocalEpisode _localEpisode;
+
+ [SetUp]
+ public void Setup()
+ {
+ _localEpisode = Builder.CreateNew()
+ .With(l => l.Path = @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-Sonarr\S01E05.mkv".AsOsAgnostic())
+ .With(l => l.ParsedEpisodeInfo =
+ Builder.CreateNew()
+ .With(p => p.EpisodeNumbers = new[] {5})
+ .With(p => p.FullSeason = false)
+ .Build())
+ .Build();
+ }
+
+ [Test]
+ public void should_be_accepted_for_existing_file()
+ {
+ _localEpisode.ExistingFile = true;
+
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void should_be_accepted_if_folder_name_is_not_parseable()
+ {
+ _localEpisode.Path = @"C:\Test\Unsorted\Series.Title\S01E01.mkv".AsOsAgnostic();
+
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void should_should_be_accepted_for_full_season()
+ {
+ _localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01\S01E01.mkv".AsOsAgnostic();
+
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void should_be_accepted_if_file_and_folder_have_the_same_episode()
+ {
+ _localEpisode.ParsedEpisodeInfo.EpisodeNumbers = new[] { 1 };
+ _localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-Sonarr\S01E01.mkv".AsOsAgnostic();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void should_be_accepted_if_file_is_one_episode_in_folder()
+ {
+ _localEpisode.ParsedEpisodeInfo.EpisodeNumbers = new[] { 1 };
+ _localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01E02.720p.HDTV-Sonarr\S01E01.mkv".AsOsAgnostic();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
+ }
+
+ [Test]
+ public void should_be_rejected_if_file_and_folder_do_not_have_same_episode()
+ {
+ _localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01.720p.HDTV-Sonarr\S01E05.mkv".AsOsAgnostic();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
+ }
+
+ [Test]
+ public void should_be_rejected_if_file_and_folder_do_not_have_same_episodes()
+ {
+ _localEpisode.ParsedEpisodeInfo.EpisodeNumbers = new[] { 5, 6 };
+ _localEpisode.Path = @"C:\Test\Unsorted\Series.Title.S01E01E02.720p.HDTV-Sonarr\S01E05E06.mkv".AsOsAgnostic();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs
index 3c4594c52..1f3492205 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotSampleSpecificationFixture.cs
@@ -42,7 +42,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
public void should_return_true_for_existing_file()
{
_localEpisode.ExistingFile = true;
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs
index a0968314b..ad27e402f 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecificationFixture.cs
@@ -48,7 +48,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
[Test]
public void should_return_true_if_not_in_working_folder()
{
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -59,7 +59,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenInWorkingFolder();
GivenLastWriteTimeUtc(DateTime.UtcNow.AddHours(-1));
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -68,7 +68,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenInWorkingFolder();
GivenLastWriteTimeUtc(DateTime.UtcNow);
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
}
[Test]
@@ -79,7 +79,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
GivenInWorkingFolder();
GivenLastWriteTimeUtc(DateTime.UtcNow.AddDays(-5));
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
}
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs
index bfbab5472..f55cdcce2 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/EpisodeImport/Specifications/UpgradeSpecificationFixture.cs
@@ -45,7 +45,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -58,7 +58,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -75,7 +75,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -92,7 +92,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeTrue();
}
[Test]
@@ -109,7 +109,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
}
[Test]
@@ -126,7 +126,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
}
[Test]
@@ -150,7 +150,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport.Specifications
.Build()
.ToList();
- Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
+ Subject.IsSatisfiedBy(_localEpisode).Accepted.Should().BeFalse();
}
}
}
diff --git a/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs b/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs
index 2961a257a..e51b8280a 100644
--- a/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs
+++ b/src/NzbDrone.Core.Test/MediaFiles/ImportApprovedEpisodesFixture.cs
@@ -6,6 +6,7 @@ using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Download;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.MediaFiles.EpisodeImport;
@@ -44,9 +45,9 @@ namespace NzbDrone.Core.Test.MediaFiles
- _rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), "Rejected!"));
- _rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), "Rejected!"));
- _rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), "Rejected!"));
+ _rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), new Rejection("Rejected!")));
+ _rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), new Rejection("Rejected!")));
+ _rejectedDecisions.Add(new ImportDecision(new LocalEpisode(), new Rejection("Rejected!")));
foreach (var episode in episodes)
{
diff --git a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
index 9bf60de39..a2df9a896 100644
--- a/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
+++ b/src/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj
@@ -227,6 +227,7 @@
+
diff --git a/src/NzbDrone.Core.Test/ParserTests/CrapParserFixture.cs b/src/NzbDrone.Core.Test/ParserTests/CrapParserFixture.cs
index 98b74c6ff..ee32d1fc3 100644
--- a/src/NzbDrone.Core.Test/ParserTests/CrapParserFixture.cs
+++ b/src/NzbDrone.Core.Test/ParserTests/CrapParserFixture.cs
@@ -29,6 +29,7 @@ namespace NzbDrone.Core.Test.ParserTests
[TestCase("08bbc153931ce3ca5fcafe1b92d3297285feb061.mkv")]
[TestCase("185d86a343e39f3341e35c4dad3ff159")]
[TestCase("ah63jka93jf0jh26ahjas961.mkv")]
+ [TestCase("qrdSD3rYzWb7cPdVIGSn4E7")]
public void should_not_parse_crap(string title)
{
Parser.Parser.ParseTitle(title).Should().BeNull();
@@ -82,5 +83,11 @@ namespace NzbDrone.Core.Test.ParserTests
success.Should().Be(repetitions);
}
+
+ [TestCase("thebiggestloser1618finale")]
+ public void should_not_parse_file_name_without_proper_spacing(string fileName)
+ {
+ Parser.Parser.ParseTitle(fileName).Should().BeNull();
+ }
}
}
diff --git a/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs b/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs
index 053b56839..392f6344f 100644
--- a/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/TvTests/RefreshEpisodeServiceFixture.cs
@@ -5,10 +5,10 @@ using FizzWare.NBuilder;
using FluentAssertions;
using Moq;
using NUnit.Framework;
+using NzbDrone.Common.Extensions;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Test.Framework;
-using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.TvTests
{
diff --git a/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs b/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs
index 200aa1faf..d847c2ce7 100644
--- a/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs
+++ b/src/NzbDrone.Core.Test/TvTests/RefreshSeriesServiceFixture.cs
@@ -4,11 +4,11 @@ using System.Linq;
using FizzWare.NBuilder;
using Moq;
using NUnit.Framework;
+using NzbDrone.Common.Extensions;
using NzbDrone.Core.MetadataSource;
using NzbDrone.Core.Test.Framework;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Tv.Commands;
-using NzbDrone.Test.Common;
namespace NzbDrone.Core.Test.TvTests
{
diff --git a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs
index f11591d54..e4c54c2a0 100644
--- a/src/NzbDrone.Core/MediaFiles/DiskScanService.cs
+++ b/src/NzbDrone.Core/MediaFiles/DiskScanService.cs
@@ -103,7 +103,7 @@ namespace NzbDrone.Core.MediaFiles
_logger.Trace("Finished getting episode files for: {0} [{1}]", series, videoFilesStopwatch.Elapsed);
var decisionsStopwatch = Stopwatch.StartNew();
- var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series, false);
+ var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, series);
decisionsStopwatch.Stop();
_logger.Trace("Import decisions complete for: {0} [{1}]", series, decisionsStopwatch.Elapsed);
diff --git a/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs b/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs
index 4730e5020..73de1ad9e 100644
--- a/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs
+++ b/src/NzbDrone.Core/MediaFiles/DownloadedEpisodesImportService.cs
@@ -4,6 +4,7 @@ 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;
@@ -26,7 +27,7 @@ namespace NzbDrone.Core.MediaFiles
private readonly IParsingService _parsingService;
private readonly IMakeImportDecision _importDecisionMaker;
private readonly IImportApprovedEpisodes _importApprovedEpisodes;
- private readonly ISampleService _sampleService;
+ private readonly IDetectSample _detectSample;
private readonly Logger _logger;
public DownloadedEpisodesImportService(IDiskProvider diskProvider,
@@ -35,7 +36,7 @@ namespace NzbDrone.Core.MediaFiles
IParsingService parsingService,
IMakeImportDecision importDecisionMaker,
IImportApprovedEpisodes importApprovedEpisodes,
- ISampleService sampleService,
+ IDetectSample detectSample,
Logger logger)
{
_diskProvider = diskProvider;
@@ -44,7 +45,7 @@ namespace NzbDrone.Core.MediaFiles
_parsingService = parsingService;
_importDecisionMaker = importDecisionMaker;
_importApprovedEpisodes = importApprovedEpisodes;
- _sampleService = sampleService;
+ _detectSample = detectSample;
_logger = logger;
}
@@ -115,9 +116,12 @@ namespace NzbDrone.Core.MediaFiles
}
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
- var quality = QualityParser.ParseQuality(cleanedUpName);
+ var folderInfo = Parser.Parser.ParseTitle(directoryInfo.Name);
- _logger.Debug("{0} folder quality: {1}", cleanedUpName, quality);
+ if (folderInfo != null)
+ {
+ _logger.Debug("{0} folder quality: {1}", cleanedUpName, folderInfo.Quality);
+ }
var videoFiles = _diskScanService.GetVideoFiles(directoryInfo.FullName);
@@ -135,7 +139,7 @@ namespace NzbDrone.Core.MediaFiles
}
}
- var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, true, quality);
+ var decisions = _importDecisionMaker.GetImportDecisions(videoFiles.ToList(), series, folderInfo, true);
var importResults = _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
if ((downloadClientItem == null || !downloadClientItem.IsReadOnly) && importResults.Any() && ShouldDeleteFolder(directoryInfo, series))
@@ -177,7 +181,9 @@ namespace NzbDrone.Core.MediaFiles
}
}
- var decisions = _importDecisionMaker.GetImportDecisions(new List() { fileInfo.FullName }, series, true);
+ var folderInfo = Parser.Parser.ParseTitle(fileInfo.DirectoryName);
+ var decisions = _importDecisionMaker.GetImportDecisions(new List() { fileInfo.FullName }, series, folderInfo, true);
+
return _importApprovedEpisodes.Import(decisions, true, downloadClientItem);
}
@@ -207,7 +213,7 @@ namespace NzbDrone.Core.MediaFiles
var size = _diskProvider.GetFileSize(videoFile);
var quality = QualityParser.ParseQuality(videoFile);
- if (!_sampleService.IsSample(series, quality, videoFile, size,
+ if (!_detectSample.IsSample(series, quality, videoFile, size,
episodeParseResult.SeasonNumber))
{
_logger.Warn("Non-sample file detected: [{0}]", videoFile);
@@ -227,14 +233,14 @@ namespace NzbDrone.Core.MediaFiles
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 }, "Locked file, try again later"), "Locked file, try again later");
+ return new ImportResult(new ImportDecision(new LocalEpisode { Path = videoFile }, new Rejection("Locked file, try again later")), "Locked file, try again later");
}
private ImportResult UnknownSeriesResult(string message, string videoFile = null)
{
var localEpisode = videoFile == null ? null : new LocalEpisode { Path = videoFile };
- return new ImportResult(new ImportDecision(localEpisode, "Unknown Series"), message);
+ return new ImportResult(new ImportDecision(localEpisode, new Rejection("Unknown Series")), message);
}
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/SampleService.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/DetectSample.cs
similarity index 95%
rename from src/NzbDrone.Core/MediaFiles/EpisodeImport/SampleService.cs
rename to src/NzbDrone.Core/MediaFiles/EpisodeImport/DetectSample.cs
index 2b93406e4..d83040965 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/SampleService.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/DetectSample.cs
@@ -8,19 +8,19 @@ using NzbDrone.Core.Tv;
namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
- public interface ISampleService
+ public interface IDetectSample
{
bool IsSample(Series series, QualityModel quality, string path, long size, int seasonNumber);
}
- public class SampleService : ISampleService
+ public class DetectSample : IDetectSample
{
private readonly IVideoFileInfoReader _videoFileInfoReader;
private readonly Logger _logger;
private static List _largeSampleSizeQualities = new List { Quality.HDTV1080p, Quality.WEBDL1080p, Quality.Bluray1080p };
- public SampleService(IVideoFileInfoReader videoFileInfoReader, Logger logger)
+ public DetectSample(IVideoFileInfoReader videoFileInfoReader, Logger logger)
{
_videoFileInfoReader = videoFileInfoReader;
_logger = logger;
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs
index 3759ea6d0..86abb87b7 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/IImportDecisionEngineSpecification.cs
@@ -3,8 +3,8 @@ using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
- public interface IImportDecisionEngineSpecification : IRejectWithReason
+ public interface IImportDecisionEngineSpecification
{
- bool IsSatisfiedBy(LocalEpisode localEpisode);
+ Decision IsSatisfiedBy(LocalEpisode localEpisode);
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs
index ea106f0d9..de2fba4b8 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportApprovedEpisodes.cs
@@ -120,7 +120,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
//Adding all the rejected decisions
importResults.AddRange(decisions.Where(c => !c.Approved)
- .Select(d => new ImportResult(d, d.Rejections.ToArray())));
+ .Select(d => new ImportResult(d, d.Rejections.Select(r => r.Reason).ToArray())));
return importResults;
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs
index da7e8d092..ba55a4aec 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecision.cs
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.Extensions;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport
@@ -8,7 +9,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public class ImportDecision
{
public LocalEpisode LocalEpisode { get; private set; }
- public IEnumerable Rejections { get; private set; }
+ public IEnumerable Rejections { get; private set; }
public bool Approved
{
@@ -18,7 +19,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
}
}
- public ImportDecision(LocalEpisode localEpisode, params string[] rejections)
+ public ImportDecision(LocalEpisode localEpisode, params Rejection[] rejections)
{
LocalEpisode = localEpisode;
Rejections = rejections.ToList();
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs
index a1bcd9b5e..871ec8c1a 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportDecisionMaker.cs
@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
using NLog;
using NzbDrone.Common.Disk;
+using NzbDrone.Common.Extensions;
using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser;
using NzbDrone.Core.Parser.Model;
@@ -15,23 +17,26 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
{
public interface IMakeImportDecision
{
- List GetImportDecisions(List videoFiles, Series series, bool sceneSource, QualityModel quality = null);
+ List GetImportDecisions(List videoFiles, Series series);
+ List GetImportDecisions(List videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
}
public class ImportDecisionMaker : IMakeImportDecision
{
- private readonly IEnumerable _specifications;
+ private readonly IEnumerable _specifications;
private readonly IParsingService _parsingService;
private readonly IMediaFileService _mediaFileService;
private readonly IDiskProvider _diskProvider;
private readonly IVideoFileInfoReader _videoFileInfoReader;
+ private readonly IDetectSample _detectSample;
private readonly Logger _logger;
- public ImportDecisionMaker(IEnumerable specifications,
+ public ImportDecisionMaker(IEnumerable specifications,
IParsingService parsingService,
IMediaFileService mediaFileService,
IDiskProvider diskProvider,
IVideoFileInfoReader videoFileInfoReader,
+ IDetectSample detectSample,
Logger logger)
{
_specifications = specifications;
@@ -39,98 +44,96 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
_mediaFileService = mediaFileService;
_diskProvider = diskProvider;
_videoFileInfoReader = videoFileInfoReader;
+ _detectSample = detectSample;
_logger = logger;
}
- public List GetImportDecisions(List videoFiles, Series series, bool sceneSource, QualityModel quality = null)
+ public List GetImportDecisions(List videoFiles, Series series)
+ {
+ return GetImportDecisions(videoFiles, series, null, false);
+ }
+
+ public List GetImportDecisions(List videoFiles, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
{
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series);
_logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count());
- return GetDecisions(newFiles, series, sceneSource, quality).ToList();
+ var shouldUseFolderName = ShouldUseFolderName(videoFiles, series, folderInfo);
+ var decisions = new List();
+
+ foreach (var file in newFiles)
+ {
+ decisions.AddIfNotNull(GetDecision(file, series, folderInfo, sceneSource, shouldUseFolderName));
+ }
+
+ return decisions;
}
- private IEnumerable GetDecisions(IEnumerable videoFiles, Series series, bool sceneSource, QualityModel quality = null)
+ private ImportDecision GetDecision(string file, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource, bool shouldUseFolderName)
{
- foreach (var file in videoFiles)
+ ImportDecision decision = null;
+
+ try
{
- ImportDecision decision = null;
+ var localEpisode = _parsingService.GetLocalEpisode(file, series, shouldUseFolderName ? folderInfo : null, sceneSource);
- try
+ if (localEpisode != null)
{
- var localEpisode = _parsingService.GetLocalEpisode(file, series, sceneSource);
+ localEpisode.Quality = GetQuality(folderInfo, localEpisode.Quality, series);
+ localEpisode.Size = _diskProvider.GetFileSize(file);
- if (localEpisode != null)
- {
- if (quality != null &&
- new QualityModelComparer(localEpisode.Series.Profile).Compare(quality,
- localEpisode.Quality) > 0)
- {
- _logger.Debug("Using quality from folder: {0}", quality);
- localEpisode.Quality = quality;
- }
-
- localEpisode.Size = _diskProvider.GetFileSize(file);
- _logger.Debug("Size: {0}", localEpisode.Size);
-
- //TODO: make it so media info doesn't ruin the import process of a new series
- if (sceneSource)
- {
- localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
- }
-
- decision = GetDecision(localEpisode);
- }
+ _logger.Debug("Size: {0}", localEpisode.Size);
- else
+ //TODO: make it so media info doesn't ruin the import process of a new series
+ if (sceneSource)
{
- localEpisode = new LocalEpisode();
- localEpisode.Path = file;
-
- decision = new ImportDecision(localEpisode, "Unable to parse file");
+ localEpisode.MediaInfo = _videoFileInfoReader.GetMediaInfo(file);
}
+
+ decision = GetDecision(localEpisode);
}
- catch (EpisodeNotFoundException e)
+
+ else
{
- var localEpisode = new LocalEpisode();
+ localEpisode = new LocalEpisode();
localEpisode.Path = file;
- decision = new ImportDecision(localEpisode, e.Message);
- }
- catch (Exception e)
- {
- _logger.ErrorException("Couldn't import file. " + file, e);
+ decision = new ImportDecision(localEpisode, new Rejection("Unable to parse file"));
}
+ }
+ catch (EpisodeNotFoundException e)
+ {
+ var localEpisode = new LocalEpisode();
+ localEpisode.Path = file;
- if (decision != null)
- {
- yield return decision;
- }
+ decision = new ImportDecision(localEpisode, new Rejection(e.Message));
+ }
+ catch (Exception e)
+ {
+ _logger.ErrorException("Couldn't import file. " + file, e);
}
+
+ return decision;
}
private ImportDecision GetDecision(LocalEpisode localEpisode)
{
var reasons = _specifications.Select(c => EvaluateSpec(c, localEpisode))
- .Where(c => !string.IsNullOrWhiteSpace(c));
+ .Where(c => c != null);
return new ImportDecision(localEpisode, reasons.ToArray());
}
- private string EvaluateSpec(IRejectWithReason spec, LocalEpisode localEpisode)
+ private Rejection EvaluateSpec(IImportDecisionEngineSpecification spec, LocalEpisode localEpisode)
{
try
{
- if (string.IsNullOrWhiteSpace(spec.RejectionReason))
- {
- throw new InvalidOperationException("[Need Rejection Text]");
- }
+ var result = spec.IsSatisfiedBy(localEpisode);
- var generalSpecification = spec as IImportDecisionEngineSpecification;
- if (generalSpecification != null && !generalSpecification.IsSatisfiedBy(localEpisode))
+ if (!result.Accepted)
{
- return spec.RejectionReason;
+ return new Rejection(result.Reason);
}
}
catch (Exception e)
@@ -138,10 +141,55 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
//e.Data.Add("report", remoteEpisode.Report.ToJson());
//e.Data.Add("parsed", remoteEpisode.ParsedEpisodeInfo.ToJson());
_logger.ErrorException("Couldn't evaluate decision on " + localEpisode.Path, e);
- return string.Format("{0}: {1}", spec.GetType().Name, e.Message);
+ return new Rejection(String.Format("{0}: {1}", spec.GetType().Name, e.Message));
}
return null;
}
+
+ private bool ShouldUseFolderName(List videoFiles, Series series, ParsedEpisodeInfo folderInfo)
+ {
+ if (folderInfo == null)
+ {
+ return false;
+ }
+
+ if (folderInfo.FullSeason)
+ {
+ return false;
+ }
+
+ return videoFiles.Count(file =>
+ {
+ var size = _diskProvider.GetFileSize(file);
+ var fileQuality = QualityParser.ParseQuality(file);
+ var sample = _detectSample.IsSample(series, GetQuality(folderInfo, fileQuality, series), file, size, folderInfo.SeasonNumber);
+
+ if (sample)
+ {
+ return false;
+ }
+
+ if (SceneChecker.IsSceneTitle(Path.GetFileName(file)))
+ {
+ return false;
+ }
+
+ return true;
+ }) == 1;
+ }
+
+ private QualityModel GetQuality(ParsedEpisodeInfo folderInfo, QualityModel fileQuality, Series series)
+ {
+ if (folderInfo != null &&
+ new QualityModelComparer(series.Profile).Compare(folderInfo.Quality,
+ fileQuality) > 0)
+ {
+ _logger.Debug("Using quality from folder: {0}", folderInfo.Quality);
+ return folderInfo.Quality;
+ }
+
+ return fileQuality;
+ }
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs
index 64ccb47b2..a0d989335 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/ImportResult.cs
@@ -1,5 +1,4 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using NzbDrone.Common.EnsureThat;
@@ -8,7 +7,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
public class ImportResult
{
public ImportDecision ImportDecision { get; private set; }
- public List Errors { get; private set; }
+ public List Errors { get; private set; }
public ImportResultType Result
{
@@ -28,7 +27,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
}
}
- public ImportResult(ImportDecision importDecision, params String[] errors)
+ public ImportResult(ImportDecision importDecision, params string[] errors)
{
Ensure.That(importDecision, () => importDecision).IsNotNull();
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs
index 1256a5207..c3fe8550e 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FreeSpaceSpecification.cs
@@ -3,6 +3,7 @@ using System.IO;
using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Core.Configuration;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
@@ -20,14 +21,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger;
}
- public string RejectionReason { get { return "Not enough free space"; } }
-
- public bool IsSatisfiedBy(LocalEpisode localEpisode)
+ public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{
if (_configService.SkipFreeSpaceCheckWhenImporting)
{
_logger.Debug("Skipping free space check when importing");
- return true;
+ return Decision.Accept();
}
try
@@ -35,7 +34,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
if (localEpisode.ExistingFile)
{
_logger.Debug("Skipping free space check for existing episode");
- return true;
+ return Decision.Accept();
}
var path = Directory.GetParent(localEpisode.Series.Path);
@@ -44,13 +43,13 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
if (!freeSpace.HasValue)
{
_logger.Debug("Free space check returned an invalid result for: {0}", path);
- return true;
+ return Decision.Accept();
}
if (freeSpace < localEpisode.Size + 100.Megabytes())
{
_logger.Warn("Not enough free space ({0}) to import: {1} ({2})", freeSpace, localEpisode, localEpisode.Size);
- return false;
+ return Decision.Reject("Not enough free space");
}
}
catch (DirectoryNotFoundException ex)
@@ -62,7 +61,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger.ErrorException("Unable to check free disk space while importing: " + localEpisode.Path, ex);
}
- return true;
+ return Decision.Accept();
}
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs
index 1c3c8bf79..7397c13e7 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/FullSeasonSpecification.cs
@@ -1,4 +1,5 @@
using NLog;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
@@ -12,17 +13,15 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger;
}
- public string RejectionReason { get { return "Full season file"; } }
-
- public bool IsSatisfiedBy(LocalEpisode localEpisode)
+ public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{
if (localEpisode.ParsedEpisodeInfo.FullSeason)
{
_logger.Debug("Single episode file detected as containing all episodes in the season");
- return false;
+ return Decision.Reject("Single episode file contains all episodes in seasons");
}
- return true;
+ return Decision.Accept();
}
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs
new file mode 100644
index 000000000..982ffe94f
--- /dev/null
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/MatchesFolderSpecification.cs
@@ -0,0 +1,54 @@
+using System;
+using System.IO;
+using System.Linq;
+using NLog;
+using NzbDrone.Core.DecisionEngine;
+using NzbDrone.Core.Parser.Model;
+
+namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
+{
+ public class MatchesFolderSpecification : IImportDecisionEngineSpecification
+ {
+ private readonly Logger _logger;
+
+ public MatchesFolderSpecification(Logger logger)
+ {
+ _logger = logger;
+ }
+ public Decision IsSatisfiedBy(LocalEpisode localEpisode)
+ {
+ if (localEpisode.ExistingFile)
+ {
+ return Decision.Accept();
+ }
+
+ var folderInfo = Parser.Parser.ParseTitle(new FileInfo(localEpisode.Path).DirectoryName);
+
+ if (folderInfo == null)
+ {
+ return Decision.Accept();
+ }
+
+ if (folderInfo.FullSeason)
+ {
+ return Decision.Accept();
+ }
+
+ var unexpected = localEpisode.ParsedEpisodeInfo.EpisodeNumbers.Where(f => !folderInfo.EpisodeNumbers.Contains(f)).ToList();
+
+ if (unexpected.Any())
+ {
+ _logger.Debug("Unexpected episode number(s) in file: {0}", unexpected);
+
+ if (unexpected.Count == 1)
+ {
+ return Decision.Reject("Episode Number {0} was unexpected", unexpected.First());
+ }
+
+ return Decision.Reject("Episode Numbers {0} were unexpected", String.Join(", ", unexpected));
+ }
+
+ return Decision.Accept();
+ }
+ }
+}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs
index 7d32566f8..3b9e072ae 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotSampleSpecification.cs
@@ -1,35 +1,41 @@
using NLog;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
{
public class NotSampleSpecification : IImportDecisionEngineSpecification
{
- private readonly ISampleService _sampleService;
+ private readonly IDetectSample _detectSample;
private readonly Logger _logger;
- public NotSampleSpecification(ISampleService sampleService,
+ public NotSampleSpecification(IDetectSample detectSample,
Logger logger)
{
- _sampleService = sampleService;
+ _detectSample = detectSample;
_logger = logger;
}
- public string RejectionReason { get { return "Sample"; } }
-
- public bool IsSatisfiedBy(LocalEpisode localEpisode)
+ public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{
if (localEpisode.ExistingFile)
{
_logger.Debug("Existing file, skipping sample check");
- return true;
+ return Decision.Accept();
+ }
+
+ var sample = _detectSample.IsSample(localEpisode.Series,
+ localEpisode.Quality,
+ localEpisode.Path,
+ localEpisode.Size,
+ localEpisode.SeasonNumber);
+
+ if (sample)
+ {
+ return Decision.Reject("Sample");
}
- return !_sampleService.IsSample(localEpisode.Series,
- localEpisode.Quality,
- localEpisode.Path,
- localEpisode.Size,
- localEpisode.SeasonNumber);
+ return Decision.Accept();
}
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs
index c18f96466..f457ddbf2 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/NotUnpackingSpecification.cs
@@ -4,6 +4,7 @@ using NLog;
using NzbDrone.Common.Disk;
using NzbDrone.Common.EnvironmentInfo;
using NzbDrone.Core.Configuration;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
@@ -21,14 +22,12 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger;
}
- public string RejectionReason { get { return "File is still being unpacked"; } }
-
- public bool IsSatisfiedBy(LocalEpisode localEpisode)
+ public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{
if (localEpisode.ExistingFile)
{
_logger.Debug("{0} is in series folder, unpacking check", localEpisode.Path);
- return true;
+ return Decision.Accept();
}
foreach (var workingFolder in _configService.DownloadClientWorkingFolders.Split('|'))
@@ -41,13 +40,13 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
if (OsInfo.IsNotWindows)
{
_logger.Debug("{0} is still being unpacked", localEpisode.Path);
- return false;
+ return Decision.Reject("File is still being unpacked");
}
if (_diskProvider.FileGetLastWrite(localEpisode.Path) > DateTime.UtcNow.AddMinutes(-5))
{
_logger.Debug("{0} appears to be unpacking still", localEpisode.Path);
- return false;
+ return Decision.Reject("File is still being unpacked");
}
}
@@ -55,7 +54,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
}
}
- return true;
+ return Decision.Accept();
}
}
}
diff --git a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs
index aa567571f..3d07306af 100644
--- a/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs
+++ b/src/NzbDrone.Core/MediaFiles/EpisodeImport/Specifications/UpgradeSpecification.cs
@@ -1,5 +1,6 @@
using System.Linq;
using NLog;
+using NzbDrone.Core.DecisionEngine;
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
@@ -14,18 +15,16 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
_logger = logger;
}
- public string RejectionReason { get { return "Not an upgrade for existing episode file(s)"; } }
-
- public bool IsSatisfiedBy(LocalEpisode localEpisode)
+ public Decision IsSatisfiedBy(LocalEpisode localEpisode)
{
var qualityComparer = new QualityModelComparer(localEpisode.Series.Profile);
if (localEpisode.Episodes.Any(e => e.EpisodeFileId != 0 && qualityComparer.Compare(e.EpisodeFile.Value.Quality, localEpisode.Quality) > 0))
{
_logger.Debug("This file isn't an upgrade for all episodes. Skipping {0}", localEpisode.Path);
- return false;
+ return Decision.Reject("Not an upgrade for existing episode file(s)");
}
- return true;
+ return Decision.Accept();
}
}
}
diff --git a/src/NzbDrone.Core/Metadata/ExistingMetadataService.cs b/src/NzbDrone.Core/Metadata/ExistingMetadataService.cs
index 177f1da91..e89b35be6 100644
--- a/src/NzbDrone.Core/Metadata/ExistingMetadataService.cs
+++ b/src/NzbDrone.Core/Metadata/ExistingMetadataService.cs
@@ -61,7 +61,7 @@ namespace NzbDrone.Core.Metadata
{
try
{
- var localEpisode = _parsingService.GetLocalEpisode(possibleMetadataFile, message.Series, false);
+ var localEpisode = _parsingService.GetLocalEpisode(possibleMetadataFile, message.Series);
if (localEpisode == null)
{
diff --git a/src/NzbDrone.Core/NzbDrone.Core.csproj b/src/NzbDrone.Core/NzbDrone.Core.csproj
index 2c4a2f698..04736e507 100644
--- a/src/NzbDrone.Core/NzbDrone.Core.csproj
+++ b/src/NzbDrone.Core/NzbDrone.Core.csproj
@@ -561,8 +561,9 @@
-
+
+
diff --git a/src/NzbDrone.Core/Parser/Parser.cs b/src/NzbDrone.Core/Parser/Parser.cs
index ba59179a4..ab684792b 100644
--- a/src/NzbDrone.Core/Parser/Parser.cs
+++ b/src/NzbDrone.Core/Parser/Parser.cs
@@ -104,7 +104,7 @@ namespace NzbDrone.Core.Parser
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Episodes with single digit episode number (S01E1, S01E5E6, etc)
- new Regex(@"^(?.*?)(?:\W?S?(?(?\d{1}))+)+(\W+|_|$)(?!\\)",
+ new Regex(@"^(?.*?)(?:(?:_|-|\s|\.)S?(?(?\d{1}))+)+(\W+|_|$)(?!\\)",
RegexOptions.IgnoreCase | RegexOptions.Compiled),
//Anime - Title Absolute Episode Number (e66)
diff --git a/src/NzbDrone.Core/Parser/ParsingService.cs b/src/NzbDrone.Core/Parser/ParsingService.cs
index 46e80a118..14d4f2de4 100644
--- a/src/NzbDrone.Core/Parser/ParsingService.cs
+++ b/src/NzbDrone.Core/Parser/ParsingService.cs
@@ -13,7 +13,8 @@ namespace NzbDrone.Core.Parser
{
public interface IParsingService
{
- LocalEpisode GetLocalEpisode(string filename, Series series, bool sceneSource);
+ LocalEpisode GetLocalEpisode(string filename, Series series);
+ LocalEpisode GetLocalEpisode(string filename, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource);
Series GetSeries(string title);
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, Int32 tvRageId = 0, SearchCriteriaBase searchCriteria = null);
RemoteEpisode Map(ParsedEpisodeInfo parsedEpisodeInfo, Int32 seriesId, IEnumerable episodeIds);
@@ -39,9 +40,25 @@ namespace NzbDrone.Core.Parser
_logger = logger;
}
- public LocalEpisode GetLocalEpisode(string filename, Series series, bool sceneSource)
+ public LocalEpisode GetLocalEpisode(string filename, Series series)
{
- var parsedEpisodeInfo = Parser.ParsePath(filename);
+ return GetLocalEpisode(filename, series, null, false);
+ }
+
+ public LocalEpisode GetLocalEpisode(string filename, Series series, ParsedEpisodeInfo folderInfo, bool sceneSource)
+ {
+ ParsedEpisodeInfo parsedEpisodeInfo;
+
+ if (folderInfo != null)
+ {
+ parsedEpisodeInfo = folderInfo.JsonClone();
+ parsedEpisodeInfo.Quality = QualityParser.ParseQuality(Path.GetFileName(filename));
+ }
+
+ else
+ {
+ parsedEpisodeInfo = Parser.ParsePath(filename);
+ }
if (parsedEpisodeInfo == null || parsedEpisodeInfo.IsPossibleSpecialEpisode)
{
diff --git a/src/NzbDrone.Core/Parser/SceneChecker.cs b/src/NzbDrone.Core/Parser/SceneChecker.cs
index 75fa4595c..339f6b17c 100644
--- a/src/NzbDrone.Core/Parser/SceneChecker.cs
+++ b/src/NzbDrone.Core/Parser/SceneChecker.cs
@@ -1,4 +1,6 @@
-namespace NzbDrone.Core.Parser
+using System;
+
+namespace NzbDrone.Core.Parser
{
public static class SceneChecker
{
@@ -10,10 +12,14 @@
if (title.Contains(" ")) return false;
var parsedTitle = Parser.ParseTitle(title);
- if (parsedTitle == null
- || parsedTitle.ReleaseGroup == null
- || parsedTitle.Quality.Quality == Qualities.Quality.Unknown
- || string.IsNullOrWhiteSpace(parsedTitle.SeriesTitle)) return false;
+
+ if (parsedTitle == null ||
+ parsedTitle.ReleaseGroup == null ||
+ parsedTitle.Quality.Quality == Qualities.Quality.Unknown ||
+ String.IsNullOrWhiteSpace(parsedTitle.SeriesTitle))
+ {
+ return false;
+ }
return true;
}
diff --git a/src/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj b/src/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj
index 105bf8b55..3500ef1ad 100644
--- a/src/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj
+++ b/src/NzbDrone.Test.Common/NzbDrone.Test.Common.csproj
@@ -91,7 +91,6 @@
-