diff --git a/Libraries/TvdbLib.dll b/Libraries/TvdbLib.dll index 06cdeceee..4e2f48986 100644 Binary files a/Libraries/TvdbLib.dll and b/Libraries/TvdbLib.dll differ diff --git a/NzbDrone.Core.Test/IndexerTests.cs b/NzbDrone.Core.Test/IndexerTests.cs index e2a14f3bb..47e549b62 100644 --- a/NzbDrone.Core.Test/IndexerTests.cs +++ b/NzbDrone.Core.Test/IndexerTests.cs @@ -596,7 +596,6 @@ namespace NzbDrone.Core.Test WithConfiguredIndexers(); const string fileName = "wombles.xml"; - const string expectedString = "nzbdetails"; Mocker.GetMock() .Setup(h => h.DownloadStream(It.IsAny(), It.IsAny())) @@ -635,7 +634,6 @@ namespace NzbDrone.Core.Test { WithConfiguredIndexers(); - const string fileName = "nzbindex.xml"; const string expectedString = "release"; Mocker.GetMock() diff --git a/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs b/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs index e754d4d0d..b92ff1258 100644 --- a/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs +++ b/NzbDrone.Core.Test/JobTests/PostDownloadScanJobFixture.cs @@ -44,7 +44,7 @@ namespace NzbDrone.Core.Test.JobTests Mocker.GetMock().Setup(s => s.ProcessDropFolder(path)); Mocker.Resolve().Start(MockNotification, new { Path = path }); - Mocker.GetMock().Verify(s => s.SabDropDirectory, Times.Never()); + Mocker.GetMock().Verify(s => s.DownloadClientTvDirectory, Times.Never()); } [Test] @@ -52,10 +52,10 @@ namespace NzbDrone.Core.Test.JobTests { var path = @"C:\Test\Unsorted TV"; - Mocker.GetMock().SetupGet(s => s.SabDropDirectory).Returns(path); + Mocker.GetMock().SetupGet(s => s.DownloadClientTvDirectory).Returns(path); Mocker.Resolve().Start(MockNotification, null); - Mocker.GetMock().Verify(s => s.SabDropDirectory, Times.Once()); + Mocker.GetMock().Verify(s => s.DownloadClientTvDirectory, Times.Once()); } [Test] @@ -63,7 +63,7 @@ namespace NzbDrone.Core.Test.JobTests { var path = @"C:\Test\Unsorted TV"; - Mocker.GetMock().SetupGet(s => s.SabDropDirectory).Returns(path); + Mocker.GetMock().SetupGet(s => s.DownloadClientTvDirectory).Returns(path); Mocker.Resolve().Start(MockNotification, null); Mocker.GetMock().Verify(s => s.ProcessDropFolder(path), Times.Once()); diff --git a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/BlackholeProviderFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/BlackholeProviderFixture.cs index 0f8a5be95..af4c40858 100644 --- a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/BlackholeProviderFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/BlackholeProviderFixture.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Text; @@ -42,7 +43,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests [Test] public void DownloadNzb_should_download_file_if_it_doesnt_exist() { - Mocker.Resolve().DownloadNzb(nzbUrl, title).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(nzbUrl, nzbPath),Times.Once()); } @@ -52,7 +53,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests { WithExistingFile(); - Mocker.Resolve().DownloadNzb(nzbUrl, title).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny()), Times.Never()); } @@ -62,11 +63,20 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests { WithFailedDownload(); - Mocker.Resolve().DownloadNzb(nzbUrl, title).Should().BeFalse(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeFalse(); ExceptionVerification.ExpectedWarns(1); } + [Test] + public void should_replace_illegal_characters_in_title() + { + var illegalTitle = "Saturday Night Live - S38E08 - Jeremy Renner/Maroon 5 [SDTV]"; + var expectedFilename = Path.Combine(blackHoleFolder, "Saturday Night Live - S38E08 - Jeremy Renner+Maroon 5 [SDTV].nzb"); + 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/ProviderTests/DownloadClientTests/PneumaticProviderFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/PneumaticProviderFixture.cs index 293b7697e..19c74d22b 100644 --- a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/PneumaticProviderFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/PneumaticProviderFixture.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net; using System.Text; @@ -29,7 +30,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests nzbPath = pneumaticFolder + title + ".nzb"; Mocker.GetMock().SetupGet(c => c.PneumaticDirectory).Returns(pneumaticFolder); - Mocker.GetMock().SetupGet(c => c.SabDropDirectory).Returns(sabDrop); + Mocker.GetMock().SetupGet(c => c.DownloadClientTvDirectory).Returns(sabDrop); } private void WithExistingFile() @@ -45,7 +46,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests [Test] public void should_download_file_if_it_doesnt_exist() { - Mocker.Resolve().DownloadNzb(nzbUrl, title).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(nzbUrl, nzbPath),Times.Once()); } @@ -55,7 +56,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests { WithExistingFile(); - Mocker.Resolve().DownloadNzb(nzbUrl, title).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeTrue(); Mocker.GetMock().Verify(c => c.DownloadFile(It.IsAny(), It.IsAny()), Times.Never()); } @@ -65,7 +66,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests { WithFailedDownload(); - Mocker.Resolve().DownloadNzb(nzbUrl, title).Should().BeFalse(); + Mocker.Resolve().DownloadNzb(nzbUrl, title, false).Should().BeFalse(); ExceptionVerification.ExpectedWarns(1); } @@ -73,7 +74,18 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests [Test] public void should_skip_if_full_season_download() { - Mocker.Resolve().DownloadNzb(nzbUrl, "30 Rock - Season 1").Should().BeFalse(); + Mocker.Resolve().DownloadNzb(nzbUrl, "30 Rock - Season 1", false).Should().BeFalse(); + } + + [Test] + 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.GetMock().Verify(c => c.DownloadFile(It.IsAny(), expectedFilename), Times.Once()); } } } diff --git a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/QueueFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/QueueFixture.cs index 7ae9fb0ba..5bbb0f80d 100644 --- a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/QueueFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/QueueFixture.cs @@ -212,7 +212,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.SabProviderTests new object[] { 1, new[] { 5 }, "30 RocK", QualityTypes.HDTV, false }, //Same Series, same quality new object[] { 1, new[] { 5, 6 }, "30 RocK", QualityTypes.HDTV, false }, //Same Series, same quality, one different episode new object[] { 1, new[] { 5, 6 }, "30 RocK", QualityTypes.HDTV, false }, //Same Series, same quality, one different episode - new object[] { 4, new[] { 8 }, "Parks and Recreation", QualityTypes.WEBDL720p }, false, //Same Series, same quality + new object[] { 4, new[] { 8 }, "Parks and Recreation", QualityTypes.WEBDL720p, false }, //Same Series, same quality }; [Test, TestCaseSource("LowerQualityCases")] diff --git a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/SabProviderFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/SabProviderFixture.cs index 50d6e939d..26d7e1dce 100644 --- a/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/SabProviderFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DownloadClientTests/SabProviderTests/SabProviderFixture.cs @@ -11,6 +11,7 @@ using Moq; using NUnit.Framework; using NzbDrone.Common; using NzbDrone.Core.Model; +using NzbDrone.Core.Model.Sabnzbd; using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.DownloadClients; using NzbDrone.Core.Repository; @@ -54,7 +55,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.SabProviderTests .Returns("{ \"status\": true }"); //Act - Mocker.Resolve().DownloadNzb(url, title).Should().BeTrue(); + Mocker.Resolve().DownloadNzb(url, title, false).Should().BeTrue(); } [Test] @@ -66,7 +67,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.SabProviderTests //Act - bool result = Mocker.Resolve().DownloadNzb("http://www.newzbin.com/browse/post/6107863/nzb", title); + bool result = Mocker.Resolve().DownloadNzb("http://www.newzbin.com/browse/post/6107863/nzb", title, false); //Assert result.Should().BeTrue(); @@ -78,7 +79,7 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.SabProviderTests WithFailResponse(); //Act - Assert.Throws(() => Mocker.Resolve().DownloadNzb(url, title).Should().BeFalse()); + Assert.Throws(() => Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse()); //ExceptionVerification.ExpectedErrors(1); } @@ -216,8 +217,52 @@ namespace NzbDrone.Core.Test.ProviderTests.DownloadClientTests.SabProviderTests Mocker.GetMock() .Setup(s => s.DownloadString(It.IsAny())).Throws(new WebException()); - Mocker.Resolve().DownloadNzb(url, title).Should().BeFalse(); + Mocker.Resolve().DownloadNzb(url, title, false).Should().BeFalse(); ExceptionVerification.ExpectedErrors(1); } + + [Test] + public void downloadNzb_should_use_sabRecentTvPriority_when_recentEpisode_is_true() + { + Mocker.GetMock() + .SetupGet(s => s.SabRecentTvPriority) + .Returns(SabPriorityType.High); + + Mocker.GetMock() + .SetupGet(s => s.SabBacklogTvPriority) + .Returns(SabPriorityType.Low); + + Mocker.GetMock() + .Setup(s => s.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")) + .Returns("{ \"status\": true }"); + + //Act + 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()); + } + + [Test] + public void downloadNzb_should_use_sabBackogTvPriority_when_recentEpisode_is_false() + { + Mocker.GetMock() + .SetupGet(s => s.SabRecentTvPriority) + .Returns(SabPriorityType.High); + + Mocker.GetMock() + .SetupGet(s => s.SabBacklogTvPriority) + .Returns(SabPriorityType.Low); + + Mocker.GetMock() + .Setup(s => s.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")) + .Returns("{ \"status\": true }"); + + //Act + 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()); + } } } \ No newline at end of file diff --git a/NzbDrone.Core.Test/ProviderTests/DownloadProviderFixture.cs b/NzbDrone.Core.Test/ProviderTests/DownloadProviderFixture.cs index 5c224f8fb..0a7fbffa9 100644 --- a/NzbDrone.Core.Test/ProviderTests/DownloadProviderFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/DownloadProviderFixture.cs @@ -59,22 +59,22 @@ namespace NzbDrone.Core.Test.ProviderTests private void WithSuccessfullAdd() { Mocker.GetMock() - .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny())) + .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(true); Mocker.GetMock() - .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny())) + .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny(), It.IsAny())) .Returns(true); } private void WithFailedAdd() { Mocker.GetMock() - .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny())) + .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny(), false)) .Returns(false); Mocker.GetMock() - .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny())) + .Setup(s => s.DownloadNzb(It.IsAny(), It.IsAny(), false)) .Returns(false); } @@ -92,10 +92,10 @@ namespace NzbDrone.Core.Test.ProviderTests //Assert Mocker.GetMock() - .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny()), Times.Once()); + .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny(), true), Times.Once()); Mocker.GetMock() - .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny()), Times.Never()); + .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny(), true), Times.Never()); Mocker.GetMock() .Verify(s => s.Add(It.Is(h => h.EpisodeId == 12 && h.SeriesId == 5)), Times.Once()); @@ -127,10 +127,10 @@ namespace NzbDrone.Core.Test.ProviderTests //Assert Mocker.GetMock() - .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny()), Times.Never()); + .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny(), true), Times.Never()); Mocker.GetMock() - .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny()), Times.Once()); + .Verify(s => s.DownloadNzb(It.IsAny(), It.IsAny(), true), Times.Once()); Mocker.GetMock() .Verify(s => s.Add(It.Is(h => h.EpisodeId == 12 && h.SeriesId == 5)), Times.Once()); diff --git a/NzbDrone.Core.Test/ProviderTests/SearchProviderTests/PerformSearchFixture.cs b/NzbDrone.Core.Test/ProviderTests/SearchProviderTests/PerformSearchFixture.cs index ccc13ed59..111081e4e 100644 --- a/NzbDrone.Core.Test/ProviderTests/SearchProviderTests/PerformSearchFixture.cs +++ b/NzbDrone.Core.Test/ProviderTests/SearchProviderTests/PerformSearchFixture.cs @@ -18,6 +18,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests { private const string SCENE_NAME = "Scene Name"; private const int SEASON_NUMBER = 5; + private const int EPISODE_NUMBER = 1; private const int PARSE_RESULT_COUNT = 10; private Mock _episodeIndexer1; @@ -170,26 +171,13 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests public void PerformSearch_should_search_all_enabled_providers() { //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformEpisodeSearch(_series, SEASON_NUMBER, _episodes.First().EpisodeNumber); //Assert VerifyFetchEpisode(Times.Once()); result.Should().HaveCount(PARSE_RESULT_COUNT * 2); } - [Test] - public void PerformSearch_should_look_for_scene_name_to_search() - { - WithSceneName(); - - //Act - Mocker.Resolve().PerformSearch(MockNotification, _series, 1, _episodes); - - //Assert - Mocker.GetMock().Verify(c => c.GetSceneName(_series.SeriesId), - Times.Once()); - } - [Test] public void broken_indexer_should_not_block_other_indexers() { @@ -197,7 +185,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests WithTwoGoodOneBrokenIndexer(); //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER); //Assert result.Should().HaveCount(PARSE_RESULT_COUNT * 2); @@ -215,7 +203,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests public void PerformSearch_for_episode_should_call_FetchEpisode() { //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER); //Assert result.Should().HaveCount(PARSE_RESULT_COUNT * 2); @@ -230,7 +218,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests _series.IsDaily = true; //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformDailyEpisodeSearch(_series, _episodes.First()); //Assert result.Should().HaveCount(PARSE_RESULT_COUNT * 2); @@ -244,7 +232,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests With30Episodes(); //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformPartialSeasonSearch(_series, SEASON_NUMBER, new List{0, 1, 2, 3}); //Assert result.Should().HaveCount(80); @@ -257,7 +245,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests WithNullEpisodes(); //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformSeasonSearch(_series, SEASON_NUMBER); //Assert result.Should().HaveCount(20); @@ -271,7 +259,7 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests WithNullIndexers(); //Act - var result = Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + var result = Mocker.Resolve().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER); //Assert result.Should().HaveCount(0); @@ -283,10 +271,9 @@ namespace NzbDrone.Core.Test.ProviderTests.SearchProviderTests { WithSceneName(); - Mocker.Resolve().PerformSearch(MockNotification, _series, SEASON_NUMBER, _episodes); + Mocker.Resolve().PerformEpisodeSearch(_series, SEASON_NUMBER, EPISODE_NUMBER); VerifyFetchEpisodeWithSceneName(Times.Once()); } - } } diff --git a/NzbDrone.Core/Datastore/Migrations/Migration20121122.cs b/NzbDrone.Core/Datastore/Migrations/Migration20121122.cs new file mode 100644 index 000000000..b81351485 --- /dev/null +++ b/NzbDrone.Core/Datastore/Migrations/Migration20121122.cs @@ -0,0 +1,22 @@ +using System; +using System.Data; +using Migrator.Framework; +using NzbDrone.Common; + +namespace NzbDrone.Core.Datastore.Migrations +{ + [Migration(20121122)] + public class Migration20121122 : NzbDroneMigration + { + protected override void MainDbUpgrade() + { + Database.ExecuteNonQuery("UPDATE Config SET [KEY] = 'SabBacklogTvPriority' WHERE [KEY] = 'SabTvPriority'"); + Database.ExecuteNonQuery("UPDATE Config SET [KEY] = 'DownloadClientTvDirectory' WHERE [KEY] = 'SabTvDropDirectory'"); + + var priority = Database.ExecuteScalar("SELECT [Value] FROM Config WHERE [Key] = 'SabBacklogTvPriority'"); + + if (priority != null) + Database.ExecuteNonQuery("INSERT INTO Config ([Key], [Value]) VALUES('SabRecentTvPriority', '" + priority + "')"); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/Jobs/PostDownloadScanJob.cs b/NzbDrone.Core/Jobs/PostDownloadScanJob.cs index 4ab9b8732..57aa13f76 100644 --- a/NzbDrone.Core/Jobs/PostDownloadScanJob.cs +++ b/NzbDrone.Core/Jobs/PostDownloadScanJob.cs @@ -47,7 +47,7 @@ namespace NzbDrone.Core.Jobs dropFolder = options.Path; else - dropFolder = _configProvider.SabDropDirectory; + dropFolder = _configProvider.DownloadClientTvDirectory; if (String.IsNullOrWhiteSpace(dropFolder)) { diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index ad200824a..ebe4b0ee0 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -230,6 +230,7 @@ + diff --git a/NzbDrone.Core/Parser.cs b/NzbDrone.Core/Parser.cs index e6da55dc7..04bc153ce 100644 --- a/NzbDrone.Core/Parser.cs +++ b/NzbDrone.Core/Parser.cs @@ -220,8 +220,7 @@ namespace NzbDrone.Core } parsedEpisode = new EpisodeParseResult - { - + { AirDate = new DateTime(airyear, airmonth, airday).Date, }; } diff --git a/NzbDrone.Core/Providers/Core/ConfigProvider.cs b/NzbDrone.Core/Providers/Core/ConfigProvider.cs index 09f83adae..44800ea49 100644 --- a/NzbDrone.Core/Providers/Core/ConfigProvider.cs +++ b/NzbDrone.Core/Providers/Core/ConfigProvider.cs @@ -145,18 +145,25 @@ namespace NzbDrone.Core.Providers.Core set { SetValue("SabTvCategory", value); } } - public virtual SabPriorityType SabTvPriority + public virtual SabPriorityType SabBacklogTvPriority { - get { return (SabPriorityType)GetValueInt("SabTvPriority"); } + get { return (SabPriorityType)GetValueInt("SabBacklogTvPriority"); } - set { SetValue("SabTvPriority", (int)value); } + set { SetValue("SabBacklogTvPriority", (int)value); } } - public virtual String SabDropDirectory + public virtual SabPriorityType SabRecentTvPriority { - get { return GetValue("SabTvDropDirectory"); } + get { return (SabPriorityType)GetValueInt("SabRecentTvPriority"); } - set { SetValue("SabTvDropDirectory", value); } + set { SetValue("SabRecentTvPriority", (int)value); } + } + + public virtual String DownloadClientTvDirectory + { + get { return GetValue("DownloadClientTvDirectory"); } + + set { SetValue("DownloadClientTvDirectory", value); } } public virtual bool SortingIncludeSeriesName @@ -557,7 +564,6 @@ namespace NzbDrone.Core.Providers.Core { EnsureCache(); - string dbValue; if (cache.TryGetValue(key, out dbValue) && dbValue != null && !String.IsNullOrEmpty(dbValue)) diff --git a/NzbDrone.Core/Providers/DiskScanProvider.cs b/NzbDrone.Core/Providers/DiskScanProvider.cs index f51e6e95b..a780756ab 100644 --- a/NzbDrone.Core/Providers/DiskScanProvider.cs +++ b/NzbDrone.Core/Providers/DiskScanProvider.cs @@ -206,6 +206,7 @@ namespace NzbDrone.Core.Providers catch (UnauthorizedAccessException ex) { Logger.Debug("Unable to apply folder permissions to: ", newFile.FullName); + Logger.TraceException(ex.Message, ex); } episodeFile.Path = newFile.FullName; diff --git a/NzbDrone.Core/Providers/DownloadClients/BlackholeProvider.cs b/NzbDrone.Core/Providers/DownloadClients/BlackholeProvider.cs index 836501ffb..3698b2f75 100644 --- a/NzbDrone.Core/Providers/DownloadClients/BlackholeProvider.cs +++ b/NzbDrone.Core/Providers/DownloadClients/BlackholeProvider.cs @@ -34,10 +34,12 @@ namespace NzbDrone.Core.Providers.DownloadClients { } - public virtual bool DownloadNzb(string url, string title) + public virtual bool DownloadNzb(string url, string title, bool recentlyAired) { try { + title = MediaFileProvider.CleanFilename(title); + var filename = Path.Combine(_configProvider.BlackholeDirectory, title + ".nzb"); if (_diskProvider.FileExists(filename)) @@ -64,7 +66,5 @@ namespace NzbDrone.Core.Providers.DownloadClients { return !_upgradeHistorySpecification.IsSatisfiedBy(newParseResult); } - - } } diff --git a/NzbDrone.Core/Providers/DownloadClients/IDownloadClient.cs b/NzbDrone.Core/Providers/DownloadClients/IDownloadClient.cs index 1ea0d603d..1cdc2988b 100644 --- a/NzbDrone.Core/Providers/DownloadClients/IDownloadClient.cs +++ b/NzbDrone.Core/Providers/DownloadClients/IDownloadClient.cs @@ -6,6 +6,6 @@ namespace NzbDrone.Core.Providers.DownloadClients public interface IDownloadClient { bool IsInQueue(EpisodeParseResult newParseResult); - bool DownloadNzb(string url, string title); + bool DownloadNzb(string url, string title, bool recentlyAired); } } diff --git a/NzbDrone.Core/Providers/DownloadClients/PneumaticProvider.cs b/NzbDrone.Core/Providers/DownloadClients/PneumaticProvider.cs index 0a6e557dd..1e94da2a6 100644 --- a/NzbDrone.Core/Providers/DownloadClients/PneumaticProvider.cs +++ b/NzbDrone.Core/Providers/DownloadClients/PneumaticProvider.cs @@ -33,7 +33,7 @@ namespace NzbDrone.Core.Providers.DownloadClients { } - public virtual bool DownloadNzb(string url, string title) + public virtual bool DownloadNzb(string url, string title, bool recentlyAired) { try { @@ -44,6 +44,8 @@ namespace NzbDrone.Core.Providers.DownloadClients return false; } + title = MediaFileProvider.CleanFilename(title); + //Save to the Pneumatic directory (The user will need to ensure its accessible by XBMC) var filename = Path.Combine(_configProvider.PneumaticDirectory, title + ".nzb"); @@ -60,7 +62,7 @@ namespace NzbDrone.Core.Providers.DownloadClients logger.Trace("NZB Download succeeded, saved to: {0}", filename); var contents = String.Format("plugin://plugin.program.pneumatic/?mode=strm&type=add_file&nzb={0}&nzbname={1}", filename, title); - _diskProvider.WriteAllText(Path.Combine(_configProvider.SabDropDirectory, title + ".strm"), contents); + _diskProvider.WriteAllText(Path.Combine(_configProvider.DownloadClientTvDirectory, title + ".strm"), contents); return true; } diff --git a/NzbDrone.Core/Providers/DownloadClients/SabProvider.cs b/NzbDrone.Core/Providers/DownloadClients/SabProvider.cs index 252b7b2b3..9b18b5b44 100644 --- a/NzbDrone.Core/Providers/DownloadClients/SabProvider.cs +++ b/NzbDrone.Core/Providers/DownloadClients/SabProvider.cs @@ -78,12 +78,13 @@ namespace NzbDrone.Core.Providers.DownloadClients } } - public virtual bool DownloadNzb(string url, string title) + public virtual bool DownloadNzb(string url, string title, bool recentlyAired) { try { string cat = _configProvider.SabTvCategory; - int priority = (int)_configProvider.SabTvPriority; + int priority = recentlyAired ? (int)_configProvider.SabRecentTvPriority : (int)_configProvider.SabBacklogTvPriority; + string name = GetNzbName(url); string nzbName = HttpUtility.UrlEncode(title); diff --git a/NzbDrone.Core/Providers/DownloadProvider.cs b/NzbDrone.Core/Providers/DownloadProvider.cs index dde52a4e9..2df3f63d2 100644 --- a/NzbDrone.Core/Providers/DownloadProvider.cs +++ b/NzbDrone.Core/Providers/DownloadProvider.cs @@ -46,10 +46,10 @@ namespace NzbDrone.Core.Providers public virtual bool DownloadReport(EpisodeParseResult parseResult) { var downloadTitle = GetDownloadTitle(parseResult); - var provider = GetActiveDownloadClient(); + var recentEpisode = CheckIfRecentEpisode(parseResult); - bool success = provider.DownloadNzb(parseResult.NzbUrl, downloadTitle); + bool success = provider.DownloadNzb(parseResult.NzbUrl, downloadTitle, recentEpisode); if (success) { @@ -154,5 +154,14 @@ namespace NzbDrone.Core.Providers return result; } + + public virtual bool CheckIfRecentEpisode(EpisodeParseResult parseResult) + { + return parseResult.Episodes + .Where(e => e.AirDate.HasValue) + .Select(e => e.AirDate) + .OrderBy(e => e.Value) + .First().Value <= DateTime.Today.AddDays(7); + } } } \ No newline at end of file diff --git a/NzbDrone.Core/Providers/Indexer/Newznab.cs b/NzbDrone.Core/Providers/Indexer/Newznab.cs index e3c6ba49a..1cf5abb9a 100644 --- a/NzbDrone.Core/Providers/Indexer/Newznab.cs +++ b/NzbDrone.Core/Providers/Indexer/Newznab.cs @@ -36,7 +36,7 @@ namespace NzbDrone.Core.Providers.Indexer foreach (var url in Urls) { - searchUrls.Add(String.Format("{0}&limit=100&q={1}&season{2}&ep{3}", url, seriesTitle, seasonNumber, episodeNumber)); + searchUrls.Add(String.Format("{0}&limit=100&q={1}&season={2}&ep={3}", url, seriesTitle, seasonNumber, episodeNumber)); } return searchUrls; @@ -60,7 +60,7 @@ namespace NzbDrone.Core.Providers.Indexer foreach (var url in Urls) { - searchUrls.Add(String.Format("{0}&limit=100&q={1}&season{2}", url, seriesTitle, seasonNumber)); + searchUrls.Add(String.Format("{0}&limit=100&q={1}&season={2}", url, seriesTitle, seasonNumber)); } return searchUrls; diff --git a/NzbDrone.Core/Providers/Indexer/NzbMatrix.cs b/NzbDrone.Core/Providers/Indexer/NzbMatrix.cs index 0fdab04df..4760d8671 100644 --- a/NzbDrone.Core/Providers/Indexer/NzbMatrix.cs +++ b/NzbDrone.Core/Providers/Indexer/NzbMatrix.cs @@ -48,7 +48,7 @@ namespace NzbDrone.Core.Providers.Indexer foreach (var url in Urls) { - searchUrls.Add(String.Format("{0}&term={1}+s{2:00}e{3:00}", url, seriesTitle, seasonNumber, episodeNumber)); + searchUrls.Add(String.Format("{0}&term=(\"{1}+s{2:00}e{3:00}\",\"{1}+{2}x{3:00}\")", url, seriesTitle, seasonNumber, episodeNumber)); } return searchUrls; @@ -72,8 +72,7 @@ namespace NzbDrone.Core.Providers.Indexer foreach (var url in Urls) { - searchUrls.Add(String.Format("{0}&term={1}+Season", url, seriesTitle)); - searchUrls.Add(String.Format("{0}&term={1}+S{2:00}", url, seriesTitle, seasonNumber)); + searchUrls.Add(String.Format("{0}&term=(\"{1}+Season\",\"{1}+S{2:00}\")", url, seriesTitle, seasonNumber)); } return searchUrls; @@ -85,7 +84,7 @@ namespace NzbDrone.Core.Providers.Indexer foreach (var url in Urls) { - searchUrls.Add(String.Format("{0}&term={1}+S{2:00}E{3}", url, seriesTitle, seasonNumber, episodeWildcard)); + searchUrls.Add(String.Format("{0}&term=(\"{1}+S{2:00}E{3}\", \"{1}+{2}x{3}\")", url, seriesTitle, seasonNumber, episodeWildcard)); } return searchUrls; diff --git a/NzbDrone.Core/Providers/NewznabProvider.cs b/NzbDrone.Core/Providers/NewznabProvider.cs index f789c973f..b3eab5b7b 100644 --- a/NzbDrone.Core/Providers/NewznabProvider.cs +++ b/NzbDrone.Core/Providers/NewznabProvider.cs @@ -140,6 +140,7 @@ namespace NzbDrone.Core.Providers catch (Exception ex) { Logger.Error("Invalid address {0}, please correct the site URL.", url); + Logger.TraceException(ex.Message, ex); throw; } diff --git a/NzbDrone.Core/Providers/SearchProvider.cs b/NzbDrone.Core/Providers/SearchProvider.cs index ac6856dd3..63d263d0c 100644 --- a/NzbDrone.Core/Providers/SearchProvider.cs +++ b/NzbDrone.Core/Providers/SearchProvider.cs @@ -15,7 +15,6 @@ namespace NzbDrone.Core.Providers { public class SearchProvider { - //Season and Episode Searching private readonly EpisodeProvider _episodeProvider; private readonly DownloadProvider _downloadProvider; private readonly SeriesProvider _seriesProvider; @@ -25,7 +24,7 @@ namespace NzbDrone.Core.Providers private readonly AllowedDownloadSpecification _allowedDownloadSpecification; private readonly SearchHistoryProvider _searchHistoryProvider; - private static readonly Logger _logger = LogManager.GetCurrentClassLogger(); + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); [Inject] public SearchProvider(EpisodeProvider episodeProvider, DownloadProvider downloadProvider, SeriesProvider seriesProvider, @@ -60,37 +59,62 @@ namespace NzbDrone.Core.Providers if (series == null) { - _logger.Error("Unable to find an series {0} in database", seriesId); + logger.Error("Unable to find an series {0} in database", seriesId); return new List(); - } + } - //Return false if the series is a daily series (we only support individual episode searching if (series.IsDaily) + { + logger.Trace("Daily series detected, skipping season search: {0}", series.Title); return new List(); + } + + logger.Debug("Getting episodes from database for series: {0} and season: {1}", seriesId, seasonNumber); + var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber); + + if (episodes == null || episodes.Count == 0) + { + logger.Warn("No episodes in database found for series: {0} and season: {1}.", seriesId, seasonNumber); + return new List(); + } notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber); - var reports = PerformSearch(notification, series, seasonNumber); + List reports; - _logger.Debug("Finished searching all indexers. Total {0}", reports.Count); + if (series.UseSceneNumbering) + { + var sceneSeasonNumbers = episodes.Select(e => e.SceneSeasonNumber).ToList(); + var sceneEpisodeNumbers = episodes.Select(e => e.SceneEpisodeNumber).ToList(); - if (reports.Count == 0) - return new List(); + if (sceneSeasonNumbers.Distinct().Count() > 1) + { + logger.Trace("Uses scene numbering, but multiple seasons found, skipping."); + return new List(); + } - _logger.Debug("Getting episodes from database for series: {0} and season: {1}", seriesId, seasonNumber); - var episodeNumbers = _episodeProvider.GetEpisodeNumbersBySeason(seriesId, seasonNumber); + reports = PerformSeasonSearch(series, sceneSeasonNumbers.First()); - if (episodeNumbers == null || episodeNumbers.Count == 0) - { - _logger.Warn("No episodes in database found for series: {0} and season: {1}.", seriesId, seasonNumber); - return new List(); + reports.Where(p => p.FullSeason && p.SeasonNumber == sceneSeasonNumbers.First()).ToList().ForEach( + e => e.EpisodeNumbers = sceneEpisodeNumbers.ToList() + ); } - notification.CurrentMessage = "Processing search results"; + else + { + reports = PerformSeasonSearch(series, seasonNumber); - reports.Where(p => p.FullSeason && p.SeasonNumber == seasonNumber).ToList().ForEach( - e => e.EpisodeNumbers = episodeNumbers.ToList() + reports.Where(p => p.FullSeason && p.SeasonNumber == seasonNumber).ToList().ForEach( + e => e.EpisodeNumbers = episodes.Select(ep => ep.EpisodeNumber).ToList() ); + } + + logger.Debug("Finished searching all indexers. Total {0}", reports.Count); + + if (reports.Count == 0) + return new List(); + + notification.CurrentMessage = "Processing search results"; searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, searchResult, series, seasonNumber); _searchHistoryProvider.Add(searchResult); @@ -111,18 +135,41 @@ namespace NzbDrone.Core.Providers if (series == null) { - _logger.Error("Unable to find an series {0} in database", seriesId); + logger.Error("Unable to find an series {0} in database", seriesId); return new List(); } - //Return empty list if the series is a daily series (we only support individual episode searching if (series.IsDaily) + { + logger.Trace("Daily series detected, skipping season search: {0}", series.Title); return new List(); + } notification.CurrentMessage = String.Format("Searching for {0} Season {1}", series.Title, seasonNumber); var episodes = _episodeProvider.GetEpisodesBySeason(seriesId, seasonNumber); - var reports = PerformSearch(notification, series, seasonNumber, episodes); - _logger.Debug("Finished searching all indexers. Total {0}", reports.Count); + + List reports; + + if (series.UseSceneNumbering) + { + var sceneSeasonNumbers = episodes.Select(e => e.SceneSeasonNumber).ToList(); + var sceneEpisodeNumbers = episodes.Select(e => e.SceneEpisodeNumber).ToList(); + + if (sceneSeasonNumbers.Distinct().Count() > 1) + { + logger.Trace("Uses scene numbering, but multiple seasons found, skipping."); + return new List(); + } + + reports = PerformPartialSeasonSearch(series, sceneSeasonNumbers.First(), GetEpisodeNumberPrefixes(sceneEpisodeNumbers)); + } + + else + { + reports = PerformPartialSeasonSearch(series, seasonNumber, GetEpisodeNumberPrefixes(episodes.Select(e => e.EpisodeNumber))); + } + + logger.Debug("Finished searching all indexers. Total {0}", reports.Count); if (reports.Count == 0) return new List(); @@ -140,40 +187,41 @@ namespace NzbDrone.Core.Providers if (episode == null) { - _logger.Error("Unable to find an episode {0} in database", episodeId); + logger.Error("Unable to find an episode {0} in database", episodeId); return false; } - //Check to see if an upgrade is possible before attempting if (!_upgradePossibleSpecification.IsSatisfiedBy(episode)) { - _logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode); + logger.Info("Search for {0} was aborted, file in disk meets or exceeds Profile's Cutoff", episode); notification.CurrentMessage = String.Format("Skipping search for {0}, the file you have is already at cutoff", episode); return false; } notification.CurrentMessage = "Looking for " + episode; - - if (episode.Series.IsDaily && !episode.AirDate.HasValue) - { - _logger.Warn("AirDate is not Valid for: {0}", episode); - notification.CurrentMessage = String.Format("Search for {0} Failed, AirDate is invalid", episode); - return false; - } + List reports; var searchResult = new SearchHistory { SearchTime = DateTime.Now, - SeriesId = episode.Series.SeriesId + SeriesId = episode.Series.SeriesId, + EpisodeId = episodeId }; - var reports = PerformSearch(notification, episode.Series, episode.SeasonNumber, new List { episode }); - - _logger.Debug("Finished searching all indexers. Total {0}", reports.Count); - notification.CurrentMessage = "Processing search results"; - if (episode.Series.IsDaily) { + if (!episode.AirDate.HasValue) + { + logger.Warn("AirDate is not Valid for: {0}", episode); + notification.CurrentMessage = String.Format("Search for {0} Failed, AirDate is invalid", episode); + return false; + } + + reports = PerformDailyEpisodeSearch(episode.Series, episode); + + logger.Debug("Finished searching all indexers. Total {0}", reports.Count); + notification.CurrentMessage = "Processing search results"; + searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, episode.Series, episode.AirDate.Value); _searchHistoryProvider.Add(searchResult); @@ -183,17 +231,17 @@ namespace NzbDrone.Core.Providers else if (episode.Series.UseSceneNumbering) { - searchResult.EpisodeId = episodeId; - var seasonNumber = episode.SceneSeasonNumber; var episodeNumber = episode.SceneEpisodeNumber; - if (seasonNumber == 0 || episodeNumber == 0) + if (seasonNumber == 0 && episodeNumber == 0) { seasonNumber = episode.SeasonNumber; episodeNumber = episode.EpisodeNumber; } + reports = PerformEpisodeSearch(episode.Series, seasonNumber, episodeNumber); + searchResult.SearchHistoryItems = ProcessSearchResults( notification, reports, @@ -211,7 +259,8 @@ namespace NzbDrone.Core.Providers else { - searchResult.EpisodeId = episodeId; + reports = PerformEpisodeSearch(episode.Series, episode.SeasonNumber, episode.EpisodeNumber); + searchResult.SearchHistoryItems = ProcessSearchResults(notification, reports, searchResult, episode.Series, episode.SeasonNumber, episode.EpisodeNumber); _searchHistoryProvider.Add(searchResult); @@ -219,77 +268,14 @@ namespace NzbDrone.Core.Providers return true; } - _logger.Warn("Unable to find {0} in any of indexers.", episode); + logger.Warn("Unable to find {0} in any of indexers.", episode); - if (reports.Any()) - { - notification.CurrentMessage = String.Format("Sorry, couldn't find {0}, that matches your preferences.", episode); - } - else - { - notification.CurrentMessage = String.Format("Sorry, couldn't find {0} in any of indexers.", episode); - } + notification.CurrentMessage = reports.Any() ? String.Format("Sorry, couldn't find {0}, that matches your preferences.", episode) + : String.Format("Sorry, couldn't find {0} in any of indexers.", episode); return false; } - public List PerformSearch(ProgressNotification notification, Series series, int seasonNumber, IList episodes = null) - { - //If single episode, do a single episode search, if full season then do a full season search, otherwise, do a partial search - - var reports = new List(); - - var title = _sceneMappingProvider.GetSceneName(series.SeriesId); - - if (string.IsNullOrWhiteSpace(title)) - { - title = series.Title; - } - - Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer => - { - try - { - if (episodes == null) - reports.AddRange(indexer.FetchSeason(title, seasonNumber)); - - //Treat as single episode - else if (episodes.Count == 1) - { - //Use SceneNumbering - Only if SceneSN and SceneEN are greater than zero - if (series.UseSceneNumbering && episodes.First().SceneSeasonNumber > 0 && episodes.First().SceneEpisodeNumber > 0) - reports.AddRange(indexer.FetchEpisode(title, episodes.First().SceneSeasonNumber, episodes.First().SceneEpisodeNumber)); - - //Standard - else if (!series.IsDaily) - reports.AddRange(indexer.FetchEpisode(title, seasonNumber, episodes.First().EpisodeNumber)); - - //Daily Episode - else - reports.AddRange(indexer.FetchDailyEpisode(title, episodes.First().AirDate.Value)); - } - - //Treat as Partial Season - else - { - var prefixes = GetEpisodeNumberPrefixes(episodes.Select(s => s.EpisodeNumber)); - - foreach (var episodePrefix in prefixes) - { - reports.AddRange(indexer.FetchPartialSeason(title, seasonNumber, episodePrefix)); - } - } - } - - catch (Exception e) - { - _logger.ErrorException("An error has occurred while fetching items from " + indexer.Name, e); - } - }); - - return reports; - } - public List ProcessSearchResults(ProgressNotification notification, IEnumerable reports, SearchHistory searchResult, Series series, int seasonNumber, int? episodeNumber = null) { var items = new List(); @@ -301,7 +287,7 @@ namespace NzbDrone.Core.Providers { try { - _logger.Trace("Analysing report " + episodeParseResult); + logger.Trace("Analysing report " + episodeParseResult); var item = new SearchHistoryItem { @@ -323,7 +309,7 @@ namespace NzbDrone.Core.Providers //If series is null or doesn't match the series we're looking for return if (episodeParseResult.Series == null || episodeParseResult.Series.SeriesId != series.SeriesId) { - _logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle); + logger.Trace("Unexpected series for search: {0}. Skipping.", episodeParseResult.CleanTitle); item.SearchError = ReportRejectionType.WrongSeries; continue; } @@ -331,7 +317,7 @@ namespace NzbDrone.Core.Providers //If SeasonNumber doesn't match or episode is not in the in the list in the parse result, skip the report. if (episodeParseResult.SeasonNumber != seasonNumber) { - _logger.Trace("Season number does not match searched season number, skipping."); + logger.Trace("Season number does not match searched season number, skipping."); item.SearchError = ReportRejectionType.WrongSeason; continue; } @@ -339,7 +325,7 @@ namespace NzbDrone.Core.Providers //If the EpisodeNumber was passed in and it is not contained in the parseResult, skip the report. if (episodeNumber.HasValue && !episodeParseResult.EpisodeNumbers.Contains(episodeNumber.Value)) { - _logger.Trace("Searched episode number is not contained in post, skipping."); + logger.Trace("Searched episode number is not contained in post, skipping."); item.SearchError = ReportRejectionType.WrongEpisode; continue; } @@ -347,7 +333,7 @@ namespace NzbDrone.Core.Providers //Make sure we haven't already downloaded a report with this episodenumber, if we have, skip the report. if (searchResult.Successes.Intersect(episodeParseResult.EpisodeNumbers).Any()) { - _logger.Trace("Episode has already been downloaded in this search, skipping."); + logger.Trace("Episode has already been downloaded in this search, skipping."); item.SearchError = ReportRejectionType.Skipped; continue; } @@ -357,7 +343,7 @@ namespace NzbDrone.Core.Providers item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult); if (item.SearchError == ReportRejectionType.None) { - _logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult); + logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult); try { if (_downloadProvider.DownloadReport(episodeParseResult)) @@ -375,7 +361,7 @@ namespace NzbDrone.Core.Providers } catch (Exception e) { - _logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e); + logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e); notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult); item.SearchError = ReportRejectionType.DownloadClientFailure; } @@ -383,7 +369,7 @@ namespace NzbDrone.Core.Providers } catch (Exception e) { - _logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e); + logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e); } } @@ -419,7 +405,7 @@ namespace NzbDrone.Core.Providers continue; } - _logger.Trace("Analysing report " + episodeParseResult); + logger.Trace("Analysing report " + episodeParseResult); //Get the matching series episodeParseResult.Series = _seriesProvider.FindSeries(episodeParseResult.CleanTitle); @@ -443,7 +429,7 @@ namespace NzbDrone.Core.Providers item.SearchError = _allowedDownloadSpecification.IsSatisfiedBy(episodeParseResult); if (item.SearchError == ReportRejectionType.None) { - _logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult); + logger.Debug("Found '{0}'. Adding to download queue.", episodeParseResult); try { if (_downloadProvider.DownloadReport(episodeParseResult)) @@ -462,7 +448,7 @@ namespace NzbDrone.Core.Providers } catch (Exception e) { - _logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e); + logger.ErrorException("Unable to add report to download queue." + episodeParseResult, e); notification.CurrentMessage = String.Format("Unable to add report to download queue. {0}", episodeParseResult); item.SearchError = ReportRejectionType.DownloadClientFailure; } @@ -470,7 +456,7 @@ namespace NzbDrone.Core.Providers } catch (Exception e) { - _logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e); + logger.ErrorException("An error has occurred while processing parse result items from " + episodeParseResult, e); } } @@ -488,5 +474,106 @@ namespace NzbDrone.Core.Providers return results.Distinct().ToList(); } + + public List PerformEpisodeSearch(Series series, int seasonNumber, int episodeNumber) + { + var reports = new List(); + var title = GetSeriesTitle(series); + + Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer => + { + try + { + reports.AddRange(indexer.FetchEpisode(title, seasonNumber, episodeNumber)); + } + + catch (Exception e) + { + logger.ErrorException(String.Format("An error has occurred while searching for {0}-S{1:00}E{2:00} from: {3}", + series.Title, seasonNumber, episodeNumber, indexer.Name), e); + } + }); + + return reports; + } + + public List PerformDailyEpisodeSearch(Series series, Episode episode) + { + var reports = new List(); + var title = GetSeriesTitle(series); + + Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer => + { + try + { + logger.Trace("Episode {0} is a daily episode, searching as daily", episode); + reports.AddRange(indexer.FetchDailyEpisode(title, episode.AirDate.Value)); + } + + catch (Exception e) + { + logger.ErrorException(String.Format("An error has occurred while searching for {0}-{1} from: {2}", + series.Title, episode.AirDate, indexer.Name), e); + } + }); + + return reports; + } + + public List PerformPartialSeasonSearch(Series series, int seasonNumber, List prefixes) + { + var reports = new List(); + var title = GetSeriesTitle(series); + + Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer => + { + try + { + foreach (var episodePrefix in prefixes) + { + reports.AddRange(indexer.FetchPartialSeason(title, seasonNumber, episodePrefix)); + } + } + + catch (Exception e) + { + logger.ErrorException(String.Format("An error has occurred while searching for {0}-S{1:00} from: {2}", + series.Title, seasonNumber, indexer.Name), e); + } + }); + + return reports; + } + + public List PerformSeasonSearch(Series series, int seasonNumber) + { + var reports = new List(); + var title = GetSeriesTitle(series); + + Parallel.ForEach(_indexerProvider.GetEnabledIndexers(), indexer => + { + try + { + reports.AddRange(indexer.FetchSeason(title, seasonNumber)); + } + + catch (Exception e) + { + logger.ErrorException("An error has occurred while searching for items from: " + indexer.Name, e); + } + }); + + return reports; + } + + public string GetSeriesTitle(Series series) + { + var title = _sceneMappingProvider.GetSceneName(series.SeriesId); + + if (String.IsNullOrWhiteSpace(title)) + title = series.Title; + + return title; + } } } diff --git a/NzbDrone.Core/Providers/SignalRProvider.cs b/NzbDrone.Core/Providers/SignalRProvider.cs index 6f3c31fee..b85cacc7f 100644 --- a/NzbDrone.Core/Providers/SignalRProvider.cs +++ b/NzbDrone.Core/Providers/SignalRProvider.cs @@ -28,11 +28,10 @@ namespace NzbDrone.Core.Providers EpisodeStatus = episodeStatus.ToString(), Quality = (quality == null ? String.Empty : quality.Quality.ToString()) }); - var test = 0; } catch (Exception ex) { - logger.Trace("Error"); + logger.TraceException("Error", ex); throw; } } diff --git a/NzbDrone.Core/Providers/SmtpProvider.cs b/NzbDrone.Core/Providers/SmtpProvider.cs index e0f831dcc..025c23657 100644 --- a/NzbDrone.Core/Providers/SmtpProvider.cs +++ b/NzbDrone.Core/Providers/SmtpProvider.cs @@ -61,6 +61,7 @@ namespace NzbDrone.Core.Providers catch(Exception ex) { Logger.Error("Error sending email. Subject: {0}", email.Subject); + Logger.TraceException(ex.Message, ex); } } diff --git a/NzbDrone.Core/Providers/XemProvider.cs b/NzbDrone.Core/Providers/XemProvider.cs index 3c1fed45c..12dbcb182 100644 --- a/NzbDrone.Core/Providers/XemProvider.cs +++ b/NzbDrone.Core/Providers/XemProvider.cs @@ -55,6 +55,14 @@ namespace NzbDrone.Core.Providers public virtual void UpdateMappings(int seriesId) { + var xemIds = _xemCommunicationProvider.GetXemSeriesIds(); + + if (!xemIds.Contains(seriesId)) + { + _logger.Trace("Xem doesn't have a mapping for this series: {0}", seriesId); + return; + } + var series = _seriesProvider.GetSeries(seriesId); if (series == null) diff --git a/NzbDrone.Services/NzbDrone.Services.Service/Providers/SceneMappingProvider.cs b/NzbDrone.Services/NzbDrone.Services.Service/Providers/SceneMappingProvider.cs index 1ff2519ef..36daef8b1 100644 --- a/NzbDrone.Services/NzbDrone.Services.Service/Providers/SceneMappingProvider.cs +++ b/NzbDrone.Services/NzbDrone.Services.Service/Providers/SceneMappingProvider.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Web; +using NLog; using NzbDrone.Services.Service.Repository; using Services.PetaPoco; @@ -11,6 +12,8 @@ namespace NzbDrone.Services.Service.Providers { private readonly IDatabase _database; + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + public SceneMappingProvider(IDatabase database) { _database = database; @@ -74,6 +77,7 @@ namespace NzbDrone.Services.Service.Providers } catch (Exception ex) { + logger.WarnException("Unable to promote scene mapping", ex); return false; } @@ -93,6 +97,7 @@ namespace NzbDrone.Services.Service.Providers } catch (Exception ex) { + logger.WarnException("Unable to promote all scene mappings", ex); return false; } diff --git a/NzbDrone.Update.Test/NzbDrone.Update.Test.csproj b/NzbDrone.Update.Test/NzbDrone.Update.Test.csproj index 16a00c2c9..acaa83dec 100644 --- a/NzbDrone.Update.Test/NzbDrone.Update.Test.csproj +++ b/NzbDrone.Update.Test/NzbDrone.Update.Test.csproj @@ -80,11 +80,11 @@ NzbDrone.Common - {CADDFCE0-7509-4430-8364-2074E1EEFCA2} + {caddfce0-7509-4430-8364-2074e1eefca2} NzbDrone.Test.Common - {4CCC53CD-8D5E-4CC4-97D2-5C9312AC2BD7} + {4ccc53cd-8d5e-4cc4-97d2-5c9312ac2bd7} NzbDrone.Update diff --git a/NzbDrone.Web/Controllers/CommandController.cs b/NzbDrone.Web/Controllers/CommandController.cs index bc1b0cf68..1bfe2ee50 100644 --- a/NzbDrone.Web/Controllers/CommandController.cs +++ b/NzbDrone.Web/Controllers/CommandController.cs @@ -1,4 +1,5 @@ using System.Web.Mvc; +using NLog; using NzbDrone.Core.Jobs; using NzbDrone.Core.Providers; using NzbDrone.Core.Providers.DownloadClients; @@ -21,6 +22,8 @@ namespace NzbDrone.Web.Controllers private readonly XbmcProvider _xbmcProvider; private readonly PlexProvider _plexProvider; + private static readonly Logger logger = LogManager.GetCurrentClassLogger(); + public CommandController(JobProvider jobProvider, SabProvider sabProvider, SmtpProvider smtpProvider, TwitterProvider twitterProvider, EpisodeProvider episodeProvider, GrowlProvider growlProvider, @@ -133,6 +136,7 @@ namespace NzbDrone.Web.Controllers } catch(Exception ex) { + logger.TraceException(ex.Message, ex); return JsonNotificationResult.Oops("Couldn't register and test Growl"); } } diff --git a/NzbDrone.Web/Controllers/SearchHistoryController.cs b/NzbDrone.Web/Controllers/SearchHistoryController.cs index 96c696e33..0e9f35d3a 100644 --- a/NzbDrone.Web/Controllers/SearchHistoryController.cs +++ b/NzbDrone.Web/Controllers/SearchHistoryController.cs @@ -53,7 +53,7 @@ namespace NzbDrone.Web.Controllers Success = s.Success, SearchError = s.SearchError.AddSpacesToEnum().Replace("None", "Grabbed"), Quality = s.Quality.ToString(), - QualityInt = (int)s.Quality, + QualityInt = s.Quality.Weight, Proper = s.Proper, Age = s.Age, Size = s.Size.ToBestFileSize(1), @@ -68,7 +68,7 @@ namespace NzbDrone.Web.Controllers { _searchHistoryProvider.ForceDownload(id); - return new JsonResult { Data = "ok", JsonRequestBehavior = JsonRequestBehavior.AllowGet }; + return JsonNotificationResult.Info("Success", "Requested episode has been sent to download client"); } public string GetDisplayName(SearchHistory searchResult) diff --git a/NzbDrone.Web/Controllers/SettingsController.cs b/NzbDrone.Web/Controllers/SettingsController.cs index 6c502ba8b..69d98ccf3 100644 --- a/NzbDrone.Web/Controllers/SettingsController.cs +++ b/NzbDrone.Web/Controllers/SettingsController.cs @@ -140,8 +140,9 @@ namespace NzbDrone.Web.Controllers SabUsername = _configProvider.SabUsername, SabPassword = _configProvider.SabPassword, SabTvCategory = tvCategory, - SabTvPriority = _configProvider.SabTvPriority, - DownloadClientDropDirectory = _configProvider.SabDropDirectory, + SabBacklogTvPriority = _configProvider.SabBacklogTvPriority, + SabRecentTvPriority = _configProvider.SabRecentTvPriority, + DownloadClientDropDirectory = _configProvider.DownloadClientTvDirectory, SabTvCategorySelectList = tvCategorySelectList, DownloadClient = (int)_configProvider.DownloadClient, BlackholeDirectory = _configProvider.BlackholeDirectory, @@ -173,7 +174,7 @@ namespace NzbDrone.Web.Controllers Bluray1080pMaxSize = qualityTypesFromDb.Single(q => q.QualityTypeId == 7).MaxSize }; - ViewData["Profiles"] = profiles; + ViewData["Profiles"] = profiles.Select(s => s.QualityProfileId).ToList(); return View(model); } @@ -269,13 +270,15 @@ namespace NzbDrone.Web.Controllers Cutoff = QualityTypes.Unknown }; - qualityProfile.QualityProfileId = _qualityProvider.Add(qualityProfile); + var qualityProfileId = _qualityProvider.Add(qualityProfile); - return GetQualityProfileView(qualityProfile); + return GetQualityProfileView(qualityProfileId); } - public PartialViewResult GetQualityProfileView(QualityProfile profile) + public PartialViewResult GetQualityProfileView(int profileId) { + var profile = _qualityProvider.Get(profileId); + var model = new QualityProfileModel(); model.QualityProfileId = profile.QualityProfileId; model.Name = profile.Name; @@ -454,8 +457,9 @@ namespace NzbDrone.Web.Controllers _configProvider.SabPassword = data.SabPassword; _configProvider.SabTvCategory = data.SabTvCategory; _configProvider.SabUsername = data.SabUsername; - _configProvider.SabTvPriority = data.SabTvPriority; - _configProvider.SabDropDirectory = data.DownloadClientDropDirectory; + _configProvider.SabBacklogTvPriority = data.SabBacklogTvPriority; + _configProvider.SabRecentTvPriority = data.SabRecentTvPriority; + _configProvider.DownloadClientTvDirectory = data.DownloadClientDropDirectory; _configProvider.BlackholeDirectory = data.BlackholeDirectory; _configProvider.DownloadClient = (DownloadClientType)data.DownloadClient; _configProvider.PneumaticDirectory = data.PneumaticDirectory; diff --git a/NzbDrone.Web/Controllers/SystemController.cs b/NzbDrone.Web/Controllers/SystemController.cs index 796fcda2c..3e08afc24 100644 --- a/NzbDrone.Web/Controllers/SystemController.cs +++ b/NzbDrone.Web/Controllers/SystemController.cs @@ -109,9 +109,9 @@ namespace NzbDrone.Web.Controllers //PostDownloadView public ActionResult PendingProcessing() { - ViewData["DropDir"] = _configProvider.SabDropDirectory; + ViewData["DropDir"] = _configProvider.DownloadClientTvDirectory; - var dropDir = _configProvider.SabDropDirectory; + var dropDir = _configProvider.DownloadClientTvDirectory; var subFolders = _diskProvider.GetDirectories(dropDir); var models = new List(); diff --git a/NzbDrone.Web/Models/DownloadClientSettingsModel.cs b/NzbDrone.Web/Models/DownloadClientSettingsModel.cs index d193949d6..e4f04bf71 100644 --- a/NzbDrone.Web/Models/DownloadClientSettingsModel.cs +++ b/NzbDrone.Web/Models/DownloadClientSettingsModel.cs @@ -50,9 +50,14 @@ namespace NzbDrone.Web.Models public String SabTvCategory { get; set; } [Required(ErrorMessage = "Please select a valid priority")] - [DisplayName("SABnzbd Priority")] - [Description("Priority to use when sending NZBs to SABnzbd")] - public SabPriorityType SabTvPriority { get; set; } + [DisplayName("SABnzbd Backlog Priority")] + [Description("Priority to use when sending episodes older than 7 days to SABnzbd")] + public SabPriorityType SabBacklogTvPriority { get; set; } + + [Required(ErrorMessage = "Please select a valid priority")] + [DisplayName("SABnzbd Recent Priority")] + [Description("Priority to use when sending episodes newer than 7 days to SABnzbd")] + public SabPriorityType SabRecentTvPriority { get; set; } [Required(ErrorMessage = "Required so NzbDrone can sort downloads")] [DisplayName("Download Client TV Directory")] diff --git a/NzbDrone.Web/Views/SearchHistory/Details.cshtml b/NzbDrone.Web/Views/SearchHistory/Details.cshtml index 01bf9674d..2aa409d0f 100644 --- a/NzbDrone.Web/Views/SearchHistory/Details.cshtml +++ b/NzbDrone.Web/Views/SearchHistory/Details.cshtml @@ -38,7 +38,7 @@ function actionColumn(source, type, val) { if (type === 'display' || type === 'filter') { - return ''; + return ''; } // 'sort' and 'type' both just use the raw data return ''; diff --git a/NzbDrone.Web/Views/Settings/Sabnzbd.cshtml b/NzbDrone.Web/Views/Settings/Sabnzbd.cshtml index ce18214d1..918e373fe 100644 --- a/NzbDrone.Web/Views/Settings/Sabnzbd.cshtml +++ b/NzbDrone.Web/Views/Settings/Sabnzbd.cshtml @@ -45,10 +45,15 @@ @Html.DropDownListFor(m => m.SabTvCategory, Model.SabTvCategorySelectList, new { @class = "inputClass selectClass" }) -