From 6e88f55a5481100781b2f070d7f3e9ce55377440 Mon Sep 17 00:00:00 2001 From: "kay.one" Date: Sun, 14 Apr 2013 18:41:39 -0700 Subject: [PATCH] cleaned up parsing logic and structure. --- NzbDrone.Common.Test/DiskProviderFixture.cs | 8 +- NzbDrone.Common/DiskProvider.cs | 17 +- .../AcceptableSizeSpecificationFixture.cs | 206 +++---- .../AllowedDownloadSpecificationFixture.cs | 52 +- ...AllowedReleaseGroupSpecificationFixture.cs | 35 +- .../CustomStartDateSpecificationFixture.cs | 29 +- .../LanguageSpecificationFixture.cs | 12 +- .../MonitoredEpisodeSpecificationFixture.cs | 43 +- ...ityAllowedByProfileSpecificationFixture.cs | 22 +- .../RetentionSpecificationFixture.cs | 42 +- .../UpgradeDiskSpecificationFixture.cs | 22 +- .../UpgradeHistorySpecificationFixture.cs | 22 +- .../NzbgetProviderTests/DownloadNzbFixture.cs | 4 +- .../NzbgetProviderTests/QueueFixture.cs | 6 +- .../PneumaticProviderFixture.cs | 10 +- .../SabProviderTests/QueueFixture.cs | 48 +- .../SabProviderTests/SabProviderFixture.cs | 26 +- .../Download/DownloadServiceFixture.cs | 6 +- NzbDrone.Core.Test/EpisodeParseResultTest.cs | 29 +- NzbDrone.Core.Test/EpisodeStatusTest.cs | 46 +- .../JobTests/AppUpdateJobFixture.cs | 4 +- .../JobTests/DiskScanJobTest.cs | 19 - .../JobTests/PostDownloadScanJobFixture.cs | 8 +- NzbDrone.Core.Test/NzbDrone.Core.Test.csproj | 7 +- .../ParserTests/ParserFixture.cs | 105 ++-- .../ParserTests/QualityParserFixture.cs | 4 +- .../DiskProviderTests/FreeDiskSpaceTest.cs | 13 +- .../CleanUpDropFolderFixture.cs | 123 ---- .../ImportFileFixture.cs | 565 +++++------------- .../DropFolderImportServiceFixture.cs | 145 +++++ .../GetFolderNameWithStatusFixture.cs | 44 -- .../ProcessDownloadFixture.cs | 469 --------------- .../ProcessDropDirectoryFixture.cs | 135 ----- .../ProcessVideoFileFixture.cs | 267 --------- .../RecycleBinProviderTests/CleanupFixture.cs | 4 +- .../FreeSpaceOnDrivesFixture.cs | 11 +- .../UpdateTests/GetAvailableUpdateFixture.cs | 13 +- .../UpdateTests/GetUpdateLogFixture.cs | 21 +- .../UpdatePackageProviderFixture.cs | 15 + .../DecisionEngine/DownloadDecision.cs | 21 +- .../DecisionEngine/DownloadDecisionMaker.cs | 36 +- .../IDecisionEngineSpecification.cs | 4 +- .../AcceptableSizeSpecification.cs | 18 +- .../AllowedReleaseGroupSpecification.cs | 12 +- .../CustomStartDateSpecification.cs | 4 +- .../Specifications/LanguageSpecification.cs | 6 +- .../MonitoredEpisodeSpecification.cs | 23 +- .../Specifications/NotInQueueSpecification.cs | 35 +- .../QualityAllowedByProfileSpecification.cs | 4 +- .../Specifications/RetentionSpecification.cs | 12 +- .../Search/DailyEpisodeMatchSpecification.cs | 6 +- .../IDecisionEngineSearchSpecification.cs | 4 +- .../Search/SeasonMatchSpecification.cs | 8 +- ... SingleEpisodeSearchMatchSpecification.cs} | 13 +- .../UpgradeDiskSpecification.cs | 8 +- .../UpgradeHistorySpecification.cs | 4 +- .../Download/Clients/BlackholeProvider.cs | 29 +- .../Nzbget/{Queue.cs => NzbGetQueue.cs} | 6 +- .../Clients/Nzbget/NzbGetQueueItem.cs | 18 + .../{NzbgetProvider.cs => NzbgetClient.cs} | 69 +-- .../Download/Clients/Nzbget/QueueItem.cs | 31 - ...neumaticProvider.cs => PneumaticClient.cs} | 16 +- .../{ => Sabnzbd}/ConnectionInfoModel.cs | 2 +- .../Download/Clients/Sabnzbd/SabQueueItem.cs | 12 +- .../{SabProvider.cs => SabnzbdClient.cs} | 68 +-- .../Download/DownloadClientProvider.cs | 24 +- NzbDrone.Core/Download/DownloadService.cs | 20 +- NzbDrone.Core/Download/EpisodeGrabbedEvent.cs | 8 +- NzbDrone.Core/Download/IDownloadClient.cs | 6 +- NzbDrone.Core/Download/SabQueueItem.cs | 23 + .../ExternalNotificationBase.cs | 4 +- NzbDrone.Core/History/HistoryService.cs | 12 +- .../SingleEpisodeSearchDefinition.cs | 1 - .../IndexerSearch/NzbSearchService.cs | 6 +- NzbDrone.Core/Indexers/BasicRssParser.cs | 27 +- .../FileSharingTalk/FileSharingTalkParser.cs | 4 +- NzbDrone.Core/Indexers/IndexerFetchService.cs | 26 +- .../Indexers/Newznab/NewznabParser.cs | 4 +- .../Indexers/NzbClub/NzbClubParser.cs | 4 +- .../Indexers/NzbIndex/NzbIndexParser.cs | 4 +- .../Indexers/NzbsRUs/NzbsrusParser.cs | 4 +- NzbDrone.Core/Indexers/Nzbx/NzbxParser.cs | 24 +- .../Indexers/Omgwtfnzbs/OmgwtfnzbsParser.cs | 4 +- NzbDrone.Core/Indexers/RssSyncService.cs | 14 +- .../Indexers/Wombles/WomblesParser.cs | 4 +- .../Implementations/PostDownloadScanJob.cs | 8 +- NzbDrone.Core/Lifecycle/AppUpdateJob.cs | 4 +- NzbDrone.Core/MediaFiles/EpisodeFile.cs | 3 +- .../MediaFiles/EpisodeFileMovingService.cs | 8 +- .../Events/EpisodeDownloadedEvent.cs | 9 +- .../Events/EpisodeFileAddedEvent.cs | 15 + NzbDrone.Core/MediaFiles/MediaFileService.cs | 4 +- NzbDrone.Core/Model/IndexerParseResult.cs | 147 ----- NzbDrone.Core/Model/MediaInfoModel.cs | 7 +- NzbDrone.Core/NzbDrone.Core.csproj | 34 +- NzbDrone.Core/Organizer/FileNameBuilder.cs | 4 +- .../LanguageType.cs => Parser/Language.cs} | 4 +- NzbDrone.Core/Parser/Model/LocalEpisode.cs | 16 + .../Parser/Model/ParsedEpisodeInfo.cs | 42 ++ NzbDrone.Core/Parser/Model/RemoteEpisode.cs | 108 ++++ NzbDrone.Core/Parser/Model/ReportInfo.cs | 15 + NzbDrone.Core/{ => Parser}/Parser.cs | 173 +++--- NzbDrone.Core/Parser/ParsingService.cs | 132 ++++ NzbDrone.Core/Providers/DiskScanProvider.cs | 150 +---- .../Providers/DropfolderImportService.cs | 121 ++++ .../Providers/PostDownloadProvider.cs | 209 ------- NzbDrone.Core/Providers/RecycleBinProvider.cs | 2 +- ...InfoProvider.cs => VideoFileInfoReader.cs} | 35 +- .../RootFolders/RootFolderService.cs | 6 +- NzbDrone.Core/Tv/Episode.cs | 32 +- NzbDrone.Core/Tv/EpisodeRepository.cs | Bin 6970 -> 7566 bytes NzbDrone.Core/Tv/EpisodeService.cs | 115 +--- .../EpisodeStatuses.cs} | 6 +- NzbDrone.Core/Tv/Series.cs | 1 - NzbDrone.Core/Tv/SeriesRepository.cs | 9 +- NzbDrone.Core/Tv/SeriesService.cs | 21 +- ...ateService.cs => UpdatePackageProvider.cs} | 21 +- NzbDrone.Core/Update/UpdateProvider.cs | 22 +- NzbDrone.ncrunchsolution | 2 +- ...ANB-W520's conflicted copy 2013-04-12).xml | 379 ++++++++++++ 120 files changed, 2149 insertions(+), 3064 deletions(-) delete mode 100644 NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/CleanUpDropFolderFixture.cs create mode 100644 NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/DropFolderImportServiceFixture.cs delete mode 100644 NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/GetFolderNameWithStatusFixture.cs delete mode 100644 NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs delete mode 100644 NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDropDirectoryFixture.cs delete mode 100644 NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessVideoFileFixture.cs create mode 100644 NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs rename NzbDrone.Core/DecisionEngine/Specifications/Search/{SingleEpisodeMatchSpecification.cs => SingleEpisodeSearchMatchSpecification.cs} (62%) rename NzbDrone.Core/Download/Clients/Nzbget/{Queue.cs => NzbGetQueue.cs} (66%) create mode 100644 NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueueItem.cs rename NzbDrone.Core/Download/Clients/Nzbget/{NzbgetProvider.cs => NzbgetClient.cs} (66%) delete mode 100644 NzbDrone.Core/Download/Clients/Nzbget/QueueItem.cs rename NzbDrone.Core/Download/Clients/{PneumaticProvider.cs => PneumaticClient.cs} (83%) rename NzbDrone.Core/Download/Clients/{ => Sabnzbd}/ConnectionInfoModel.cs (73%) rename NzbDrone.Core/Download/Clients/Sabnzbd/{SabProvider.cs => SabnzbdClient.cs} (76%) create mode 100644 NzbDrone.Core/Download/SabQueueItem.cs create mode 100644 NzbDrone.Core/MediaFiles/Events/EpisodeFileAddedEvent.cs delete mode 100644 NzbDrone.Core/Model/IndexerParseResult.cs rename NzbDrone.Core/{Model/LanguageType.cs => Parser/Language.cs} (88%) create mode 100644 NzbDrone.Core/Parser/Model/LocalEpisode.cs create mode 100644 NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs create mode 100644 NzbDrone.Core/Parser/Model/RemoteEpisode.cs create mode 100644 NzbDrone.Core/Parser/Model/ReportInfo.cs rename NzbDrone.Core/{ => Parser}/Parser.cs (67%) create mode 100644 NzbDrone.Core/Parser/ParsingService.cs create mode 100644 NzbDrone.Core/Providers/DropfolderImportService.cs delete mode 100644 NzbDrone.Core/Providers/PostDownloadProvider.cs rename NzbDrone.Core/Providers/{MediaInfoProvider.cs => VideoFileInfoReader.cs} (84%) rename NzbDrone.Core/{Model/EpisodeStatusType.cs => Tv/EpisodeStatuses.cs} (93%) rename NzbDrone.Core/Update/{AvailableUpdateService.cs => UpdatePackageProvider.cs} (67%) create mode 100644 UI/.idea/workspace (KEIVANB-W520's conflicted copy 2013-04-12).xml diff --git a/NzbDrone.Common.Test/DiskProviderFixture.cs b/NzbDrone.Common.Test/DiskProviderFixture.cs index d0ad18fa9..d385913ee 100644 --- a/NzbDrone.Common.Test/DiskProviderFixture.cs +++ b/NzbDrone.Common.Test/DiskProviderFixture.cs @@ -154,22 +154,22 @@ public void paths_should_not_be_equeal(string first, string second) public void empty_folder_should_return_folder_modified_date() { var tempfolder = new DirectoryInfo(TempFolder); - Mocker.Resolve().GetLastDirectoryWrite(TempFolder).Should().Be(tempfolder.LastWriteTimeUtc); + Mocker.Resolve().GetLastFolderWrite(TempFolder).Should().Be(tempfolder.LastWriteTimeUtc); } [Test] public void folder_should_return_correct_value_for_last_write() { var appPath = new EnvironmentProvider().WorkingDirectory; - Mocker.Resolve().GetLastDirectoryWrite(appPath).Should().BeOnOrAfter(DateTime.UtcNow.AddMinutes(-10)); - Mocker.Resolve().GetLastDirectoryWrite(appPath).Should().BeBefore(DateTime.UtcNow); + Mocker.Resolve().GetLastFolderWrite(appPath).Should().BeOnOrAfter(DateTime.UtcNow.AddMinutes(-10)); + Mocker.Resolve().GetLastFolderWrite(appPath).Should().BeBefore(DateTime.UtcNow); } [Test] [Explicit] public void check_last_write() { - Console.WriteLine(Mocker.Resolve().GetLastDirectoryWrite(@"C:\DRIVERS")); + Console.WriteLine(Mocker.Resolve().GetLastFolderWrite(@"C:\DRIVERS")); Console.WriteLine(new DirectoryInfo(@"C:\DRIVERS").LastWriteTimeUtc); } diff --git a/NzbDrone.Common/DiskProvider.cs b/NzbDrone.Common/DiskProvider.cs index fe5c10bf4..31501f7ea 100644 --- a/NzbDrone.Common/DiskProvider.cs +++ b/NzbDrone.Common/DiskProvider.cs @@ -24,7 +24,7 @@ static extern bool GetDiskFreeSpaceEx(string lpDirectoryName, private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - public virtual DateTime GetLastDirectoryWrite(string path) + public virtual DateTime GetLastFolderWrite(string path) { if (!FolderExists(path)) { @@ -50,6 +50,15 @@ public virtual DateTime GetLastFileWrite(string path) return new FileInfo(path).LastWriteTimeUtc; } + + public virtual void EnsureFolder(string path) + { + if (!FolderExists(path)) + { + CreateFolder(path); + } + } + public virtual bool FolderExists(string path) { return Directory.Exists(path); @@ -84,7 +93,7 @@ public virtual long GetSize(string path) return fi.Length; } - public virtual String CreateDirectory(string path) + public virtual String CreateFolder(string path) { return Directory.CreateDirectory(path).FullName; } @@ -191,7 +200,7 @@ public virtual void InheritFolderPermissions(string filename) File.SetAccessControl(filename, fs); } - public virtual ulong FreeDiskSpace(string path) + public virtual ulong GetAvilableSpace(string path) { if (!FolderExists(path)) throw new DirectoryNotFoundException(path); @@ -237,7 +246,7 @@ public virtual bool IsFolderLocked(string path) { var files = GetFileInfos(path, "*.*", SearchOption.AllDirectories); - foreach(var fileInfo in files) + foreach (var fileInfo in files) { if (IsFileLocked(fileInfo)) return true; diff --git a/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs index a209b6a0e..27c46354a 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/AcceptableSizeSpecificationFixture.cs @@ -1,28 +1,22 @@ - - -using System.Linq; -using System; -using System.Collections.Generic; +using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - - public class AcceptableSizeSpecificationFixture : CoreTest + + public class AcceptableSizeSpecificationFixture : CoreTest { - private IndexerParseResult parseResultMulti; - private IndexerParseResult parseResultSingle; + private RemoteEpisode parseResultMulti; + private RemoteEpisode parseResultSingle; private Series series30minutes; private Series series60minutes; private QualitySize qualityType; @@ -30,35 +24,26 @@ public class AcceptableSizeSpecificationFixture : CoreTest [SetUp] public void Setup() { - parseResultMulti = new IndexerParseResult + parseResultMulti = new RemoteEpisode { - SeriesTitle = "Title", - Language = LanguageType.English, + Report = new ReportInfo(), Quality = new QualityModel(Quality.SDTV, true), - EpisodeNumbers = new List { 3, 4 }, - SeasonNumber = 12, - AirDate = DateTime.Now.AddDays(-12).Date + Episodes = new List { new Episode(), new Episode() } }; - parseResultSingle = new IndexerParseResult + parseResultSingle = new RemoteEpisode { - SeriesTitle = "Title", - Language = LanguageType.English, + Report = new ReportInfo(), Quality = new QualityModel(Quality.SDTV, true), - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, - AirDate = DateTime.Now.AddDays(-12).Date + Episodes = new List { new Episode() } + }; series30minutes = Builder.CreateNew() - .With(c => c.Monitored = true) - .With(d => d.CleanTitle = parseResultMulti.CleanTitle) .With(c => c.Runtime = 30) .Build(); series60minutes = Builder.CreateNew() - .With(c => c.Monitored = true) - .With(d => d.CleanTitle = parseResultMulti.CleanTitle) .With(c => c.Runtime = 60) .Build(); @@ -73,42 +58,38 @@ public void Setup() [Test] public void IsAcceptableSize_true_single_episode_not_first_or_last_30_minute() { - WithStrictMocker(); - parseResultSingle.Series = series30minutes; - parseResultSingle.Size = 184572800; + parseResultSingle.Report.Size = 184572800; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } [Test] public void IsAcceptableSize_true_single_episode_not_first_or_last_60_minute() { - WithStrictMocker(); - parseResultSingle.Series = series60minutes; - parseResultSingle.Size = 368572800; + parseResultSingle.Report.Size = 368572800; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } @@ -118,18 +99,18 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_30_minute() WithStrictMocker(); parseResultSingle.Series = series30minutes; - parseResultSingle.Size = 1.Gigabytes(); + parseResultSingle.Report.Size = 1.Gigabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeFalse(); } @@ -139,18 +120,18 @@ public void IsAcceptableSize_false_single_episode_not_first_or_last_60_minute() WithStrictMocker(); parseResultSingle.Series = series60minutes; - parseResultSingle.Size = 1.Gigabytes(); + parseResultSingle.Report.Size = 1.Gigabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeFalse(); } @@ -160,18 +141,18 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_30_minute() WithStrictMocker(); parseResultMulti.Series = series30minutes; - parseResultMulti.Size = 184572800; + parseResultMulti.Report.Size = 184572800; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultMulti); - + bool result = Subject.IsSatisfiedBy(parseResultMulti); + + result.Should().BeTrue(); } @@ -181,18 +162,18 @@ public void IsAcceptableSize_true_multi_episode_not_first_or_last_60_minute() WithStrictMocker(); parseResultMulti.Series = series60minutes; - parseResultMulti.Size = 368572800; + parseResultMulti.Report.Size = 368572800; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultMulti); - + bool result = Subject.IsSatisfiedBy(parseResultMulti); + + result.Should().BeTrue(); } @@ -202,18 +183,18 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_30_minute() WithStrictMocker(); parseResultMulti.Series = series30minutes; - parseResultMulti.Size = 1.Gigabytes(); + parseResultMulti.Report.Size = 1.Gigabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultMulti); - + bool result = Subject.IsSatisfiedBy(parseResultMulti); + + result.Should().BeFalse(); } @@ -223,18 +204,18 @@ public void IsAcceptableSize_false_multi_episode_not_first_or_last_60_minute() WithStrictMocker(); parseResultMulti.Series = series60minutes; - parseResultMulti.Size = 10.Gigabytes(); + parseResultMulti.Report.Size = 10.Gigabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(false); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultMulti); - + bool result = Subject.IsSatisfiedBy(parseResultMulti); + + result.Should().BeFalse(); } @@ -244,18 +225,18 @@ public void IsAcceptableSize_true_single_episode_first_30_minute() WithStrictMocker(); parseResultSingle.Series = series30minutes; - parseResultSingle.Size = 184572800; + parseResultSingle.Report.Size = 184572800; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } @@ -265,18 +246,18 @@ public void IsAcceptableSize_true_single_episode_first_60_minute() WithStrictMocker(); parseResultSingle.Series = series60minutes; - parseResultSingle.Size = 368572800; + parseResultSingle.Report.Size = 368572800; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } @@ -286,18 +267,18 @@ public void IsAcceptableSize_false_single_episode_first_30_minute() WithStrictMocker(); parseResultSingle.Series = series30minutes; - parseResultSingle.Size = 1.Gigabytes(); + parseResultSingle.Report.Size = 1.Gigabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeFalse(); } @@ -307,18 +288,18 @@ public void IsAcceptableSize_false_single_episode_first_60_minute() WithStrictMocker(); parseResultSingle.Series = series60minutes; - parseResultSingle.Size = 10.Gigabytes(); + parseResultSingle.Report.Size = 10.Gigabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeFalse(); } @@ -328,19 +309,19 @@ public void IsAcceptableSize_true_unlimited_30_minute() WithStrictMocker(); parseResultSingle.Series = series30minutes; - parseResultSingle.Size = 18457280000; + parseResultSingle.Report.Size = 18457280000; qualityType.MaxSize = 0; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } @@ -350,54 +331,55 @@ public void IsAcceptableSize_true_unlimited_60_minute() WithStrictMocker(); parseResultSingle.Series = series60minutes; - parseResultSingle.Size = 36857280000; + parseResultSingle.Report.Size = 36857280000; qualityType.MaxSize = 0; Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } [Test] public void IsAcceptableSize_should_treat_daily_series_as_single_episode() { + parseResultSingle.Series = series60minutes; - parseResultSingle.Size = 300.Megabytes(); - parseResultSingle.AirDate = DateTime.Today; - parseResultSingle.EpisodeNumbers = null; + parseResultSingle.Series.SeriesType = SeriesTypes.Daily; + + parseResultSingle.Report.Size = 300.Megabytes(); qualityType.MaxSize = (int)600.Megabytes(); Mocker.GetMock().Setup(s => s.Get(1)).Returns(qualityType); Mocker.GetMock().Setup( - s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny(), It.IsAny(), It.IsAny())) + s => s.IsFirstOrLastEpisodeOfSeason(It.IsAny())) .Returns(true); - - bool result = Mocker.Resolve().IsSatisfiedBy(parseResultSingle); - + bool result = Subject.IsSatisfiedBy(parseResultSingle); + + result.Should().BeTrue(); } [Test] public void should_return_true_if_RAWHD() { - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { - Quality = new QualityModel(Quality.RAWHD, false) + Quality = new QualityModel(Quality.RAWHD, false) }; - Mocker.Resolve().IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs index b3252ef23..5ff82a998 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/AllowedDownloadSpecificationFixture.cs @@ -3,8 +3,9 @@ using FluentAssertions; using Moq; using NUnit.Framework; -using NzbDrone.Core.Model; using NzbDrone.Core.DecisionEngine; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests @@ -12,7 +13,8 @@ namespace NzbDrone.Core.Test.DecisionEngineTests [TestFixture] public class AllowedDownloadSpecificationFixture : CoreTest { - private List _parseResults; + private List _reports; + private RemoteEpisode _remoteEpisode; private Mock _pass1; private Mock _pass2; @@ -33,15 +35,19 @@ public void Setup() _fail2 = new Mock(); _fail3 = new Mock(); - _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true); - _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true); - _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true); + _pass1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true); + _pass2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true); + _pass3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(true); - _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); - _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); - _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); + _fail1.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); + _fail2.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); + _fail3.Setup(c => c.IsSatisfiedBy(It.IsAny())).Returns(false); - _parseResults = new List() { new IndexerParseResult() }; + _reports = new List(); + _remoteEpisode = new RemoteEpisode(); + + Mocker.GetMock().Setup(c => c.Map(It.IsAny())) + .Returns(_remoteEpisode); } @@ -55,14 +61,14 @@ public void should_call_all_specifications() { GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3); - Subject.GetRssDecision(_parseResults).ToList(); + Subject.GetRssDecision(_reports).ToList(); - _fail1.Verify(c => c.IsSatisfiedBy(_parseResults[0]), Times.Once()); - _fail2.Verify(c => c.IsSatisfiedBy(_parseResults[0]), Times.Once()); - _fail3.Verify(c => c.IsSatisfiedBy(_parseResults[0]), Times.Once()); - _pass1.Verify(c => c.IsSatisfiedBy(_parseResults[0]), Times.Once()); - _pass2.Verify(c => c.IsSatisfiedBy(_parseResults[0]), Times.Once()); - _pass3.Verify(c => c.IsSatisfiedBy(_parseResults[0]), Times.Once()); + _fail1.Verify(c => c.IsSatisfiedBy(_remoteEpisode), Times.Once()); + _fail2.Verify(c => c.IsSatisfiedBy(_remoteEpisode), Times.Once()); + _fail3.Verify(c => c.IsSatisfiedBy(_remoteEpisode), Times.Once()); + _pass1.Verify(c => c.IsSatisfiedBy(_remoteEpisode), Times.Once()); + _pass2.Verify(c => c.IsSatisfiedBy(_remoteEpisode), Times.Once()); + _pass3.Verify(c => c.IsSatisfiedBy(_remoteEpisode), Times.Once()); } [Test] @@ -70,7 +76,7 @@ public void should_return_rejected_if_one_of_specs_fail() { GivenSpecifications(_pass1, _fail1, _pass2, _pass3); - var result = Subject.GetRssDecision(_parseResults); + var result = Subject.GetRssDecision(_reports); result.Single().Approved.Should().BeFalse(); } @@ -80,7 +86,7 @@ public void should_return_pass_if_all_specs_pass() { GivenSpecifications(_pass1, _pass2, _pass3); - var result = Subject.GetRssDecision(_parseResults); + var result = Subject.GetRssDecision(_reports); result.Single().Approved.Should().BeTrue(); } @@ -90,19 +96,11 @@ public void should_have_same_number_of_rejections_as_specs_that_failed() { GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3); - var result = Subject.GetRssDecision(_parseResults); + var result = Subject.GetRssDecision(_reports); result.Single().Rejections.Should().HaveCount(3); } - [Test] - public void parse_result_should_be_attached_to_decision() - { - GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3); - - var result = Subject.GetRssDecision(_parseResults); - result.Single().ParseResult.Should().Be(_parseResults.Single()); - } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/DecisionEngineTests/AllowedReleaseGroupSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/AllowedReleaseGroupSpecificationFixture.cs index 691a7551d..4f66e74cc 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/AllowedReleaseGroupSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/AllowedReleaseGroupSpecificationFixture.cs @@ -1,11 +1,7 @@ -using System; -using System.Collections.Generic; -using FluentAssertions; +using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; -using NzbDrone.Core.Qualities; -using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests @@ -14,45 +10,42 @@ namespace NzbDrone.Core.Test.DecisionEngineTests public class AllowedReleaseGroupSpecificationFixture : CoreTest { - private IndexerParseResult parseResult; + private RemoteEpisode _parseResult; [SetUp] public void Setup() { - parseResult = new IndexerParseResult - { - SeriesTitle = "Title", - Language = LanguageType.English, - Quality = new QualityModel(Quality.SDTV, true), - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, - AirDate = DateTime.Now.AddDays(-12).Date, - ReleaseGroup = "2HD" - }; + _parseResult = new RemoteEpisode + { + Report = new ReportInfo + { + ReleaseGroup = "2HD" + } + }; } [Test] public void should_be_true_when_allowedReleaseGroups_is_empty() { - Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(_parseResult).Should().BeTrue(); } [Test] public void should_be_true_when_allowedReleaseGroups_is_nzbs_releaseGroup() { - Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(_parseResult).Should().BeTrue(); } [Test] public void should_be_true_when_allowedReleaseGroups_contains_nzbs_releaseGroup() { - Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(_parseResult).Should().BeTrue(); } [Test] public void should_be_false_when_allowedReleaseGroups_does_not_contain_nzbs_releaseGroup() { - Subject.IsSatisfiedBy(parseResult).Should().BeFalse(); + Subject.IsSatisfiedBy(_parseResult).Should().BeFalse(); } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/DecisionEngineTests/CustomStartDateSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/CustomStartDateSpecificationFixture.cs index 773f66c68..4dc0ace87 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/CustomStartDateSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/CustomStartDateSpecificationFixture.cs @@ -1,30 +1,23 @@ - - -using System.Linq; -using System; +using System; using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; -using Moq; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.DecisionEngine; - using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - - public class CustomStartDateSpecificationFixture : CoreTest + + public class CustomStartDateSpecificationFixture : CoreTest { private CustomStartDateSpecification _customStartDateSpecification; - private IndexerParseResult parseResultMulti; - private IndexerParseResult parseResultSingle; + private RemoteEpisode parseResultMulti; + private RemoteEpisode parseResultSingle; private Series fakeSeries; private Episode firstEpisode; private Episode secondEpisode; @@ -42,21 +35,15 @@ public void Setup() .With(c => c.CustomStartDate = null) .Build(); - parseResultMulti = new IndexerParseResult + parseResultMulti = new RemoteEpisode { - SeriesTitle = "Title", Series = fakeSeries, - EpisodeNumbers = new List { 3, 4 }, - SeasonNumber = 12, Episodes = new List { firstEpisode, secondEpisode } }; - parseResultSingle = new IndexerParseResult + parseResultSingle = new RemoteEpisode { - SeriesTitle = "Title", Series = fakeSeries, - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, Episodes = new List { firstEpisode } }; } diff --git a/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs index 1cfc4f6f3..84770eede 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/LanguageSpecificationFixture.cs @@ -9,6 +9,8 @@ using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Providers; using NzbDrone.Core.DecisionEngine; @@ -20,21 +22,21 @@ namespace NzbDrone.Core.Test.DecisionEngineTests public class LanguageSpecificationFixture : CoreTest { - private IndexerParseResult parseResult; + private RemoteEpisode parseResult; private void WithEnglishRelease() { - parseResult = Builder + parseResult = Builder .CreateNew() - .With(p => p.Language = LanguageType.English) + .With(p => p.Language = Language.English) .Build(); } private void WithGermanRelease() { - parseResult = Builder + parseResult = Builder .CreateNew() - .With(p => p.Language = LanguageType.German) + .With(p => p.Language = Language.German) .Build(); } diff --git a/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs index 1fb502e6c..394ea652c 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/MonitoredEpisodeSpecificationFixture.cs @@ -1,30 +1,24 @@ - - -using System.Linq; -using System; +using System; using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; using Moq; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.DecisionEngine; - using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - - public class MonitoredEpisodeSpecificationFixture : CoreTest + + public class MonitoredEpisodeSpecificationFixture : CoreTest { private MonitoredEpisodeSpecification monitoredEpisodeSpecification; - private IndexerParseResult parseResultMulti; - private IndexerParseResult parseResultSingle; + private RemoteEpisode parseResultMulti; + private RemoteEpisode parseResultSingle; private Series fakeSeries; private Episode firstEpisode; private Episode secondEpisode; @@ -38,33 +32,26 @@ public void Setup() .With(c => c.Monitored = true) .Build(); - parseResultMulti = new IndexerParseResult + + var singleEpisodeList = new List { firstEpisode }; + var doubleEpisodeList = new List { firstEpisode, secondEpisode }; + + parseResultMulti = new RemoteEpisode { - SeriesTitle = "Title", Series = fakeSeries, - EpisodeNumbers = new List { 3, 4 }, - SeasonNumber = 12, + Episodes = doubleEpisodeList }; - parseResultSingle = new IndexerParseResult + parseResultSingle = new RemoteEpisode { - SeriesTitle = "Title", Series = fakeSeries, - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, + Episodes = singleEpisodeList }; firstEpisode = new Episode { Ignored = false }; secondEpisode = new Episode { Ignored = false }; - var singleEpisodeList = new List { firstEpisode }; - var doubleEpisodeList = new List { firstEpisode, secondEpisode }; - Mocker.GetMock().Setup(c => c.GetEpisodesByParseResult(parseResultSingle)).Returns(singleEpisodeList); - Mocker.GetMock().Setup(c => c.GetEpisodesByParseResult(parseResultMulti)).Returns(doubleEpisodeList); - - Mocker.GetMock().Setup(c => c.GetByTitle(parseResultMulti.CleanTitle)).Returns(fakeSeries); - Mocker.GetMock().Setup(c => c.GetByTitle(parseResultSingle.CleanTitle)).Returns(fakeSeries); } private void WithFirstEpisodeIgnored() @@ -97,7 +84,7 @@ public void not_monitored_series_should_be_skipped() public void not_in_db_should_be_skipped() { Mocker.GetMock() - .Setup(p => p.GetByTitle(It.IsAny())) + .Setup(p => p.FindByTitle(It.IsAny())) .Returns(null); monitoredEpisodeSpecification.IsSatisfiedBy(parseResultMulti).Should().BeFalse(); diff --git a/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs index f89c69999..a5d1e5174 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/QualityAllowedByProfileSpecificationFixture.cs @@ -1,26 +1,22 @@  using System.Collections.Generic; -using System.Linq; using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.DecisionEngine; - using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - - public class QualityAllowedByProfileSpecificationFixture : CoreTest + + public class QualityAllowedByProfileSpecificationFixture : CoreTest { - private QualityAllowedByProfileSpecification _qualityAllowedByProfile; - private IndexerParseResult parseResult; + private RemoteEpisode parseResult; public static object[] AllowedTestCases = { @@ -39,18 +35,14 @@ public class QualityAllowedByProfileSpecificationFixture : CoreTest [SetUp] public void Setup() { - _qualityAllowedByProfile = Mocker.Resolve(); - var fakeSeries = Builder.CreateNew() .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p }) .Build(); - parseResult = new IndexerParseResult + parseResult = new RemoteEpisode { Series = fakeSeries, Quality = new QualityModel(Quality.DVD, true), - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, }; } @@ -60,7 +52,7 @@ public void should_allow_if_quality_is_defined_in_profile(Quality qualityType) parseResult.Quality.Quality = qualityType; parseResult.Series.QualityProfile.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; - _qualityAllowedByProfile.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); } [Test, TestCaseSource("DeniedTestCases")] @@ -69,7 +61,7 @@ public void should_not_allow_if_quality_is_not_defined_in_profile(Quality qualit parseResult.Quality.Quality = qualityType; parseResult.Series.QualityProfile.Allowed = new List { Quality.DVD, Quality.HDTV720p, Quality.Bluray1080p }; - _qualityAllowedByProfile.IsSatisfiedBy(parseResult).Should().BeFalse(); + Subject.IsSatisfiedBy(parseResult).Should().BeFalse(); } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/DecisionEngineTests/RetentionSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/RetentionSpecificationFixture.cs index e654857a1..a4d473872 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/RetentionSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/RetentionSpecificationFixture.cs @@ -1,38 +1,28 @@ - - -using System.Linq; -using System; -using System.Collections.Generic; -using FizzWare.NBuilder; -using FluentAssertions; -using Moq; +using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.Configuration; using NzbDrone.Core.DecisionEngine.Specifications; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.DecisionEngine; - +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - - public class RetentionSpecificationFixture : CoreTest - { - private RetentionSpecification retentionSpecification; - private IndexerParseResult parseResult; + public class RetentionSpecificationFixture : CoreTest + { + + private RemoteEpisode parseResult; [SetUp] public void Setup() { - retentionSpecification = Mocker.Resolve(); - - parseResult = new IndexerParseResult + parseResult = new RemoteEpisode { - Age = 100 + Report = new ReportInfo + { + Age = 100 + } }; } @@ -60,35 +50,35 @@ private void WithEqualRetention() public void unlimited_retention_should_return_true() { WithUnlimitedRetention(); - retentionSpecification.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); } [Test] public void longer_retention_should_return_true() { WithLongRetention(); - retentionSpecification.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); } [Test] public void equal_retention_should_return_true() { WithEqualRetention(); - retentionSpecification.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); } [Test] public void shorter_retention_should_return_false() { WithShortRetention(); - retentionSpecification.IsSatisfiedBy(parseResult).Should().BeFalse(); + Subject.IsSatisfiedBy(parseResult).Should().BeFalse(); } [Test] public void zeroDay_report_should_return_true() { WithUnlimitedRetention(); - retentionSpecification.IsSatisfiedBy(parseResult).Should().BeTrue(); + Subject.IsSatisfiedBy(parseResult).Should().BeTrue(); } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs index 7ca40b306..ae4196ab8 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeDiskSpecificationFixture.cs @@ -1,17 +1,13 @@ - - -using System; +using System; using System.Collections.Generic; -using System.Linq; using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Test.Framework; @@ -20,12 +16,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - public class UpgradeDiskSpecificationFixture : CoreTest + public class UpgradeDiskSpecificationFixture : CoreTest { private UpgradeDiskSpecification _upgradeDisk; - private IndexerParseResult parseResultMulti; - private IndexerParseResult parseResultSingle; + private RemoteEpisode parseResultMulti; + private RemoteEpisode parseResultSingle; private EpisodeFile firstFile; private EpisodeFile secondFile; @@ -45,21 +41,17 @@ public void Setup() .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p }) .Build(); - parseResultMulti = new IndexerParseResult + parseResultMulti = new RemoteEpisode { Series = fakeSeries, Quality = new QualityModel(Quality.DVD, true), - EpisodeNumbers = new List { 3, 4 }, - SeasonNumber = 12, Episodes = doubleEpisodeList }; - parseResultSingle = new IndexerParseResult + parseResultSingle = new RemoteEpisode { Series = fakeSeries, Quality = new QualityModel(Quality.DVD, true), - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, Episodes = singleEpisodeList }; } diff --git a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs index 4e0474da7..15d42760b 100644 --- a/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs +++ b/NzbDrone.Core.Test/DecisionEngineTests/UpgradeHistorySpecificationFixture.cs @@ -1,16 +1,12 @@ - - -using System.Collections.Generic; -using System.Linq; +using System.Collections.Generic; using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.History; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Test.Framework; @@ -18,12 +14,12 @@ namespace NzbDrone.Core.Test.DecisionEngineTests { [TestFixture] - public class UpgradeHistorySpecificationFixture : CoreTest + public class UpgradeHistorySpecificationFixture : CoreTest { private UpgradeHistorySpecification _upgradeHistory; - private IndexerParseResult _parseResultMulti; - private IndexerParseResult _parseResultSingle; + private RemoteEpisode _parseResultMulti; + private RemoteEpisode _parseResultSingle; private QualityModel _upgradableQuality; private QualityModel _notupgradableQuality; private Series _fakeSeries; @@ -45,21 +41,17 @@ public void Setup() .With(c => c.QualityProfile = new QualityProfile { Cutoff = Quality.Bluray1080p }) .Build(); - _parseResultMulti = new IndexerParseResult + _parseResultMulti = new RemoteEpisode { Series = _fakeSeries, Quality = new QualityModel(Quality.DVD, true), - EpisodeNumbers = new List { 3, 4 }, - SeasonNumber = 12, Episodes = doubleEpisodeList }; - _parseResultSingle = new IndexerParseResult + _parseResultSingle = new RemoteEpisode { Series = _fakeSeries, Quality = new QualityModel(Quality.DVD, true), - EpisodeNumbers = new List { 3 }, - SeasonNumber = 12, Episodes = singleEpisodeList }; diff --git a/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs b/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs index e53b6c4de..87c438ffa 100644 --- a/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/DownloadNzbFixture.cs @@ -43,7 +43,7 @@ public void should_add_item_to_queue() It.Is(c => c.Equals("{\"method\":\"appendurl\",\"params\":[\"30 Rock - S01E01 - Pilot [HDTV-720p]\",\"TV\",0,false,\"http://www.nzbdrone.com\"]}")))) .Returns("{\"version\": \"1.1\",\"result\": true}"); - Mocker.Resolve() + Mocker.Resolve() .DownloadNzb(url, title, false) .Should() .BeTrue(); @@ -54,7 +54,7 @@ public void should_throw_when_error_is_returned() { WithFailResponse(); - Assert.Throws(() => Mocker.Resolve().DownloadNzb("http://www.nzbdrone.com", "30 Rock - S01E01 - Pilot [HDTV-720p]", false)); + Assert.Throws(() => Mocker.Resolve().DownloadNzb("http://www.nzbdrone.com", "30 Rock - S01E01 - Pilot [HDTV-720p]", false)); } } } diff --git a/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs b/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs index 23d7b013e..5b815726f 100644 --- a/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadClientTests/NzbgetProviderTests/QueueFixture.cs @@ -50,7 +50,7 @@ public void should_return_no_items_when_queue_is_empty() { WithEmptyQueue(); - Mocker.Resolve() + Mocker.Resolve() .GetQueue() .Should() .BeEmpty(); @@ -61,7 +61,7 @@ public void should_return_item_when_queue_has_item() { WithFullQueue(); - Mocker.Resolve() + Mocker.Resolve() .GetQueue() .Should() .HaveCount(1); @@ -72,7 +72,7 @@ public void should_throw_when_error_is_returned() { WithFailResponse(); - Assert.Throws(() => Mocker.Resolve().GetQueue()); + Assert.Throws(() => Mocker.Resolve().GetQueue()); } } } diff --git a/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs b/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs index 56c35fd0c..1c61d0ad0 100644 --- a/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadClientTests/PneumaticProviderFixture.cs @@ -42,7 +42,7 @@ private void WithFailedDownload() [Test] public void should_download_file_if_it_doesnt_exist() { - Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(nzbUrl, nzbPath),Times.Once()); } @@ -52,7 +52,7 @@ public void should_not_download_file_if_it_doesn_exist() { WithExistingFile(); - Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny()), Times.Never()); } @@ -62,7 +62,7 @@ public void should_return_false_on_failed_download() { WithFailedDownload(); - Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeFalse(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeFalse(); ExceptionVerification.ExpectedWarns(1); } @@ -70,7 +70,7 @@ public void should_return_false_on_failed_download() [Test] public void should_skip_if_full_season_download() { - Mocker.Resolve().DownloadNzb(nzbUrl, "30 Rock - Season 1", false).Should().BeFalse(); + Mocker.Resolve().DownloadNzb(nzbUrl, "30 Rock - Season 1", false).Should().BeFalse(); } [Test] @@ -79,7 +79,7 @@ public void should_replace_illegal_characters_in_title() var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]"; var expectedFilename = Path.Combine(pneumaticFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV].nzb"); - Mocker.Resolve().DownloadNzb(nzbUrl, illegalTitle, false).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, illegalTitle, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), expectedFilename), Times.Once()); } diff --git a/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/QueueFixture.cs b/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/QueueFixture.cs index 7c6eac4fb..1b5c75c22 100644 --- a/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/QueueFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/QueueFixture.cs @@ -1,4 +1,4 @@ -using System; +/*using System; using System.Collections.Generic; using System.Linq; using FluentAssertions; @@ -22,7 +22,6 @@ public class QueueFixture : CoreTest [SetUp] public void Setup() { - string sabHost = "192.168.5.55"; int sabPort = 2222; string apikey = "5c770e3197e4fe763423ee7c392c25d1"; @@ -77,7 +76,7 @@ public void GetQueue_should_return_an_empty_list_when_the_queue_is_empty() { WithEmptyQueue(); - var result = Mocker.Resolve().GetQueue(); + var result = Mocker.Resolve().GetQueue(); result.Should().BeEmpty(); } @@ -87,7 +86,7 @@ public void GetQueue_should_throw_when_there_is_an_error_getting_the_queue() { WithFailResponse(); - Assert.Throws(() => Mocker.Resolve().GetQueue(), "API Key Incorrect"); + Assert.Throws(() => Mocker.Resolve().GetQueue(), "API Key Incorrect"); } [Test] @@ -95,7 +94,7 @@ public void GetQueue_should_return_a_list_with_items_when_the_queue_has_items() { WithFullQueue(); - var result = Mocker.Resolve().GetQueue(); + var result = Mocker.Resolve().GetQueue(); result.Should().HaveCount(7); } @@ -105,10 +104,9 @@ public void GetQueue_should_return_a_list_with_items_even_when_priority_is_non_s { WithUnknownPriorityQueue(); - var result = Mocker.Resolve().GetQueue(); + var result = Mocker.Resolve().GetQueue(); result.Should().HaveCount(7); - result.Should().OnlyContain(i => i.Priority == SabPriorityType.Normal); } [Test] @@ -116,7 +114,7 @@ public void is_in_queue_should_find_if_exact_episode_is_in_queue() { WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { EpisodeTitle = "Title", EpisodeNumbers = new List { 5 }, @@ -126,7 +124,7 @@ public void is_in_queue_should_find_if_exact_episode_is_in_queue() }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeTrue(); } @@ -136,7 +134,7 @@ public void is_in_queue_should_find_if_exact_daily_episode_is_in_queue() { WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { Quality = new QualityModel { Quality = Quality.Bluray720p, Proper = false }, AirDate = new DateTime(2011, 12, 01), @@ -144,7 +142,7 @@ public void is_in_queue_should_find_if_exact_daily_episode_is_in_queue() }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeTrue(); } @@ -155,7 +153,7 @@ public void is_in_queue_should_find_if_exact_full_season_release_is_in_queue() WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { Quality = new QualityModel { Quality = Quality.Bluray720p, Proper = false }, FullSeason = true, @@ -163,7 +161,7 @@ public void is_in_queue_should_find_if_exact_full_season_release_is_in_queue() Series = new Series { Title = "My Name is earl", CleanTitle = Parser.NormalizeTitle("My Name is earl") }, }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeTrue(); } @@ -184,7 +182,7 @@ public void IsInQueue_should_not_find_diffrent_episode_queue(int season, int[] e { WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { EpisodeTitle = "Title", EpisodeNumbers = new List(episodes), @@ -193,7 +191,7 @@ public void IsInQueue_should_not_find_diffrent_episode_queue(int season, int[] e Series = new Series { Title = title, CleanTitle = Parser.NormalizeTitle(title) }, }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeFalse(); } @@ -213,7 +211,7 @@ public void IsInQueue_should_find_same_or_lower_quality_episode_queue(int season { WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { EpisodeTitle = "Title", EpisodeNumbers = new List(episodes), @@ -222,7 +220,7 @@ public void IsInQueue_should_find_same_or_lower_quality_episode_queue(int season Series = new Series { Title = title, CleanTitle = Parser.NormalizeTitle(title) }, }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeTrue(); } @@ -240,7 +238,7 @@ public void IsInQueue_should_find_items_marked_as_duplicate(int season, int[] ep { WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { EpisodeTitle = "Title", EpisodeNumbers = new List(episodes), @@ -249,7 +247,7 @@ public void IsInQueue_should_find_items_marked_as_duplicate(int season, int[] ep Series = new Series { Title = title, CleanTitle = Parser.NormalizeTitle(title) }, }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeTrue(); } @@ -267,7 +265,7 @@ public void IsInQueue_should_find_double_episodes_(int season, int[] episodes, s { WithFullQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { EpisodeTitle = "Title", EpisodeNumbers = new List(episodes), @@ -276,7 +274,7 @@ public void IsInQueue_should_find_double_episodes_(int season, int[] episodes, s Series = new Series { Title = title, CleanTitle = Parser.NormalizeTitle(title) }, }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeTrue(); } @@ -286,7 +284,7 @@ public void IsInQueue_should_return_false_if_queue_is_empty() { WithEmptyQueue(); - var parseResult = new IndexerParseResult + var parseResult = new RemoteEpisode { EpisodeTitle = "Title", EpisodeNumbers = new List { 1 }, @@ -295,7 +293,7 @@ public void IsInQueue_should_return_false_if_queue_is_empty() Series = new Series { Title = "Test", CleanTitle = Parser.NormalizeTitle("Test") }, }; - var result = Mocker.Resolve().IsInQueue(parseResult); + var result = Mocker.Resolve().IsInQueue(parseResult); result.Should().BeFalse(); } @@ -305,7 +303,7 @@ public void GetQueue_should_parse_timeleft_with_hours_greater_than_24_hours() { WithFullQueue(); - var result = Mocker.Resolve().GetQueue(); + var result = Mocker.Resolve().GetQueue(); result.Should().NotBeEmpty(); var timeleft = result.First(q => q.Id == "SABnzbd_nzo_qv6ilb").Timeleft; @@ -323,4 +321,4 @@ public void TearDown() } -} \ No newline at end of file +}*/ \ No newline at end of file diff --git a/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs b/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs index 64b60c9f3..97962f51c 100644 --- a/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadClientTests/SabProviderTests/SabProviderFixture.cs @@ -45,7 +45,7 @@ public void add_url_should_format_request_properly() .Returns("{ \"status\": true }"); - Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); } [Test] @@ -54,7 +54,7 @@ public void add_by_url_should_detect_and_handle_sab_errors() WithFailResponse(); - Assert.Throws(() => Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse()); + Assert.Throws(() => Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse()); //ExceptionVerification.ExpectedErrors(1); } @@ -75,7 +75,7 @@ public void should_be_able_to_get_categories_when_config_is_passed_in() .Returns(ReadAllText("Files","Categories_json.txt")); - var result = Mocker.Resolve().GetCategories(host, port, apikey, username, password); + var result = Mocker.Resolve().GetCategories(host, port, apikey, username, password); result.Should().NotBeNull(); @@ -90,7 +90,7 @@ public void should_be_able_to_get_categories_using_config() .Returns(ReadAllText("Files","Categories_json.txt")); - var result = Mocker.Resolve().GetCategories(); + var result = Mocker.Resolve().GetCategories(); result.Should().NotBeNull(); @@ -105,7 +105,7 @@ public void GetHistory_should_return_a_list_with_items_when_the_history_has_item .Returns(ReadAllText("Files", "History.txt")); - var result = Mocker.Resolve().GetHistory(); + var result = Mocker.Resolve().GetHistory(); result.Should().HaveCount(1); @@ -119,7 +119,7 @@ public void GetHistory_should_return_an_empty_list_when_the_queue_is_empty() .Returns(ReadAllText("Files","HistoryEmpty.txt")); - var result = Mocker.Resolve().GetHistory(); + var result = Mocker.Resolve().GetHistory(); result.Should().BeEmpty(); @@ -133,7 +133,7 @@ public void GetHistory_should_return_an_empty_list_when_there_is_an_error_gettin .Returns(ReadAllText("Files","JsonError.txt")); - Assert.Throws(() => Mocker.Resolve().GetHistory(), "API Key Incorrect"); + Assert.Throws(() => Mocker.Resolve().GetHistory(), "API Key Incorrect"); } [Test] @@ -146,7 +146,7 @@ public void GetVersion_should_return_the_version_using_passed_in_values() .Returns(response); - var result = Mocker.Resolve().GetVersion("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); + var result = Mocker.Resolve().GetVersion("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); result.Should().NotBeNull(); @@ -163,7 +163,7 @@ public void GetVersion_should_return_the_version_using_saved_values() .Returns(response); - var result = Mocker.Resolve().GetVersion(); + var result = Mocker.Resolve().GetVersion(); result.Should().NotBeNull(); @@ -180,7 +180,7 @@ public void Test_should_return_version_as_a_string() .Returns(response); - var result = Mocker.Resolve().Test("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); + var result = Mocker.Resolve().Test("192.168.5.55", 2222, "5c770e3197e4fe763423ee7c392c25d1", "admin", "pass"); result.Should().Be("0.6.9"); @@ -192,7 +192,7 @@ public void should_return_false_when_WebException_is_thrown() Mocker.GetMock() .Setup(s => s.DownloadString(It.IsAny())).Throws(new WebException()); - Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse(); + Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse(); ExceptionVerification.ExpectedErrors(1); } @@ -212,7 +212,7 @@ public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_tru .Returns("{ \"status\": true }"); - Mocker.Resolve().DownloadNzb(url, title, true).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(url, title, true).Should().BeTrue(); Mocker.GetMock() .Verify(v => v.DownloadString("http://192.168.5.55:2222/api?mode=addurl&name=http://www.nzbclub.com/nzb_download.aspx?mid=1950232&priority=1&pp=3&cat=tv&nzbname=My+Series+Name+-+5x2-5x3+-+My+title+%5bBluray720p%5d+%5bProper%5d&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"), Times.Once()); @@ -234,7 +234,7 @@ public void downloadNzb_should_use_sabBackogTvPriority_when_recentEpisode_is_fal .Returns("{ \"status\": true }"); - Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); Mocker.GetMock() .Verify(v => v.DownloadString("http://192.168.5.55:2222/api?mode=addurl&name=http://www.nzbclub.com/nzb_download.aspx?mid=1950232&priority=-1&pp=3&cat=tv&nzbname=My+Series+Name+-+5x2-5x3+-+My+title+%5bBluray720p%5d+%5bProper%5d&output=json&apikey=5c770e3197e4fe763423ee7c392c25d1&ma_username=admin&ma_password=pass"), Times.Once()); diff --git a/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs b/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs index 3460625f7..af8fe2c43 100644 --- a/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs +++ b/NzbDrone.Core.Test/Download/DownloadServiceFixture.cs @@ -6,6 +6,7 @@ using NUnit.Framework; using NzbDrone.Core.Download; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Tv; @@ -15,7 +16,7 @@ namespace NzbDrone.Core.Test.Download [TestFixture] public class DownloadServiceFixture : CoreTest { - private IndexerParseResult _parseResult; + private RemoteEpisode _parseResult; [SetUp] public void Setup() @@ -29,10 +30,9 @@ public void Setup() .All().With(s => s.SeriesId = 5) .Build().ToList(); - _parseResult = Builder.CreateNew() + _parseResult = Builder.CreateNew() .With(c => c.Quality = new QualityModel(Quality.DVD, false)) .With(c => c.Series = Builder.CreateNew().Build()) - .With(c => c.EpisodeNumbers = new List { 2 }) .With(c => c.Episodes = episodes) .Build(); } diff --git a/NzbDrone.Core.Test/EpisodeParseResultTest.cs b/NzbDrone.Core.Test/EpisodeParseResultTest.cs index aed60dc85..4d14a77af 100644 --- a/NzbDrone.Core.Test/EpisodeParseResultTest.cs +++ b/NzbDrone.Core.Test/EpisodeParseResultTest.cs @@ -1,9 +1,11 @@ -using System; +/* +using System; using System.Collections.Generic; using System.Linq; using FizzWare.NBuilder; using FluentAssertions; using NUnit.Framework; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; using NzbDrone.Core.Model; @@ -18,7 +20,7 @@ public class EpisodeParseResultTest : CoreTest [Test] public void tostring_single_season_episode() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.EpisodeNumbers = new List { 3 }; @@ -33,7 +35,7 @@ public void tostring_single_season_episode() [Test] public void tostring_single_season_episode_proper() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.EpisodeNumbers = new List { 3 }; @@ -48,7 +50,7 @@ public void tostring_single_season_episode_proper() [Test] public void tostring_multi_season_episode() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.EpisodeNumbers = new List { 3, 4, 5 }; @@ -63,7 +65,7 @@ public void tostring_multi_season_episode() [Test] public void tostring_multi_season_episode_proper() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.EpisodeNumbers = new List { 3, 4, 5 }; @@ -79,7 +81,7 @@ public void tostring_multi_season_episode_proper() [Test] public void tostring_full_season() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.FullSeason = true; @@ -94,7 +96,7 @@ public void tostring_full_season() [Test] public void tostring_full_season_proper() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.FullSeason = true; @@ -108,7 +110,7 @@ public void tostring_full_season_proper() [Test] public void tostring_daily_show() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.FullSeason = true; @@ -122,7 +124,7 @@ public void tostring_daily_show() [Test] public void tostring_daily_show_proper() { - var parseResult = new IndexerParseResult(); + var parseResult = new RemoteEpisode(); parseResult.SeriesTitle = "My Series"; parseResult.SeasonNumber = 12; parseResult.FullSeason = true; @@ -162,7 +164,7 @@ public void create_proper_sab_titles(int seasons, int[] episodes, string title, .With(e => e.Title = title) .Build()); - var parsResult = new IndexerParseResult() + var parsResult = new RemoteEpisode() { AirDate = DateTime.Now, EpisodeNumbers = episodes.ToList(), @@ -184,7 +186,7 @@ public string create_proper_sab_season_title(bool proper) .With(c => c.Title = "My Series Name") .Build(); - var parsResult = new IndexerParseResult() + var parsResult = new RemoteEpisode() { AirDate = DateTime.Now, Quality = new QualityModel(Quality.Bluray720p, proper), @@ -210,7 +212,7 @@ public string create_proper_sab_daily_titles(bool proper) .With(e => e.Title = "My Episode Title") .Build(); - var parsResult = new IndexerParseResult + var parsResult = new RemoteEpisode { AirDate = new DateTime(2011, 12, 1), Quality = new QualityModel(Quality.Bluray720p, proper), @@ -238,7 +240,7 @@ public void should_not_repeat_the_same_episode_title() .With(e => e.Title = "My Episode Title (2)") .Build(); - var parsResult = new IndexerParseResult + var parsResult = new RemoteEpisode { AirDate = DateTime.Now, EpisodeNumbers = new List { 10, 11 }, @@ -253,3 +255,4 @@ public void should_not_repeat_the_same_episode_title() } } +*/ diff --git a/NzbDrone.Core.Test/EpisodeStatusTest.cs b/NzbDrone.Core.Test/EpisodeStatusTest.cs index c789537c7..8d266fe98 100644 --- a/NzbDrone.Core.Test/EpisodeStatusTest.cs +++ b/NzbDrone.Core.Test/EpisodeStatusTest.cs @@ -14,11 +14,11 @@ namespace NzbDrone.Core.Test public class EpisodeStatusTest : CoreTest { - [TestCase(1, false, false, EpisodeStatusType.NotAired)] - [TestCase(-2, false, false, EpisodeStatusType.Missing)] - [TestCase(0, false, false, EpisodeStatusType.AirsToday)] - [TestCase(1, true, false, EpisodeStatusType.Ready)] - public void no_grab_date(int offsetDays, bool hasEpisodes, bool ignored, EpisodeStatusType status) + [TestCase(1, false, false, EpisodeStatuses.NotAired)] + [TestCase(-2, false, false, EpisodeStatuses.Missing)] + [TestCase(0, false, false, EpisodeStatuses.AirsToday)] + [TestCase(1, true, false, EpisodeStatuses.Ready)] + public void no_grab_date(int offsetDays, bool hasEpisodes, bool ignored, EpisodeStatuses status) { Episode episode = Builder.CreateNew() .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays)) @@ -34,11 +34,11 @@ public void no_grab_date(int offsetDays, bool hasEpisodes, bool ignored, Episode episode.Status.Should().Be(status); } - [TestCase(1, false, false, EpisodeStatusType.Missing)] - [TestCase(-2, false, false, EpisodeStatusType.Missing)] - [TestCase(1, true, false, EpisodeStatusType.Ready)] + [TestCase(1, false, false, EpisodeStatuses.Missing)] + [TestCase(-2, false, false, EpisodeStatuses.Missing)] + [TestCase(1, true, false, EpisodeStatuses.Ready)] public void old_grab_date(int offsetDays, bool hasEpisodes, bool ignored, - EpisodeStatusType status) + EpisodeStatuses status) { Episode episode = Builder.CreateNew() .With(e => e.Ignored = ignored) @@ -54,13 +54,13 @@ public void old_grab_date(int offsetDays, bool hasEpisodes, bool ignored, episode.Status.Should().Be(status); } - [TestCase(1, false, false, EpisodeStatusType.Downloading)] - [TestCase(-2, false, false, EpisodeStatusType.Downloading)] - [TestCase(1, true, false, EpisodeStatusType.Ready)] - [TestCase(1, true, true, EpisodeStatusType.Ready)] - [TestCase(1, false, true, EpisodeStatusType.Downloading)] + [TestCase(1, false, false, EpisodeStatuses.Downloading)] + [TestCase(-2, false, false, EpisodeStatuses.Downloading)] + [TestCase(1, true, false, EpisodeStatuses.Ready)] + [TestCase(1, true, true, EpisodeStatuses.Ready)] + [TestCase(1, false, true, EpisodeStatuses.Downloading)] public void recent_grab_date(int offsetDays, bool hasEpisodes, bool ignored, - EpisodeStatusType status) + EpisodeStatuses status) { Episode episode = Builder.CreateNew() .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays)) @@ -77,8 +77,8 @@ public void recent_grab_date(int offsetDays, bool hasEpisodes, bool ignored, } - [TestCase(1, true, true, EpisodeStatusType.Ready)] - public void ignored_episode(int offsetDays, bool ignored, bool hasEpisodes, EpisodeStatusType status) + [TestCase(1, true, true, EpisodeStatuses.Ready)] + public void ignored_episode(int offsetDays, bool ignored, bool hasEpisodes, EpisodeStatuses status) { Episode episode = Builder.CreateNew() .With(e => e.AirDate = DateTime.Now.AddDays(offsetDays)) @@ -105,15 +105,15 @@ public void low_air_date() .Build(); - episode.Status.Should().Be(EpisodeStatusType.NotAired); + episode.Status.Should().Be(EpisodeStatuses.NotAired); } - [TestCase(false, false, EpisodeStatusType.Failed, PostDownloadStatusType.Failed)] - [TestCase(false, false, EpisodeStatusType.Unpacking, PostDownloadStatusType.Unpacking)] - [TestCase(true, false, EpisodeStatusType.Ready, PostDownloadStatusType.Failed)] - [TestCase(true, true, EpisodeStatusType.Ready, PostDownloadStatusType.Unpacking)] + [TestCase(false, false, EpisodeStatuses.Failed, PostDownloadStatusType.Failed)] + [TestCase(false, false, EpisodeStatuses.Unpacking, PostDownloadStatusType.Unpacking)] + [TestCase(true, false, EpisodeStatuses.Ready, PostDownloadStatusType.Failed)] + [TestCase(true, true, EpisodeStatuses.Ready, PostDownloadStatusType.Unpacking)] public void episode_downloaded_post_download_status_is_used(bool hasEpisodes, bool ignored, - EpisodeStatusType status, PostDownloadStatusType postDownloadStatus) + EpisodeStatuses status, PostDownloadStatusType postDownloadStatus) { Episode episode = Builder.CreateNew() .With(e => e.Ignored = ignored) diff --git a/NzbDrone.Core.Test/JobTests/AppUpdateJobFixture.cs b/NzbDrone.Core.Test/JobTests/AppUpdateJobFixture.cs index 8ba040873..de780c449 100644 --- a/NzbDrone.Core.Test/JobTests/AppUpdateJobFixture.cs +++ b/NzbDrone.Core.Test/JobTests/AppUpdateJobFixture.cs @@ -36,7 +36,7 @@ public void Setup() { Mocker.GetMock().SetupGet(c => c.SystemTemp).Returns(@"C:\Temp\"); Mocker.GetMock().SetupGet(c => c.Guid).Returns(_clientGuid); - Mocker.GetMock().Setup(c => c.GetAvailableUpdate(It.IsAny())).Returns(updatePackage); + Mocker.GetMock().Setup(c => c.GetAvailableUpdate()).Returns(updatePackage); } @@ -127,7 +127,7 @@ public void should_start_update_client() [Test] public void when_no_updates_are_available_should_return_without_error_or_warnings() { - Mocker.GetMock().Setup(c => c.GetAvailableUpdate(It.IsAny())).Returns((UpdatePackage)null); + Mocker.GetMock().Setup(c => c.GetAvailableUpdate()).Returns((UpdatePackage)null); StartUpdate(); diff --git a/NzbDrone.Core.Test/JobTests/DiskScanJobTest.cs b/NzbDrone.Core.Test/JobTests/DiskScanJobTest.cs index a32188e5c..6af7ed625 100644 --- a/NzbDrone.Core.Test/JobTests/DiskScanJobTest.cs +++ b/NzbDrone.Core.Test/JobTests/DiskScanJobTest.cs @@ -35,10 +35,6 @@ public void series_specific_scan_should_scan_series() .Setup(p => p.Get(series.Id)) .Returns(series); - Mocker.GetMock() - .Setup(p => p.Scan(series)) - .Returns(new List()); - Mocker.Resolve().Start(new ProgressNotification("Test"), new { SeriesId = series.Id }); @@ -60,13 +56,6 @@ public void job_with_no_target_should_scan_all_series() .Setup(p => p.All()) .Returns(series); - Mocker.GetMock() - .Setup(s => s.Scan(series[0])) - .Returns(new List()); - - Mocker.GetMock() - .Setup(s => s.Scan(series[1])) - .Returns(new List()); Mocker.Resolve().Start(new ProgressNotification("Test"), null); @@ -113,14 +102,6 @@ public void job_with_no_target_should_scan_series_with_episodes() .Setup(p => p.All()) .Returns(series); - Mocker.GetMock() - .Setup(s => s.Scan(series[0])) - .Returns(new List()); - - Mocker.GetMock() - .Setup(s => s.Scan(series[1])) - .Returns(new List()); - Mocker.Resolve().Start(new ProgressNotification("Test"), null); Mocker.VerifyAllMocks(); diff --git a/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs b/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs index dd564d6e7..90a9f8eb5 100644 --- a/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs +++ b/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs @@ -31,10 +31,10 @@ public void should_use_options_Path_when_provided() { var path = @"C:\Test\Unsorted TV"; - Mocker.GetMock().Setup(s => s.ProcessDropFolder(path)); + Mocker.GetMock().Setup(s => s.ProcessDropFolder(path)); Mocker.Resolve().Start(MockNotification, new { Path = path }); - Mocker.GetMock().Verify(s => s.ProcessDropFolder(path), Times.Once()); + Mocker.GetMock().Verify(s => s.ProcessDropFolder(path), Times.Once()); } [Test] @@ -42,7 +42,7 @@ public void should_not_get_sabDropDir_when_path_is_supplied() { var path = @"C:\Test\Unsorted TV"; - Mocker.GetMock().Setup(s => s.ProcessDropFolder(path)); + Mocker.GetMock().Setup(s => s.ProcessDropFolder(path)); Mocker.Resolve().Start(MockNotification, new { Path = path }); Mocker.GetMock().Verify(s => s.DownloadClientTvDirectory, Times.Never()); @@ -67,7 +67,7 @@ public void should_use_sabDropDir_when_options_Path_is_not_provided() Mocker.GetMock().SetupGet(s => s.DownloadClientTvDirectory).Returns(path); Mocker.Resolve().Start(MockNotification, null); - Mocker.GetMock().Verify(s => s.ProcessDropFolder(path), Times.Once()); + Mocker.GetMock().Verify(s => s.ProcessDropFolder(path), Times.Once()); } } } diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index a4d41f31a..0695f24b5 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -152,10 +152,7 @@ - - - @@ -173,8 +170,7 @@ - - + @@ -207,6 +203,7 @@ + diff --git a/NzbDrone.Core.Test/ParserTests/ParserFixture.cs b/NzbDrone.Core.Test/ParserTests/ParserFixture.cs index 448f8c0bf..6f159e318 100644 --- a/NzbDrone.Core.Test/ParserTests/ParserFixture.cs +++ b/NzbDrone.Core.Test/ParserTests/ParserFixture.cs @@ -6,6 +6,8 @@ using NzbDrone.Common.Contract; using NzbDrone.Core.Indexers; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Test.Framework; using NzbDrone.Test.Common; @@ -79,16 +81,15 @@ public class ParserFixture : CoreTest [TestCase("Portlandia.S03E10.Alexandra.720p.WEB-DL.AAC2.0.H.264-CROM.mkv", "Portlandia", 3, 10)] public void ParseTitle_single(string postTitle, string title, int seasonNumber, int episodeNumber) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.Should().NotBeNull(); result.EpisodeNumbers.Should().HaveCount(1); result.SeasonNumber.Should().Be(seasonNumber); result.EpisodeNumbers.First().Should().Be(episodeNumber); - result.CleanTitle.Should().Be(Parser.NormalizeTitle(title)); + result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); result.OriginalString.Should().Be(postTitle); } - [Test] [TestCase(@"z:\tv shows\battlestar galactica (2003)\Season 3\S03E05 - Collaborators.mkv", 3, 5)] [TestCase(@"z:\tv shows\modern marvels\Season 16\S16E03 - The Potato.mkv", 16, 3)] [TestCase(@"z:\tv shows\robot chicken\Specials\S00E16 - Dear Consumer - SD TV.avi", 0, 16)] @@ -101,7 +102,7 @@ public void ParseTitle_single(string postTitle, string title, int seasonNumber, [TestCase(@"S:\TV Drop\King of the Hill - 10x12 - 24 Hour Propane People [SDTV]\Hour Propane People.avi", 10, 12)] public void PathParse_tests(string path, int season, int episode) { - var result = Parser.ParsePath(path); + var result = Parser.Parser.ParsePath(path); result.EpisodeNumbers.Should().HaveCount(1); result.SeasonNumber.Should().Be(season); result.EpisodeNumbers[0].Should().Be(episode); @@ -113,7 +114,7 @@ public void PathParse_tests(string path, int season, int episode) [Test] public void unparsable_path_should_report_the_path() { - Parser.ParsePath("C:\\").Should().BeNull(); + Parser.Parser.ParsePath("C:\\").Should().BeNull(); MockedRestProvider.Verify(c => c.PostData(It.IsAny(), It.IsAny()), Times.Exactly(2)); @@ -125,7 +126,7 @@ public void unparsable_title_should_report_title() { const string TITLE = "SOMETHING"; - Parser.ParseTitle(TITLE).Should().BeNull(); + Parser.Parser.ParseTitle(TITLE).Should().BeNull(); MockedRestProvider.Verify(c => c.PostData(It.IsAny(), It.Is(r => r.Title == TITLE)), Times.Once()); @@ -153,10 +154,10 @@ public void unparsable_title_should_report_title() [TestCase("Hell.on.Wheels.S02E09-E10.720p.HDTV.x264-EVOLVE", "Hell on Wheels", 2, new[] { 9, 10 })] public void TitleParse_multi(string postTitle, string title, int season, int[] episodes) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.SeasonNumber.Should().Be(season); result.EpisodeNumbers.Should().BeEquivalentTo(episodes); - result.CleanTitle.Should().Be(Parser.NormalizeTitle(title)); + result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); result.OriginalString.Should().Be(postTitle); } @@ -173,10 +174,10 @@ public void TitleParse_multi(string postTitle, string title, int season, int[] e [TestCase("2020.NZ.2011.12.02.PDTV.XviD-C4TV", "2020nz", 2011, 12, 2)] public void parse_daily_episodes(string postTitle, string title, int year, int month, int day) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); var airDate = new DateTime(year, month, day); result.Should().NotBeNull(); - result.CleanTitle.Should().Be(Parser.NormalizeTitle(title)); + result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); result.AirDate.Should().Be(airDate); result.EpisodeNumbers.Should().BeNull(); result.OriginalString.Should().Be(postTitle); @@ -187,7 +188,7 @@ public void parse_daily_should_fail_if_episode_is_far_in_future() { var title = string.Format("{0:yyyy.MM.dd} - Denis Leary - HD TV.mkv", DateTime.Now.AddDays(2)); - Parser.ParseTitle(title).Should().BeNull(); + Parser.Parser.ParseTitle(title).Should().BeNull(); } @@ -198,9 +199,9 @@ public void parse_daily_should_fail_if_episode_is_far_in_future() [TestCase("Adventure Time S02 720p HDTV x264 CRON", "Adventure Time", 2)] public void full_season_release_parse(string postTitle, string title, int season) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.SeasonNumber.Should().Be(season); - result.CleanTitle.Should().Be(Parser.NormalizeTitle(title)); + result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(title)); result.EpisodeNumbers.Count.Should().Be(0); result.FullSeason.Should().BeTrue(); result.OriginalString.Should().Be(postTitle); @@ -213,7 +214,7 @@ public void full_season_release_parse(string postTitle, string title, int season [TestCase("Parenthood.2010", "parenthood2010")] public void series_name_normalize(string parsedSeriesName, string seriesName) { - var result = Parser.NormalizeTitle(parsedSeriesName); + var result = Parser.Parser.NormalizeTitle(parsedSeriesName); result.Should().Be(seriesName); } @@ -225,7 +226,7 @@ public void series_name_normalize(string parsedSeriesName, string seriesName) [TestCase("24", "24")] public void Normalize_Title(string dirty, string clean) { - var result = Parser.NormalizeTitle(dirty); + var result = Parser.Parser.NormalizeTitle(dirty); result.Should().Be(clean); } @@ -253,7 +254,7 @@ public void Normalize_removed_common_words(string word) foreach (var s in dirtyFormat) { var dirty = String.Format(s, word); - Parser.NormalizeTitle(dirty).Should().Be("wordword"); + Parser.Parser.NormalizeTitle(dirty).Should().Be("wordword"); } } @@ -279,7 +280,7 @@ public void Normalize_not_removed_common_words_in_the_middle(string word) foreach (var s in dirtyFormat) { var dirty = String.Format(s, word); - Parser.NormalizeTitle(dirty).Should().Be(("word" + word.ToLower() + "word")); + Parser.Parser.NormalizeTitle(dirty).Should().Be(("word" + word.ToLower() + "word")); } } @@ -295,38 +296,38 @@ public void Normalize_not_removed_common_words_in_the_middle(string word) [TestCase("Adventure Time S02 720p HDTV x264 CRON", "adventuretime")] public void parse_series_name(string postTitle, string title) { - var result = Parser.ParseSeriesName(postTitle); - result.Should().Be(Parser.NormalizeTitle(title)); + var result = Parser.Parser.ParseSeriesName(postTitle); + result.Should().Be(Parser.Parser.NormalizeTitle(title)); } - [TestCase("Castle.2009.S01E14.English.HDTV.XviD-LOL", LanguageType.English)] - [TestCase("Castle.2009.S01E14.French.HDTV.XviD-LOL", LanguageType.French)] - [TestCase("Castle.2009.S01E14.Spanish.HDTV.XviD-LOL", LanguageType.Spanish)] - [TestCase("Castle.2009.S01E14.German.HDTV.XviD-LOL", LanguageType.German)] - [TestCase("Castle.2009.S01E14.Germany.HDTV.XviD-LOL", LanguageType.English)] - [TestCase("Castle.2009.S01E14.Italian.HDTV.XviD-LOL", LanguageType.Italian)] - [TestCase("Castle.2009.S01E14.Danish.HDTV.XviD-LOL", LanguageType.Danish)] - [TestCase("Castle.2009.S01E14.Dutch.HDTV.XviD-LOL", LanguageType.Dutch)] - [TestCase("Castle.2009.S01E14.Japanese.HDTV.XviD-LOL", LanguageType.Japanese)] - [TestCase("Castle.2009.S01E14.Cantonese.HDTV.XviD-LOL", LanguageType.Cantonese)] - [TestCase("Castle.2009.S01E14.Mandarin.HDTV.XviD-LOL", LanguageType.Mandarin)] - [TestCase("Castle.2009.S01E14.Korean.HDTV.XviD-LOL", LanguageType.Korean)] - [TestCase("Castle.2009.S01E14.Russian.HDTV.XviD-LOL", LanguageType.Russian)] - [TestCase("Castle.2009.S01E14.Polish.HDTV.XviD-LOL", LanguageType.Polish)] - [TestCase("Castle.2009.S01E14.Vietnamese.HDTV.XviD-LOL", LanguageType.Vietnamese)] - [TestCase("Castle.2009.S01E14.Swedish.HDTV.XviD-LOL", LanguageType.Swedish)] - [TestCase("Castle.2009.S01E14.Norwegian.HDTV.XviD-LOL", LanguageType.Norwegian)] - [TestCase("Castle.2009.S01E14.Finnish.HDTV.XviD-LOL", LanguageType.Finnish)] - [TestCase("Castle.2009.S01E14.Turkish.HDTV.XviD-LOL", LanguageType.Turkish)] - [TestCase("Castle.2009.S01E14.Portuguese.HDTV.XviD-LOL", LanguageType.Portuguese)] - [TestCase("Castle.2009.S01E14.HDTV.XviD-LOL", LanguageType.English)] - [TestCase("person.of.interest.1x19.ita.720p.bdmux.x264-novarip", LanguageType.Italian)] - [TestCase("Salamander.S01E01.FLEMISH.HDTV.x264-BRiGAND", LanguageType.Flemish)] - [TestCase("H.Polukatoikia.S03E13.Greek.PDTV.XviD-Ouzo", LanguageType.Greek)] - [TestCase("Burn.Notice.S04E15.Brotherly.Love.GERMAN.DUBBED.WS.WEBRiP.XviD.REPACK-TVP", LanguageType.German)] - public void parse_language(string postTitle, LanguageType language) + [TestCase("Castle.2009.S01E14.English.HDTV.XviD-LOL", Language.English)] + [TestCase("Castle.2009.S01E14.French.HDTV.XviD-LOL", Language.French)] + [TestCase("Castle.2009.S01E14.Spanish.HDTV.XviD-LOL", Language.Spanish)] + [TestCase("Castle.2009.S01E14.German.HDTV.XviD-LOL", Language.German)] + [TestCase("Castle.2009.S01E14.Germany.HDTV.XviD-LOL", Language.English)] + [TestCase("Castle.2009.S01E14.Italian.HDTV.XviD-LOL", Language.Italian)] + [TestCase("Castle.2009.S01E14.Danish.HDTV.XviD-LOL", Language.Danish)] + [TestCase("Castle.2009.S01E14.Dutch.HDTV.XviD-LOL", Language.Dutch)] + [TestCase("Castle.2009.S01E14.Japanese.HDTV.XviD-LOL", Language.Japanese)] + [TestCase("Castle.2009.S01E14.Cantonese.HDTV.XviD-LOL", Language.Cantonese)] + [TestCase("Castle.2009.S01E14.Mandarin.HDTV.XviD-LOL", Language.Mandarin)] + [TestCase("Castle.2009.S01E14.Korean.HDTV.XviD-LOL", Language.Korean)] + [TestCase("Castle.2009.S01E14.Russian.HDTV.XviD-LOL", Language.Russian)] + [TestCase("Castle.2009.S01E14.Polish.HDTV.XviD-LOL", Language.Polish)] + [TestCase("Castle.2009.S01E14.Vietnamese.HDTV.XviD-LOL", Language.Vietnamese)] + [TestCase("Castle.2009.S01E14.Swedish.HDTV.XviD-LOL", Language.Swedish)] + [TestCase("Castle.2009.S01E14.Norwegian.HDTV.XviD-LOL", Language.Norwegian)] + [TestCase("Castle.2009.S01E14.Finnish.HDTV.XviD-LOL", Language.Finnish)] + [TestCase("Castle.2009.S01E14.Turkish.HDTV.XviD-LOL", Language.Turkish)] + [TestCase("Castle.2009.S01E14.Portuguese.HDTV.XviD-LOL", Language.Portuguese)] + [TestCase("Castle.2009.S01E14.HDTV.XviD-LOL", Language.English)] + [TestCase("person.of.interest.1x19.ita.720p.bdmux.x264-novarip", Language.Italian)] + [TestCase("Salamander.S01E01.FLEMISH.HDTV.x264-BRiGAND", Language.Flemish)] + [TestCase("H.Polukatoikia.S03E13.Greek.PDTV.XviD-Ouzo", Language.Greek)] + [TestCase("Burn.Notice.S04E15.Brotherly.Love.GERMAN.DUBBED.WS.WEBRiP.XviD.REPACK-TVP", Language.German)] + public void parse_language(string postTitle, Language language) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.Language.Should().Be(language); } @@ -339,9 +340,9 @@ public void parse_language(string postTitle, LanguageType language) [TestCase("Doctor Who Confidential Season 3", "Doctor Who Confidential", 3)] public void parse_season_info(string postTitle, string seriesName, int seasonNumber) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); - result.CleanTitle.Should().Be(Parser.NormalizeTitle(seriesName)); + result.SeriesTitle.Should().Be(Parser.Parser.NormalizeTitle(seriesName)); result.SeasonNumber.Should().Be(seasonNumber); result.FullSeason.Should().BeTrue(); result.OriginalString.Should().Be(postTitle); @@ -352,7 +353,7 @@ public void parse_season_info(string postTitle, string seriesName, int seasonNum [TestCase("Instant Star S03 EXTRAS DVDRip XviD OSiTV")] public void parse_season_extras(string postTitle) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.Should().BeNull(); } @@ -362,7 +363,7 @@ public void parse_season_extras(string postTitle) [TestCase("CSI.S11.SUBPACK.DVDRip.XviD-REWARD")] public void parse_season_subpack(string postTitle) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.Should().BeNull(); } @@ -370,7 +371,7 @@ public void parse_season_subpack(string postTitle) [TestCase("Fussball Bundesliga 10e2011e30 Spieltag FC Bayern Muenchen vs Bayer 04 Leverkusen German WS dTV XviD WoGS")] public void unparsable_should_log_error_but_not_throw(string title) { - Parser.ParseTitle(title); + Parser.Parser.ParseTitle(title); ExceptionVerification.IgnoreWarns(); ExceptionVerification.ExpectedErrors(1); } @@ -386,7 +387,7 @@ public void parse_header(string title, string expected) [TestCase("password - \"bdc435cb-93c4-4902-97ea-ca00568c3887.337\" yEnc")] public void should_not_parse_encypted_posts(string title) { - Parser.ParseTitle(title).Should().BeNull(); + Parser.Parser.ParseTitle(title).Should().BeNull(); ExceptionVerification.IgnoreWarns(); } } diff --git a/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs b/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs index 00c1d2621..ff14791f2 100644 --- a/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs +++ b/NzbDrone.Core.Test/ParserTests/QualityParserFixture.cs @@ -96,7 +96,7 @@ public class QualityParserFixture : CoreTest [Test, TestCaseSource("QualityParserCases")] public void quality_parse(string postTitle, Quality quality, bool proper) { - var result = Parser.ParseTitle(postTitle); + var result = Parser.Parser.ParseTitle(postTitle); result.Quality.Quality.Should().Be(quality); result.Quality.Proper.Should().Be(proper); } @@ -105,7 +105,7 @@ public void quality_parse(string postTitle, Quality quality, bool proper) public void parsing_our_own_quality_enum(Quality quality) { var fileName = String.Format("My series S01E01 [{0}]", quality); - var result = Parser.ParseTitle(fileName); + var result = Parser.Parser.ParseTitle(fileName); result.Quality.Quality.Should().Be(quality); } } diff --git a/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs b/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs index 387dc6d24..94d59b132 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskProviderTests/FreeDiskSpaceTest.cs @@ -1,15 +1,8 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; - +using System.IO; using FluentAssertions; -using Moq; using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common.AutoMoq; namespace NzbDrone.Core.Test.ProviderTests.DiskProviderTests { @@ -19,7 +12,7 @@ public class FreeDiskSpaceTest : CoreTest [Test] public void should_return_free_disk_space() { - var result = Subject.FreeDiskSpace(Directory.GetCurrentDirectory()); + var result = Subject.GetAvilableSpace(Directory.GetCurrentDirectory()); //Checks to ensure that the free space on the first is greater than 0 (It should be in 99.99999999999999% of cases... I hope) result.Should().BeGreaterThan(0); @@ -27,7 +20,7 @@ public void should_return_free_disk_space() [Test] public void should_throw_if_drive_doesnt_exist() { - Assert.Throws(() => Subject.FreeDiskSpace(@"Z:\NOT_A_REAL_PATH\DOES_NOT_EXIST")); + Assert.Throws(() => Subject.GetAvilableSpace(@"Z:\NOT_A_REAL_PATH\DOES_NOT_EXIST")); } } } diff --git a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/CleanUpDropFolderFixture.cs b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/CleanUpDropFolderFixture.cs deleted file mode 100644 index a9fedf483..000000000 --- a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/CleanUpDropFolderFixture.cs +++ /dev/null @@ -1,123 +0,0 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; -using FizzWare.NBuilder; -using Moq; -using NUnit.Framework; -using NzbDrone.Common; -using NzbDrone.Core.MediaFiles; -using NzbDrone.Core.Organizer; -using NzbDrone.Core.Tv; -using NzbDrone.Core.Providers; - -using NzbDrone.Core.Test.Framework; - -namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests -{ - - public class CleanUpDropFolderFixture : CoreTest - { - [Test] - public void should_do_nothing_if_no_files_are_found() - { - - var folder = @"C:\Test\DropDir\The Office"; - - Mocker.GetMock().Setup(s => s.GetFiles(folder, SearchOption.AllDirectories)) - .Returns(new string[0]); - - - Mocker.Resolve().CleanUpDropFolder(folder); - - - Mocker.GetMock().Verify(v => v.GetFileByPath(It.IsAny()), Times.Never()); - } - - [Test] - public void should_do_nothing_if_no_conflicting_files_are_found() - { - - var folder = @"C:\Test\DropDir\The Office"; - var filename = Path.Combine(folder, "NotAProblem.avi"); - - var episodeFile = Builder.CreateNew() - .With(f => f.Path = filename.NormalizePath()) - .With(f => f.SeriesId = 12345) - .Build(); - - Mocker.GetMock().Setup(s => s.GetFiles(folder, SearchOption.AllDirectories)) - .Returns(new string[] { filename }); - - Mocker.GetMock().Setup(s => s.GetFileByPath(filename)) - .Returns(() => null); - - - Mocker.Resolve().CleanUpDropFolder(folder); - - - Mocker.GetMock().Verify(v => v.GetFileByPath(filename), Times.Once()); - Mocker.GetMock().Verify(v => v.Get(It.IsAny()), Times.Never()); - } - - [Test] - public void should_move_file_if_a_conflict_is_found() - { - - var folder = @"C:\Test\DropDir\The Office"; - var filename = Path.Combine(folder, "Problem.avi"); - var seriesId = 12345; - var newFilename = "S01E01 - Title"; - var newFilePath = @"C:\Test\TV\The Office\Season 01\S01E01 - Title.avi"; - - var episodeFile = Builder.CreateNew() - .With(f => f.Path = filename.NormalizePath()) - .With(f => f.SeriesId = seriesId) - .Build(); - - var series = Builder.CreateNew() - .With(s => s.Id = seriesId) - .With(s => s.Title = "The Office") - .Build(); - - var episode = Builder.CreateListOfSize(1) - .All() - .With(e => e.SeriesId = seriesId) - .With(e => e.EpisodeFile = episodeFile) - .Build().ToList(); - - Mocker.GetMock().Setup(v => v.GetFileByPath(filename)) - .Returns(() => null); - - Mocker.GetMock().Setup(s => s.GetFiles(folder, SearchOption.AllDirectories)) - .Returns(new string[] { filename }); - - Mocker.GetMock().Setup(s => s.GetFileByPath(filename)) - .Returns(episodeFile); - - Mocker.GetMock().Setup(s => s.Get(It.IsAny())) - .Returns(series); - - Mocker.GetMock().Setup(s => s.GetEpisodesByFileId(episodeFile.Id)) - .Returns(episode); - - Mocker.GetMock().Setup(s => s.BuildFilename(It.IsAny>(), series, It.IsAny())) - .Returns(newFilename); - - Mocker.GetMock().Setup(s => s.BuildFilePath(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny())) - .Returns(newFilePath); - - Mocker.GetMock() - .Setup(s => s.FileExists(filename)) - .Returns(true); - - Mocker.GetMock().Setup(s => s.MoveFile(episodeFile.Path, newFilePath)); - - - Mocker.Resolve().CleanUpDropFolder(folder); - - - Mocker.GetMock().Verify(v => v.GetFileByPath(filename), Times.Once()); - Mocker.GetMock().Verify(v => v.MoveFile(filename.NormalizePath(), newFilePath), Times.Once()); - } - } -} diff --git a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs index 3dde91b2f..2cd8f919c 100644 --- a/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DiskScanProviderTests/ImportFileFixture.cs @@ -7,562 +7,281 @@ using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; using NzbDrone.Core.Providers; - using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common; -using NzbDrone.Test.Common.AutoMoq; namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests { - public class ImportFileFixture : CoreTest + public class ImportFileFixture : CoreTest { - public static object[] ImportTestCases = - { - new object[] { Quality.SDTV, false }, - new object[] { Quality.DVD, true }, - new object[] { Quality.HDTV720p, false } - }; - private readonly long SIZE = 80.Megabytes(); - private Series _series; + + private long _fileSize = 80.Megabytes(); + private Series _fakeSeries; + private List _fakeEpisodes; + private Episode _fakeEpisode; [SetUp] public void Setup() { - _series = Builder + _fakeSeries = Builder .CreateNew() - .With(s => s.SeriesType = SeriesTypes.Standard) .Build(); + + _fakeEpisode = Builder + .CreateNew() + .Build(); + + + _fakeEpisodes = Builder.CreateListOfSize(2) + .All() + .With(c => c.SeasonNumber = 3) + .With(e => e.EpisodeFile = new EpisodeFile()) + .BuildList(); + + GivenNewFile(); + + GivenVideoDuration(TimeSpan.FromMinutes(20)); + + GivenFileSize(_fileSize); + } - public void With80MBFile() + private void GivenFileSize(long size) { + _fileSize = size; + Mocker.GetMock() .Setup(d => d.GetSize(It.IsAny())) - .Returns(80.Megabytes()); + .Returns(size); } - public void WithDailySeries() + private void GivenVideoDuration(TimeSpan duration) { - _series.SeriesType = SeriesTypes.Daily; + Mocker.GetMock() + .Setup(d => d.GetRunTime(It.IsAny())) + .Returns(duration); + } + + + private void GivenEpisodes(IEnumerable episodes, QualityModel quality) + { + Mocker.GetMock() + .Setup(c => c.GetEpisodes(It.IsAny(), It.IsAny())) + .Returns(new LocalEpisode + { + Episodes = episodes.ToList(), + Quality = quality + }); + } + + private void GivenNewFile() + { + Mocker.GetMock() + .Setup(p => p.Exists(It.IsAny())) + .Returns(false); } [Test] public void import_new_file_should_succeed() { - const string newFile = @"WEEDS.S03E01.DUAL.dvd.HELLYWOOD.avi"; - - var fakeSeries = Builder.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew().Build(); - - //Mocks - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - - var result = Mocker.Resolve().ImportFile(fakeSeries, newFile); - - - VerifyFileImport(result, Mocker, fakeEpisode, SIZE); + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel()); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); + VerifyFileImport(result); } - [Test, TestCaseSource("ImportTestCases")] - public void import_new_file_with_better_same_quality_should_succeed(Quality currentFileQuality, bool currentFileProper) + + + [Test] + public void import_new_file_with_same_quality_should_succeed() { - const string newFile = @"WEEDS.S03E01.DUAL.1080p.HELLYWOOD.mkv"; + _fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) }; + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.SDTV)); - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew() - .With(e => e.EpisodeFile = Builder.CreateNew() - .With(g => g.Quality = new QualityModel(currentFileQuality, currentFileProper)) - .Build() - ).Build(); - - - With80MBFile(); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - - var result = Mocker.Resolve().ImportFile(fakeSeries, newFile); - - - VerifyFileImport(result, Mocker, fakeEpisode, SIZE); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); + VerifyFileImport(result); } - [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] - [TestCase("WEEDS.S03E01.DUAL.SDTV.XviD.AC3.-HELLYWOOD.avi")] - public void import_new_file_episode_has_same_or_better_quality_should_skip(string fileName) + [Test] + public void import_new_file_with_better_quality_should_succeed() { + _fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) }; + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew() - .With(c => c.EpisodeFile = Builder.CreateNew() - .With(e => e.Quality = new QualityModel(Quality.Bluray720p)).Build() - ) - .Build(); - - //Mocks - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifySkipImport(result, Mocker); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); + VerifyFileImport(result); } + [Test] + public void import_new_file_episode_has_better_quality_should_skip() + { + _fakeEpisode.EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p) }; + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.SDTV)); + + var result = Subject.ImportFile(_fakeSeries, "file.ext"); + + VerifySkipImport(result); + } + + [Test] public void import_unparsable_file_should_skip() { - const string fileName = @"C:\Test\WEEDS.avi"; + Mocker.GetMock() + .Setup(c => c.GetEpisodes(It.IsAny(), It.IsAny())) + .Returns(null); - var fakeSeries = Builder.CreateNew().Build(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())).Returns(false); - - With80MBFile(); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifySkipImport(result, Mocker); - ExceptionVerification.ExpectedWarns(1); + VerifySkipImport(result); } [Test] public void import_existing_file_should_skip() { - const string fileName = "WEEDS.S03E01-06.DUAL.BDRip.XviD.AC3.-HELLYWOOD.avi"; - - var fakeSeries = Builder.CreateNew().Build(); - - WithStrictMocker(); Mocker.GetMock() .Setup(p => p.Exists(It.IsAny())) .Returns(true); - With80MBFile(); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifySkipImport(result, Mocker); + VerifySkipImport(result); } [Test] public void import_file_with_no_episode_in_db_should_skip() { - //Constants - const string fileName = "WEEDS.S03E01.DUAL.BDRip.XviD.AC3.-HELLYWOOD.avi"; + GivenEpisodes(new List(), new QualityModel()); - //Fakes - var fakeSeries = Builder.CreateNew().Build(); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - //Mocks - Mocker.GetMock(MockBehavior.Strict) - .Setup(e => e.IsChildOfPath(fileName, fakeSeries.Path)).Returns(false); - - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(c => c.GetEpisodesByParseResult(It.IsAny())) - .Returns(new List()); - - - - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifySkipImport(result, Mocker); - } - - [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] - [TestCase("WEEDS.S03E01.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv")] - public void import_new_file_episode_has_better_quality_than_existing(string fileName) - { - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - var fakeEpisode = Builder.CreateNew() - .With(c => c.EpisodeFile = Builder.CreateNew() - .With(e => e.Quality = new QualityModel(Quality.SDTV)).Build() - ) - .Build(); - - //Mocks - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifyFileImport(result, Mocker, fakeEpisode, SIZE); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Once()); - } - - [TestCase("WEEDS.S03E01.DUAL.hdtv.XviD.AC3.-HELLYWOOD.avi")] - [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] - [TestCase("WEEDS.S03E01.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv")] - public void import_new_multi_part_file_episode_has_equal_or_better_quality_than_existing(string fileName) - { - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - - var fakeEpisodes = Builder.CreateListOfSize(2) - .All() - .With(e => e.EpisodeFile = Builder.CreateNew() - .With(f => f.Quality = new QualityModel(Quality.SDTV)) - .Build()) - .Build().ToList(); - - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(fakeEpisodes); - - - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifyFileImport(result, Mocker, fakeEpisodes[0], SIZE); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Once()); - } - - [TestCase("WEEDS.S03E01.DUAL.DVD.XviD.AC3.-HELLYWOOD.avi")] - [TestCase("WEEDS.S03E01.DUAL.HDTV.XviD.AC3.-HELLYWOOD.avi")] - public void skip_import_new_multi_part_file_episode_existing_has_better_quality(string fileName) - { - //Fakes - var fakeSeries = Builder.CreateNew().Build(); - - var fakeEpisodes = Builder.CreateListOfSize(2) - .All() - .With(e => e.EpisodeFile = Builder.CreateNew() - .With(f => f.Quality = new QualityModel(Quality.Bluray720p)) - .Build()) - .Build().ToList(); - - //Mocks - - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(fakeEpisodes); - - - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifySkipImport(result, Mocker); + VerifySkipImport(result); } [Test] - public void import_new_multi_part_file_episode_replace_two_files() + public void import_new_multi_part_file_episode_with_better_quality_than_existing() { - const string fileName = "WEEDS.S03E01E02.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv"; + _fakeEpisodes[0].EpisodeFile = new EpisodeFile(); + _fakeEpisodes[1].EpisodeFile = new EpisodeFile(); - //Fakes - var fakeSeries = Builder.CreateNew().Build(); + _fakeEpisodes[0].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) }; + _fakeEpisodes[1].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.SDTV) }; - var fakeEpisodeFiles = Builder.CreateListOfSize(2) - .All() - .With(e => e.Quality = new QualityModel(Quality.SDTV)) - .Build(); + GivenEpisodes(_fakeEpisodes, new QualityModel(Quality.HDTV1080p)); - var fakeEpisode1 = Builder.CreateNew() - .With(c => c.EpisodeFile = fakeEpisodeFiles[0]) - .Build(); - - var fakeEpisode2 = Builder.CreateNew() - .With(c => c.EpisodeFile = fakeEpisodeFiles[1]) - .Build(); - - //Mocks - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode1, fakeEpisode2 }); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifyFileImport(result, Mocker, fakeEpisode1, SIZE); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Exactly(2)); + VerifyFileImport(result); } [Test] - public void should_import_new_episode_no_existing_episode_file() + public void skip_import_new_multi_part_file_episode_existing_has_better_quality() { - const string fileName = "WEEDS.S03E01E02.DUAL.bluray.x264.AC3.-HELLYWOOD.mkv"; + _fakeEpisodes[0].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p) }; + _fakeEpisodes[1].EpisodeFile = new EpisodeFile { Quality = new QualityModel(Quality.HDTV1080p) }; - //Fakes - var fakeSeries = Builder.CreateNew().Build(); + GivenEpisodes(_fakeEpisodes, new QualityModel(Quality.SDTV)); - var fakeEpisode = Builder.CreateNew() - .Build(); - - //Mocks - With80MBFile(); - - Mocker.GetMock() - .Setup(p => p.Exists(It.IsAny())) - .Returns(false); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - var result = Mocker.Resolve().ImportFile(fakeSeries, fileName); - - - VerifyFileImport(result, Mocker, fakeEpisode, SIZE); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); + VerifySkipImport(result); } - [Test] - public void should_set_parseResult_SceneSource_if_not_in_series_Path() - { - var series = Builder - .CreateNew() - .With(s => s.Path == @"C:\Test\TV\30 Rock") - .Build(); - - const string path = @"C:\Test\Unsorted TV\30 Rock\30.rock.s01e01.pilot.mkv"; - - With80MBFile(); - - Mocker.GetMock().Setup(s => s.GetEpisodesByParseResult(It.IsAny())) - .Returns(new List()); - - Mocker.GetMock().Setup(s => s.IsChildOfPath(path, series.Path)) - .Returns(false); - - Mocker.Resolve().ImportFile(series, path); - - Mocker.Verify(s => s.GetEpisodesByParseResult(It.Is(p => p.SceneSource)), Times.Once()); - } [Test] - public void should_not_set_parseResult_SceneSource_if_in_series_Path() + public void should_skip_if_file_size_is_under_70MB_and_runTime_under_3_minutes() { - var series = Builder - .CreateNew() - .With(s => s.Path == @"C:\Test\TV\30 Rock") - .Build(); + GivenFileSize(50.Megabytes()); + GivenVideoDuration(TimeSpan.FromMinutes(1)); - const string path = @"C:\Test\TV\30 Rock\30.rock.s01e01.pilot.mkv"; + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); - With80MBFile(); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - Mocker.GetMock().Setup(s => s.GetEpisodesByParseResult(It.IsAny())) - .Returns(new List()); - - Mocker.GetMock().Setup(s => s.IsChildOfPath(path, series.Path)) - .Returns(true); - - Mocker.Resolve().ImportFile(series, path); - - Mocker.Verify(s => s.GetEpisodesByParseResult(It.Is(p => p.SceneSource == false)), Times.Once()); - } - - [Test] - public void should_return_null_if_file_size_is_under_70MB_and_runTime_under_3_minutes() - { - const string path = @"C:\Test\TV\30.rock.s01e01.pilot.avi"; - - Mocker.GetMock() - .Setup(m => m.Exists(path)) - .Returns(false); - - Mocker.GetMock() - .Setup(d => d.GetSize(path)) - .Returns(20.Megabytes()); - - Mocker.GetMock() - .Setup(s => s.GetRunTime(path)) - .Returns(60); - - Mocker.Resolve().ImportFile(_series, path).Should().BeNull(); + VerifySkipImport(result); } [Test] public void should_import_if_file_size_is_under_70MB_but_runTime_over_3_minutes() { - var fakeEpisode = Builder.CreateNew() - .Build(); + GivenFileSize(50.Megabytes()); + GivenVideoDuration(TimeSpan.FromMinutes(20)); - const string path = @"C:\Test\TV\30.rock.s01e01.pilot.avi"; + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); - Mocker.GetMock() - .Setup(m => m.Exists(path)) - .Returns(false); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - Mocker.GetMock() - .Setup(d => d.GetSize(path)) - .Returns(20.Megabytes()); - - Mocker.GetMock() - .Setup(s => s.GetRunTime(path)) - .Returns(600); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - var result = Mocker.Resolve().ImportFile(_series, path); - - VerifyFileImport(result, Mocker, fakeEpisode, 20.Megabytes()); + VerifyFileImport(result); Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); } [Test] public void should_import_if_file_size_is_over_70MB_but_runTime_under_3_minutes() { - With80MBFile(); + GivenFileSize(100.Megabytes()); + GivenVideoDuration(TimeSpan.FromMinutes(1)); - var fakeEpisode = Builder.CreateNew() - .Build(); + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); - const string path = @"C:\Test\TV\30.rock.s01e01.pilot.avi"; + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - Mocker.GetMock() - .Setup(m => m.Exists(path)) - .Returns(false); - - Mocker.GetMock() - .Setup(s => s.GetRunTime(path)) - .Returns(60); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - var result = Mocker.Resolve().ImportFile(_series, path); - - VerifyFileImport(result, Mocker, fakeEpisode, SIZE); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); + VerifyFileImport(result); } [Test] public void should_import_special_even_if_file_size_is_under_70MB_and_runTime_under_3_minutes() { - With80MBFile(); + GivenFileSize(10.Megabytes()); + GivenVideoDuration(TimeSpan.FromMinutes(1)); - var fakeEpisode = Builder.CreateNew() - .Build(); + _fakeEpisode.SeasonNumber = 0; - const string path = @"C:\Test\TV\30.rock.s00e01.pre-pilot.avi"; + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); - Mocker.GetMock() - .Setup(m => m.Exists(path)) - .Returns(false); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - Mocker.GetMock() - .Setup(d => d.GetSize(path)) - .Returns(20.Megabytes()); - - Mocker.GetMock() - .Setup(s => s.GetRunTime(path)) - .Returns(60); - - Mocker.GetMock() - .Setup(e => e.GetEpisodesByParseResult(It.IsAny())).Returns(new List { fakeEpisode }); - - var result = Mocker.Resolve().ImportFile(_series, path); - - VerifyFileImport(result, Mocker, fakeEpisode, 20.Megabytes()); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); + VerifyFileImport(result); } [Test] - public void should_return_null_if_daily_series_with_file_size_is_under_70MB_and_runTime_under_3_minutes() + public void should_skip_if_daily_series_with_file_size_is_under_70MB_and_runTime_under_3_minutes() { - WithDailySeries(); + GivenFileSize(10.Megabytes()); + GivenVideoDuration(TimeSpan.FromMinutes(1)); - const string path = @"C:\Test\TV\30.rock.s01e01.pilot.avi"; + _fakeEpisode.SeasonNumber = 0; + _fakeSeries.SeriesType = SeriesTypes.Daily; - Mocker.GetMock() - .Setup(m => m.Exists(path)) - .Returns(false); + GivenEpisodes(new[] { _fakeEpisode }, new QualityModel(Quality.HDTV1080p)); - Mocker.GetMock() - .Setup(d => d.GetSize(path)) - .Returns(20.Megabytes()); + var result = Subject.ImportFile(_fakeSeries, "file.ext"); - Mocker.GetMock() - .Setup(s => s.GetRunTime(path)) - .Returns(60); - - Mocker.Resolve().ImportFile(_series, path).Should().BeNull(); + VerifySkipImport(result); } - private static void VerifyFileImport(EpisodeFile result, AutoMoqer Mocker, Episode fakeEpisode, long size) + private void VerifyFileImport(EpisodeFile result) { result.Should().NotBeNull(); - result.SeriesId.Should().Be(fakeEpisode.SeriesId); - result.Size.Should().Be(size); + result.SeriesId.Should().Be(_fakeSeries.Id); + result.Size.Should().Be(_fileSize); result.DateAdded.Should().HaveDay(DateTime.Now.Day); - Mocker.GetMock().Verify(p => p.Add(It.IsAny()), Times.Once()); - //Get the count of episodes linked - var count = Mocker.GetMock().Object.GetEpisodesByParseResult(null).Count; - - Mocker.GetMock().Verify(p => p.UpdateEpisode(It.Is(e => e.EpisodeFileId == result.Id)), Times.Exactly(count)); + Mocker.GetMock().Verify(c => c.Add(result), Times.Once()); } - private static void VerifySkipImport(EpisodeFile result, AutoMoqer Mocker) + private void VerifySkipImport(EpisodeFile result) { result.Should().BeNull(); Mocker.GetMock().Verify(p => p.Add(It.IsAny()), Times.Never()); - Mocker.GetMock().Verify(p => p.UpdateEpisode(It.IsAny()), Times.Never()); - Mocker.GetMock().Verify(p => p.DeleteFile(It.IsAny()), Times.Never()); } } } diff --git a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/DropFolderImportServiceFixture.cs b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/DropFolderImportServiceFixture.cs new file mode 100644 index 000000000..9fb92ddd6 --- /dev/null +++ b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/DropFolderImportServiceFixture.cs @@ -0,0 +1,145 @@ +using System; +using System.IO; +using FizzWare.NBuilder; +using Moq; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Tv; +using NzbDrone.Core.Providers; +using NzbDrone.Core.Test.Framework; + +namespace NzbDrone.Core.Test.ProviderTests.PostDownloadProviderTests +{ + [TestFixture] + public class DropFolderImportServiceFixture : CoreTest + { + private EpisodeFile _fakeEpisodeFile; + + + private string[] _subFolders = new[] { "c:\\root\\foldername" }; + private string[] _videoFiles = new[] { "c:\\root\\foldername\\video.ext" }; + + [SetUp] + public void Setup() + { + _fakeEpisodeFile = Builder.CreateNew().Build(); + + + Mocker.GetMock().Setup(c => c.GetVideoFiles(It.IsAny(), It.IsAny())) + .Returns(_videoFiles); + + Mocker.GetMock().Setup(c => c.GetDirectories(It.IsAny())) + .Returns(_subFolders); + } + + private void WithOldWrite() + { + Mocker.GetMock() + .Setup(c => c.GetLastFolderWrite(It.IsAny())) + .Returns(DateTime.Now.AddDays(-5)); + } + + private void WithRecentFolderWrite() + { + Mocker.GetMock() + .Setup(c => c.GetLastFolderWrite(It.IsAny())) + .Returns(DateTime.UtcNow); + } + + [Test] + public void should_import_file() + { + Subject.ProcessDropFolder("c:\\drop\\"); + + VerifyImport(); + } + + [Test] + public void should_skip_if_folder_is_too_fresh() + { + WithRecentFolderWrite(); + + Subject.ProcessDropFolder("c:\\drop\\"); + + VerifyNoImport(); + } + + + [Test] + public void should_search_for_series_using_folder_name() + { + WithOldWrite(); + + Subject.ProcessDropFolder("c:\\drop\\"); + + Mocker.GetMock().Verify(c => c.FindByTitle("foldername"), Times.Once()); + + } + + [Test] + public void should_search_for_series_using_file_name() + { + /*WithOldWrite(); + WithValidSeries(); + WithImportableFiles(); + + var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - S01E01 - Episode Title"); + Subject.ProcessDownload(droppedFolder); + + Mocker.GetMock() + .Verify(c => c.Scan(_fakeSeries, It.IsAny()));*/ + + } + + + [Test] + public void all_imported_files_should_be_moved() + { + Mocker.GetMock().Setup(c => c.ImportFile(It.IsAny(), It.IsAny())) + .Returns(_fakeEpisodeFile); + + Subject.ProcessDropFolder("c:\\drop\\"); + + Mocker.GetMock().Verify(c => c.MoveEpisodeFile(_fakeEpisodeFile, true), Times.Once()); + } + + [Test] + public void should_not_attempt_move_if_nothing_is_imported() + { + Mocker.GetMock().Setup(c => c.ImportFile(It.IsAny(), It.IsAny())) + .Returns(null); + + Subject.ProcessDropFolder("c:\\drop\\"); + + Mocker.GetMock().Verify(c => c.MoveEpisodeFile(It.IsAny(), It.IsAny()), Times.Never()); + } + + + [Test] + public void should_skip_if_folder_is_in_use_by_another_process() + { + + Mocker.GetMock().Setup(c => c.IsFileLocked(It.IsAny())) + .Returns(true); + + Subject.ProcessDropFolder("c:\\drop\\"); + VerifyNoImport(); + } + + + + private void VerifyNoImport() + { + Mocker.GetMock().Verify(c => c.ImportFile(It.IsAny(), It.IsAny()), + Times.Never()); + } + + + private void VerifyImport() + { + Mocker.GetMock().Verify(c => c.ImportFile(It.IsAny(), It.IsAny()), + Times.Once()); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/GetFolderNameWithStatusFixture.cs b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/GetFolderNameWithStatusFixture.cs deleted file mode 100644 index 9ec85097b..000000000 --- a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/GetFolderNameWithStatusFixture.cs +++ /dev/null @@ -1,44 +0,0 @@ - - -using System.Linq; -using System; -using System.IO; -using FluentAssertions; -using NUnit.Framework; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; -using NzbDrone.Core.Test.Framework; - -namespace NzbDrone.Core.Test.ProviderTests.PostDownloadProviderTests -{ - [TestFixture] - - public class GetFolderNameWithStatusFixture : CoreTest - { - [TestCase(@"c:\_NzbDrone_InvalidEpisode_Title", @"c:\_UnknownSeries_Title", PostDownloadStatusType.UnknownSeries)] - [TestCase(@"c:\Title", @"c:\_Failed_Title", PostDownloadStatusType.Failed)] - [TestCase(@"c:\Root\Test Title", @"c:\Root\_ParseError_Test Title", PostDownloadStatusType.ParseError)] - public void GetFolderNameWithStatus_should_return_a_string_with_the_error_removing_existing_error(string currentName, string excpectedName, PostDownloadStatusType status) - { - PostDownloadProvider.GetTaggedFolderName(new DirectoryInfo(currentName), status).Should().Be( - excpectedName); - } - - [TestCase(PostDownloadStatusType.NoError)] - [ExpectedException(typeof(InvalidOperationException))] - public void GetFolderNameWithStatus_should_throw_if_status_is_not_an_error(PostDownloadStatusType status) - { - PostDownloadProvider.GetTaggedFolderName(new DirectoryInfo(TempFolder), status); - } - - - [TestCase("_NzbDrone_ParseError_The Office (US) - S01E01 - Episode Title", "The Office (US) - S01E01 - Episode Title")] - [TestCase("_Status_The Office (US) - S01E01 - Episode Title", "The Office (US) - S01E01 - Episode Title")] - [TestCase("The Office (US) - S01E01 - Episode Title", "The Office (US) - S01E01 - Episode Title")] - [TestCase("_The Office (US) - S01E01 - Episode Title", "_The Office (US) - S01E01 - Episode Title")] - public void RemoveStatus_should_remove_status_string_from_folder_name(string folderName, string cleanFolderName) - { - PostDownloadProvider.RemoveStatusFromFolderName(folderName).Should().Be(cleanFolderName); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs deleted file mode 100644 index d360d029f..000000000 --- a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDownloadFixture.cs +++ /dev/null @@ -1,469 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using FizzWare.NBuilder; -using Marr.Data; -using Moq; -using NUnit.Framework; -using NzbDrone.Common; -using NzbDrone.Core.MediaFiles; -using NzbDrone.Core.RootFolders; -using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; - -using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common; -using NzbDrone.Test.Common.AutoMoq; - -namespace NzbDrone.Core.Test.ProviderTests.PostDownloadProviderTests -{ - [TestFixture] - public class ProcessDownloadFixture : CoreTest - { - Series fakeSeries; - - [SetUp] - public void Setup() - { - fakeSeries = Builder.CreateNew() - .With(s => s.RootFolder = new LazyLoaded(new RootFolder { Path = @"C:\Test\TV" })) - .With(s => s.FolderName = "30 Rock") - .Build(); - } - - private void WithOldWrite() - { - Mocker.GetMock() - .Setup(c => c.GetLastDirectoryWrite(It.IsAny())) - .Returns(DateTime.Now.AddDays(-5)); - } - - private void WithRecentWrite() - { - Mocker.GetMock() - .Setup(c => c.GetLastDirectoryWrite(It.IsAny())) - .Returns(DateTime.UtcNow); - } - - private void WithValidSeries() - { - Mocker.GetMock() - .Setup(c => c.GetByTitle(It.IsAny())) - .Returns(fakeSeries); - - Mocker.GetMock() - .Setup(c => c.FolderExists(fakeSeries.Path)) - .Returns(true); - } - - private void WithImportableFiles() - { - Mocker.GetMock() - .Setup(c => c.Scan(It.IsAny(), It.IsAny())) - .Returns(Builder.CreateListOfSize(1).Build().ToList()); - } - - private void WithLotsOfFreeDiskSpace() - { - Mocker.GetMock().Setup(s => s.FreeDiskSpace(It.IsAny())).Returns(1000000000); - } - - private void WithImportedFiles(string droppedFolder) - { - var fakeEpisodeFiles = Builder.CreateListOfSize(2) - .All() - .With(f => f.SeriesId = fakeSeries.Id) - .Build().ToList(); - - Mocker.GetMock().Setup(s => s.Scan(fakeSeries, droppedFolder)).Returns(fakeEpisodeFiles); - } - - [Test] - public void should_skip_if_folder_is_tagged_and_too_fresh() - { - WithStrictMocker(); - WithRecentWrite(); - - var droppedFolder = new DirectoryInfo(TempFolder + "\\_test\\"); - droppedFolder.Create(); - - Mocker.Resolve().ProcessDownload(droppedFolder); - } - - [Test] - public void should_continue_processing_if_folder_is_tagged_and_not_fresh() - { - WithOldWrite(); - - var droppedFolder = new DirectoryInfo(TempFolder + "\\_test\\"); - droppedFolder.Create(); - - - Mocker.GetMock().Setup(s => s.GetByTitle(It.IsAny())).Returns(null).Verifiable(); - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - ExceptionVerification.IgnoreWarns(); - } - - - [Test] - public void should_search_for_series_using_title_without_status() - { - WithOldWrite(); - - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\_unpack_The Office - S01E01 - Episode Title"); - - Mocker.GetMock().Setup(s => s.GetByTitle("office")).Returns(null).Verifiable(); - - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - ExceptionVerification.IgnoreWarns(); - } - - [Test] - public void should_search_for_series_using_folder_name() - { - WithOldWrite(); - WithValidSeries(); - WithImportableFiles(); - - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - S01E01 - Episode Title"); - Mocker.Resolve().ProcessDownload(droppedFolder); - - Mocker.GetMock() - .Verify(c=>c.Scan(fakeSeries, It.IsAny())); - - } - - [Test] - public void should_search_for_series_using_file_name() - { - WithOldWrite(); - WithValidSeries(); - WithImportableFiles(); - - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - S01E01 - Episode Title"); - Mocker.Resolve().ProcessDownload(droppedFolder); - - Mocker.GetMock() - .Verify(c => c.Scan(fakeSeries, It.IsAny())); - - } - - [Test] - [Ignore("Disabled tagging")] - public void when_series_isnt_found_folder_should_be_tagged_as_unknown_series() - { - - WithStrictMocker(); - WithOldWrite(); - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - S01E01 - Episode Title"); - - var taggedFolder = @"C:\Test\Unsorted TV\_UnknownSeries_The Office - S01E01 - Episode Title"; - - - Mocker.GetMock().Setup(s => s.GetByTitle("office")).Returns(null); - Mocker.GetMock().Setup(s => s.MoveDirectory(droppedFolder.FullName, taggedFolder)); - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - [Ignore("Disabled tagging")] - public void when_no_files_are_imported_folder_should_be_tagged_with_parse_error() - { - - WithStrictMocker(); - WithOldWrite(); - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - S01E01 - Episode Title"); - - var taggedFolder = @"C:\Test\Unsorted TV\_ParseError_The Office - S01E01 - Episode Title"; - - var fakeSeries = Builder.CreateNew() - .With(s => s.Title = "The Office") - .Build(); - - - Mocker.GetMock().Setup(s => s.GetByTitle("office")).Returns(fakeSeries); - Mocker.GetMock().Setup(s => s.Scan(fakeSeries, droppedFolder.FullName)).Returns(new List()); - Mocker.GetMock().Setup(s => s.MoveDirectory(droppedFolder.FullName, taggedFolder)); - Mocker.GetMock().Setup(s => s.GetDirectorySize(droppedFolder.FullName)).Returns(Constants.IgnoreFileSize + 10.Megabytes()); - - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - ExceptionVerification.ExpectedWarns(1); - } - - - [Test] - [Ignore("Disabled tagging")] - public void when_no_file_are_imported_and_folder_size_isnt_small_enought_folder_should_be_tagged_unknown() - { - - WithStrictMocker(); - WithOldWrite(); - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - Season 01"); - - var taggedFolder = PostDownloadProvider.GetTaggedFolderName(droppedFolder, PostDownloadStatusType.Unknown); - - var fakeSeries = Builder.CreateNew() - .With(s => s.Title = "The Office") - .Build(); - - var fakeEpisodeFiles = Builder.CreateListOfSize(2) - .All() - .With(f => f.SeriesId = fakeSeries.Id) - .Build().ToList(); - - - Mocker.GetMock().Setup(s => s.GetByTitle("office")).Returns(fakeSeries); - Mocker.GetMock().Setup(s => s.MoveDirectory(droppedFolder.FullName, taggedFolder)); - Mocker.GetMock().Setup(s => s.GetDirectorySize(droppedFolder.FullName)).Returns(Constants.IgnoreFileSize + 10.Megabytes()); - Mocker.GetMock().Setup(s => s.Scan(fakeSeries, droppedFolder.FullName)).Returns(fakeEpisodeFiles); - Mocker.GetMock().Setup(s => s.MoveEpisodeFile(It.IsAny(), true)).Returns(new EpisodeFile()); - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - ExceptionVerification.ExpectedWarns(1); - } - - [TestCase(@"\_UnknownSeries_The Office - S01E01 - Episode Title")] - [TestCase(@"\_UnknownSeries_The Office - S01E01 - Episode Title\")] - [TestCase("\\Test\\_UnknownSeries_The Office - S01E01 - Episode Title\\")] - [TestCase("\\Test\\_UnknownSeries_The Office - S01E01 - Episode Title")] - public void folder_shouldnt_be_tagged_with_same_tag_again(string path) - { - - - var droppedFolder = new DirectoryInfo(TempFolder + path); - droppedFolder.Create(); - WithOldWrite(); - - - Mocker.GetMock().Setup(s => s.GetByTitle(It.IsAny())).Returns(null); - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - Mocker.GetMock().Verify(c => c.MoveDirectory(It.IsAny(), It.IsAny()), Times.Never()); - } - - [Test] - public void folder_should_not_be_tagged_if_existing_tag_is_diffrent() - { - - WithOldWrite(); - var droppedFolder = new DirectoryInfo(TempFolder + @"\_UnknownEpisode_The Office - S01E01 - Episode Title"); - droppedFolder.Create(); - droppedFolder.LastWriteTime = DateTime.Now.AddHours(-1); - - var taggedFolder = TempFolder + @"\_UnknownSeries_The Office - S01E01 - Episode Title"; - - Mocker.GetMock().Setup(s => s.GetByTitle(It.IsAny())).Returns(null); - - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - Mocker.GetMock().Verify(c => c.MoveDirectory(droppedFolder.FullName, taggedFolder), Times.Never()); - ExceptionVerification.IgnoreWarns(); - } - - [Test] - public void when_files_are_imported_and_folder_is_small_enough_dir_should_be_deleted() - { - - WithStrictMocker(); - WithLotsOfFreeDiskSpace(); - - var droppedFolder = new DirectoryInfo(@"C:\Test\Unsorted TV\The Office - Season 01"); - - WithImportedFiles(droppedFolder.FullName); - - Mocker.GetMock().Setup(s => s.GetByTitle("office")).Returns(fakeSeries); - Mocker.GetMock().Setup(s => s.CleanUpDropFolder(droppedFolder.FullName)); - Mocker.GetMock().Setup(s => s.MoveEpisodeFile(It.IsAny(), true)).Returns(new EpisodeFile()); - Mocker.GetMock().Setup(s => s.GetDirectorySize(droppedFolder.FullName)).Returns(Constants.IgnoreFileSize - 1.Megabytes()); - Mocker.GetMock().Setup(s => s.DeleteFolder(droppedFolder.FullName, true)); - Mocker.GetMock().Setup(s => s.FolderExists(fakeSeries.Path)).Returns(true); - Mocker.GetMock().Setup(s => s.IsFolderLocked(droppedFolder.FullName)).Returns(false); - - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.VerifyAllMocks(); - } - - [Test] - public void all_imported_files_should_be_moved() - { - var droppedFolder = new DirectoryInfo(TempFolder); - - var fakeSeries = Builder.CreateNew() - .Build(); - - var fakeEpisodeFiles = Builder.CreateListOfSize(2) - .Build().ToList(); - - Mocker.GetMock().Setup(s => s.GetByTitle(It.IsAny())).Returns(fakeSeries); - Mocker.GetMock().Setup(s => s.FolderExists(fakeSeries.Path)).Returns(true); - Mocker.GetMock().Setup(s => s.Scan(fakeSeries, droppedFolder.FullName)).Returns(fakeEpisodeFiles); - - - Mocker.Resolve().ProcessDownload(droppedFolder); - - - Mocker.GetMock().Verify(c => c.MoveEpisodeFile(It.IsAny(), true), - Times.Exactly(fakeEpisodeFiles.Count)); - Mocker.VerifyAllMocks(); - } - - [Test] - public void should_logError_and_return_if_size_exceeds_free_space() - { - var downloadName = new DirectoryInfo(@"C:\Test\Drop\30.Rock.S01E01.Pilot"); - - var series = Builder.CreateNew() - .With(s => s.Title = "30 Rock") - .With(s => s.RootFolder = new LazyLoaded(new RootFolder { Path = @"C:\Test\TV" })) - .With(s => s.FolderName = "30 Rock") - .Build(); - - Mocker.GetMock() - .Setup(c => c.GetByTitle("rock")) - .Returns(series); - - Mocker.GetMock() - .Setup(s => s.GetDirectorySize(downloadName.FullName)) - .Returns(10); - - Mocker.GetMock() - .Setup(s => s.FolderExists(series.Path)) - .Returns(true); - - Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(series.Path)) - .Returns(9); - - - Mocker.Resolve().ProcessDownload(downloadName); - - - - Mocker.GetMock().Verify(c => c.Scan(series, downloadName.FullName), Times.Never()); - ExceptionVerification.ExpectedErrors(1); - } - - [Test] - public void should_process_if_free_disk_space_exceeds_size() - { - WithLotsOfFreeDiskSpace(); - WithValidSeries(); - - var downloadName = new DirectoryInfo(@"C:\Test\Drop\30.Rock.S01E01.Pilot"); - - WithImportedFiles(downloadName.FullName); - - Mocker.GetMock() - .Setup(c => c.GetByTitle("rock")) - .Returns(fakeSeries); - - Mocker.GetMock() - .Setup(s => s.GetDirectorySize(downloadName.FullName)) - .Returns(8); - - - Mocker.Resolve().ProcessDownload(downloadName); - - - - Mocker.GetMock().Verify(c => c.Scan(fakeSeries, downloadName.FullName), Times.Once()); - } - - [Test] - public void should_process_if_free_disk_space_equals_size() - { - var downloadName = new DirectoryInfo(@"C:\Test\Drop\30.Rock.S01E01.Pilot"); - - WithImportedFiles(downloadName.FullName); - WithValidSeries(); - - Mocker.GetMock() - .Setup(s => s.GetDirectorySize(downloadName.FullName)) - .Returns(10); - - Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(It.IsAny())) - .Returns(10); - - - Mocker.Resolve().ProcessDownload(downloadName); - - - - Mocker.GetMock().Verify(c => c.Scan(fakeSeries, downloadName.FullName), Times.Once()); - } - - [Test] - public void should_create_series_directory_if_series_path_does_not_exist() - { - var downloadName = new DirectoryInfo(@"C:\Test\Drop\30.Rock.S01E01.Pilot"); - - WithValidSeries(); - WithLotsOfFreeDiskSpace(); - WithImportedFiles(downloadName.FullName); - - Mocker.GetMock() - .Setup(s => s.FolderExists(fakeSeries.Path)) - .Returns(false); - - Mocker.GetMock().Setup(s => s.GetByTitle("office")).Returns(fakeSeries); - Mocker.GetMock().Setup(s => s.CleanUpDropFolder(downloadName.FullName)); - Mocker.GetMock().Setup(s => s.MoveEpisodeFile(It.IsAny(), true)).Returns(new EpisodeFile()); - Mocker.GetMock().Setup(s => s.GetDirectorySize(downloadName.FullName)).Returns(Constants.IgnoreFileSize - 1.Megabytes()); - Mocker.GetMock().Setup(s => s.DeleteFolder(downloadName.FullName, true)); - Mocker.GetMock().Setup(s => s.IsFolderLocked(downloadName.FullName)).Returns(false); - - Mocker.Resolve().ProcessDownload(downloadName); - - Mocker.GetMock().Verify(c => c.CreateDirectory(fakeSeries.Path), Times.Once()); - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_skip_if_folder_is_in_use_by_another_process() - { - var downloadName = new DirectoryInfo(@"C:\Test\Drop\30.Rock.S01E01.Pilot"); - - WithValidSeries(); - - Mocker.GetMock() - .Setup(s => s.IsFolderLocked(downloadName.FullName)) - .Returns(true); - - Mocker.Resolve().ProcessDownload(downloadName); - - Mocker.GetMock().Verify(c => c.GetDirectorySize(It.IsAny()), Times.Never()); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDropDirectoryFixture.cs b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDropDirectoryFixture.cs deleted file mode 100644 index 84c65efec..000000000 --- a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessDropDirectoryFixture.cs +++ /dev/null @@ -1,135 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using FizzWare.NBuilder; -using Marr.Data; -using Moq; -using NUnit.Framework; -using NzbDrone.Common; -using NzbDrone.Core.MediaFiles; -using NzbDrone.Core.RootFolders; -using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; - -using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common; -using NzbDrone.Test.Common.AutoMoq; - -namespace NzbDrone.Core.Test.ProviderTests.PostDownloadProviderTests -{ - [TestFixture] - public class ProcessDropDirectoryFixture : CoreTest - { - Series fakeSeries; - - [SetUp] - public void Setup() - { - fakeSeries = Builder.CreateNew() - .With(s => s.RootFolder = new LazyLoaded(new RootFolder { Path = @"C:\Test\TV" })) - .With(s => s.FolderName = "30 Rock") - .Build(); - } - - private void WithLotsOfFreeDiskSpace() - { - Mocker.GetMock().Setup(s => s.FreeDiskSpace(It.IsAny())).Returns(1000000000); - } - - [Test] - public void ProcessDropFolder_should_only_process_folders_that_arent_known_series_folders() - { - WithLotsOfFreeDiskSpace(); - - var subFolders = new[] - { - @"c:\drop\episode1", - @"c:\drop\episode2", - @"c:\drop\episode3", - @"c:\drop\episode4" - }; - - Mocker.GetMock() - .Setup(c => c.GetVideoFiles(It.IsAny(), false)) - .Returns(new List()); - - Mocker.GetMock() - .Setup(c => c.GetDirectories(It.IsAny())) - .Returns(subFolders); - - Mocker.GetMock() - .Setup(c => c.SeriesPathExists(subFolders[1])) - .Returns(true); - - Mocker.GetMock() - .Setup(c => c.GetByTitle(It.IsAny())) - .Returns(fakeSeries); - - Mocker.GetMock() - .Setup(c => c.Scan(It.IsAny(), It.IsAny())) - .Returns(new List()); - - Mocker.GetMock() - .Setup(c => c.GetDirectorySize(It.IsAny())) - .Returns(10); - - Mocker.GetMock() - .Setup(c => c.FolderExists(It.IsAny())) - .Returns(true); - - - Mocker.Resolve().ProcessDropFolder(@"C:\drop\"); - - - Mocker.GetMock().Verify(c => c.Scan(It.IsAny(), subFolders[0]), Times.Once()); - Mocker.GetMock().Verify(c => c.Scan(It.IsAny(), subFolders[1]), Times.Never()); - Mocker.GetMock().Verify(c => c.Scan(It.IsAny(), subFolders[2]), Times.Once()); - Mocker.GetMock().Verify(c => c.Scan(It.IsAny(), subFolders[3]), Times.Once()); - } - - [Test] - public void ProcessDropFolder_should_process_individual_video_files_in_drop_folder() - { - WithLotsOfFreeDiskSpace(); - - var files = new List - { - @"c:\drop\30 Rock - episode1.avi", - @"c:\drop\30 Rock - episode2.mkv", - @"c:\drop\30 Rock - episode3.mp4", - @"c:\drop\30 Rock - episode4.wmv" - }; - - Mocker.GetMock() - .Setup(c => c.GetVideoFiles(It.IsAny(), false)) - .Returns(files); - - Mocker.GetMock() - .Setup(c => c.GetByTitle(It.IsAny())) - .Returns(fakeSeries); - - Mocker.GetMock() - .Setup(c => c.Scan(It.IsAny(), It.IsAny())) - .Returns(new List()); - - Mocker.GetMock() - .Setup(c => c.GetDirectorySize(It.IsAny())) - .Returns(10); - - Mocker.GetMock() - .Setup(c => c.FolderExists(It.IsAny())) - .Returns(true); - - - Mocker.Resolve().ProcessDropFolder(@"C:\drop\"); - - - - Mocker.GetMock().Verify(c => c.ImportFile(It.IsAny(), It.IsAny()), Times.Exactly(4)); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessVideoFileFixture.cs b/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessVideoFileFixture.cs deleted file mode 100644 index 10d9e5e96..000000000 --- a/NzbDrone.Core.Test/ProviderTests/PostDownloadProviderTests/ProcessVideoFileFixture.cs +++ /dev/null @@ -1,267 +0,0 @@ - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -using FizzWare.NBuilder; -using Marr.Data; -using Moq; -using NUnit.Framework; -using NzbDrone.Common; -using NzbDrone.Core.MediaFiles; -using NzbDrone.Core.RootFolders; -using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -using NzbDrone.Core.Providers; - -using NzbDrone.Core.Test.Framework; -using NzbDrone.Test.Common; -using NzbDrone.Test.Common.AutoMoq; - -namespace NzbDrone.Core.Test.ProviderTests.PostDownloadProviderTests -{ - [TestFixture] - public class ProcessVideoFileFixture : CoreTest - { - Series fakeSeries; - - [SetUp] - public void Setup() - { - fakeSeries = Builder.CreateNew() - .With(s => s.RootFolder = new LazyLoaded(new RootFolder { Path = @"C:\Test\TV" })) - .With(s => s.FolderName = "30 Rock") - .Build(); - } - - private void WithOldWrite() - { - Mocker.GetMock() - .Setup(c => c.GetLastFileWrite(It.IsAny())) - .Returns(DateTime.Now.AddDays(-5)); - } - - private void WithRecentWrite() - { - Mocker.GetMock() - .Setup(c => c.GetLastFileWrite(It.IsAny())) - .Returns(DateTime.UtcNow); - } - - private void WithValidSeries() - { - Mocker.GetMock() - .Setup(c => c.GetByTitle(It.IsAny())) - .Returns(fakeSeries); - - Mocker.GetMock() - .Setup(s => s.FolderExists(fakeSeries.Path)) - .Returns(true); - } - - private void WithImportableFiles() - { - Mocker.GetMock() - .Setup(c => c.Scan(It.IsAny(), It.IsAny())) - .Returns(Builder.CreateListOfSize(1).Build().ToList()); - } - - private void WithLotsOfFreeDiskSpace() - { - Mocker.GetMock().Setup(s => s.FreeDiskSpace(It.IsAny())).Returns(1000000000); - } - - private void WithImportedFile(string file) - { - var fakeEpisodeFile = Builder.CreateNew() - .With(f => f.SeriesId = fakeSeries.Id) - .Build(); - - Mocker.GetMock().Setup(s => s.ImportFile(fakeSeries, file)).Returns(fakeEpisodeFile); - } - - [Test] - public void should_skip_if_and_too_fresh() - { - WithStrictMocker(); - WithRecentWrite(); - - var file = Path.Combine(TempFolder, "test.avi"); - - Mocker.Resolve().ProcessVideoFile(file); - } - - [Test] - public void should_continue_processing_if_not_fresh() - { - WithOldWrite(); - - var file = Path.Combine(TempFolder, "test.avi"); - - - Mocker.GetMock().Setup(s => s.GetByTitle(It.IsAny())).Returns(null).Verifiable(); - Mocker.Resolve().ProcessVideoFile(file); - - - Mocker.GetMock().Verify(s => s.GetByTitle(It.IsAny()), Times.Once()); - ExceptionVerification.IgnoreWarns(); - } - - [Test] - public void should_return_if_series_is_not_found() - { - WithOldWrite(); - - var file = Path.Combine(TempFolder, "test.avi"); - - - Mocker.GetMock().Setup(s => s.GetByTitle(It.IsAny())).Returns(null); - Mocker.Resolve().ProcessVideoFile(file); - - - Mocker.GetMock().Verify(s => s.GetSize(It.IsAny()), Times.Never()); - ExceptionVerification.IgnoreWarns(); - } - - [Test] - public void should_move_file_if_imported() - { - WithLotsOfFreeDiskSpace(); - WithOldWrite(); - - var file = Path.Combine(TempFolder, "test.avi"); - - WithValidSeries(); - WithImportedFile(file); - - - Mocker.Resolve().ProcessVideoFile(file); - - - Mocker.GetMock().Verify(s => s.MoveEpisodeFile(It.IsAny(), true), Times.Once()); - ExceptionVerification.IgnoreWarns(); - } - - [Test] - public void should_logError_and_return_if_size_exceeds_free_space() - { - var downloadName = @"C:\Test\Drop\30.Rock.S01E01.Pilot.mkv"; - - var series = Builder.CreateNew() - .With(s => s.Title = "30 Rock") - .With(s => s.RootFolder = new LazyLoaded(new RootFolder { Path = @"C:\Test\TV" })) - .With(s => s.FolderName = "30 Rock") - .Build(); - - Mocker.GetMock() - .Setup(c => c.GetByTitle("rock")) - .Returns(series); - - Mocker.GetMock() - .Setup(s => s.GetSize(downloadName)) - .Returns(10); - - Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(series.Path)) - .Returns(9); - - Mocker.GetMock() - .Setup(s => s.FolderExists(series.Path)) - .Returns(true); - - - Mocker.Resolve().ProcessVideoFile(downloadName); - - - - Mocker.GetMock().Verify(c => c.ImportFile(series, downloadName), Times.Never()); - ExceptionVerification.ExpectedErrors(1); - } - - [Test] - public void should_process_if_free_disk_space_exceeds_size() - { - WithLotsOfFreeDiskSpace(); - WithValidSeries(); - - var downloadName = @"C:\Test\Drop\30.Rock.S01E01.Pilot.mkv"; - - Mocker.GetMock() - .Setup(c => c.GetByTitle("rock")) - .Returns(fakeSeries); - - Mocker.GetMock() - .Setup(s => s.GetSize(downloadName)) - .Returns(8); - - - Mocker.Resolve().ProcessVideoFile(downloadName); - - - - Mocker.GetMock().Verify(c => c.ImportFile(fakeSeries, downloadName), Times.Once()); - } - - [Test] - public void should_process_if_free_disk_space_equals_size() - { - var downloadName = @"C:\Test\Drop\30.Rock.S01E01.Pilot.mkv"; - - WithValidSeries(); - - Mocker.GetMock() - .Setup(s => s.GetDirectorySize(downloadName)) - .Returns(10); - - Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(It.IsAny())) - .Returns(10); - - - Mocker.Resolve().ProcessVideoFile(downloadName); - - - - Mocker.GetMock().Verify(c => c.ImportFile(fakeSeries, downloadName), Times.Once()); - } - - [Test] - public void should_return_if_series_Path_doesnt_exist() - { - var downloadName = @"C:\Test\Drop\30.Rock.S01E01.Pilot.mkv"; - - WithValidSeries(); - - Mocker.GetMock() - .Setup(s => s.FolderExists(fakeSeries.Path)) - .Returns(false); - - - Mocker.Resolve().ProcessVideoFile(downloadName); - - - - ExceptionVerification.ExpectedWarns(1); - } - - [Test] - public void should_skip_if_file_is_in_use_by_another_process() - { - var downloadName = @"C:\Test\Drop\30.Rock.S01E01.Pilot.mkv"; - - WithValidSeries(); - - Mocker.GetMock() - .Setup(s => s.IsFileLocked(It.Is(f => f.FullName == downloadName))) - .Returns(true); - - - Mocker.Resolve().ProcessVideoFile(downloadName); - - - - Mocker.GetMock().Verify(c => c.ImportFile(fakeSeries, downloadName), Times.Never()); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs b/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs index e2d52c603..b1f8c4c1d 100644 --- a/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/RecycleBinProviderTests/CleanupFixture.cs @@ -18,7 +18,7 @@ public class CleanupFixture : CoreTest private void WithExpired() { - Mocker.GetMock().Setup(s => s.GetLastDirectoryWrite(It.IsAny())) + Mocker.GetMock().Setup(s => s.GetLastFolderWrite(It.IsAny())) .Returns(DateTime.UtcNow.AddDays(-10)); Mocker.GetMock().Setup(s => s.GetLastFileWrite(It.IsAny())) @@ -27,7 +27,7 @@ private void WithExpired() private void WithNonExpired() { - Mocker.GetMock().Setup(s => s.GetLastDirectoryWrite(It.IsAny())) + Mocker.GetMock().Setup(s => s.GetLastFolderWrite(It.IsAny())) .Returns(DateTime.UtcNow.AddDays(-3)); Mocker.GetMock().Setup(s => s.GetLastFileWrite(It.IsAny())) diff --git a/NzbDrone.Core.Test/RootFolderTests/FreeSpaceOnDrivesFixture.cs b/NzbDrone.Core.Test/RootFolderTests/FreeSpaceOnDrivesFixture.cs index 94f5bde79..619aa92f9 100644 --- a/NzbDrone.Core.Test/RootFolderTests/FreeSpaceOnDrivesFixture.cs +++ b/NzbDrone.Core.Test/RootFolderTests/FreeSpaceOnDrivesFixture.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using FluentAssertions; using Moq; using NUnit.Framework; @@ -16,7 +15,7 @@ namespace NzbDrone.Core.Test.RootFolderTests { [TestFixture] - + public class FreeSpaceOnDrivesFixture : CoreTest { [Test] @@ -31,7 +30,7 @@ public void should_return_one_drive_when_only_one_root_dir_exists() .Returns(@"C:\"); Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(@"C:\")) + .Setup(s => s.GetAvilableSpace(@"C:\")) .Returns(123456); var result = Subject.FreeSpaceOnDrives(); @@ -52,7 +51,7 @@ public void should_return_one_drive_when_two_rootDirs_on_the_same_drive_exist() .Returns(@"C:\"); Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(@"C:\")) + .Setup(s => s.GetAvilableSpace(@"C:\")) .Returns(123456); var result = Subject.FreeSpaceOnDrives(); @@ -77,7 +76,7 @@ public void should_return_two_drives_when_two_rootDirs_on_the_different_drive_ex .Returns(@"D:\"); Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(It.IsAny())) + .Setup(s => s.GetAvilableSpace(It.IsAny())) .Returns(123456); var result = Subject.FreeSpaceOnDrives(); @@ -97,7 +96,7 @@ public void should_skip_rootDir_if_not_found_on_disk() .Returns(@"C:\"); Mocker.GetMock() - .Setup(s => s.FreeDiskSpace(It.IsAny())) + .Setup(s => s.GetAvilableSpace(It.IsAny())) .Throws(new DirectoryNotFoundException()); var result = Subject.FreeSpaceOnDrives(); diff --git a/NzbDrone.Core.Test/UpdateTests/GetAvailableUpdateFixture.cs b/NzbDrone.Core.Test/UpdateTests/GetAvailableUpdateFixture.cs index e861a9671..2f4f26519 100644 --- a/NzbDrone.Core.Test/UpdateTests/GetAvailableUpdateFixture.cs +++ b/NzbDrone.Core.Test/UpdateTests/GetAvailableUpdateFixture.cs @@ -25,7 +25,10 @@ public void Setup() [TestCase("1.0.0.0")] public void should_return_null_if_latest_is_lower_than_current_version(string currentVersion) { - var updatePackage = Subject.GetAvailableUpdate(new Version(currentVersion)); + + Mocker.GetMock().SetupGet(c => c.Version).Returns(new Version(currentVersion)); + + var updatePackage = Subject.GetAvailableUpdate(); updatePackage.Should().BeNull(); } @@ -33,7 +36,9 @@ public void should_return_null_if_latest_is_lower_than_current_version(string cu [Test] public void should_return_null_if_latest_is_equal_to_current_version() { - var updatePackage = Subject.GetAvailableUpdate(LatestTestVersion); + Mocker.GetMock().SetupGet(c => c.Version).Returns(LatestTestVersion); + + var updatePackage = Subject.GetAvailableUpdate(); updatePackage.Should().BeNull(); } @@ -43,7 +48,9 @@ public void should_return_null_if_latest_is_equal_to_current_version() [TestCase("0.0.10.10")] public void should_return_update_if_latest_is_higher_than_current_version(string currentVersion) { - var updatePackage = Subject.GetAvailableUpdate(new Version(currentVersion)); + Mocker.GetMock().SetupGet(c => c.Version).Returns(new Version(currentVersion)); + + var updatePackage = Subject.GetAvailableUpdate(); updatePackage.Should().NotBeNull(); updatePackage.Version.Should().Be(LatestTestVersion); diff --git a/NzbDrone.Core.Test/UpdateTests/GetUpdateLogFixture.cs b/NzbDrone.Core.Test/UpdateTests/GetUpdateLogFixture.cs index 4752e7e6f..0f45b7a27 100644 --- a/NzbDrone.Core.Test/UpdateTests/GetUpdateLogFixture.cs +++ b/NzbDrone.Core.Test/UpdateTests/GetUpdateLogFixture.cs @@ -7,21 +7,21 @@ namespace NzbDrone.Core.Test.UpdateTests { - class GetUpdateLogFixture : CoreTest + class GetUpdateLogFixture : CoreTest { - String UpdateLogFolder; + String _updateLogFolder; [SetUp] - public void setup() + public void Setup() { WithTempAsAppPath(); - UpdateLogFolder = Mocker.GetMock().Object.GetUpdateLogFolder(); + _updateLogFolder = Mocker.GetMock().Object.GetUpdateLogFolder(); Mocker.GetMock() - .Setup(c => c.GetFiles(UpdateLogFolder, SearchOption.TopDirectoryOnly)) - .Returns(new [] + .Setup(c => c.GetFiles(_updateLogFolder, SearchOption.TopDirectoryOnly)) + .Returns(new[] { "C:\\nzbdrone\\update\\2011.09.20-19-08.txt", "C:\\nzbdrone\\update\\2011.10.20-20-08.txt", @@ -29,7 +29,7 @@ public void setup() }); Mocker.GetMock() - .Setup(c => c.FolderExists(UpdateLogFolder)) + .Setup(c => c.FolderExists(_updateLogFolder)) .Returns(true); } @@ -38,18 +38,17 @@ public void setup() public void get_logs_should_return_empty_list_if_directory_doesnt_exist() { Mocker.GetMock() - .Setup(c => c.FolderExists(UpdateLogFolder)) + .Setup(c => c.FolderExists(_updateLogFolder)) .Returns(false); - var logs = Mocker.Resolve().UpdateLogFile(); - logs.Should().BeEmpty(); + Subject.GetUpdateLogFiles().Should().BeEmpty(); } [Test] public void get_logs_should_return_list_of_files_in_log_folder() { - var logs = Mocker.Resolve().UpdateLogFile(); + var logs = Subject.GetUpdateLogFiles(); logs.Should().HaveCount(3); } diff --git a/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs b/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs new file mode 100644 index 000000000..a1d283fed --- /dev/null +++ b/NzbDrone.Core.Test/UpdateTests/UpdatePackageProviderFixture.cs @@ -0,0 +1,15 @@ +using System; +using FluentAssertions; +using NUnit.Framework; +using NzbDrone.Common; +using NzbDrone.Core.Configuration; +using NzbDrone.Core.Test.Framework; +using NzbDrone.Core.Update; + +namespace NzbDrone.Core.Test.UpdateTests +{ + public class UpdatePackageProviderFixture : CoreTest + { + + } +} diff --git a/NzbDrone.Core/DecisionEngine/DownloadDecision.cs b/NzbDrone.Core/DecisionEngine/DownloadDecision.cs index 9ec5b9bb0..2a7b455fa 100644 --- a/NzbDrone.Core/DecisionEngine/DownloadDecision.cs +++ b/NzbDrone.Core/DecisionEngine/DownloadDecision.cs @@ -1,12 +1,14 @@ using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine { public class DownloadDecision { - public IndexerParseResult ParseResult { get; private set; } + public RemoteEpisode Episode { get; private set; } public IEnumerable Rejections { get; private set; } public bool Approved @@ -17,23 +19,10 @@ public bool Approved } } - public DownloadDecision(IndexerParseResult parseResult, params string[] rejections) + public DownloadDecision(RemoteEpisode episode, params string[] rejections) { - ParseResult = parseResult; + Episode = episode; Rejections = rejections.ToList(); } - - - public static IndexerParseResult PickBestReport(IEnumerable downloadDecisions) - { - var reports = downloadDecisions - .Where(c => c.Approved) - .Select(c => c.ParseResult) - .OrderByDescending(c => c.Quality) - .ThenBy(c => c.EpisodeNumbers.MinOrDefault()) - .ThenBy(c => c.Age); - - return reports.SingleOrDefault(); - } } } \ No newline at end of file diff --git a/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs b/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs index 9f1fac6b8..9c7c6d13b 100644 --- a/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs +++ b/NzbDrone.Core/DecisionEngine/DownloadDecisionMaker.cs @@ -2,62 +2,64 @@ using System.Linq; using NzbDrone.Core.DecisionEngine.Specifications.Search; using NzbDrone.Core.IndexerSearch.Definitions; -using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine { public interface IMakeDownloadDecision { - IEnumerable GetRssDecision(IEnumerable episodeParseResults); - IEnumerable GetSearchDecision(IEnumerable episodeParseResult, SearchDefinitionBase searchDefinitionBase); + IEnumerable GetRssDecision(IEnumerable reports); + IEnumerable GetSearchDecision(IEnumerable reports, SearchDefinitionBase searchDefinitionBase); } public class DownloadDecisionMaker : IMakeDownloadDecision { private readonly IEnumerable _specifications; + private readonly IParsingService _parsingService; - public DownloadDecisionMaker(IEnumerable specifications) + public DownloadDecisionMaker(IEnumerable specifications, IParsingService parsingService) { _specifications = specifications; + _parsingService = parsingService; } - public IEnumerable GetRssDecision(IEnumerable episodeParseResults) + public IEnumerable GetRssDecision(IEnumerable reports) { - foreach (var parseResult in episodeParseResults) + foreach (var report in reports) { - parseResult.Decision = new DownloadDecision(parseResult, GetGeneralRejectionReasons(parseResult).ToArray()); - yield return parseResult.Decision; + var parseResult = _parsingService.Map(report); + yield return new DownloadDecision(parseResult, GetGeneralRejectionReasons(parseResult).ToArray()); } } - public IEnumerable GetSearchDecision(IEnumerable episodeParseResults, SearchDefinitionBase searchDefinitionBase) + public IEnumerable GetSearchDecision(IEnumerable reports, SearchDefinitionBase searchDefinitionBase) { - foreach (var parseResult in episodeParseResults) + foreach (var report in reports) { + var parseResult = _parsingService.Map(report); var generalReasons = GetGeneralRejectionReasons(parseResult); var searchReasons = GetSearchRejectionReasons(parseResult, searchDefinitionBase); - parseResult.Decision = new DownloadDecision(parseResult, generalReasons.Union(searchReasons).ToArray()); - - yield return parseResult.Decision; + yield return new DownloadDecision(parseResult, generalReasons.Union(searchReasons).ToArray()); } } - private IEnumerable GetGeneralRejectionReasons(IndexerParseResult indexerParseResult) + private IEnumerable GetGeneralRejectionReasons(RemoteEpisode report) { return _specifications .OfType() - .Where(spec => !spec.IsSatisfiedBy(indexerParseResult)) + .Where(spec => !spec.IsSatisfiedBy(report)) .Select(spec => spec.RejectionReason); } - private IEnumerable GetSearchRejectionReasons(IndexerParseResult indexerParseResult, SearchDefinitionBase searchDefinitionBase) + private IEnumerable GetSearchRejectionReasons(RemoteEpisode report, SearchDefinitionBase searchDefinitionBase) { return _specifications .OfType() - .Where(spec => !spec.IsSatisfiedBy(indexerParseResult, searchDefinitionBase)) + .Where(spec => !spec.IsSatisfiedBy(report, searchDefinitionBase)) .Select(spec => spec.RejectionReason); } } diff --git a/NzbDrone.Core/DecisionEngine/IDecisionEngineSpecification.cs b/NzbDrone.Core/DecisionEngine/IDecisionEngineSpecification.cs index 33260f1f2..85cc0be05 100644 --- a/NzbDrone.Core/DecisionEngine/IDecisionEngineSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/IDecisionEngineSpecification.cs @@ -1,9 +1,11 @@ using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine { public interface IDecisionEngineSpecification : IRejectWithReason { - bool IsSatisfiedBy(IndexerParseResult subject); + bool IsSatisfiedBy(RemoteEpisode subject); } } \ No newline at end of file diff --git a/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs index 4b42a1c70..d74613470 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/AcceptableSizeSpecification.cs @@ -1,5 +1,8 @@ +using System.Linq; using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; @@ -23,7 +26,7 @@ public string RejectionReason get { return "File size too big or small"; } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { _logger.Trace("Beginning size check for: {0}", subject); @@ -47,24 +50,19 @@ public virtual bool IsSatisfiedBy(IndexerParseResult subject) //Multiply maxSize by Series.Runtime maxSize = maxSize * series.Runtime; - //Multiply maxSize by the number of episodes parsed (if EpisodeNumbers is null it will be treated as a single episode) - //TODO: is this check really necessary? shouldn't we blowup? - if (subject.EpisodeNumbers != null) - maxSize = maxSize * subject.EpisodeNumbers.Count; + maxSize = maxSize * subject.Episodes.Count; //Check if there was only one episode parsed //and it is the first or last episode of the season - if (subject.EpisodeNumbers != null && subject.EpisodeNumbers.Count == 1 && - _episodeService.IsFirstOrLastEpisodeOfSeason(series.Id, - subject.SeasonNumber, subject.EpisodeNumbers[0])) + if (subject.Episodes.Count == 1 && _episodeService.IsFirstOrLastEpisodeOfSeason(subject.Episodes.Single().Id)) { maxSize = maxSize * 2; } //If the parsed size is greater than maxSize we don't want it - if (subject.Size > maxSize) + if (subject.Report.Size > maxSize) { - _logger.Trace("Item: {0}, Size: {1} is greater than maximum allowed size ({2}), rejecting.", subject, subject.Size, maxSize); + _logger.Trace("Item: {0}, Size: {1} is greater than maximum allowed size ({2}), rejecting.", subject, subject.Report.Size, maxSize); return false; } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/AllowedReleaseGroupSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/AllowedReleaseGroupSpecification.cs index 8a3ce67b0..6ce96c527 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/AllowedReleaseGroupSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/AllowedReleaseGroupSpecification.cs @@ -2,6 +2,8 @@ using NLog; using NzbDrone.Core.Configuration; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -25,7 +27,7 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { _logger.Trace("Beginning release group check for: {0}", subject); @@ -37,16 +39,18 @@ public virtual bool IsSatisfiedBy(IndexerParseResult subject) if (string.IsNullOrWhiteSpace(allowed)) return true; + var releaseGroup = subject.Report.ReleaseGroup; + foreach (var group in allowed.Trim(',', ' ').Split(',')) { - if (subject.ReleaseGroup.Equals(group.Trim(' '), StringComparison.CurrentCultureIgnoreCase)) + if (releaseGroup.Equals(group.Trim(' '), StringComparison.CurrentCultureIgnoreCase)) { - _logger.Trace("Item: {0}'s release group is wanted: {1}", subject, subject.ReleaseGroup); + _logger.Trace("Item: {0}'s release group is wanted: {1}", subject, releaseGroup); return true; } } - _logger.Trace("Item: {0}'s release group is not wanted: {1}", subject, subject.ReleaseGroup); + _logger.Trace("Item: {0}'s release group is not wanted: {1}", subject, releaseGroup); return false; } } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/CustomStartDateSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/CustomStartDateSpecification.cs index 5a9b43fda..0603c4bf8 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/CustomStartDateSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/CustomStartDateSpecification.cs @@ -1,6 +1,8 @@ using System.Linq; using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -22,7 +24,7 @@ public string RejectionReason } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { if (!subject.Series.CustomStartDate.HasValue) { diff --git a/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs index 74eac7ea8..7aaeeb1e3 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/LanguageSpecification.cs @@ -1,5 +1,7 @@ using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -20,10 +22,10 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { _logger.Trace("Checking if report meets language requirements. {0}", subject.Language); - if (subject.Language != LanguageType.English) + if (subject.Language != Language.English) { _logger.Trace("Report Language: {0} rejected because it is not English", subject.Language); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/MonitoredEpisodeSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/MonitoredEpisodeSpecification.cs index e6997af83..37fa01993 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/MonitoredEpisodeSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/MonitoredEpisodeSpecification.cs @@ -1,6 +1,8 @@ using System.Linq; using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; namespace NzbDrone.Core.DecisionEngine.Specifications @@ -26,29 +28,16 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { - var series = _seriesRepository.GetByTitle(subject.CleanTitle); - - if (series == null) + if (!subject.Series.Monitored) { - _logger.Trace("{0} is not mapped to any series in DB. skipping", subject.CleanTitle); + _logger.Debug("{0} is present in the DB but not tracked. skipping.", subject.Series.Title); return false; } - subject.Series = series; - - if (!series.Monitored) - { - _logger.Debug("{0} is present in the DB but not tracked. skipping.", subject.CleanTitle); - return false; - } - - var episodes = _episodeService.GetEpisodesByParseResult(subject); - subject.Episodes = episodes; - //return monitored if any of the episodes are monitored - if (episodes.Any(episode => !episode.Ignored)) + if (subject.Episodes.Any(episode => !episode.Ignored)) { return true; } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs index c43cdcd3e..98f348439 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/NotInQueueSpecification.cs @@ -1,6 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; using NLog; using NzbDrone.Core.Download; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Tv; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -21,9 +27,34 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { - return !_downloadClientProvider.GetDownloadClient().IsInQueue(subject); + var downloadClient = _downloadClientProvider.GetDownloadClient(); + + var queue = downloadClient.GetQueue().Select(q => Parser.Parser.ParseTitle(q.Title)); + + return !IsInQueue(subject, queue); + } + + public virtual bool IsInQueue(RemoteEpisode newEpisode, IEnumerable queue) + { + var matchingTitle = queue.Where(q => String.Equals(q.SeriesTitle, newEpisode.Series.CleanTitle, StringComparison.InvariantCultureIgnoreCase)); + + var matchingTitleWithQuality = matchingTitle.Where(q => q.Quality >= newEpisode.Quality); + + if (newEpisode.Series.SeriesType == SeriesTypes.Daily) + { + return matchingTitleWithQuality.Any(q => q.AirDate.Value.Date == newEpisode.AirDate.Value.Date); + } + + var matchingSeason = matchingTitleWithQuality.Where(q => q.SeasonNumber == newEpisode.SeasonNumber); + + if (newEpisode.FullSeason) + { + return matchingSeason.Any(); + } + + return matchingSeason.Any(q => q.EpisodeNumbers != null && q.EpisodeNumbers.Any(e => newEpisode.EpisodeNumbers.Contains(e))); } } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs index 6aaba8a57..c20130016 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/QualityAllowedByProfileSpecification.cs @@ -1,5 +1,7 @@ using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -20,7 +22,7 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { _logger.Trace("Checking if report meets quality requirements. {0}", subject.Quality); if (!subject.Series.QualityProfile.Allowed.Contains(subject.Quality.Quality)) diff --git a/NzbDrone.Core/DecisionEngine/Specifications/RetentionSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/RetentionSpecification.cs index 968e24ce5..487e4aa2e 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/RetentionSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/RetentionSpecification.cs @@ -1,6 +1,8 @@ using NLog; using NzbDrone.Core.Configuration; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -24,12 +26,14 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { - _logger.Trace("Checking if report meets retention requirements. {0}", subject.Age); - if (_configService.Retention > 0 && subject.Age > _configService.Retention) + var age = subject.Report.Age; + + _logger.Trace("Checking if report meets retention requirements. {0}", age); + if (_configService.Retention > 0 && age > _configService.Retention) { - _logger.Trace("Report age: {0} rejected by user's retention limit", subject.Age); + _logger.Trace("Report age: {0} rejected by user's retention limit", age); return false; } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs index 95a45bcff..2ff1f60d5 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/DailyEpisodeMatchSpecification.cs @@ -1,6 +1,8 @@ using NLog; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; namespace NzbDrone.Core.DecisionEngine.Specifications.Search @@ -23,7 +25,7 @@ public string RejectionReason return "Episode doesn't match"; } } - public bool IsSatisfiedBy(IndexerParseResult indexerParseResult, SearchDefinitionBase searchDefinitionBase) + public bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase searchDefinitionBase) { var dailySearchSpec = searchDefinitionBase as DailyEpisodeSearchDefinition; @@ -31,7 +33,7 @@ public bool IsSatisfiedBy(IndexerParseResult indexerParseResult, SearchDefinitio var episode = _episodeService.GetEpisode(dailySearchSpec.SeriesId, dailySearchSpec.Airtime); - if (!indexerParseResult.AirDate.HasValue || indexerParseResult.AirDate.Value != episode.AirDate.Value) + if (!remoteEpisode.AirDate.HasValue || remoteEpisode.AirDate.Value != episode.AirDate.Value) { _logger.Trace("Episode AirDate does not match searched episode number, skipping."); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/IDecisionEngineSearchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/IDecisionEngineSearchSpecification.cs index f670d3f5a..11a3f317c 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/IDecisionEngineSearchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/IDecisionEngineSearchSpecification.cs @@ -1,11 +1,13 @@ using NzbDrone.Core.IndexerSearch; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications.Search { public interface IDecisionEngineSearchSpecification : IRejectWithReason { - bool IsSatisfiedBy(IndexerParseResult indexerParseResult, SearchDefinitionBase searchDefinitionBase); + bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase searchDefinitionBase); } } \ No newline at end of file diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs index 58f265e25..fd9eba9cd 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/SeasonMatchSpecification.cs @@ -1,6 +1,8 @@ using NLog; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications.Search { @@ -21,17 +23,17 @@ public string RejectionReason } } - public bool IsSatisfiedBy(IndexerParseResult indexerParseResult, SearchDefinitionBase searchDefinitionBase) + public bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase searchDefinitionBase) { var singleEpisodeSpec = searchDefinitionBase as SeasonSearchDefinition; if (singleEpisodeSpec == null) return true; - if (singleEpisodeSpec.SeasonNumber != indexerParseResult.SeasonNumber) + if (singleEpisodeSpec.SeasonNumber != remoteEpisode.SeasonNumber) { _logger.Trace("Season number does not match searched season number, skipping."); return false; } - + return true; } } diff --git a/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeMatchSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs similarity index 62% rename from NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeMatchSpecification.cs rename to NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs index 1aa7be413..a4033c61e 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeMatchSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/Search/SingleEpisodeSearchMatchSpecification.cs @@ -1,14 +1,17 @@ +using System.Linq; using NLog; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications.Search { - public class SingleEpisodeMatchSpecification : IDecisionEngineSearchSpecification + public class SingleEpisodeSearchMatchSpecification : IDecisionEngineSearchSpecification { private readonly Logger _logger; - public SingleEpisodeMatchSpecification(Logger logger) + public SingleEpisodeSearchMatchSpecification(Logger logger) { _logger = logger; } @@ -21,18 +24,18 @@ public string RejectionReason } } - public bool IsSatisfiedBy(IndexerParseResult indexerParseResult, SearchDefinitionBase searchDefinitionBase) + public bool IsSatisfiedBy(RemoteEpisode remoteEpisode, SearchDefinitionBase searchDefinitionBase) { var singleEpisodeSpec = searchDefinitionBase as SingleEpisodeSearchDefinition; if (singleEpisodeSpec == null) return true; - if (singleEpisodeSpec.SeasonNumber != indexerParseResult.SeasonNumber) + if (singleEpisodeSpec.SeasonNumber != remoteEpisode.SeasonNumber) { _logger.Trace("Season number does not match searched season number, skipping."); return false; } - if (!indexerParseResult.EpisodeNumbers.Contains(singleEpisodeSpec.EpisodeNumber)) + if (!remoteEpisode.Episodes.Select(c => c.EpisodeNumber).Contains(singleEpisodeSpec.EpisodeNumber)) { _logger.Trace("Episode number does not match searched episode number, skipping."); return false; diff --git a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs index 209c8d7ee..f3e7e1010 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeDiskSpecification.cs @@ -1,8 +1,7 @@ using System; using System.Linq; using NLog; -using NzbDrone.Core.Model; -using NzbDrone.Core.Tv; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -25,13 +24,16 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { foreach (var file in subject.Episodes.Select(c => c.EpisodeFile).Where(c => c != null)) { _logger.Trace("Comparing file quality with report. Existing file is {0}", file.Quality); + if (!_qualityUpgradableSpecification.IsUpgradable(subject.Series.QualityProfile, file.Quality, subject.Quality)) + { return false; + } if (subject.Quality.Proper && file.DateAdded < DateTime.Today.AddDays(-7)) { diff --git a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs index c6e962030..ec5200c62 100644 --- a/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs +++ b/NzbDrone.Core/DecisionEngine/Specifications/UpgradeHistorySpecification.cs @@ -1,6 +1,6 @@ using NLog; using NzbDrone.Core.History; -using NzbDrone.Core.Model; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.DecisionEngine.Specifications { @@ -25,7 +25,7 @@ public string RejectionReason } } - public virtual bool IsSatisfiedBy(IndexerParseResult subject) + public virtual bool IsSatisfiedBy(RemoteEpisode subject) { foreach (var episode in subject.Episodes) { diff --git a/NzbDrone.Core/Download/Clients/BlackholeProvider.cs b/NzbDrone.Core/Download/Clients/BlackholeProvider.cs index a00f01410..0b7af0851 100644 --- a/NzbDrone.Core/Download/Clients/BlackholeProvider.cs +++ b/NzbDrone.Core/Download/Clients/BlackholeProvider.cs @@ -1,11 +1,13 @@ using System; +using System.Collections.Generic; using System.IO; using NLog; using NzbDrone.Common; using NzbDrone.Core.Configuration; -using NzbDrone.Core.DecisionEngine.Specifications; using NzbDrone.Core.Model; using NzbDrone.Core.Organizer; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Download.Clients { @@ -14,24 +16,25 @@ public class BlackholeProvider : IDownloadClient private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; private readonly DiskProvider _diskProvider; - private readonly UpgradeHistorySpecification _upgradeHistorySpecification; + private readonly Logger _logger; - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); public BlackholeProvider(IConfigService configService, IHttpProvider httpProvider, - DiskProvider diskProvider, UpgradeHistorySpecification upgradeHistorySpecification) + DiskProvider diskProvider, Logger logger) { _configService = configService; _httpProvider = httpProvider; _diskProvider = diskProvider; - _upgradeHistorySpecification = upgradeHistorySpecification; + _logger = logger; } - public BlackholeProvider() + + public bool IsInQueue(RemoteEpisode newEpisode) { + throw new NotImplementedException(); } - public virtual bool DownloadNzb(string url, string title, bool recentlyAired) + public bool DownloadNzb(string url, string title, bool recentlyAired) { try { @@ -42,26 +45,26 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) if (_diskProvider.FileExists(filename)) { //Return true so a lesser quality is not returned. - logger.Info("NZB already exists on disk: {0}", filename); + _logger.Info("NZB already exists on disk: {0}", filename); return true; } - logger.Trace("Downloading NZB from: {0} to: {1}", url, filename); + _logger.Trace("Downloading NZB from: {0} to: {1}", url, filename); _httpProvider.DownloadFile(url, filename); - logger.Trace("NZB Download succeeded, saved to: {0}", filename); + _logger.Trace("NZB Download succeeded, saved to: {0}", filename); return true; } catch (Exception ex) { - logger.WarnException("Failed to download NZB: " + url, ex); + _logger.WarnException("Failed to download NZB: " + url, ex); return false; } } - public virtual bool IsInQueue(IndexerParseResult newParseResult) + public IEnumerable GetQueue() { - return !_upgradeHistorySpecification.IsSatisfiedBy(newParseResult); + return new QueueItem[0]; } } } diff --git a/NzbDrone.Core/Download/Clients/Nzbget/Queue.cs b/NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueue.cs similarity index 66% rename from NzbDrone.Core/Download/Clients/Nzbget/Queue.cs rename to NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueue.cs index e9f647442..86cd09843 100644 --- a/NzbDrone.Core/Download/Clients/Nzbget/Queue.cs +++ b/NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueue.cs @@ -1,16 +1,14 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using Newtonsoft.Json; namespace NzbDrone.Core.Download.Clients.Nzbget { - public class Queue + public class NzbGetQueue { public String Version { get; set; } [JsonProperty(PropertyName = "result")] - public List QueueItems { get; set; } + public List QueueItems { get; set; } } } diff --git a/NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueueItem.cs b/NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueueItem.cs new file mode 100644 index 000000000..9f60faa57 --- /dev/null +++ b/NzbDrone.Core/Download/Clients/Nzbget/NzbGetQueueItem.cs @@ -0,0 +1,18 @@ +using System; +using NzbDrone.Core.Model; + +namespace NzbDrone.Core.Download.Clients.Nzbget +{ + public class NzbGetQueueItem + { + private string _nzbName; + + public Int32 NzbId { get; set; } + + public string NzbName { get; set; } + + public String Category { get; set; } + public Int32 FileSizeMb { get; set; } + public Int32 RemainingSizeMb { get; set; } + } +} diff --git a/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProvider.cs b/NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs similarity index 66% rename from NzbDrone.Core/Download/Clients/Nzbget/NzbgetProvider.cs rename to NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs index 72129eaf1..27e55d7e9 100644 --- a/NzbDrone.Core/Download/Clients/Nzbget/NzbgetProvider.cs +++ b/NzbDrone.Core/Download/Clients/Nzbget/NzbgetClient.cs @@ -1,66 +1,26 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using Newtonsoft.Json; using NLog; using NzbDrone.Common; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Model; -using NzbDrone.Core.Tv; namespace NzbDrone.Core.Download.Clients.Nzbget { - public class NzbgetProvider : IDownloadClient + public class NzbgetClient : IDownloadClient { private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; private readonly Logger _logger; - public NzbgetProvider(IConfigService configService, IHttpProvider httpProvider, Logger logger) + public NzbgetClient(IConfigService configService, IHttpProvider httpProvider, Logger logger) { _configService = configService; _httpProvider = httpProvider; _logger = logger; } - public NzbgetProvider() - { - } - - public virtual bool IsInQueue(IndexerParseResult newParseResult) - { - try - { - var queue = GetQueue().Where(c => c.ParseResult != null); - - var matchigTitle = queue.Where(q => String.Equals(q.ParseResult.CleanTitle, newParseResult.Series.CleanTitle, StringComparison.InvariantCultureIgnoreCase)); - - var matchingTitleWithQuality = matchigTitle.Where(q => q.ParseResult.Quality >= newParseResult.Quality); - - - if (newParseResult.Series.SeriesType == SeriesTypes.Daily) - { - return matchingTitleWithQuality.Any(q => q.ParseResult.AirDate.Value.Date == newParseResult.AirDate.Value.Date); - } - - var matchingSeason = matchingTitleWithQuality.Where(q => q.ParseResult.SeasonNumber == newParseResult.SeasonNumber); - - if (newParseResult.FullSeason) - { - return matchingSeason.Any(); - } - - return matchingSeason.Any(q => q.ParseResult.EpisodeNumbers != null && q.ParseResult.EpisodeNumbers.Any(e => newParseResult.EpisodeNumbers.Contains(e))); - } - - catch (Exception ex) - { - _logger.WarnException("Unable to connect to Nzbget to check queue.", ex); - return false; - } - } - public virtual bool DownloadNzb(string url, string title, bool recentlyAired) { try @@ -71,7 +31,7 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) var command = new JsonRequest { Method = "appendurl", - Params = new object[]{ title, cat, priority, false, url } + Params = new object[] { title, cat, priority, false, url } }; _logger.Info("Adding report [{0}] to the queue.", title); @@ -93,19 +53,30 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) return false; } - public virtual List GetQueue() + public virtual IEnumerable GetQueue() { var command = new JsonRequest { - Method = "listgroups", - Params = null + Method = "listgroups", + Params = null }; var response = PostCommand(JsonConvert.SerializeObject(command)); CheckForError(response); - return JsonConvert.DeserializeObject(response).QueueItems; + var itmes = JsonConvert.DeserializeObject(response).QueueItems; + + foreach (var nzbGetQueueItem in itmes) + { + var queueItem = new QueueItem(); + queueItem.Id = nzbGetQueueItem.NzbId.ToString(); + queueItem.Title = nzbGetQueueItem.NzbName; + queueItem.Size = nzbGetQueueItem.FileSizeMb; + queueItem.SizeLeft = nzbGetQueueItem.RemainingSizeMb; + + yield return queueItem; + } } public virtual VersionModel GetVersion(string host = null, int port = 0, string username = null, string password = null) @@ -144,11 +115,11 @@ public virtual string Test(string host, int port, string username, string passwo var version = GetVersion(host, port, username, password); return version.Result; } - catch(Exception ex) + catch (Exception ex) { _logger.DebugException("Failed to Test Nzbget", ex); } - + return String.Empty; } diff --git a/NzbDrone.Core/Download/Clients/Nzbget/QueueItem.cs b/NzbDrone.Core/Download/Clients/Nzbget/QueueItem.cs deleted file mode 100644 index 173be61a7..000000000 --- a/NzbDrone.Core/Download/Clients/Nzbget/QueueItem.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Linq; -using Newtonsoft.Json; -using NzbDrone.Core.Model; - -namespace NzbDrone.Core.Download.Clients.Nzbget -{ - public class QueueItem - { - private string _title; - - public Int32 NzbId { get; set; } - - [JsonProperty(PropertyName = "NzbName")] - public string Title - { - get { return _title; } - set - { - _title = value; - ParseResult = Parser.ParseTitle(value.Replace("DUPLICATE / ", String.Empty)); - } - } - - public String Category { get; set; } - public Int32 FileSizeMb { get; set; } - public Int32 RemainingSizeMb { get; set; } - - public ParseResult ParseResult { private set; get; } - } -} diff --git a/NzbDrone.Core/Download/Clients/PneumaticProvider.cs b/NzbDrone.Core/Download/Clients/PneumaticClient.cs similarity index 83% rename from NzbDrone.Core/Download/Clients/PneumaticProvider.cs rename to NzbDrone.Core/Download/Clients/PneumaticClient.cs index b621e0c66..05096855a 100644 --- a/NzbDrone.Core/Download/Clients/PneumaticProvider.cs +++ b/NzbDrone.Core/Download/Clients/PneumaticClient.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using NLog; @@ -9,10 +10,12 @@ using NzbDrone.Core.Model; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Organizer; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Download.Clients { - public class PneumaticProvider : IDownloadClient + public class PneumaticClient : IDownloadClient { private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; @@ -20,7 +23,7 @@ public class PneumaticProvider : IDownloadClient private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - public PneumaticProvider(IConfigService configService, IHttpProvider httpProvider, + public PneumaticClient(IConfigService configService, IHttpProvider httpProvider, DiskProvider diskProvider) { _configService = configService; @@ -33,7 +36,7 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) try { //Todo: Allow full season releases - if (Parser.ParseTitle(title).FullSeason) + if (Parser.Parser.ParseTitle(title).FullSeason) { logger.Info("Skipping Full Season Release: {0}", title); return false; @@ -68,7 +71,12 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) } } - public virtual bool IsInQueue(IndexerParseResult newParseResult) + public IEnumerable GetQueue() + { + return new QueueItem[0]; + } + + public virtual bool IsInQueue(RemoteEpisode newEpisode) { return false; } diff --git a/NzbDrone.Core/Download/Clients/ConnectionInfoModel.cs b/NzbDrone.Core/Download/Clients/Sabnzbd/ConnectionInfoModel.cs similarity index 73% rename from NzbDrone.Core/Download/Clients/ConnectionInfoModel.cs rename to NzbDrone.Core/Download/Clients/Sabnzbd/ConnectionInfoModel.cs index 5ee05103e..cb03c1953 100644 --- a/NzbDrone.Core/Download/Clients/ConnectionInfoModel.cs +++ b/NzbDrone.Core/Download/Clients/Sabnzbd/ConnectionInfoModel.cs @@ -1,4 +1,4 @@ -namespace NzbDrone.Core.Download.Clients +namespace NzbDrone.Core.Download.Clients.Sabnzbd { public class ConnectionInfoModel { diff --git a/NzbDrone.Core/Download/Clients/Sabnzbd/SabQueueItem.cs b/NzbDrone.Core/Download/Clients/Sabnzbd/SabQueueItem.cs index 17ff4c915..f063c4b7b 100644 --- a/NzbDrone.Core/Download/Clients/Sabnzbd/SabQueueItem.cs +++ b/NzbDrone.Core/Download/Clients/Sabnzbd/SabQueueItem.cs @@ -19,15 +19,7 @@ public class SabQueueItem private string _title; [JsonProperty(PropertyName = "filename")] - public string Title - { - get { return _title; } - set - { - _title = value; - ParseResult = Parser.ParseTitle(value.Replace("DUPLICATE / ", String.Empty)); - } - } + public string Title { get; set; } [JsonConverter(typeof(SabnzbdPriorityTypeConverter))] public SabPriorityType Priority { get; set; } @@ -42,7 +34,5 @@ public string Title [JsonProperty(PropertyName = "nzo_id")] public string Id { get; set; } - - public ParseResult ParseResult { private set; get; } } } diff --git a/NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs b/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs similarity index 76% rename from NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs rename to NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs index a55820c7b..7d589de37 100644 --- a/NzbDrone.Core/Download/Clients/Sabnzbd/SabProvider.cs +++ b/NzbDrone.Core/Download/Clients/Sabnzbd/SabnzbdClient.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Net; using System.Web; using Newtonsoft.Json; @@ -8,61 +7,21 @@ using NLog; using NzbDrone.Common; using NzbDrone.Core.Configuration; -using NzbDrone.Core.Model; -using NzbDrone.Core.Tv; -using RestSharp.Contrib; -using HttpUtility = System.Web.HttpUtility; namespace NzbDrone.Core.Download.Clients.Sabnzbd { - public class SabProvider : IDownloadClient + public class SabnzbdClient : IDownloadClient { private static readonly Logger logger = LogManager.GetCurrentClassLogger(); private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; - public SabProvider(IConfigService configService, IHttpProvider httpProvider) + public SabnzbdClient(IConfigService configService, IHttpProvider httpProvider) { _configService = configService; _httpProvider = httpProvider; } - public SabProvider() - { - } - - public virtual bool IsInQueue(IndexerParseResult newParseResult) - { - try - { - var queue = GetQueue().Where(c => c.ParseResult != null); - - var matchigTitle = queue.Where(q => String.Equals(q.ParseResult.CleanTitle, newParseResult.Series.CleanTitle, StringComparison.InvariantCultureIgnoreCase)); - - var matchingTitleWithQuality = matchigTitle.Where(q => q.ParseResult.Quality >= newParseResult.Quality); - - if (newParseResult.Series.SeriesType == SeriesTypes.Daily) - { - return matchingTitleWithQuality.Any(q => q.ParseResult.AirDate.Value.Date == newParseResult.AirDate.Value.Date); - } - - var matchingSeason = matchingTitleWithQuality.Where(q => q.ParseResult.SeasonNumber == newParseResult.SeasonNumber); - - if (newParseResult.FullSeason) - { - return matchingSeason.Any(); - } - - return matchingSeason.Any(q => q.ParseResult.EpisodeNumbers != null && q.ParseResult.EpisodeNumbers.Any(e => newParseResult.EpisodeNumbers.Contains(e))); - } - - catch (Exception ex) - { - logger.WarnException("Unable to connect to SABnzbd to check queue.", ex); - return false; - } - } - public virtual bool DownloadNzb(string url, string title, bool recentlyAired) { try @@ -80,7 +39,7 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) logger.Info("Adding report [{0}] to the queue.", title); var response = _httpProvider.DownloadString(request); - + logger.Debug("Queue Response: [{0}]", response); CheckForError(response); @@ -95,15 +54,26 @@ public virtual bool DownloadNzb(string url, string title, bool recentlyAired) return false; } - public virtual List GetQueue(int start = 0, int limit = 0) + public IEnumerable GetQueue() { - string action = String.Format("mode=queue&output=json&start={0}&limit={1}", start, limit); + string action = String.Format("mode=queue&output=json&start={0}&limit={1}", 0, 0); string request = GetSabRequest(action); string response = _httpProvider.DownloadString(request); CheckForError(response); - return JsonConvert.DeserializeObject(JObject.Parse(response).SelectToken("queue").ToString()).Items; + var sabQeueu = JsonConvert.DeserializeObject(JObject.Parse(response).SelectToken("queue").ToString()).Items; + + foreach (var sabQueueItem in sabQeueu) + { + var queueItem = new QueueItem(); + queueItem.Id = sabQueueItem.Id; + queueItem.Title = sabQueueItem.Title; + queueItem.Size = sabQueueItem.Size; + queueItem.SizeLeft = sabQueueItem.Size; + + yield return queueItem; + } } public virtual List GetHistory(int start = 0, int limit = 0) @@ -191,11 +161,11 @@ public virtual string Test(string host, int port, string apiKey, string username var version = GetVersion(host, port, apiKey, username, password); return version.Version; } - catch(Exception ex) + catch (Exception ex) { logger.DebugException("Failed to Test SABnzbd", ex); } - + return String.Empty; } diff --git a/NzbDrone.Core/Download/DownloadClientProvider.cs b/NzbDrone.Core/Download/DownloadClientProvider.cs index 6073edf55..9fc1c3479 100644 --- a/NzbDrone.Core/Download/DownloadClientProvider.cs +++ b/NzbDrone.Core/Download/DownloadClientProvider.cs @@ -14,23 +14,23 @@ public interface IProvideDownloadClient public class DownloadClientProvider : IProvideDownloadClient { - private readonly SabProvider _sabProvider; + private readonly SabnzbdClient _sabnzbdClient; private readonly IConfigService _configService; private readonly BlackholeProvider _blackholeProvider; - private readonly PneumaticProvider _pneumaticProvider; - private readonly NzbgetProvider _nzbgetProvider; + private readonly PneumaticClient _pneumaticClient; + private readonly NzbgetClient _nzbgetClient; - public DownloadClientProvider(SabProvider sabProvider, IConfigService configService, + public DownloadClientProvider(SabnzbdClient sabnzbdClient, IConfigService configService, BlackholeProvider blackholeProvider, - PneumaticProvider pneumaticProvider, - NzbgetProvider nzbgetProvider) + PneumaticClient pneumaticClient, + NzbgetClient nzbgetClient) { - _sabProvider = sabProvider; + _sabnzbdClient = sabnzbdClient; _configService = configService; _blackholeProvider = blackholeProvider; - _pneumaticProvider = pneumaticProvider; - _nzbgetProvider = nzbgetProvider; + _pneumaticClient = pneumaticClient; + _nzbgetClient = nzbgetClient; } public IDownloadClient GetDownloadClient() @@ -41,13 +41,13 @@ public IDownloadClient GetDownloadClient() return _blackholeProvider; case DownloadClientType.Pneumatic: - return _pneumaticProvider; + return _pneumaticClient; case DownloadClientType.Nzbget: - return _nzbgetProvider; + return _nzbgetClient; default: - return _sabProvider; + return _sabnzbdClient; } } } diff --git a/NzbDrone.Core/Download/DownloadService.cs b/NzbDrone.Core/Download/DownloadService.cs index 6ac18c79b..2eb8996b8 100644 --- a/NzbDrone.Core/Download/DownloadService.cs +++ b/NzbDrone.Core/Download/DownloadService.cs @@ -6,13 +6,15 @@ using NzbDrone.Core.Configuration; using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; namespace NzbDrone.Core.Download { public interface IDownloadService { - bool DownloadReport(IndexerParseResult parseResult); + bool DownloadReport(RemoteEpisode episode); } public class DownloadService : IDownloadService @@ -32,31 +34,31 @@ public DownloadService(IProvideDownloadClient downloadClientProvider, IConfigSer _logger = logger; } - public bool DownloadReport(IndexerParseResult parseResult) + public bool DownloadReport(RemoteEpisode episode) { - var downloadTitle = parseResult.OriginalString; + var downloadTitle = episode.Report.Title; if (!_configService.DownloadClientUseSceneName) { - downloadTitle = parseResult.GetDownloadTitle(); + downloadTitle = episode.GetDownloadTitle(); } var provider = _downloadClientProvider.GetDownloadClient(); - var recentEpisode = ContainsRecentEpisode(parseResult); + var recentEpisode = ContainsRecentEpisode(episode); - bool success = provider.DownloadNzb(parseResult.NzbUrl, downloadTitle, recentEpisode); + bool success = provider.DownloadNzb(episode.Report.NzbUrl, downloadTitle, recentEpisode); if (success) { _logger.Info("Report sent to download client. {0}", downloadTitle); - _eventAggregator.Publish(new EpisodeGrabbedEvent(parseResult)); + _eventAggregator.Publish(new EpisodeGrabbedEvent(episode)); } return success; } - private static bool ContainsRecentEpisode(IndexerParseResult parseResult) + private static bool ContainsRecentEpisode(RemoteEpisode episode) { - return parseResult.Episodes.Any(e => e.AirDate >= DateTime.Today.AddDays(-7)); + return episode.Episodes.Any(e => e.AirDate >= DateTime.Today.AddDays(-7)); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs b/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs index a88c642cd..af4bce9c9 100644 --- a/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs +++ b/NzbDrone.Core/Download/EpisodeGrabbedEvent.cs @@ -1,15 +1,17 @@ using NzbDrone.Common.Eventing; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Download { public class EpisodeGrabbedEvent : IEvent { - public IndexerParseResult ParseResult { get; private set; } + public RemoteEpisode Episode { get; private set; } - public EpisodeGrabbedEvent(IndexerParseResult parseResult) + public EpisodeGrabbedEvent(RemoteEpisode episode) { - ParseResult = parseResult; + Episode = episode; } } } \ No newline at end of file diff --git a/NzbDrone.Core/Download/IDownloadClient.cs b/NzbDrone.Core/Download/IDownloadClient.cs index a2077df11..ae6e96f2c 100644 --- a/NzbDrone.Core/Download/IDownloadClient.cs +++ b/NzbDrone.Core/Download/IDownloadClient.cs @@ -1,11 +1,13 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using NzbDrone.Core.Model; namespace NzbDrone.Core.Download { public interface IDownloadClient { - bool IsInQueue(IndexerParseResult newParseResult); bool DownloadNzb(string url, string title, bool recentlyAired); + IEnumerable GetQueue(); } + } diff --git a/NzbDrone.Core/Download/SabQueueItem.cs b/NzbDrone.Core/Download/SabQueueItem.cs new file mode 100644 index 000000000..03398ea4a --- /dev/null +++ b/NzbDrone.Core/Download/SabQueueItem.cs @@ -0,0 +1,23 @@ +using System; +using Newtonsoft.Json; +using NzbDrone.Core.Download.Clients.Sabnzbd; +using NzbDrone.Core.Download.Clients.Sabnzbd.JsonConverters; +using NzbDrone.Core.Model; + +namespace NzbDrone.Core.Download +{ + public class QueueItem + { + public decimal Size { get; set; } + + public string Title { get; set; } + + public decimal SizeLeft { get; set; } + + public int Percentage { get; set; } + + public string Id { get; set; } + + public TimeSpan Timeleft { get; set; } + } +} diff --git a/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs b/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs index 9571560b2..1b4596891 100644 --- a/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs +++ b/NzbDrone.Core/ExternalNotification/ExternalNotificationBase.cs @@ -83,7 +83,7 @@ public void Handle(EpisodeGrabbedEvent message) try { _logger.Trace("Sending grab notification to {0}", Name); - OnGrab(message.ParseResult.GetDownloadTitle()); + OnGrab(message.Episode.GetDownloadTitle()); } catch (Exception e) @@ -100,7 +100,7 @@ public void Handle(EpisodeDownloadedEvent message) try { _logger.Trace("Sending download notification to {0}", Name); - OnDownload(message.ParseResult.ToString(), message.ParseResult.Series); + OnDownload(message.ParseResult.ToString(), message.Series); } catch (Exception e) { diff --git a/NzbDrone.Core/History/HistoryService.cs b/NzbDrone.Core/History/HistoryService.cs index 21b042204..6e534f8af 100644 --- a/NzbDrone.Core/History/HistoryService.cs +++ b/NzbDrone.Core/History/HistoryService.cs @@ -50,17 +50,17 @@ public virtual QualityModel GetBestQualityInHistory(int episodeId) public void Handle(EpisodeGrabbedEvent message) { - foreach (var episode in message.ParseResult.Episodes) + foreach (var episode in message.Episode.Episodes) { var history = new History { Date = DateTime.Now, - Indexer = message.ParseResult.Indexer, - Quality = message.ParseResult.Quality, - NzbTitle = message.ParseResult.OriginalString, + Indexer = message.Episode.Report.Indexer, + Quality = message.Episode.Quality, + NzbTitle = message.Episode.Report.Title, EpisodeId = episode.Id, - NzbInfoUrl = message.ParseResult.NzbInfoUrl, - ReleaseGroup = message.ParseResult.ReleaseGroup, + NzbInfoUrl = message.Episode.Report.NzbInfoUrl, + ReleaseGroup = message.Episode.Report.ReleaseGroup, }; _historyRepository.Insert(history); diff --git a/NzbDrone.Core/IndexerSearch/Definitions/SingleEpisodeSearchDefinition.cs b/NzbDrone.Core/IndexerSearch/Definitions/SingleEpisodeSearchDefinition.cs index aaa392a4f..959a72814 100644 --- a/NzbDrone.Core/IndexerSearch/Definitions/SingleEpisodeSearchDefinition.cs +++ b/NzbDrone.Core/IndexerSearch/Definitions/SingleEpisodeSearchDefinition.cs @@ -2,7 +2,6 @@ namespace NzbDrone.Core.IndexerSearch.Definitions { public class SingleEpisodeSearchDefinition : SearchDefinitionBase { - //TODO make sure these are populated with scene if required public int EpisodeNumber { get; set; } public int SeasonNumber { get; set; } diff --git a/NzbDrone.Core/IndexerSearch/NzbSearchService.cs b/NzbDrone.Core/IndexerSearch/NzbSearchService.cs index 6b8dc228a..841f6a8ab 100644 --- a/NzbDrone.Core/IndexerSearch/NzbSearchService.cs +++ b/NzbDrone.Core/IndexerSearch/NzbSearchService.cs @@ -7,6 +7,8 @@ using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Indexers; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Tv; using System.Linq; @@ -105,10 +107,10 @@ private List PartialSeasonSearch(SeasonSearchDefinition search return spec; } - private List Dispatch(Func> searchAction, SearchDefinitionBase definitionBase) + private List Dispatch(Func> searchAction, SearchDefinitionBase definitionBase) { var indexers = _indexerService.GetAvailableIndexers(); - var parseResults = new List(); + var parseResults = new List(); Parallel.ForEach(indexers, indexer => { diff --git a/NzbDrone.Core/Indexers/BasicRssParser.cs b/NzbDrone.Core/Indexers/BasicRssParser.cs index c7c59524e..7dbfcf756 100644 --- a/NzbDrone.Core/Indexers/BasicRssParser.cs +++ b/NzbDrone.Core/Indexers/BasicRssParser.cs @@ -6,12 +6,14 @@ using System.Text.RegularExpressions; using NLog; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers { public interface IParseFeed { - IEnumerable Process(Stream source); + IEnumerable Process(Stream source); } public class BasicRssParser : IParseFeed @@ -23,12 +25,12 @@ public BasicRssParser() _logger = LogManager.GetCurrentClassLogger(); } - public IEnumerable Process(Stream source) + public IEnumerable Process(Stream source) { var reader = new SyndicationFeedXmlReader(source); var feed = SyndicationFeed.Load(reader).Items; - var result = new List(); + var result = new List(); foreach (var syndicationItem in feed) { @@ -38,7 +40,7 @@ public IEnumerable Process(Stream source) if (parsedEpisode != null) { parsedEpisode.NzbUrl = GetNzbUrl(syndicationItem); - parsedEpisode.NzbInfoUrl = GetNzbUrl(syndicationItem); + parsedEpisode.NzbInfoUrl = GetNzbInfoUrl(syndicationItem); result.Add(parsedEpisode); } } @@ -68,23 +70,20 @@ protected virtual string GetNzbInfoUrl(SyndicationItem item) return String.Empty; } - protected virtual IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected virtual ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { return currentResult; } - private IndexerParseResult ParseFeed(SyndicationItem item) + private ReportInfo ParseFeed(SyndicationItem item) { var title = GetTitle(item); - var episodeParseResult = Parser.ParseTitle(title); - if (episodeParseResult != null) - { - episodeParseResult.Age = DateTime.Now.Date.Subtract(item.PublishDate.Date).Days; - episodeParseResult.OriginalString = title; - episodeParseResult.SceneSource = true; - episodeParseResult.ReleaseGroup = ParseReleaseGroup(title); - } + var episodeParseResult = new ReportInfo(); + + episodeParseResult.Title = title; + episodeParseResult.Age = DateTime.Now.Date.Subtract(item.PublishDate.Date).Days; + episodeParseResult.ReleaseGroup = ParseReleaseGroup(title); _logger.Trace("Parsed: {0} from: {1}", episodeParseResult, item.Title.Text); diff --git a/NzbDrone.Core/Indexers/FileSharingTalk/FileSharingTalkParser.cs b/NzbDrone.Core/Indexers/FileSharingTalk/FileSharingTalkParser.cs index 82621c435..33a22d7a8 100644 --- a/NzbDrone.Core/Indexers/FileSharingTalk/FileSharingTalkParser.cs +++ b/NzbDrone.Core/Indexers/FileSharingTalk/FileSharingTalkParser.cs @@ -1,5 +1,7 @@ using System.ServiceModel.Syndication; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.FileSharingTalk { @@ -10,7 +12,7 @@ protected override string GetNzbInfoUrl(SyndicationItem item) return item.Id; } - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Indexers/IndexerFetchService.cs b/NzbDrone.Core/Indexers/IndexerFetchService.cs index a89c4ce87..e2e1291b1 100644 --- a/NzbDrone.Core/Indexers/IndexerFetchService.cs +++ b/NzbDrone.Core/Indexers/IndexerFetchService.cs @@ -5,17 +5,19 @@ using NzbDrone.Common; using NzbDrone.Core.IndexerSearch.Definitions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers { public interface IFetchFeedFromIndexers { - IList FetchRss(IIndexerBase indexer); + IList FetchRss(IIndexerBase indexer); - IList Fetch(IIndexerBase indexer, SeasonSearchDefinition searchDefinition); - IList Fetch(IIndexerBase indexer, SingleEpisodeSearchDefinition searchDefinition); - IList Fetch(IIndexerBase indexer, PartialSeasonSearchDefinition searchDefinition); - IList Fetch(IIndexerBase indexer, DailyEpisodeSearchDefinition searchDefinition); + IList Fetch(IIndexerBase indexer, SeasonSearchDefinition searchDefinition); + IList Fetch(IIndexerBase indexer, SingleEpisodeSearchDefinition searchDefinition); + IList Fetch(IIndexerBase indexer, PartialSeasonSearchDefinition searchDefinition); + IList Fetch(IIndexerBase indexer, DailyEpisodeSearchDefinition searchDefinition); } public class FetchFeedService : IFetchFeedFromIndexers @@ -31,7 +33,7 @@ public FetchFeedService(IHttpProvider httpProvider, Logger logger) } - public virtual IList FetchRss(IIndexerBase indexer) + public virtual IList FetchRss(IIndexerBase indexer) { _logger.Debug("Fetching feeds from " + indexer.Name); @@ -42,7 +44,7 @@ public virtual IList FetchRss(IIndexerBase indexer) return result; } - public IList Fetch(IIndexerBase indexer, SeasonSearchDefinition searchDefinition) + public IList Fetch(IIndexerBase indexer, SeasonSearchDefinition searchDefinition) { _logger.Debug("Searching for {0}", searchDefinition); @@ -54,7 +56,7 @@ public IList Fetch(IIndexerBase indexer, SeasonSearchDefinit return result; } - public IList Fetch(IIndexerBase indexer, SingleEpisodeSearchDefinition searchDefinition) + public IList Fetch(IIndexerBase indexer, SingleEpisodeSearchDefinition searchDefinition) { _logger.Debug("Searching for {0}", searchDefinition); @@ -67,7 +69,7 @@ public IList Fetch(IIndexerBase indexer, SingleEpisodeSearch } - public IList Fetch(IIndexerBase indexer, PartialSeasonSearchDefinition searchDefinition) + public IList Fetch(IIndexerBase indexer, PartialSeasonSearchDefinition searchDefinition) { _logger.Debug("Searching for {0}", searchDefinition); @@ -79,7 +81,7 @@ public IList Fetch(IIndexerBase indexer, PartialSeasonSearch return result; } - public IList Fetch(IIndexerBase indexer, DailyEpisodeSearchDefinition searchDefinition) + public IList Fetch(IIndexerBase indexer, DailyEpisodeSearchDefinition searchDefinition) { _logger.Debug("Searching for {0}", searchDefinition); @@ -90,9 +92,9 @@ public IList Fetch(IIndexerBase indexer, DailyEpisodeSearchD return result; } - private List Fetch(IIndexerBase indexer, IEnumerable urls) + private List Fetch(IIndexerBase indexer, IEnumerable urls) { - var result = new List(); + var result = new List(); foreach (var url in urls) { diff --git a/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs b/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs index c053c96b5..fe3d94ff3 100644 --- a/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs +++ b/NzbDrone.Core/Indexers/Newznab/NewznabParser.cs @@ -1,6 +1,8 @@ using System; using System.ServiceModel.Syndication; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Newznab { @@ -18,7 +20,7 @@ protected override string GetNzbInfoUrl(SyndicationItem item) return item.Id; } - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Indexers/NzbClub/NzbClubParser.cs b/NzbDrone.Core/Indexers/NzbClub/NzbClubParser.cs index ab3970caf..d45ce8332 100644 --- a/NzbDrone.Core/Indexers/NzbClub/NzbClubParser.cs +++ b/NzbDrone.Core/Indexers/NzbClub/NzbClubParser.cs @@ -2,12 +2,14 @@ using System.ServiceModel.Syndication; using System.Text.RegularExpressions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.NzbClub { public class NzbClubParser : BasicRssParser { - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Indexers/NzbIndex/NzbIndexParser.cs b/NzbDrone.Core/Indexers/NzbIndex/NzbIndexParser.cs index 8dc386e51..d537251bb 100644 --- a/NzbDrone.Core/Indexers/NzbIndex/NzbIndexParser.cs +++ b/NzbDrone.Core/Indexers/NzbIndex/NzbIndexParser.cs @@ -2,6 +2,8 @@ using System.ServiceModel.Syndication; using System.Text.RegularExpressions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.NzbIndex { @@ -18,7 +20,7 @@ protected override string GetNzbInfoUrl(SyndicationItem item) return item.Links[0].Uri.ToString(); } - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Indexers/NzbsRUs/NzbsrusParser.cs b/NzbDrone.Core/Indexers/NzbsRUs/NzbsrusParser.cs index 4ad848966..c4ba74227 100644 --- a/NzbDrone.Core/Indexers/NzbsRUs/NzbsrusParser.cs +++ b/NzbDrone.Core/Indexers/NzbsRUs/NzbsrusParser.cs @@ -1,12 +1,14 @@ using System.ServiceModel.Syndication; using System.Text.RegularExpressions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.NzbsRUs { public class NzbsrusParser : BasicRssParser { - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Indexers/Nzbx/NzbxParser.cs b/NzbDrone.Core/Indexers/Nzbx/NzbxParser.cs index f5a30ef80..c7e026d46 100644 --- a/NzbDrone.Core/Indexers/Nzbx/NzbxParser.cs +++ b/NzbDrone.Core/Indexers/Nzbx/NzbxParser.cs @@ -4,6 +4,8 @@ using NLog; using Newtonsoft.Json; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Nzbx { @@ -18,9 +20,9 @@ public NzbxParser(Logger logger) _serializer = new JsonSerializer(); } - public IEnumerable Process(Stream source) + public IEnumerable Process(Stream source) { - var result = new List(); + var result = new List(); var jsonReader = new JsonTextReader(new StreamReader(source)); var feed = _serializer.Deserialize>(jsonReader); @@ -28,18 +30,14 @@ public IEnumerable Process(Stream source) { try { - var episodeParseResult = Parser.ParseTitle(item.Name); - if (episodeParseResult != null) - { - episodeParseResult.Age = DateTime.Now.Date.Subtract(item.PostDate).Days; - episodeParseResult.OriginalString = item.Name; - episodeParseResult.SceneSource = true; - episodeParseResult.NzbUrl = String.Format("http://nzbx.co/nzb?{0}*|*{1}", item.Guid, item.Name); - episodeParseResult.NzbInfoUrl = String.Format("http://nzbx.co/d?{0}", item.Guid); - episodeParseResult.Size = item.Size; + var episodeParseResult = new ReportInfo(); + episodeParseResult.Age = DateTime.Now.Date.Subtract(item.PostDate).Days; + episodeParseResult.Title = item.Name; + episodeParseResult.NzbUrl = String.Format("http://nzbx.co/nzb?{0}*|*{1}", item.Guid, item.Name); + episodeParseResult.NzbInfoUrl = String.Format("http://nzbx.co/d?{0}", item.Guid); + episodeParseResult.Size = item.Size; - result.Add(episodeParseResult); - } + result.Add(episodeParseResult); } catch (Exception itemEx) { diff --git a/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsParser.cs b/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsParser.cs index 284d56a57..788de718e 100644 --- a/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsParser.cs +++ b/NzbDrone.Core/Indexers/Omgwtfnzbs/OmgwtfnzbsParser.cs @@ -2,6 +2,8 @@ using System.ServiceModel.Syndication; using System.Text.RegularExpressions; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Omgwtfnzbs { @@ -26,7 +28,7 @@ protected override string GetNzbInfoUrl(SyndicationItem item) return String.Empty; } - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Indexers/RssSyncService.cs b/NzbDrone.Core/Indexers/RssSyncService.cs index 539ee31f3..251cef92f 100644 --- a/NzbDrone.Core/Indexers/RssSyncService.cs +++ b/NzbDrone.Core/Indexers/RssSyncService.cs @@ -6,6 +6,8 @@ using NzbDrone.Core.DecisionEngine; using NzbDrone.Core.Download; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers { @@ -40,10 +42,10 @@ public void Sync() var qualifiedReports = decisions .Where(c => c.Approved) - .Select(c => c.ParseResult) + .Select(c => c.Episode) .OrderByDescending(c => c.Quality) - .ThenBy(c => c.EpisodeNumbers.MinOrDefault()) - .ThenBy(c => c.Age); + .ThenBy(c => c.Episodes.Select(e => e.EpisodeNumber).MinOrDefault()) + .ThenBy(c => c.Report.Age); foreach (var episodeParseResult in qualifiedReports) @@ -65,7 +67,7 @@ public void Sync() public interface IFetchAndParseRss { - List Fetch(); + List Fetch(); } public class FetchAndParseRssService : IFetchAndParseRss @@ -79,9 +81,9 @@ public FetchAndParseRssService(IIndexerService indexerService, IFetchFeedFromInd _feedFetcher = feedFetcher; } - public List Fetch() + public List Fetch() { - var result = new List(); + var result = new List(); var indexers = _indexerService.GetAvailableIndexers(); diff --git a/NzbDrone.Core/Indexers/Wombles/WomblesParser.cs b/NzbDrone.Core/Indexers/Wombles/WomblesParser.cs index 3cdc5d3fb..7e5635d21 100644 --- a/NzbDrone.Core/Indexers/Wombles/WomblesParser.cs +++ b/NzbDrone.Core/Indexers/Wombles/WomblesParser.cs @@ -1,5 +1,7 @@ using System.ServiceModel.Syndication; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; namespace NzbDrone.Core.Indexers.Wombles { @@ -15,7 +17,7 @@ protected override string GetNzbInfoUrl(SyndicationItem item) return null; } - protected override IndexerParseResult PostProcessor(SyndicationItem item, IndexerParseResult currentResult) + protected override ReportInfo PostProcessor(SyndicationItem item, ReportInfo currentResult) { if (currentResult != null) { diff --git a/NzbDrone.Core/Jobs/Implementations/PostDownloadScanJob.cs b/NzbDrone.Core/Jobs/Implementations/PostDownloadScanJob.cs index f12306cfe..5d67058f7 100644 --- a/NzbDrone.Core/Jobs/Implementations/PostDownloadScanJob.cs +++ b/NzbDrone.Core/Jobs/Implementations/PostDownloadScanJob.cs @@ -12,13 +12,13 @@ public class PostDownloadScanJob : IJob { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - private readonly PostDownloadProvider _postDownloadProvider; + private readonly DropFolderImportService _dropFolderImportService; private readonly IConfigService _configService; private readonly DiskProvider _diskProvider; - public PostDownloadScanJob(PostDownloadProvider postDownloadProvider,IConfigService configService, DiskProvider diskProvider) + public PostDownloadScanJob(DropFolderImportService dropFolderImportService,IConfigService configService, DiskProvider diskProvider) { - _postDownloadProvider = postDownloadProvider; + _dropFolderImportService = dropFolderImportService; _configService = configService; _diskProvider = diskProvider; } @@ -59,7 +59,7 @@ public virtual void Start(ProgressNotification notification, dynamic options) return; } - _postDownloadProvider.ProcessDropFolder(dropFolder); + _dropFolderImportService.ProcessDropFolder(dropFolder); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Lifecycle/AppUpdateJob.cs b/NzbDrone.Core/Lifecycle/AppUpdateJob.cs index b62d04893..97cd3ccbd 100644 --- a/NzbDrone.Core/Lifecycle/AppUpdateJob.cs +++ b/NzbDrone.Core/Lifecycle/AppUpdateJob.cs @@ -49,7 +49,7 @@ public virtual void Start(ProgressNotification notification, dynamic options) { notification.CurrentMessage = "Checking for updates"; - var updatePackage = _updateService.GetAvailableUpdate(_environmentProvider.Version); + var updatePackage = _updateService.GetAvailableUpdate(); //No updates available if (updatePackage == null) @@ -88,7 +88,7 @@ public virtual void Start(ProgressNotification notification, dynamic options) var process = _processProvider.Start(startInfo); notification.CurrentMessage = "Update in progress. NzbDrone will restart shortly."; - _processProvider.WaitForExit(process); + _processProvider.WaitForExit(process); } } } \ No newline at end of file diff --git a/NzbDrone.Core/MediaFiles/EpisodeFile.cs b/NzbDrone.Core/MediaFiles/EpisodeFile.cs index 38bea3ba8..72c7d1598 100644 --- a/NzbDrone.Core/MediaFiles/EpisodeFile.cs +++ b/NzbDrone.Core/MediaFiles/EpisodeFile.cs @@ -26,8 +26,9 @@ public EpisodeFile(EpisodeFile source) public long Size { get; set; } public DateTime DateAdded { get; set; } public string SceneName { get; set; } - public string ReleaseGroup { get; set; } public QualityModel Quality { get; set; } + + public LazyList Episodes { get; set; } } } \ No newline at end of file diff --git a/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs b/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs index d7b516eb5..5a89debbd 100644 --- a/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs +++ b/NzbDrone.Core/MediaFiles/EpisodeFileMovingService.cs @@ -59,7 +59,7 @@ public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, bool newDownload = f return null; } - _diskProvider.CreateDirectory(new FileInfo(newFile).DirectoryName); + _diskProvider.CreateFolder(new FileInfo(newFile).DirectoryName); _logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, newFile); _diskProvider.MoveFile(episodeFile.Path, newFile); @@ -78,14 +78,12 @@ public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, bool newDownload = f episodeFile.Path = newFile; _mediaFileService.Update(episodeFile); - var parseResult = Parser.ParsePath(episodeFile.Path); - parseResult.Series = series; + var parseResult = Parser.Parser.ParsePath(episodeFile.Path); parseResult.Quality = episodeFile.Quality; - parseResult.Episodes = episodes; if (newDownload) { - _eventAggregator.Publish(new EpisodeDownloadedEvent(parseResult)); + _eventAggregator.Publish(new EpisodeDownloadedEvent(parseResult, series)); } return episodeFile; diff --git a/NzbDrone.Core/MediaFiles/Events/EpisodeDownloadedEvent.cs b/NzbDrone.Core/MediaFiles/Events/EpisodeDownloadedEvent.cs index 8c41c37ea..2392c3c53 100644 --- a/NzbDrone.Core/MediaFiles/Events/EpisodeDownloadedEvent.cs +++ b/NzbDrone.Core/MediaFiles/Events/EpisodeDownloadedEvent.cs @@ -1,15 +1,20 @@ using NzbDrone.Common.Eventing; using NzbDrone.Core.Model; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Tv; namespace NzbDrone.Core.MediaFiles.Events { public class EpisodeDownloadedEvent : IEvent { - public FileNameParseResult ParseResult { get; private set; } + public ParsedEpisodeInfo ParseResult { get; private set; } + public Series Series { get; set; } - public EpisodeDownloadedEvent(FileNameParseResult parseResult) + public EpisodeDownloadedEvent(ParsedEpisodeInfo parseResult, Series series) { ParseResult = parseResult; + Series = series; } } } \ No newline at end of file diff --git a/NzbDrone.Core/MediaFiles/Events/EpisodeFileAddedEvent.cs b/NzbDrone.Core/MediaFiles/Events/EpisodeFileAddedEvent.cs new file mode 100644 index 000000000..f332dfc7a --- /dev/null +++ b/NzbDrone.Core/MediaFiles/Events/EpisodeFileAddedEvent.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using NzbDrone.Common.Eventing; + +namespace NzbDrone.Core.MediaFiles.Events +{ + public class EpisodeFileAddedEvent : IEvent + { + public EpisodeFile EpisodeFile { get; private set; } + + public EpisodeFileAddedEvent(EpisodeFile episodeFile) + { + EpisodeFile = episodeFile; + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/MediaFiles/MediaFileService.cs b/NzbDrone.Core/MediaFiles/MediaFileService.cs index 1665c6301..3d0f97a03 100644 --- a/NzbDrone.Core/MediaFiles/MediaFileService.cs +++ b/NzbDrone.Core/MediaFiles/MediaFileService.cs @@ -39,7 +39,9 @@ public MediaFileService(IMediaFileRepository mediaFileRepository, IConfigService public EpisodeFile Add(EpisodeFile episodeFile) { - return _mediaFileRepository.Insert(episodeFile); + var addedFile = _mediaFileRepository.Insert(episodeFile); + _eventAggregator.Publish(new EpisodeFileAddedEvent(addedFile)); + return addedFile; } public void Update(EpisodeFile episodeFile) diff --git a/NzbDrone.Core/Model/IndexerParseResult.cs b/NzbDrone.Core/Model/IndexerParseResult.cs deleted file mode 100644 index bf3f68c35..000000000 --- a/NzbDrone.Core/Model/IndexerParseResult.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Linq; -using System.Collections.Generic; -using NzbDrone.Core.DecisionEngine; -using NzbDrone.Core.Organizer; -using NzbDrone.Core.Tv; - -namespace NzbDrone.Core.Model -{ - public class ParseResult - { - public string SeriesTitle { get; set; } - - public string CleanTitle - { - get - { - return Parser.NormalizeTitle(SeriesTitle); - } - } - - - public string EpisodeTitle { get; set; } - - public int SeasonNumber { get; set; } - - public List EpisodeNumbers { get; set; } - - public DateTime? AirDate { get; set; } - - public QualityModel Quality { get; set; } - - public LanguageType Language { get; set; } - - public string OriginalString { get; set; } - - public Series Series { get; set; } - - public bool FullSeason { get; set; } - - public long Size { get; set; } - - public bool SceneSource { get; set; } - - public IList Episodes { get; set; } - - public override string ToString() - { - string episodeString = "[Unknown Episode]"; - - if (AirDate != null && EpisodeNumbers == null) - { - episodeString = string.Format("{0}", AirDate.Value.ToString("yyyy-MM-dd")); - } - else if (FullSeason) - { - episodeString = string.Format("Season {0:00}", SeasonNumber); - } - else if (EpisodeNumbers != null && EpisodeNumbers.Any()) - { - episodeString = string.Format("S{0:00}E{1}", SeasonNumber, String.Join("-", EpisodeNumbers.Select(c => c.ToString("00")))); - } - - return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality); - } - } - - - public class IndexerParseResult : ParseResult - { - public DownloadDecision Decision { get; set; } - - public string NzbUrl { get; set; } - - public string NzbInfoUrl { get; set; } - - public String Indexer { get; set; } - - public int Age { get; set; } - - public string ReleaseGroup { get; set; } - - public string GetDownloadTitle() - { - var seriesTitle = FileNameBuilder.CleanFilename(Series.Title); - - //Handle Full Naming - if (FullSeason) - { - var seasonResult = String.Format("{0} - Season {1} [{2}]", seriesTitle, - SeasonNumber, Quality.Quality); - - if (Quality.Proper) - seasonResult += " [Proper]"; - - return seasonResult; - } - - if (Series.SeriesType == SeriesTypes.Daily) - { - var dailyResult = String.Format("{0} - {1:yyyy-MM-dd} - {2} [{3}]", seriesTitle, - AirDate, Episodes.First().Title, Quality.Quality); - - if (Quality.Proper) - dailyResult += " [Proper]"; - - return dailyResult; - } - - //Show Name - 1x01-1x02 - Episode Name - //Show Name - 1x01 - Episode Name - var episodeString = new List(); - var episodeNames = new List(); - - foreach (var episode in Episodes) - { - episodeString.Add(String.Format("{0}x{1:00}", episode.SeasonNumber, episode.EpisodeNumber)); - episodeNames.Add(Parser.CleanupEpisodeTitle(episode.Title)); - } - - var epNumberString = String.Join("-", episodeString); - string episodeName; - - - if (episodeNames.Distinct().Count() == 1) - episodeName = episodeNames.First(); - - else - episodeName = String.Join(" + ", episodeNames.Distinct()); - - var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, episodeName, Quality.Quality); - - if (Quality.Proper) - { - result += " [Proper]"; - } - - return result; - } - } - - - public class FileNameParseResult :ParseResult - { - - } -} \ No newline at end of file diff --git a/NzbDrone.Core/Model/MediaInfoModel.cs b/NzbDrone.Core/Model/MediaInfoModel.cs index b75cf638b..9b2ada461 100644 --- a/NzbDrone.Core/Model/MediaInfoModel.cs +++ b/NzbDrone.Core/Model/MediaInfoModel.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace NzbDrone.Core.Model +namespace NzbDrone.Core.Model { public class MediaInfoModel { diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index 19856bfde..dec99946a 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -228,15 +228,16 @@ - + - + + @@ -307,6 +308,7 @@ + @@ -335,18 +337,25 @@ - - + + - + + + + + + + + @@ -377,9 +386,9 @@ - - - + + + @@ -415,7 +424,7 @@ Code - + Code @@ -470,7 +479,7 @@ Code - + Code @@ -505,12 +514,9 @@ Code - - - @@ -521,7 +527,7 @@ - + diff --git a/NzbDrone.Core/Organizer/FileNameBuilder.cs b/NzbDrone.Core/Organizer/FileNameBuilder.cs index 4d44ef5cc..176843fda 100644 --- a/NzbDrone.Core/Organizer/FileNameBuilder.cs +++ b/NzbDrone.Core/Organizer/FileNameBuilder.cs @@ -53,7 +53,7 @@ public string BuildFilename(IList episodes, Series series, EpisodeFile var episodeNames = new List { - Parser.CleanupEpisodeTitle(sortedEpisodes.First().Title) + Parser.Parser.CleanupEpisodeTitle(sortedEpisodes.First().Title) }; var result = String.Empty; @@ -85,7 +85,7 @@ public string BuildFilename(IList episodes, Series series, EpisodeFile } result = result.Replace("%0e", String.Format("{0:00}", episode.EpisodeNumber)); - episodeNames.Add(Parser.CleanupEpisodeTitle(episode.Title)); + episodeNames.Add(Parser.Parser.CleanupEpisodeTitle(episode.Title)); } } diff --git a/NzbDrone.Core/Model/LanguageType.cs b/NzbDrone.Core/Parser/Language.cs similarity index 88% rename from NzbDrone.Core/Model/LanguageType.cs rename to NzbDrone.Core/Parser/Language.cs index de11ee25e..564de13f2 100644 --- a/NzbDrone.Core/Model/LanguageType.cs +++ b/NzbDrone.Core/Parser/Language.cs @@ -1,6 +1,6 @@ -namespace NzbDrone.Core.Model +namespace NzbDrone.Core.Parser { - public enum LanguageType + public enum Language { English = 0, French = 1, diff --git a/NzbDrone.Core/Parser/Model/LocalEpisode.cs b/NzbDrone.Core/Parser/Model/LocalEpisode.cs new file mode 100644 index 000000000..097945d1e --- /dev/null +++ b/NzbDrone.Core/Parser/Model/LocalEpisode.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using NzbDrone.Core.Tv; +using System.Linq; + +namespace NzbDrone.Core.Parser.Model +{ + public class LocalEpisode + { + //public ParsedEpisodeInfo ParsedEpisodeInfo { get; set; } + public List Episodes { get; set; } + + public QualityModel Quality { get; set; } + public int SeasonNumber { get { return Episodes.Select(c => c.SeasonNumber).Distinct().Single(); } } + + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs b/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs new file mode 100644 index 000000000..213e953f5 --- /dev/null +++ b/NzbDrone.Core/Parser/Model/ParsedEpisodeInfo.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Model; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Parser.Model +{ + public class ParsedEpisodeInfo + { + public string SeriesTitle { get; set; } + public string OriginalString { get; set; } + public QualityModel Quality { get; set; } + public int SeasonNumber { get; set; } + public List EpisodeNumbers { get; set; } + public DateTime? AirDate { get; set; } + public Language Language { get; set; } + + public bool FullSeason { get; set; } + public bool SceneSource { get; set; } + + public override string ToString() + { + string episodeString = "[Unknown Episode]"; + + if (AirDate != null && EpisodeNumbers == null) + { + episodeString = string.Format("{0}", AirDate.Value.ToString("yyyy-MM-dd")); + } + else if (FullSeason) + { + episodeString = string.Format("Season {0:00}", SeasonNumber); + } + else if (EpisodeNumbers != null && EpisodeNumbers.Any()) + { + episodeString = string.Format("S{0:00}E{1}", SeasonNumber, String.Join("-", EpisodeNumbers.Select(c => c.ToString("00")))); + } + + return string.Format("{0} - {1} {2}", SeriesTitle, episodeString, Quality); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Parser/Model/RemoteEpisode.cs b/NzbDrone.Core/Parser/Model/RemoteEpisode.cs new file mode 100644 index 000000000..7f517d972 --- /dev/null +++ b/NzbDrone.Core/Parser/Model/RemoteEpisode.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NzbDrone.Core.Organizer; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Parser.Model +{ + public class RemoteEpisode + { + public ReportInfo Report { get; set; } + + public bool FullSeason { get; set; } + + public Series Series { get; set; } + + public List Episodes { get; set; } + + public QualityModel Quality { get; set; } + + public Language Language { get; set; } + + public int SeasonNumber + { + get { return Episodes.Select(e => e.SeasonNumber).Distinct().SingleOrDefault(); } + } + + + public DateTime? AirDate + { + get + { + return Episodes.Single().AirDate; + } + } + + public IEnumerable EpisodeNumbers + { + get + { + return Episodes.Select(c => c.EpisodeNumber).Distinct(); + } + } + + public string GetDownloadTitle() + { + var seriesTitle = FileNameBuilder.CleanFilename(Series.Title); + + //Handle Full Naming + if (FullSeason) + { + var seasonResult = String.Format("{0} - Season {1} [{2}]", seriesTitle, SeasonNumber, Quality); + + if (Quality.Proper) + seasonResult += " [Proper]"; + + return seasonResult; + } + + if (Series.SeriesType == SeriesTypes.Daily) + { + var dailyResult = String.Format("{0} - {1:yyyy-MM-dd} - {2} [{3}]", seriesTitle, + AirDate, Episodes.First().Title, Quality); + + if (Quality.Proper) + dailyResult += " [Proper]"; + + return dailyResult; + } + + //Show Name - 1x01-1x02 - Episode Name + //Show Name - 1x01 - Episode Name + var episodeString = new List(); + var episodeNames = new List(); + + foreach (var episode in Episodes) + { + episodeString.Add(String.Format("{0}x{1:00}", episode.SeasonNumber, episode.EpisodeNumber)); + episodeNames.Add(Core.Parser.Parser.CleanupEpisodeTitle(episode.Title)); + } + + var epNumberString = String.Join("-", episodeString); + string episodeName; + + + if (episodeNames.Distinct().Count() == 1) + episodeName = episodeNames.First(); + + else + episodeName = String.Join(" + ", episodeNames.Distinct()); + + var result = String.Format("{0} - {1} - {2} [{3}]", seriesTitle, epNumberString, episodeName, Quality); + + if (Quality.Proper) + { + result += " [Proper]"; + } + + return result; + } + + + public override string ToString() + { + throw new NotImplementedException(); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Parser/Model/ReportInfo.cs b/NzbDrone.Core/Parser/Model/ReportInfo.cs new file mode 100644 index 000000000..565c62531 --- /dev/null +++ b/NzbDrone.Core/Parser/Model/ReportInfo.cs @@ -0,0 +1,15 @@ +using System; + +namespace NzbDrone.Core.Parser.Model +{ + public class ReportInfo + { + public string Title { get; set; } + public long Size { get; set; } + public string NzbUrl { get; set; } + public string NzbInfoUrl { get; set; } + public String Indexer { get; set; } + public int Age { get; set; } + public string ReleaseGroup { get; set; } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Parser.cs b/NzbDrone.Core/Parser/Parser.cs similarity index 67% rename from NzbDrone.Core/Parser.cs rename to NzbDrone.Core/Parser/Parser.cs index 71f948c49..98a4b10ce 100644 --- a/NzbDrone.Core/Parser.cs +++ b/NzbDrone.Core/Parser/Parser.cs @@ -1,76 +1,76 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Text.RegularExpressions; using NLog; using NzbDrone.Common; +using NzbDrone.Core.Model; +using NzbDrone.Core.Parser.Model; using NzbDrone.Core.Qualities; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; -namespace NzbDrone.Core +namespace NzbDrone.Core.Parser { public static class Parser { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Regex[] ReportTitleRegex = new[] - { - //Episodes with airdate - new Regex(@"^(?.+?)?\W*(?<airyear>\d{4})\W+(?<airmonth>[0-1][0-9])\W+(?<airday>[0-3][0-9])\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + { + //Episodes with airdate + new Regex(@"^(?<title>.+?)?\W*(?<airyear>\d{4})\W+(?<airmonth>[0-1][0-9])\W+(?<airday>[0-3][0-9])\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Multi-Part episodes without a title (S01E05.S01E06) - new Regex(@"^(?:\W*S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,2}(?!\d+)))+){2,}\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Multi-Part episodes without a title (S01E05.S01E06) + new Regex(@"^(?:\W*S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,2}(?!\d+)))+){2,}\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Multi-episode Repeated (S01E05 - S01E06, 1x05 - 1x06, etc) - new Regex(@"^(?<title>.+?)(?:\W+S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,2}(?!\d+)))+){2,}\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Multi-episode Repeated (S01E05 - S01E06, 1x05 - 1x06, etc) + new Regex(@"^(?<title>.+?)(?:\W+S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:[ex]){1,2}(?<episode>\d{1,2}(?!\d+)))+){2,}\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc) - new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Episodes without a title, Single (S01E05, 1x05) AND Multi (S01E04E05, 1x04x05, etc) + new Regex(@"^(?:S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc) - new Regex(@"^(?<title>.+?)(?:\W+S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc) + new Regex(@"^(?<title>.+?)(?:\W+S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Episodes over 99 (3-digits or more) (S01E105, S01E105E106, etc) - new Regex(@"^(?<title>.*?)(?:\W?S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]){1,2}(?<episode>\d+))+)+\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Episodes over 99 (3-digits or more) (S01E105, S01E105E106, etc) + new Regex(@"^(?<title>.*?)(?:\W?S?(?<season>(?<!\d+)\d{1,2}(?!\d+))(?:(?:\-|[ex]){1,2}(?<episode>\d+))+)+\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:\-|[ex]|\W[ex])(?<episode>\d{2}(?!\d+)))+\W*)+\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + new Regex(@"^(?:S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:\-|[ex]|\W[ex])(?<episode>\d{2}(?!\d+)))+\W*)+\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc) - new Regex(@"^(?<title>.+?)(?:\W+S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Episodes with a title, Single episodes (S01E05, 1x05, etc) & Multi-episode (S01E05E06, S01E05-06, S01E05 E06, etc) + new Regex(@"^(?<title>.+?)(?:\W+S?(?<season>(?<!\d+)(?:\d{1,2}|\d{4})(?!\d+))(?:(?:\-|[ex]|\W[ex]){1,2}(?<episode>\d{2}(?!\d+)))+)\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Supports 103/113 naming - new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+)\d{1})(?<episode>\d{2}(?!p|i|\d+)))+\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Supports 103/113 naming + new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+)\d{1})(?<episode>\d{2}(?!p|i|\d+)))+\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Mini-Series, treated as season 1, episodes are labelled as Part01, Part 01, Part.1 - new Regex(@"^(?<title>.+?)(?:\W+(?:(?:Part\W?|(?<!\d+\W+)e)(?<episode>\d{1,2}(?!\d+)))+)\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Mini-Series, treated as season 1, episodes are labelled as Part01, Part 01, Part.1 + new Regex(@"^(?<title>.+?)(?:\W+(?:(?:Part\W?|(?<!\d+\W+)e)(?<episode>\d{1,2}(?!\d+)))+)\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Supports 1103/1113 naming - new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+|\(|\[)\d{2})(?<episode>\d{2}(?!p|i|\d+|\)|\])))+\W?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled), + //Supports 1103/1113 naming + new Regex(@"^(?<title>.+?)?(?:\W?(?<season>(?<!\d+|\(|\[)\d{2})(?<episode>\d{2}(?!p|i|\d+|\)|\])))+\W?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled), - //Supports Season only releases - new Regex(@"^(?<title>.+?)\W(?:S|Season)\W?(?<season>\d{1,2}(?!\d+))\W?(?<extras>EXTRAS|SUBPACK)?(?!\\)", - RegexOptions.IgnoreCase | RegexOptions.Compiled) - }; + //Supports Season only releases + new Regex(@"^(?<title>.+?)\W(?:S|Season)\W?(?<season>\d{1,2}(?!\d+))\W?(?<extras>EXTRAS|SUBPACK)?(?!\\)", + RegexOptions.IgnoreCase | RegexOptions.Compiled) + }; private static readonly Regex NormalizeRegex = new Regex(@"((^|\W)(a|an|the|and|or|of)($|\W|_))|\W|_|(?:(?<=[^0-9]+)|\b)(?!(?:19\d{2}|20\d{2}))\d+(?=[^0-9ip]+|\b)", RegexOptions.IgnoreCase | RegexOptions.Compiled); private static readonly Regex SimpleTitleRegex = new Regex(@"480[i|p]|720[i|p]|1080[i|p]|[x|h|x\s|h\s]264|DD\W?5\W1|\<|\>|\?|\*|\:|\||""", - RegexOptions.IgnoreCase | RegexOptions.Compiled); + RegexOptions.IgnoreCase | RegexOptions.Compiled); @@ -78,16 +78,16 @@ public static class Parser private static readonly Regex LanguageRegex = new Regex(@"(?:\W|_)(?<italian>ita|italian)|(?<german>german\b)|(?<flemish>flemish)|(?<greek>greek)(?:\W|_)", RegexOptions.IgnoreCase | RegexOptions.Compiled); - public static FileNameParseResult ParsePath(string path) + public static ParsedEpisodeInfo ParsePath(string path) { var fileInfo = new FileInfo(path); - var result = ParseTitle<FileNameParseResult>(fileInfo.Name); + var result = ParseTitle(fileInfo.Name); if (result == null) { Logger.Trace("Attempting to parse episode info using full path. {0}", fileInfo.FullName); - result = ParseTitle<FileNameParseResult>(fileInfo.FullName); + result = ParseTitle(fileInfo.FullName); } if (result != null) @@ -102,7 +102,7 @@ public static FileNameParseResult ParsePath(string path) return result; } - public static T ParseTitle<T>(string title) where T : ParseResult, new() + public static ParsedEpisodeInfo ParseTitle(string title) { try { @@ -115,7 +115,7 @@ public static FileNameParseResult ParsePath(string path) if (match.Count != 0) { - var result = ParseMatchCollection<T>(match); + var result = ParseMatchCollection(match); if (result != null) { //Check if episode is in the future (most likley a parse error) @@ -141,14 +141,14 @@ public static FileNameParseResult ParsePath(string path) return null; } - private static T ParseMatchCollection<T>(MatchCollection matchCollection) where T : ParseResult, new() + private static ParsedEpisodeInfo ParseMatchCollection(MatchCollection matchCollection) { var seriesName = matchCollection[0].Groups["title"].Value.Replace('.', ' '); int airYear; Int32.TryParse(matchCollection[0].Groups["airyear"].Value, out airYear); - T result; + ParsedEpisodeInfo result; if (airYear < 1900) { @@ -169,11 +169,11 @@ public static FileNameParseResult ParsePath(string path) if (seasons.Distinct().Count() > 1) return null; - result = new T - { - SeasonNumber = seasons.First(), - EpisodeNumbers = new List<int>() - }; + result = new ParsedEpisodeInfo + { + SeasonNumber = seasons.First(), + EpisodeNumbers = new List<int>() + }; foreach (Match matchGroup in matchCollection) { @@ -212,13 +212,13 @@ public static FileNameParseResult ParsePath(string path) airmonth = tempDay; } - result = new T - { - AirDate = new DateTime(airYear, airmonth, airday).Date, - }; + result = new ParsedEpisodeInfo + { + AirDate = new DateTime(airYear, airmonth, airday).Date, + }; } - result.SeriesTitle = seriesName; + result.SeriesTitle = NormalizeTitle(seriesName); Logger.Trace("Episode Parsed. {0}", result); @@ -229,12 +229,14 @@ public static string ParseSeriesName(string title) { Logger.Trace("Parsing string '{0}'", title); - var parseResult = ParseTitle<ParseResult>(title); + var parseResult = ParseTitle(title); if (parseResult == null) + { return NormalizeTitle(title); + } - return parseResult.CleanTitle; + return parseResult.SeriesTitle; } private static QualityModel ParseQuality(string name) @@ -376,7 +378,7 @@ private static QualityModel ParseQuality(string name) } if ((normalizedName.Contains("sdtv") || normalizedName.Contains("pdtv") || - (result.Quality == Quality.Unknown && normalizedName.Contains("hdtv"))) && + (result.Quality == Quality.Unknown && normalizedName.Contains("hdtv"))) && !normalizedName.Contains("mpeg")) { result.Quality = Quality.SDTV; @@ -386,80 +388,78 @@ private static QualityModel ParseQuality(string name) return result; } - private static LanguageType ParseLanguage(string title) + private static Language ParseLanguage(string title) { var lowerTitle = title.ToLower(); if (lowerTitle.Contains("english")) - return LanguageType.English; + return Language.English; if (lowerTitle.Contains("french")) - return LanguageType.French; + return Language.French; if (lowerTitle.Contains("spanish")) - return LanguageType.Spanish; + return Language.Spanish; if (lowerTitle.Contains("danish")) - return LanguageType.Danish; + return Language.Danish; if (lowerTitle.Contains("dutch")) - return LanguageType.Dutch; + return Language.Dutch; if (lowerTitle.Contains("japanese")) - return LanguageType.Japanese; + return Language.Japanese; if (lowerTitle.Contains("cantonese")) - return LanguageType.Cantonese; + return Language.Cantonese; if (lowerTitle.Contains("mandarin")) - return LanguageType.Mandarin; + return Language.Mandarin; if (lowerTitle.Contains("korean")) - return LanguageType.Korean; + return Language.Korean; if (lowerTitle.Contains("russian")) - return LanguageType.Russian; + return Language.Russian; if (lowerTitle.Contains("polish")) - return LanguageType.Polish; + return Language.Polish; if (lowerTitle.Contains("vietnamese")) - return LanguageType.Vietnamese; + return Language.Vietnamese; if (lowerTitle.Contains("swedish")) - return LanguageType.Swedish; + return Language.Swedish; if (lowerTitle.Contains("norwegian")) - return LanguageType.Norwegian; + return Language.Norwegian; if (lowerTitle.Contains("finnish")) - return LanguageType.Finnish; + return Language.Finnish; if (lowerTitle.Contains("turkish")) - return LanguageType.Turkish; + return Language.Turkish; if (lowerTitle.Contains("portuguese")) - return LanguageType.Portuguese; + return Language.Portuguese; var match = LanguageRegex.Match(title); if (match.Groups["italian"].Captures.Cast<Capture>().Any()) - return LanguageType.Italian; + return Language.Italian; if (match.Groups["german"].Captures.Cast<Capture>().Any()) - return LanguageType.German; + return Language.German; if (match.Groups["flemish"].Captures.Cast<Capture>().Any()) - return LanguageType.Flemish; + return Language.Flemish; if (match.Groups["greek"].Captures.Cast<Capture>().Any()) - return LanguageType.Greek; + return Language.Greek; - return LanguageType.English; + return Language.English; } - - public static string NormalizeTitle(string title) { long number = 0; @@ -476,5 +476,6 @@ public static string CleanupEpisodeTitle(string title) //this will remove (1),(2) from the end of multi part episodes. return MultiPartCleanupRegex.Replace(title, string.Empty).Trim(); } + } } \ No newline at end of file diff --git a/NzbDrone.Core/Parser/ParsingService.cs b/NzbDrone.Core/Parser/ParsingService.cs new file mode 100644 index 000000000..6b141e213 --- /dev/null +++ b/NzbDrone.Core/Parser/ParsingService.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NLog; +using NzbDrone.Core.Parser.Model; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Parser +{ + public interface IParsingService + { + LocalEpisode GetEpisodes(string fileName, Series series); + Series GetSeries(string title); + RemoteEpisode Map(ReportInfo indexerParseResult); + } + + public class ParsingService : IParsingService + { + private readonly IEpisodeService _episodeService; + private readonly ISeriesService _seriesService; + private readonly Logger _logger; + + public ParsingService(IEpisodeService episodeService, ISeriesService seriesService, Logger logger) + { + _episodeService = episodeService; + _seriesService = seriesService; + _logger = logger; + } + + + public LocalEpisode GetEpisodes(string fileName, Series series) + { + var parseResult = Parser.ParseTitle(fileName); + + if (parseResult == null) + { + return null; + } + + var episodes = GetEpisodesByParseResult(parseResult, series); + + if (!episodes.Any()) + { + return null; + } + + return new LocalEpisode + { + Quality = parseResult.Quality, + Episodes = episodes, + }; + } + + public Series GetSeries(string title) + { + var parseResult = Parser.ParseTitle(title); + return _seriesService.FindByTitle(parseResult.SeriesTitle); + } + + public RemoteEpisode Map(ReportInfo indexerParseResult) + { + throw new NotImplementedException(); + } + + private List<Episode> GetEpisodesByParseResult(ParsedEpisodeInfo parseResult, Series series) + { + var result = new List<Episode>(); + + if (parseResult.AirDate.HasValue) + { + if (series.SeriesType == SeriesTypes.Standard) + { + //Todo: Collect this as a Series we want to treat as a daily series, or possible parsing error + _logger.Warn("Found daily-style episode for non-daily series: {0}. {1}", series.Title, parseResult.OriginalString); + return new List<Episode>(); + } + + var episodeInfo = _episodeService.GetEpisode(series.Id, parseResult.AirDate.Value); + + if (episodeInfo != null) + { + result.Add(episodeInfo); + } + + return result; + } + + if (parseResult.EpisodeNumbers == null) + return result; + + foreach (var episodeNumber in parseResult.EpisodeNumbers) + { + Episode episodeInfo = null; + + if (series.UseSceneNumbering && parseResult.SceneSource) + { + episodeInfo = _episodeService.GetEpisode(series.Id, parseResult.SeasonNumber, episodeNumber, true); + } + + if (episodeInfo == null) + { + episodeInfo = _episodeService.GetEpisode(series.Id, parseResult.SeasonNumber, episodeNumber); + if (episodeInfo == null && parseResult.AirDate != null) + { + episodeInfo = _episodeService.GetEpisode(series.Id, parseResult.AirDate.Value); + } + } + + if (episodeInfo != null) + { + result.Add(episodeInfo); + + if (series.UseSceneNumbering) + { + _logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}x{4:00}", + series.Title, + episodeInfo.SceneSeasonNumber, + episodeInfo.SceneEpisodeNumber, + episodeInfo.SeasonNumber, + episodeInfo.EpisodeNumber); + } + } + else + { + _logger.Debug("Unable to find {0}", parseResult); + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index accbc4fbc..b65501ec6 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -5,8 +5,8 @@ using NLog; using NzbDrone.Common; using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Parser; using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; namespace NzbDrone.Core.Providers { @@ -15,80 +15,40 @@ public class DiskScanProvider private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly string[] MediaExtensions = new[] { ".mkv", ".avi", ".wmv", ".mp4", ".mpg", ".mpeg", ".xvid", ".flv", ".mov", ".rm", ".rmvb", ".divx", ".dvr-ms", ".ts", ".ogm", ".m4v", ".strm" }; private readonly DiskProvider _diskProvider; - private readonly IEpisodeService _episodeService; private readonly ICleanGhostFiles _ghostFileCleaner; private readonly IMediaFileService _mediaFileService; - private readonly RecycleBinProvider _recycleBinProvider; - private readonly MediaInfoProvider _mediaInfoProvider; - private readonly ISeriesRepository _seriesRepository; - private readonly IMoveEpisodeFiles _moveEpisodeFiles; + private readonly IVideoFileInfoReader _videoFileInfoReader; + private readonly IParsingService _parsingService; - public DiskScanProvider(DiskProvider diskProvider, IEpisodeService episodeService, ICleanGhostFiles ghostFileCleaner, IMediaFileService mediaFileService, - RecycleBinProvider recycleBinProvider, MediaInfoProvider mediaInfoProvider, ISeriesRepository seriesRepository, IMoveEpisodeFiles moveEpisodeFiles) + public DiskScanProvider(DiskProvider diskProvider, ICleanGhostFiles ghostFileCleaner, IMediaFileService mediaFileService, IVideoFileInfoReader videoFileInfoReader, + IParsingService parsingService) { _diskProvider = diskProvider; - _episodeService = episodeService; _ghostFileCleaner = ghostFileCleaner; _mediaFileService = mediaFileService; - _recycleBinProvider = recycleBinProvider; - _mediaInfoProvider = mediaInfoProvider; - _seriesRepository = seriesRepository; - _moveEpisodeFiles = moveEpisodeFiles; + _videoFileInfoReader = videoFileInfoReader; + _parsingService = parsingService; } - public DiskScanProvider() + public virtual void Scan(Series series) { - } - - /// <summary> - /// Scans the specified series folder for media files - /// </summary> - /// <param name = "series">The series to be scanned</param> - public virtual List<EpisodeFile> Scan(Series series) - { - return Scan(series, series.Path); - } - - /// <summary> - /// Scans the specified series folder for media files - /// </summary> - /// <param name = "series">The series to be scanned</param> - /// <param name="path">Path to scan</param> - public virtual List<EpisodeFile> Scan(Series series, string path) - { - if (!_diskProvider.FolderExists(path)) + if (!_diskProvider.FolderExists(series.Path)) { - Logger.Warn("Series folder doesn't exist: {0}", path); - return new List<EpisodeFile>(); - } - - if (_episodeService.GetEpisodeBySeries(series.Id).Count == 0) - { - Logger.Debug("Series {0} has no episodes. skipping", series.Title); - return new List<EpisodeFile>(); + Logger.Warn("Series folder doesn't exist: {0}", series.Path); + return; } _ghostFileCleaner.RemoveNonExistingFiles(series.Id); - var mediaFileList = GetVideoFiles(path); - var importedFiles = new List<EpisodeFile>(); + var mediaFileList = GetVideoFiles(series.Path); foreach (var filePath in mediaFileList) { - var file = ImportFile(series, filePath); - if (file != null) - { - importedFiles.Add(file); - } + ImportFile(series, filePath); } //Todo: Find the "best" episode file for all found episodes and import that one //Todo: Move the episode linking to here, instead of import (or rename import) - - series.LastDiskSync = DateTime.Now; - _seriesRepository.Update(series); - - return importedFiles; } public virtual EpisodeFile ImportFile(Series series, string filePath) @@ -101,48 +61,27 @@ public virtual EpisodeFile ImportFile(Series series, string filePath) return null; } - var parseResult = Parser.ParsePath(filePath); + var parsedEpisode = _parsingService.GetEpisodes(filePath, series); - if (parseResult == null) + if (parsedEpisode == null || !parsedEpisode.Episodes.Any()) + { return null; + } var size = _diskProvider.GetSize(filePath); - var runTime = _mediaInfoProvider.GetRunTime(filePath); - if (series.SeriesType == SeriesTypes.Daily || parseResult.SeasonNumber > 0) + if (series.SeriesType == SeriesTypes.Daily || parsedEpisode.SeasonNumber > 0) { - if (size < Constants.IgnoreFileSize && runTime < 180) + var runTime = _videoFileInfoReader.GetRunTime(filePath); + if (size < Constants.IgnoreFileSize && runTime.TotalMinutes < 3) { Logger.Trace("[{0}] appears to be a sample. skipping.", filePath); return null; } } - if (!_diskProvider.IsChildOfPath(filePath, series.Path)) - parseResult.SceneSource = true; - - parseResult.SeriesTitle = series.Title; //replaces the nasty path as title to help with logging - parseResult.Series = series; - - var episodes = _episodeService.GetEpisodesByParseResult(parseResult); - - if (episodes.Count <= 0) + if (parsedEpisode.Episodes.Any(e => e.EpisodeFile != null && e.EpisodeFile.Quality > parsedEpisode.Quality)) { - Logger.Debug("Can't find any matching episodes in the database. Skipping {0}", filePath); - return null; - } - - //Make sure this file is an upgrade for ALL episodes already on disk - if (episodes.All(e => e.EpisodeFile == null || e.EpisodeFile.Quality <= parseResult.Quality)) - { - Logger.Debug("Deleting the existing file(s) on disk to upgrade to: {0}", filePath); - //Do the delete for files where there is already an episode on disk - episodes.Where(e => e.EpisodeFile != null).Select(e => e.EpisodeFile.Path).Distinct().ToList().ForEach(p => _recycleBinProvider.DeleteFile(p)); - } - - else - { - //Skip this file because its not an upgrade Logger.Trace("This file isn't an upgrade for all episodes. Skipping {0}", filePath); return null; } @@ -152,56 +91,17 @@ public virtual EpisodeFile ImportFile(Series series, string filePath) episodeFile.SeriesId = series.Id; episodeFile.Path = filePath.NormalizePath(); episodeFile.Size = size; - episodeFile.Quality = parseResult.Quality; - episodeFile.SeasonNumber = parseResult.SeasonNumber; + episodeFile.Quality = parsedEpisode.Quality; + episodeFile.SeasonNumber = parsedEpisode.SeasonNumber; episodeFile.SceneName = Path.GetFileNameWithoutExtension(filePath.NormalizePath()); //Todo: We shouldn't actually import the file until we confirm its the only one we want. //Todo: Separate episodeFile creation from importing (pass file to import to import) _mediaFileService.Add(episodeFile); - - //Link file to all episodes - foreach (var ep in episodes) - { - ep.EpisodeFile = episodeFile; - ep.PostDownloadStatus = PostDownloadStatusType.NoError; - _episodeService.UpdateEpisode(ep); - Logger.Debug("Linking [{0}] > [{1}]", filePath, ep); - } - return episodeFile; } - - public virtual void CleanUpDropFolder(string path) - { - //Todo: We should rename files before importing them to prevent this issue from ever happening - - var filesOnDisk = GetVideoFiles(path); - - foreach (var file in filesOnDisk) - { - try - { - var episodeFile = _mediaFileService.GetFileByPath(file); - - if (episodeFile != null) - { - Logger.Trace("[{0}] was imported but not moved, moving it now", file); - - _moveEpisodeFiles.MoveEpisodeFile(episodeFile, true); - } - - } - catch (Exception ex) - { - Logger.WarnException("Failed to move episode file from drop folder: " + file, ex); - throw; - } - } - } - - public virtual List<string> GetVideoFiles(string path, bool allDirectories = true) + public virtual string[] GetVideoFiles(string path, bool allDirectories = true) { Logger.Debug("Scanning '{0}' for video files", path); @@ -211,7 +111,7 @@ public virtual List<string> GetVideoFiles(string path, bool allDirectories = tru var mediaFileList = filesOnDisk.Where(c => MediaExtensions.Contains(Path.GetExtension(c).ToLower())).ToList(); Logger.Trace("{0} video files were found in {1}", mediaFileList.Count, path); - return mediaFileList; + return mediaFileList.ToArray(); } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/DropfolderImportService.cs b/NzbDrone.Core/Providers/DropfolderImportService.cs new file mode 100644 index 000000000..c453baf2a --- /dev/null +++ b/NzbDrone.Core/Providers/DropfolderImportService.cs @@ -0,0 +1,121 @@ +using System; +using System.IO; +using NLog; +using NzbDrone.Common; +using NzbDrone.Core.MediaFiles; +using NzbDrone.Core.Parser; +using NzbDrone.Core.Tv; + +namespace NzbDrone.Core.Providers +{ + public interface IDropFolderImportService + { + void ProcessDropFolder(string dropFolder); + } + + public class DropFolderImportService : IDropFolderImportService + { + private readonly DiskProvider _diskProvider; + private readonly DiskScanProvider _diskScanProvider; + private readonly ISeriesService _seriesService; + private readonly IMoveEpisodeFiles _episodeFileMover; + private readonly IParsingService _parsingService; + private readonly Logger _logger; + + public DropFolderImportService(DiskProvider diskProvider, + DiskScanProvider diskScanProvider, + ISeriesService seriesService, + IMoveEpisodeFiles episodeFileMover, + IParsingService parsingService, + Logger logger) + { + _diskProvider = diskProvider; + _diskScanProvider = diskScanProvider; + _seriesService = seriesService; + _episodeFileMover = episodeFileMover; + _parsingService = parsingService; + _logger = logger; + } + + public virtual void ProcessDropFolder(string dropFolder) + { + foreach (var subfolder in _diskProvider.GetDirectories(dropFolder)) + { + try + { + if (!_seriesService.SeriesPathExists(subfolder)) + { + ProcessSubFolder(new DirectoryInfo(subfolder)); + } + } + catch (Exception e) + { + _logger.ErrorException("An error has occurred while importing folder: " + subfolder, e); + } + } + + foreach (var videoFile in _diskScanProvider.GetVideoFiles(dropFolder, false)) + { + try + { + var series = _parsingService.GetSeries(videoFile); + ProcessVideoFile(videoFile, series); + } + catch (Exception ex) + { + _logger.ErrorException("An error has occurred while importing video file" + videoFile, ex); + } + } + + //TODO: cleanup empty folders + } + + public void ProcessSubFolder(DirectoryInfo subfolderInfo) + { + if (_diskProvider.GetLastFolderWrite(subfolderInfo.FullName).AddMinutes(2) > DateTime.UtcNow) + { + _logger.Trace("[{0}] is too fresh. skipping", subfolderInfo.FullName); + return; + } + + var series = _parsingService.GetSeries(subfolderInfo.Name); + + if (series == null) + { + _logger.Trace("Unknown Series {0}", subfolderInfo.Name); + return; + } + + var files = _diskScanProvider.GetVideoFiles(subfolderInfo.FullName); + + foreach (var file in files) + { + ProcessVideoFile(file, series); + } + } + + + public void ProcessVideoFile(string videoFile, Series series) + { + if (_diskProvider.GetLastFileWrite(videoFile).AddMinutes(2) > DateTime.UtcNow) + { + _logger.Trace("[{0}] is too fresh. skipping", videoFile); + return; + } + + if (_diskProvider.IsFileLocked(new FileInfo(videoFile))) + { + _logger.Trace("[{0}] is currently locked by another process, skipping", videoFile); + return; + } + + var episodeFile = _diskScanProvider.ImportFile(series, videoFile); + + if (episodeFile != null) + { + _episodeFileMover.MoveEpisodeFile(episodeFile, true); + } + } + + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Providers/PostDownloadProvider.cs b/NzbDrone.Core/Providers/PostDownloadProvider.cs deleted file mode 100644 index 0f5fe96ef..000000000 --- a/NzbDrone.Core/Providers/PostDownloadProvider.cs +++ /dev/null @@ -1,209 +0,0 @@ -using System; -using System.IO; -using System.Linq; -using System.Text.RegularExpressions; -using NLog; -using NzbDrone.Common; -using NzbDrone.Core.MediaFiles; -using NzbDrone.Core.Tv; -using NzbDrone.Core.Model; - -namespace NzbDrone.Core.Providers -{ - public class PostDownloadProvider - { - private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); - - private static readonly Regex StatusRegex = new Regex(@"^_[\w_]*_", RegexOptions.Compiled); - private readonly DiskProvider _diskProvider; - private readonly DiskScanProvider _diskScanProvider; - private readonly ISeriesRepository _seriesRepository; - private readonly IMoveEpisodeFiles _episodeFileMover; - - public PostDownloadProvider(DiskProvider diskProvider, DiskScanProvider diskScanProvider, ISeriesRepository seriesRepository, IMoveEpisodeFiles episodeFileMover) - { - _diskProvider = diskProvider; - _diskScanProvider = diskScanProvider; - _seriesRepository = seriesRepository; - _episodeFileMover = episodeFileMover; - } - - public PostDownloadProvider() - { - } - - public virtual void ProcessDropFolder(string dropFolder) - { - foreach (var subfolder in _diskProvider.GetDirectories(dropFolder)) - { - try - { - if (!_seriesRepository.SeriesPathExists(subfolder)) - { - ProcessDownload(new DirectoryInfo(subfolder)); - } - } - catch (Exception e) - { - Logger.ErrorException("An error has occurred while importing folder: " + subfolder, e); - } - } - - foreach(var videoFile in _diskScanProvider.GetVideoFiles(dropFolder, false)) - { - try - { - ProcessVideoFile(videoFile); - } - catch(Exception ex) - { - Logger.ErrorException("An error has occurred while importing video file" + videoFile, ex); - } - } - } - - public virtual void ProcessDownload(DirectoryInfo subfolderInfo) - { - if (subfolderInfo.Name.StartsWith("_") && _diskProvider.GetLastDirectoryWrite(subfolderInfo.FullName).AddMinutes(2) > DateTime.UtcNow) - { - Logger.Trace("[{0}] is too fresh. skipping", subfolderInfo.Name); - return; - } - - if (_diskProvider.IsFolderLocked(subfolderInfo.FullName)) - { - Logger.Trace("[{0}] is currently locked by another process, skipping", subfolderInfo.Name); - return; - } - - string seriesName = Parser.ParseSeriesName(RemoveStatusFromFolderName(subfolderInfo.Name)); - var series = _seriesRepository.GetByTitle(seriesName); - - if (series == null) - { - Logger.Trace("Unknown Series on Import: {0}", subfolderInfo.Name); - TagFolder(subfolderInfo, PostDownloadStatusType.UnknownSeries); - return; - } - - if (!_diskProvider.FolderExists(series.Path)) - { - Logger.Warn("Series Folder doesn't exist: {0}, creating it", series.Path); - _diskProvider.CreateDirectory(series.Path); - } - - var size = _diskProvider.GetDirectorySize(subfolderInfo.FullName); - var freeSpace = _diskProvider.FreeDiskSpace(series.Path); - - if (Convert.ToUInt64(size) > freeSpace) - { - Logger.Error("Not enough free disk space for series: {0}, {1}", series.Title, series.Path); - return; - } - - _diskScanProvider.CleanUpDropFolder(subfolderInfo.FullName); - - var importedFiles = _diskScanProvider.Scan(series, subfolderInfo.FullName); - importedFiles.ForEach(file => _episodeFileMover.MoveEpisodeFile(file, true)); - - //Delete the folder only if folder is small enough - if (_diskProvider.GetDirectorySize(subfolderInfo.FullName) < Constants.IgnoreFileSize) - { - Logger.Trace("Episode(s) imported, deleting folder: {0}", subfolderInfo.Name); - _diskProvider.DeleteFolder(subfolderInfo.FullName, true); - } - else - { - if (importedFiles.Count == 0) - { - Logger.Trace("No Imported files: {0}", subfolderInfo.Name); - TagFolder(subfolderInfo, PostDownloadStatusType.ParseError); - } - else - { - //Unknown Error Importing (Possibly a lesser quality than episode currently on disk) - Logger.Trace("Unable to import series (Unknown): {0}", subfolderInfo.Name); - TagFolder(subfolderInfo, PostDownloadStatusType.Unknown); - } - } - } - - public virtual void ProcessVideoFile(string videoFile) - { - if (_diskProvider.GetLastFileWrite(videoFile).AddMinutes(2) > DateTime.UtcNow) - { - Logger.Trace("[{0}] is too fresh. skipping", videoFile); - return; - } - - if (_diskProvider.IsFileLocked(new FileInfo(videoFile))) - { - Logger.Trace("[{0}] is currently locked by another process, skipping", videoFile); - return; - } - - var seriesName = Parser.ParseSeriesName(Path.GetFileNameWithoutExtension(videoFile)); - var series = _seriesRepository.GetByTitle(seriesName); - - if (series == null) - { - Logger.Trace("Unknown Series on Import: {0}", videoFile); - return; - } - - if (!_diskProvider.FolderExists(series.Path)) - { - Logger.Warn("Series Folder doesn't exist: {0}", series.Path); - return; - } - - var size = _diskProvider.GetSize(videoFile); - var freeSpace = _diskProvider.FreeDiskSpace(series.Path); - - if (Convert.ToUInt64(size) > freeSpace) - { - Logger.Error("Not enough free disk space for series: {0}, {1}", series.Title, series.Path); - return; - } - - var episodeFile = _diskScanProvider.ImportFile(series, videoFile); - if (episodeFile != null) - { - _episodeFileMover.MoveEpisodeFile(episodeFile, true); - } - } - - private void TagFolder(DirectoryInfo directory, PostDownloadStatusType status) - { - //Turning off tagging folder for now, to stop messing people's series folders. - return; - var target = GetTaggedFolderName(directory, status); - - if (!DiskProvider.PathEquals(target, directory.FullName)) - { - Logger.Warn("Unable to download [{0}]. Status: {1}",directory.Name, status); - _diskProvider.MoveDirectory(directory.FullName, target); - } - else - { - Logger.Debug("Unable to download [{0}], {1}", directory.Name, status); - } - } - - public static string GetTaggedFolderName(DirectoryInfo directoryInfo, PostDownloadStatusType status) - { - if (status == PostDownloadStatusType.NoError) - throw new InvalidOperationException("Can't tag a folder with a None-error status. " + status); - - string cleanName = RemoveStatusFromFolderName(directoryInfo.Name); - string newName = string.Format("_{0}_{1}", status, cleanName); - - return Path.Combine(directoryInfo.Parent.FullName, newName); - } - - public static string RemoveStatusFromFolderName(string folderName) - { - return StatusRegex.Replace(folderName, string.Empty); - } - } -} \ No newline at end of file diff --git a/NzbDrone.Core/Providers/RecycleBinProvider.cs b/NzbDrone.Core/Providers/RecycleBinProvider.cs index 46ada2e0a..857ad77bd 100644 --- a/NzbDrone.Core/Providers/RecycleBinProvider.cs +++ b/NzbDrone.Core/Providers/RecycleBinProvider.cs @@ -114,7 +114,7 @@ public virtual void Cleanup() foreach (var folder in _diskProvider.GetDirectories(_configService.RecycleBin)) { - if (_diskProvider.GetLastDirectoryWrite(folder).AddDays(7) > DateTime.UtcNow) + if (_diskProvider.GetLastFolderWrite(folder).AddDays(7) > DateTime.UtcNow) { logger.Trace("Folder hasn't expired yet, skipping: {0}", folder); continue; diff --git a/NzbDrone.Core/Providers/MediaInfoProvider.cs b/NzbDrone.Core/Providers/VideoFileInfoReader.cs similarity index 84% rename from NzbDrone.Core/Providers/MediaInfoProvider.cs rename to NzbDrone.Core/Providers/VideoFileInfoReader.cs index 7cde3afed..bceb048ca 100644 --- a/NzbDrone.Core/Providers/MediaInfoProvider.cs +++ b/NzbDrone.Core/Providers/VideoFileInfoReader.cs @@ -1,8 +1,5 @@ using System; -using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text; using MediaInfoLib; using NLog; using NzbDrone.Common; @@ -10,22 +7,26 @@ namespace NzbDrone.Core.Providers { - public class MediaInfoProvider + public interface IVideoFileInfoReader + { + MediaInfoModel GetMediaInfo(string filename); + TimeSpan GetRunTime(string filename); + } + + public class VideoFileInfoReader : IVideoFileInfoReader { private readonly DiskProvider _diskProvider; + private readonly Logger _logger; - private static readonly Logger logger = LogManager.GetCurrentClassLogger(); - public MediaInfoProvider(DiskProvider diskProvider) + public VideoFileInfoReader(DiskProvider diskProvider, Logger logger) { _diskProvider = diskProvider; + _logger = logger; } - public MediaInfoProvider() - { - } - public virtual MediaInfoModel GetMediaInfo(string filename) + public MediaInfoModel GetMediaInfo(string filename) { if (!_diskProvider.FileExists(filename)) throw new FileNotFoundException("Media file does not exist: " + filename); @@ -34,7 +35,7 @@ public virtual MediaInfoModel GetMediaInfo(string filename) try { - logger.Trace("Getting media info from {0}", filename); + _logger.Trace("Getting media info from {0}", filename); mediaInfo.Option("ParseSpeed", "0.2"); int open = mediaInfo.Open(filename); @@ -102,20 +103,20 @@ public virtual MediaInfoModel GetMediaInfo(string filename) } catch (Exception ex) { - logger.ErrorException("Unable to parse media info from file: " + filename, ex); + _logger.ErrorException("Unable to parse media info from file: " + filename, ex); mediaInfo.Close(); } return null; } - public virtual Int32 GetRunTime(string filename) + public TimeSpan GetRunTime(string filename) { var mediaInfo = new MediaInfo(); try { - logger.Trace("Getting media info from {0}", filename); + _logger.Trace("Getting media info from {0}", filename); mediaInfo.Option("ParseSpeed", "0.2"); int open = mediaInfo.Open(filename); @@ -126,16 +127,16 @@ public virtual Int32 GetRunTime(string filename) Int32.TryParse(mediaInfo.Get(StreamKind.General, 0, "PlayTime"), out runTime); mediaInfo.Close(); - return runTime / 1000; //Convert to seconds + return TimeSpan.FromMilliseconds(runTime); } } catch (Exception ex) { - logger.ErrorException("Unable to parse media info from file: " + filename, ex); + _logger.ErrorException("Unable to parse media info from file: " + filename, ex); mediaInfo.Close(); } - return 0; + return new TimeSpan(); } } } diff --git a/NzbDrone.Core/RootFolders/RootFolderService.cs b/NzbDrone.Core/RootFolders/RootFolderService.cs index c47be5c0f..0c8964263 100644 --- a/NzbDrone.Core/RootFolders/RootFolderService.cs +++ b/NzbDrone.Core/RootFolders/RootFolderService.cs @@ -41,7 +41,7 @@ public virtual List<RootFolder> All() { if (_diskProvider.FolderExists(folder.Path)) { - folder.FreeSpace = _diskProvider.FreeDiskSpace(folder.Path); + folder.FreeSpace = _diskProvider.GetAvilableSpace(folder.Path); folder.UnmappedFolders = GetUnmappedFolders(folder.Path); } }); @@ -62,7 +62,7 @@ public virtual RootFolder Add(RootFolder rootFolder) _rootFolderRepository.Insert(rootFolder); - rootFolder.FreeSpace = _diskProvider.FreeDiskSpace(rootFolder.Path); + rootFolder.FreeSpace = _diskProvider.GetAvilableSpace(rootFolder.Path); rootFolder.UnmappedFolders = GetUnmappedFolders(rootFolder.Path); return rootFolder; } @@ -113,7 +113,7 @@ public virtual Dictionary<string, ulong> FreeSpaceOnDrives() { try { - freeSpace.Add(pathRoot, _diskProvider.FreeDiskSpace(rootDir.Path)); + freeSpace.Add(pathRoot, _diskProvider.GetAvilableSpace(rootDir.Path)); } catch (Exception ex) { diff --git a/NzbDrone.Core/Tv/Episode.cs b/NzbDrone.Core/Tv/Episode.cs index 7f4ccfef9..addc4c10f 100644 --- a/NzbDrone.Core/Tv/Episode.cs +++ b/NzbDrone.Core/Tv/Episode.cs @@ -35,45 +35,37 @@ public bool HasFile get { return EpisodeFile != null; } } - public int EpisodeFileId + public int EpisodeFileId { get; set; } + + + public EpisodeStatuses Status { get { - if (!HasFile) return 0; - return EpisodeFile.Id; - } - } - - - - public EpisodeStatusType Status - { - get - { - if (HasFile) return EpisodeStatusType.Ready; + if (HasFile) return EpisodeStatuses.Ready; if (GrabDate != null) { if (PostDownloadStatus == PostDownloadStatusType.Unpacking) - return EpisodeStatusType.Unpacking; + return EpisodeStatuses.Unpacking; if (PostDownloadStatus == PostDownloadStatusType.Failed) - return EpisodeStatusType.Failed; + return EpisodeStatuses.Failed; if (GrabDate.Value.AddDays(1) >= DateTime.Now) - return EpisodeStatusType.Downloading; + return EpisodeStatuses.Downloading; } if (GrabDate != null && GrabDate.Value.AddDays(1) >= DateTime.Now) - return EpisodeStatusType.Downloading; + return EpisodeStatuses.Downloading; if (AirDate != null && AirDate.Value.Date == DateTime.Today) - return EpisodeStatusType.AirsToday; + return EpisodeStatuses.AirsToday; if (AirDate != null && AirDate.Value.Date < DateTime.Now) - return EpisodeStatusType.Missing; + return EpisodeStatuses.Missing; - return EpisodeStatusType.NotAired; + return EpisodeStatuses.NotAired; } } diff --git a/NzbDrone.Core/Tv/EpisodeRepository.cs b/NzbDrone.Core/Tv/EpisodeRepository.cs index e66a1adbe15d57b6de9396b90158f2259ee3bc0f..98d43f63495d240abc5b21abaaca7a11b73ee1da 100644 GIT binary patch delta 491 zcmdmG)@MDTO0u*#GcR4iuPVu<C_gV%&pE#+RnIp+B{gSb`7fq=1t2KP&rDGWPAv(@ zFD`M(FVD-#PfQ6eNh~QX*2v5&QAjPwEC#CgOwm!mR1s2Hkg8A&R;+2w%LOtH1YkzG zW##}iq8kG;H4QAYIg^>0a}tN3J4^$n4d|LNRUo-xvLcJv<Ov)slWlmolJZi^6<i^X zSEyF-Oi{4K?-!sv#3u^1Ixv+AwstV49;VHcKe8*x!JLlWuahg;RY0x@$L|`bJ0WHO S9Rdj+91cNNyg7#F9v=Y0v91CD delta 20 ccmeCP-eoqSYU8x;Oq)emesgR-z;})h0Az&;F8}}l diff --git a/NzbDrone.Core/Tv/EpisodeService.cs b/NzbDrone.Core/Tv/EpisodeService.cs index 83a094f5d..8142d64b2 100644 --- a/NzbDrone.Core/Tv/EpisodeService.cs +++ b/NzbDrone.Core/Tv/EpisodeService.cs @@ -15,11 +15,10 @@ namespace NzbDrone.Core.Tv public interface IEpisodeService { Episode GetEpisode(int id); - Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber); + Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useScene = false); Episode GetEpisode(int seriesId, DateTime date); List<Episode> GetEpisodeBySeries(int seriesId); List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber); - List<Episode> GetEpisodesByParseResult(ParseResult parseResult); List<Episode> EpisodesWithoutFiles(bool includeSpecials); List<Episode> GetEpisodesByFileId(int episodeFileId); List<Episode> EpisodesWithFiles(); @@ -27,7 +26,7 @@ public interface IEpisodeService void UpdateEpisode(Episode episode); List<int> GetEpisodeNumbersBySeason(int seriesId, int seasonNumber); void SetEpisodeIgnore(int episodeId, bool isIgnored); - bool IsFirstOrLastEpisodeOfSeason(int seriesId, int seasonNumber, int episodeNumber); + bool IsFirstOrLastEpisodeOfSeason(int episodeId); void SetPostDownloadStatus(List<int> episodeIds, PostDownloadStatusType postDownloadStatus); void UpdateEpisodes(List<Episode> episodes); List<Episode> EpisodesBetweenDates(DateTime start, DateTime end); @@ -36,7 +35,8 @@ public interface IEpisodeService public class EpisodeService : IEpisodeService, IHandle<EpisodeGrabbedEvent>, IHandle<EpisodeFileDeletedEvent>, - IHandleAsync<SeriesDeletedEvent>, + IHandle<EpisodeFileAddedEvent>, + IHandleAsync<SeriesDeletedEvent>, IHandleAsync<SeriesAddedEvent> { @@ -65,8 +65,12 @@ public Episode GetEpisode(int id) return _episodeRepository.Get(id); } - public Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber) + public Episode GetEpisode(int seriesId, int seasonNumber, int episodeNumber, bool useSceneNumbering = false) { + if (useSceneNumbering) + { + return _episodeRepository.GetEpisodeBySceneNumbering(seriesId, seasonNumber, episodeNumber); + } return _episodeRepository.Get(seriesId, seasonNumber, episodeNumber); } @@ -85,86 +89,6 @@ public List<Episode> GetEpisodesBySeason(int seriesId, int seasonNumber) return _episodeRepository.GetEpisodes(seriesId, seasonNumber); } - public List<Episode> GetEpisodesByParseResult(ParseResult parseResult) - { - var result = new List<Episode>(); - - if (parseResult.AirDate.HasValue) - { - if (parseResult.Series.SeriesType == SeriesTypes.Standard) - { - //Todo: Collect this as a Series we want to treat as a daily series, or possible parsing error - logger.Warn("Found daily-style episode for non-daily series: {0}. {1}", parseResult.Series.Title, parseResult.OriginalString); - return new List<Episode>(); - } - - var episodeInfo = GetEpisode(parseResult.Series.Id, parseResult.AirDate.Value); - - if (episodeInfo != null) - { - result.Add(episodeInfo); - parseResult.EpisodeTitle = episodeInfo.Title; - } - - return result; - } - - if (parseResult.EpisodeNumbers == null) - return result; - - //Set it to empty before looping through the episode numbers - parseResult.EpisodeTitle = String.Empty; - - foreach (var episodeNumber in parseResult.EpisodeNumbers) - { - Episode episodeInfo = null; - - if (parseResult.SceneSource && parseResult.Series.UseSceneNumbering) - { - episodeInfo = _episodeRepository.GetEpisodeBySceneNumbering(parseResult.Series.Id, - parseResult.SeasonNumber, episodeNumber); - } - - if (episodeInfo == null) - { - episodeInfo = GetEpisode(parseResult.Series.Id, parseResult.SeasonNumber, episodeNumber); - if (episodeInfo == null && parseResult.AirDate != null) - { - episodeInfo = GetEpisode(parseResult.Series.Id, parseResult.AirDate.Value); - } - } - - if (episodeInfo != null) - { - result.Add(episodeInfo); - - if (parseResult.Series.UseSceneNumbering) - { - logger.Info("Using Scene to TVDB Mapping for: {0} - Scene: {1}x{2:00} - TVDB: {3}x{4:00}", - parseResult.Series.Title, - episodeInfo.SceneSeasonNumber, - episodeInfo.SceneEpisodeNumber, - episodeInfo.SeasonNumber, - episodeInfo.EpisodeNumber); - } - - if (parseResult.EpisodeNumbers.Count == 1) - { - parseResult.EpisodeTitle = episodeInfo.Title.Trim(); - } - else - { - parseResult.EpisodeTitle = Parser.CleanupEpisodeTitle(episodeInfo.Title); - } - } - else - { - logger.Debug("Unable to find {0}", parseResult); - } - } - - return result; - } public List<Episode> EpisodesWithoutFiles(bool includeSpecials) { @@ -307,16 +231,15 @@ public void SetEpisodeIgnore(int episodeId, bool isIgnored) logger.Info("Ignore flag for Episode:{0} was set to {1}", episodeId, isIgnored); } - public bool IsFirstOrLastEpisodeOfSeason(int seriesId, int seasonNumber, int episodeNumber) + public bool IsFirstOrLastEpisodeOfSeason(int episodeId) { - var episodes = GetEpisodesBySeason(seriesId, seasonNumber).OrderBy(e => e.EpisodeNumber); + var episode = GetEpisode(episodeId); + var seasonEpisodes = GetEpisodesBySeason(episode.SeriesId, episode.SeasonNumber); - if (!episodes.Any()) - return false; //Ensure that this is either the first episode //or is the last episode in a season that has 10 or more episodes - if (episodes.First().EpisodeNumber == episodeNumber || (episodes.Count() >= 10 && episodes.Last().EpisodeNumber == episodeNumber)) + if (seasonEpisodes.First().EpisodeNumber == episode.EpisodeNumber || (seasonEpisodes.Count() >= 10 && seasonEpisodes.Last().EpisodeNumber == episode.EpisodeNumber)) return true; return false; @@ -363,7 +286,7 @@ public List<Episode> EpisodesBetweenDates(DateTime start, DateTime end) public void Handle(EpisodeGrabbedEvent message) { - foreach (var episode in message.ParseResult.Episodes) + foreach (var episode in message.Episode.Episodes) { logger.Trace("Marking episode {0} as fetched.", episode.Id); episode.GrabDate = DateTime.UtcNow; @@ -394,5 +317,15 @@ public void HandleAsync(SeriesAddedEvent message) { RefreshEpisodeInfo(message.Series); } + + public void Handle(EpisodeFileAddedEvent message) + { + foreach (var episode in message.EpisodeFile.Episodes.Value) + { + _episodeRepository.SetFileId(episode.Id, message.EpisodeFile.Id); + _episodeRepository.SetPostDownloadStatus(episode.Id, PostDownloadStatusType.NoError); + _logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.Path, episode); + } + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Model/EpisodeStatusType.cs b/NzbDrone.Core/Tv/EpisodeStatuses.cs similarity index 93% rename from NzbDrone.Core/Model/EpisodeStatusType.cs rename to NzbDrone.Core/Tv/EpisodeStatuses.cs index 7c6fa61d0..0098daa5d 100644 --- a/NzbDrone.Core/Model/EpisodeStatusType.cs +++ b/NzbDrone.Core/Tv/EpisodeStatuses.cs @@ -1,6 +1,6 @@ -namespace NzbDrone.Core.Model +namespace NzbDrone.Core.Tv { - public enum EpisodeStatusType + public enum EpisodeStatuses { /// <summary> /// Episode has not aired yet @@ -24,7 +24,7 @@ public enum EpisodeStatusType /// files are available /// </summary> AirsToday, - + /// <summary> /// Episode is being downloaded /// </summary> diff --git a/NzbDrone.Core/Tv/Series.cs b/NzbDrone.Core/Tv/Series.cs index 8b38e2b6e..d542015e8 100644 --- a/NzbDrone.Core/Tv/Series.cs +++ b/NzbDrone.Core/Tv/Series.cs @@ -36,7 +36,6 @@ public Series() public int QualityProfileId { get; set; } public bool SeasonFolder { get; set; } public DateTime? LastInfoSync { get; set; } - public DateTime? LastDiskSync { get; set; } public int Runtime { get; set; } public List<MediaCover.MediaCover> Images { get; set; } public SeriesTypes SeriesType { get; set; } diff --git a/NzbDrone.Core/Tv/SeriesRepository.cs b/NzbDrone.Core/Tv/SeriesRepository.cs index 1c80d302a..65c5ebda9 100644 --- a/NzbDrone.Core/Tv/SeriesRepository.cs +++ b/NzbDrone.Core/Tv/SeriesRepository.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using NzbDrone.Core.Datastore; @@ -8,7 +9,7 @@ public interface ISeriesRepository : IBasicRepository<Series> { bool SeriesPathExists(string path); List<Series> Search(string title); - Series GetByTitle(string cleanTitle); + Series FindByTitle(string cleanTitle); Series FindByTvdbId(int tvdbId); void SetSeriesType(int seriesId, SeriesTypes seriesTypes); void SetTvRageId(int seriesId, int tvRageId); @@ -31,9 +32,9 @@ public List<Series> Search(string title) return Query.Where(s => s.Title.Contains(title)); } - public Series GetByTitle(string cleanTitle) + public Series FindByTitle(string cleanTitle) { - return Query.SingleOrDefault(s => s.CleanTitle.Equals(cleanTitle)); + return Query.SingleOrDefault(s => s.CleanTitle.Equals(cleanTitle, StringComparison.InvariantCultureIgnoreCase)); } public Series FindByTvdbId(int tvdbId) diff --git a/NzbDrone.Core/Tv/SeriesService.cs b/NzbDrone.Core/Tv/SeriesService.cs index 6c929b389..a8892f032 100644 --- a/NzbDrone.Core/Tv/SeriesService.cs +++ b/NzbDrone.Core/Tv/SeriesService.cs @@ -12,6 +12,7 @@ using NzbDrone.Core.MetadataSource; using NzbDrone.Core.Model; using NzbDrone.Core.Organizer; +using NzbDrone.Core.Parser; using NzbDrone.Core.RootFolders; using NzbDrone.Core.Tv.Events; @@ -25,10 +26,12 @@ public interface ISeriesService void AddSeries(Series newSeries); void UpdateFromSeriesEditor(IList<Series> editedSeries); Series FindByTvdbId(int tvdbId); + Series FindByTitle(string title); void SetSeriesType(int seriesId, SeriesTypes seriesTypes); void DeleteSeries(int seriesId, bool deleteFiles); List<Series> GetAllSeries(); void UpdateSeries(Series series); + bool SeriesPathExists(string folder); } public class SeriesService : ISeriesService, IHandleAsync<SeriesAddedEvent> @@ -70,7 +73,7 @@ public Series UpdateSeriesInfo(int seriesId) series.AirTime = tvDbSeries.AirTime; series.Overview = tvDbSeries.Overview; series.Status = tvDbSeries.Status; - series.CleanTitle = Parser.NormalizeTitle(tvDbSeries.Title); + series.CleanTitle = Parser.Parser.NormalizeTitle(tvDbSeries.Title); series.LastInfoSync = DateTime.Now; series.Runtime = tvDbSeries.Runtime; series.Images = tvDbSeries.Images; @@ -93,16 +96,16 @@ public void AddSeries(Series newSeries) { Ensure.That(() => newSeries).IsNotNull(); - if(String.IsNullOrWhiteSpace(newSeries.FolderName)) + if (String.IsNullOrWhiteSpace(newSeries.FolderName)) { newSeries.FolderName = FileNameBuilder.CleanFilename(newSeries.Title); - _diskProvider.CreateDirectory(Path.Combine(_rootFolderService.Get(newSeries.RootFolderId).Path, newSeries.FolderName)); + _diskProvider.CreateFolder(Path.Combine(_rootFolderService.Get(newSeries.RootFolderId).Path, newSeries.FolderName)); } _logger.Info("Adding Series [{0}] Path: [{1}]", newSeries.Title, newSeries.Path); newSeries.Monitored = true; - newSeries.CleanTitle = Parser.NormalizeTitle(newSeries.Title); + newSeries.CleanTitle = Parser.Parser.NormalizeTitle(newSeries.Title); if (newSeries.QualityProfileId == 0) newSeries.QualityProfileId = _configService.DefaultQualityProfile; @@ -143,6 +146,11 @@ public Series FindByTvdbId(int tvdbId) return _seriesRepository.FindByTvdbId(tvdbId); } + public Series FindByTitle(string title) + { + return _seriesRepository.FindByTitle(Parser.Parser.NormalizeTitle(title)); + } + public void SetSeriesType(int seriesId, SeriesTypes seriesTypes) { _seriesRepository.SetSeriesType(seriesId, seriesTypes); @@ -165,6 +173,11 @@ public void UpdateSeries(Series series) _seriesRepository.Update(series); } + public bool SeriesPathExists(string folder) + { + return _seriesRepository.SeriesPathExists(folder); + } + public void HandleAsync(SeriesAddedEvent message) { UpdateSeriesInfo(message.Series.Id); diff --git a/NzbDrone.Core/Update/AvailableUpdateService.cs b/NzbDrone.Core/Update/UpdatePackageProvider.cs similarity index 67% rename from NzbDrone.Core/Update/AvailableUpdateService.cs rename to NzbDrone.Core/Update/UpdatePackageProvider.cs index f8226abca..e8b2b0f23 100644 --- a/NzbDrone.Core/Update/AvailableUpdateService.cs +++ b/NzbDrone.Core/Update/UpdatePackageProvider.cs @@ -1,33 +1,41 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Text.RegularExpressions; +using NLog; using NzbDrone.Common; using NzbDrone.Core.Configuration; namespace NzbDrone.Core.Update { - public interface IAvailableUpdateService + public interface IUpdatePackageProvider { IEnumerable<UpdatePackage> GetAvailablePackages(); + UpdatePackage GetLatestUpdate(); } - public class AvailableUpdateService : IAvailableUpdateService + public class UpdatePackageProvider : IUpdatePackageProvider { private readonly IConfigService _configService; private readonly IHttpProvider _httpProvider; + private readonly Logger _logger; private static readonly Regex ParseRegex = new Regex(@"(?:\>)(?<filename>NzbDrone.+?(?<version>\d+\.\d+\.\d+\.\d+).+?)(?:\<\/A\>)", RegexOptions.IgnoreCase); - public AvailableUpdateService(IConfigService configService, IHttpProvider httpProvider) + public UpdatePackageProvider(IConfigService configService, IHttpProvider httpProvider, Logger logger) { _configService = configService; _httpProvider = httpProvider; + _logger = logger; } public IEnumerable<UpdatePackage> GetAvailablePackages() { var updateList = new List<UpdatePackage>(); var updateUrl = _configService.UpdateUrl; + + _logger.Debug("Getting a list of updates from {0}", updateUrl); + var rawUpdateList = _httpProvider.DownloadString(updateUrl); var matches = ParseRegex.Matches(rawUpdateList); @@ -40,7 +48,14 @@ public IEnumerable<UpdatePackage> GetAvailablePackages() updateList.Add(updatePackage); } + _logger.Debug("Found {0} update packages", updateUrl.Length); + return updateList; } + + public UpdatePackage GetLatestUpdate() + { + return GetAvailablePackages().OrderByDescending(c => c.Version).FirstOrDefault(); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Update/UpdateProvider.cs b/NzbDrone.Core/Update/UpdateProvider.cs index 9675b1501..8e680e0e6 100644 --- a/NzbDrone.Core/Update/UpdateProvider.cs +++ b/NzbDrone.Core/Update/UpdateProvider.cs @@ -11,35 +11,35 @@ namespace NzbDrone.Core.Update { public interface IUpdateService { - UpdatePackage GetAvailableUpdate(Version currentVersion); - Dictionary<DateTime, string> UpdateLogFile(); + UpdatePackage GetAvailableUpdate(); + Dictionary<DateTime, string> GetUpdateLogFiles(); } } public class UpdateService : IUpdateService { - private readonly IAvailableUpdateService _availableUpdateService; + private readonly IUpdatePackageProvider _updatePackageProvider; private readonly EnvironmentProvider _environmentProvider; private readonly DiskProvider _diskProvider; private readonly Logger _logger; - public UpdateService(IAvailableUpdateService availableUpdateService, EnvironmentProvider environmentProvider, DiskProvider diskProvider, Logger logger) + public UpdateService(IUpdatePackageProvider updatePackageProvider, EnvironmentProvider environmentProvider, DiskProvider diskProvider, Logger logger) { - _availableUpdateService = availableUpdateService; + _updatePackageProvider = updatePackageProvider; _environmentProvider = environmentProvider; _diskProvider = diskProvider; _logger = logger; } - public UpdatePackage GetAvailableUpdate(Version currentVersion) + public UpdatePackage GetAvailableUpdate() { - var latestAvailable = _availableUpdateService.GetAvailablePackages().OrderByDescending(c => c.Version).FirstOrDefault(); + var latestAvailable = _updatePackageProvider.GetLatestUpdate(); - if (latestAvailable != null && latestAvailable.Version > currentVersion) + if (latestAvailable != null && latestAvailable.Version > _environmentProvider.Version) { - _logger.Debug("An update is available ({0}) => ({1})", currentVersion, latestAvailable.Version); + _logger.Debug("An update is available ({0}) => ({1})", _environmentProvider.Version, latestAvailable.Version); return latestAvailable; } @@ -47,13 +47,13 @@ public UpdatePackage GetAvailableUpdate(Version currentVersion) return null; } - public Dictionary<DateTime, string> UpdateLogFile() + public Dictionary<DateTime, string> GetUpdateLogFiles() { var list = new Dictionary<DateTime, string>(); - CultureInfo provider = CultureInfo.InvariantCulture; if (_diskProvider.FolderExists(_environmentProvider.GetUpdateLogFolder())) { + var provider = CultureInfo.InvariantCulture; var files = _diskProvider.GetFiles(_environmentProvider.GetUpdateLogFolder(), SearchOption.TopDirectoryOnly).ToList(); foreach (var file in files.Select(c => new FileInfo(c)).OrderByDescending(c => c.Name)) diff --git a/NzbDrone.ncrunchsolution b/NzbDrone.ncrunchsolution index 444b34b1d..969da6dd4 100644 --- a/NzbDrone.ncrunchsolution +++ b/NzbDrone.ncrunchsolution @@ -1,6 +1,6 @@ <SolutionConfiguration> <FileVersion>1</FileVersion> - <AutoEnableOnStartup>False</AutoEnableOnStartup> + <AutoEnableOnStartup>True</AutoEnableOnStartup> <AllowParallelTestExecution>true</AllowParallelTestExecution> <AllowTestsToRunInParallelWithThemselves>true</AllowTestsToRunInParallelWithThemselves> <FrameworkUtilisationTypeForNUnit>UseDynamicAnalysis</FrameworkUtilisationTypeForNUnit> diff --git a/UI/.idea/workspace (KEIVANB-W520's conflicted copy 2013-04-12).xml b/UI/.idea/workspace (KEIVANB-W520's conflicted copy 2013-04-12).xml new file mode 100644 index 000000000..acaea62b3 --- /dev/null +++ b/UI/.idea/workspace (KEIVANB-W520's conflicted copy 2013-04-12).xml @@ -0,0 +1,379 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ChangeListManager"> + <list default="true" id="5e86c40b-3895-4973-999b-c900ff0d6df1" name="Default" comment=""> + <change type="DELETED" beforePath="C:\Dropbox\Git\NzbDrone\UI\Content\Bootstrap\media.less" afterPath="" /> + <change type="DELETED" beforePath="C:\Dropbox\Git\NzbDrone\UI\Content\Bootstrap\mixins.less" afterPath="" /> + <change type="DELETED" beforePath="C:\Dropbox\Git\NzbDrone\UI\Content\Bootstrap\modals.less" afterPath="" /> + <change type="DELETED" beforePath="C:\Dropbox\Git\NzbDrone\UI\Content\Bootstrap\navbar.less" afterPath="" /> + <change type="DELETED" beforePath="C:\Dropbox\Git\NzbDrone\UI\Content\Bootstrap\navs.less" afterPath="" /> + <change type="DELETED" beforePath="C:\Dropbox\Git\NzbDrone\UI\Content\Bootstrap\pager.less" afterPath="" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/../NzbDrone.ncrunchsolution" afterPath="$PROJECT_DIR$/../NzbDrone.ncrunchsolution" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/../NzbDrone.Core/Tv/EpisodeRepository.cs" afterPath="$PROJECT_DIR$/../NzbDrone.Core/Tv/EpisodeRepository.cs" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/../Gruntfile.js" afterPath="$PROJECT_DIR$/../Gruntfile.js" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/../package.json" afterPath="$PROJECT_DIR$/../package.json" /> + <change type="MODIFICATION" beforePath="$PROJECT_DIR$/Content/Bootstrap/reset.less" afterPath="$PROJECT_DIR$/Content/Bootstrap/reset.less" /> + </list> + <ignored path="NzbDrone.UI.iws" /> + <ignored path=".idea/workspace.xml" /> + <file path="/Dummy.txt" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365724686050" ignored="false" /> + <file path="/a.dummy" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365724699951" ignored="false" /> + <file path="/AutoComplete.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365639488201" ignored="false" /> + <file path="/backbone.ajax.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365639501764" ignored="false" /> + <file path="/backbone.modelbinder.mixin.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365654406557" ignored="false" /> + <file path="/Index.html" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365640244425" ignored="false" /> + <file path="/*.regexp" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365642994641" ignored="false" /> + <file path="$PROJECT_DIR$/Series/Delete/DeleteSeriesView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <file path="$PROJECT_DIR$/Calendar/CalendarItemView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <file path="$PROJECT_DIR$/Series/Details/EpisodeItemView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <file path="$PROJECT_DIR$/AddSeries/RootFolders/RootFolderView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <file path="$PROJECT_DIR$/Settings/Quality/Size/QualitySizeView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <file path="$PROJECT_DIR$/Series/Edit/EditSeriesView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <file path="$PROJECT_DIR$/Missing/MissingItemView.js" changelist="5e86c40b-3895-4973-999b-c900ff0d6df1" time="1365643509974" ignored="false" /> + <option name="TRACKING_ENABLED" value="true" /> + <option name="SHOW_DIALOG" value="false" /> + <option name="HIGHLIGHT_CONFLICTS" value="true" /> + <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> + <option name="LAST_RESOLUTION" value="IGNORE" /> + </component> + <component name="ChangesViewManager" flattened_view="true" show_ignored="false" /> + <component name="CreatePatchCommitExecutor"> + <option name="PATCH_PATH" value="" /> + </component> + <component name="DaemonCodeAnalyzer"> + <disable_hints /> + </component> + <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" /> + <component name="FavoritesManager"> + <favorites_list name="NzbDrone.UI" /> + </component> + <component name="FileEditorManager"> + <leaf> + <file leaf-file-name="Controller.js" pinned="false" current="true" current-in-tab="true"> + <entry file="file://$PROJECT_DIR$/Controller.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="92" column="51" selection-start="3820" selection-end="3820" vertical-scroll-proportion="0.4800693"> + <folding /> + </state> + </provider> + </entry> + </file> + <file leaf-file-name="SeriesItemView.js" pinned="false" current="false" current-in-tab="false"> + <entry file="file://$PROJECT_DIR$/Series/Index/SeriesItemView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="43" column="26" selection-start="1217" selection-end="1221" vertical-scroll-proportion="0.0"> + <folding /> + </state> + </provider> + </entry> + </file> + </leaf> + </component> + <component name="FindManager"> + <FindUsagesManager> + <setting name="OPEN_NEW_TAB" value="false" /> + </FindUsagesManager> + </component> + <component name="Git.Settings"> + <option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$/.." /> + </component> + <component name="GitLogSettings"> + <option name="myDateState"> + <MyDateState /> + </option> + </component> + <component name="IdeDocumentHistory"> + <option name="changedFiles"> + <list> + <option value="$PROJECT_DIR$/Missing/MissingItemView.js" /> + <option value="$PROJECT_DIR$/Series/Delete/DeleteSeriesView.js" /> + <option value="$PROJECT_DIR$/Series/Details/EpisodeItemView.js" /> + <option value="$PROJECT_DIR$/Series/Edit/EditSeriesView.js" /> + <option value="$PROJECT_DIR$/Series/Index/SeriesItemView.js" /> + <option value="$PROJECT_DIR$/Settings/DownloadClient/DownloadClientView.js" /> + <option value="$PROJECT_DIR$/Settings/Indexers/IndexersView.js" /> + <option value="$PROJECT_DIR$/Settings/Misc/MiscView.js" /> + <option value="$PROJECT_DIR$/Settings/Naming/NamingView.js" /> + <option value="$PROJECT_DIR$/Settings/Notifications/NotificationsView.js" /> + <option value="$PROJECT_DIR$/Settings/Quality/Profile/EditQualityProfileView.js" /> + <option value="$PROJECT_DIR$/Settings/Quality/Profile/QualityProfileView.js" /> + <option value="$PROJECT_DIR$/Settings/Quality/QualityView.js" /> + <option value="$PROJECT_DIR$/Settings/System/SystemView.js" /> + <option value="$PROJECT_DIR$/Upcoming/UpcomingItemView.js" /> + <option value="$PROJECT_DIR$/Mixins/backbone.modelbinder.mixin.js" /> + </list> + </option> + </component> + <component name="ProjectFrameBounds"> + <option name="x" value="1912" /> + <option name="y" value="-8" /> + <option name="width" value="1936" /> + <option name="height" value="1056" /> + </component> + <component name="ProjectLevelVcsManager" settingsEditedManually="false"> + <OptionsSetting value="true" id="Add" /> + <OptionsSetting value="true" id="Remove" /> + <OptionsSetting value="true" id="Checkout" /> + <OptionsSetting value="true" id="Update" /> + <OptionsSetting value="true" id="Status" /> + <OptionsSetting value="true" id="Edit" /> + <ConfirmationsSetting value="0" id="Add" /> + <ConfirmationsSetting value="0" id="Remove" /> + </component> + <component name="ProjectReloadState"> + <option name="STATE" value="0" /> + </component> + <component name="ProjectView"> + <navigator currentView="ProjectPane" proportions="" version="1" splitterProportion="0.5"> + <flattenPackages /> + <showMembers /> + <showModules /> + <showLibraryContents ProjectPane="true" /> + <hideEmptyPackages /> + <abbreviatePackageNames /> + <autoscrollToSource /> + <autoscrollFromSource /> + <sortByType /> + </navigator> + <panes> + <pane id="Scope" /> + <pane id="ProjectPane"> + <subPane> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="NzbDrone.UI" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="NzbDrone.UI" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="UI" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + <PATH> + <PATH_ELEMENT> + <option name="myItemId" value="NzbDrone.UI" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="UI" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + <PATH_ELEMENT> + <option name="myItemId" value="Mixins" /> + <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" /> + </PATH_ELEMENT> + </PATH> + </subPane> + </pane> + </panes> + </component> + <component name="PropertiesComponent"> + <property name="options.splitter.main.proportions" value="0.3" /> + <property name="WebServerToolWindowFactoryState" value="false" /> + <property name="options.lastSelected" value="preferences.keymap" /> + <property name="FullScreen" value="false" /> + <property name="GoToClass.includeJavaFiles" value="false" /> + <property name="options.searchVisible" value="true" /> + <property name="options.splitter.details.proportions" value="0.2" /> + </component> + <component name="RunManager"> + <configuration default="true" type="DartUnitRunConfigurationType" factoryName="DartUnit"> + <option name="VMOptions" /> + <option name="arguments" /> + <option name="filePath" /> + <option name="scope" value="ALL" /> + <option name="testName" /> + <method /> + </configuration> + <list size="0" /> + </component> + <component name="ShelveChangesManager" show_recycled="false" /> + <component name="TaskManager"> + <task active="true" id="Default" summary="Default task"> + <changelist id="5e86c40b-3895-4973-999b-c900ff0d6df1" name="Default" comment="" /> + <created>1365554071026</created> + <updated>1365554071026</updated> + </task> + <servers /> + </component> + <component name="ToolWindowManager"> + <frame x="1912" y="-8" width="1936" height="1056" extended-state="6" /> + <editor active="true" /> + <layout> + <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> + <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> + <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> + <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> + <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.24934107" sideWeight="0.67" order="0" side_tool="false" content_ui="combo" /> + <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> + <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> + <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> + <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> + <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> + <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> + <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> + <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="SLIDING" type="SLIDING" visible="false" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> + <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" /> + <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> + </layout> + </component> + <component name="VcsContentAnnotationSettings"> + <option name="myLimit" value="2678400000" /> + </component> + <component name="VcsManagerConfiguration"> + <option name="OFFER_MOVE_TO_ANOTHER_CHANGELIST_ON_PARTIAL_COMMIT" value="true" /> + <option name="CHECK_CODE_SMELLS_BEFORE_PROJECT_COMMIT" value="true" /> + <option name="CHECK_NEW_TODO" value="true" /> + <option name="myTodoPanelSettings"> + <value> + <are-packages-shown value="false" /> + <are-modules-shown value="false" /> + <flatten-packages value="false" /> + <is-autoscroll-to-source value="false" /> + </value> + </option> + <option name="PERFORM_UPDATE_IN_BACKGROUND" value="true" /> + <option name="PERFORM_COMMIT_IN_BACKGROUND" value="true" /> + <option name="PERFORM_EDIT_IN_BACKGROUND" value="true" /> + <option name="PERFORM_CHECKOUT_IN_BACKGROUND" value="true" /> + <option name="PERFORM_ADD_REMOVE_IN_BACKGROUND" value="true" /> + <option name="PERFORM_ROLLBACK_IN_BACKGROUND" value="false" /> + <option name="CHECK_LOCALLY_CHANGED_CONFLICTS_IN_BACKGROUND" value="false" /> + <option name="CHANGED_ON_SERVER_INTERVAL" value="60" /> + <option name="SHOW_ONLY_CHANGED_IN_SELECTION_DIFF" value="true" /> + <option name="CHECK_COMMIT_MESSAGE_SPELLING" value="true" /> + <option name="DEFAULT_PATCH_EXTENSION" value="patch" /> + <option name="SHORT_DIFF_HORISONTALLY" value="true" /> + <option name="SHORT_DIFF_EXTRA_LINES" value="2" /> + <option name="SOFT_WRAPS_IN_SHORT_DIFF" value="true" /> + <option name="INCLUDE_TEXT_INTO_PATCH" value="false" /> + <option name="INCLUDE_TEXT_INTO_SHELF" value="false" /> + <option name="SHOW_FILE_HISTORY_DETAILS" value="true" /> + <option name="SHOW_VCS_ERROR_NOTIFICATIONS" value="true" /> + <option name="SHOW_DIRTY_RECURSIVELY" value="false" /> + <option name="LIMIT_HISTORY" value="true" /> + <option name="MAXIMUM_HISTORY_ROWS" value="1000" /> + <option name="UPDATE_FILTER_SCOPE_NAME" /> + <option name="USE_COMMIT_MESSAGE_MARGIN" value="false" /> + <option name="COMMIT_MESSAGE_MARGIN_SIZE" value="72" /> + <option name="WRAP_WHEN_TYPING_REACHES_RIGHT_MARGIN" value="false" /> + <option name="FORCE_NON_EMPTY_COMMENT" value="false" /> + <option name="CLEAR_INITIAL_COMMIT_MESSAGE" value="false" /> + <option name="LAST_COMMIT_MESSAGE" /> + <option name="MAKE_NEW_CHANGELIST_ACTIVE" value="false" /> + <option name="OPTIMIZE_IMPORTS_BEFORE_PROJECT_COMMIT" value="false" /> + <option name="CHECK_FILES_UP_TO_DATE_BEFORE_COMMIT" value="false" /> + <option name="REFORMAT_BEFORE_PROJECT_COMMIT" value="false" /> + <option name="REFORMAT_BEFORE_FILE_COMMIT" value="false" /> + <option name="FILE_HISTORY_DIALOG_COMMENTS_SPLITTER_PROPORTION" value="0.8" /> + <option name="FILE_HISTORY_DIALOG_SPLITTER_PROPORTION" value="0.5" /> + <option name="ACTIVE_VCS_NAME" /> + <option name="UPDATE_GROUP_BY_PACKAGES" value="false" /> + <option name="UPDATE_GROUP_BY_CHANGELIST" value="false" /> + <option name="UPDATE_FILTER_BY_SCOPE" value="false" /> + <option name="SHOW_FILE_HISTORY_AS_TREE" value="false" /> + <option name="FILE_HISTORY_SPLITTER_PROPORTION" value="0.6" /> + </component> + <component name="XDebuggerManager"> + <breakpoint-manager /> + </component> + <component name="editorHistoryManager"> + <entry file="file://$PROJECT_DIR$/Series/Delete/DeleteSeriesView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="18" column="12" selection-start="461" selection-end="461" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Series/Details/EpisodeItemView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="15" column="12" selection-start="335" selection-end="335" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Series/Edit/EditSeriesView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="21" column="12" selection-start="704" selection-end="704" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/DownloadClient/DownloadClientView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="22" column="0" selection-start="725" selection-end="725" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Indexers/IndexersView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="3" column="0" selection-start="24" selection-end="24" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Misc/MiscView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="14" column="0" selection-start="337" selection-end="337" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Naming/NamingView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="18" column="0" selection-start="426" selection-end="426" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Notifications/NotificationsView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="3" column="0" selection-start="24" selection-end="24" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Quality/Profile/EditQualityProfileView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="13" column="0" selection-start="380" selection-end="380" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Quality/Profile/QualityProfileView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="10" column="0" selection-start="245" selection-end="245" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/Quality/QualityView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="9" column="0" selection-start="216" selection-end="216" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Settings/System/SystemView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="3" column="0" selection-start="24" selection-end="24" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Upcoming/UpcomingItemView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="11" column="3" selection-start="252" selection-end="252" vertical-scroll-proportion="0.0" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/JsLibraries/sugar.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="799" column="26" selection-start="24272" selection-end="24277" vertical-scroll-proportion="0.018691588" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Mixins/backbone.modelbinder.mixin.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="22" column="55" selection-start="573" selection-end="573" vertical-scroll-proportion="0.4050633" /> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Series/Index/SeriesItemView.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="43" column="26" selection-start="1217" selection-end="1221" vertical-scroll-proportion="0.0"> + <folding /> + </state> + </provider> + </entry> + <entry file="file://$PROJECT_DIR$/Controller.js"> + <provider selected="true" editor-type-id="text-editor"> + <state line="92" column="51" selection-start="3820" selection-end="3820" vertical-scroll-proportion="0.4800693"> + <folding /> + </state> + </provider> + </entry> + </component> +</project> +