diff --git a/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs b/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs index 0c81a1d47..fa49d4cdb 100644 --- a/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs +++ b/src/NzbDrone.Core.Test/Download/DownloadClientTests/TransmissionTests/TransmissionFixture.cs @@ -117,6 +117,11 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests _settings.TvCategory = "sonarr"; } + protected void GivenTvDirectory() + { + _settings.TvDirectory = @"C:/Downloads/Finished/sonarr"; + } + protected void GivenFailedDownload() { Mocker.GetMock() @@ -242,6 +247,22 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests id.Should().NotBeNullOrEmpty(); } + [Test] + public void Download_with_TvDirectory_should_force_directory() + { + GivenTvDirectory(); + GivenSuccessfulDownload(); + + var remoteEpisode = CreateRemoteEpisode(); + + var id = Subject.Download(remoteEpisode); + + id.Should().NotBeNullOrEmpty(); + + Mocker.GetMock() + .Verify(v => v.AddTorrentFromData(It.IsAny(), @"C:/Downloads/Finished/sonarr", It.IsAny()), Times.Once()); + } + [Test] public void Download_with_category_should_force_directory() { @@ -276,6 +297,21 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests .Verify(v => v.AddTorrentFromData(It.IsAny(), @"C:/Downloads/Finished/transmission/sonarr", It.IsAny()), Times.Once()); } + [Test] + public void Download_without_TvDirectory_and_Category_should_use_default() + { + GivenSuccessfulDownload(); + + var remoteEpisode = CreateRemoteEpisode(); + + var id = Subject.Download(remoteEpisode); + + id.Should().NotBeNullOrEmpty(); + + Mocker.GetMock() + .Verify(v => v.AddTorrentFromData(It.IsAny(), null, It.IsAny()), Times.Once()); + } + [TestCase("magnet:?xt=urn:btih:ZPBPA2P6ROZPKRHK44D5OW6NHXU5Z6KR&tr=udp", "CBC2F069FE8BB2F544EAE707D75BCD3DE9DCF951")] public void Download_should_get_hash_from_magnet_url(string magnetUrl, string expectedHash) { @@ -368,6 +404,24 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.TransmissionTests items.First().Status.Should().Be(DownloadItemStatus.Downloading); } + public void should_exclude_items_not_in_TvDirectory() + { + GivenTvDirectory(); + + _downloading.DownloadDir = @"C:/Downloads/Finished/sonarr/subdir"; + + GivenTorrents(new List + { + _downloading, + _queued + }); + + var items = Subject.GetItems().ToList(); + + items.Count.Should().Be(1); + items.First().Status.Should().Be(DownloadItemStatus.Downloading); + } + [Test] public void should_fix_forward_slashes() { diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs b/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs index 75f39787b..67715fdf0 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/Transmission.cs @@ -65,12 +65,21 @@ namespace NzbDrone.Core.Download.Clients.Transmission private string GetDownloadDirectory() { - if (Settings.TvCategory.IsNullOrWhiteSpace()) return null; - - var config = _proxy.GetConfig(Settings); - var destDir = (string)config.GetValueOrDefault("download-dir"); + if (Settings.TvDirectory.IsNotNullOrWhiteSpace()) + { + return Settings.TvDirectory; + } + else if (Settings.TvCategory.IsNotNullOrWhiteSpace()) + { + var config = _proxy.GetConfig(Settings); + var destDir = (string)config.GetValueOrDefault("download-dir"); - return string.Format("{0}/{1}", destDir.TrimEnd('/'), Settings.TvCategory); + return string.Format("{0}/{1}", destDir.TrimEnd('/'), Settings.TvCategory); + } + else + { + return null; + } } public override string Name @@ -103,14 +112,20 @@ namespace NzbDrone.Core.Download.Clients.Transmission if (torrent.TotalSize == 0) continue; - var outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.DownloadDir)); + var outputPath = new OsPath(torrent.DownloadDir); - if (Settings.TvCategory.IsNotNullOrWhiteSpace()) + if (Settings.TvDirectory.IsNotNullOrWhiteSpace()) + { + if (!new OsPath(Settings.TvDirectory).Contains(outputPath)) continue; + } + else if (Settings.TvCategory.IsNotNullOrWhiteSpace()) { var directories = outputPath.FullPath.Split('\\', '/'); if (!directories.Contains(string.Format("{0}", Settings.TvCategory))) continue; } + outputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, outputPath); + var item = new DownloadClientItem(); item.DownloadId = torrent.HashString.ToUpper(); item.Category = Settings.TvCategory; diff --git a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs index 51504f054..633ee7a57 100644 --- a/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs +++ b/src/NzbDrone.Core/Download/Clients/Transmission/TransmissionSettings.cs @@ -3,6 +3,7 @@ using FluentValidation; using NzbDrone.Core.Annotations; using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.Validation; +using NzbDrone.Common.Extensions; namespace NzbDrone.Core.Download.Clients.Transmission { @@ -16,6 +17,10 @@ namespace NzbDrone.Core.Download.Clients.Transmission RuleFor(c => c.UrlBase).ValidUrlBase(); RuleFor(c => c.TvCategory).Matches(@"^\.?[-a-z]*$", RegexOptions.IgnoreCase).WithMessage("Allowed characters a-z and -"); + + RuleFor(c => c.TvCategory).Empty() + .When(c => c.TvDirectory.IsNotNullOrWhiteSpace()) + .WithMessage("Cannot use Category and Directory"); } } @@ -45,16 +50,19 @@ namespace NzbDrone.Core.Download.Clients.Transmission [FieldDefinition(4, Label = "Password", Type = FieldType.Password)] public string Password { get; set; } - [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional. Creates a .[category] subdirectory in the output directory.")] + [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Sonarr avoids conflicts with unrelated downloads, but it's optional. Creates a [category] subdirectory in the output directory.")] public string TvCategory { get; set; } - [FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(TransmissionPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")] + [FieldDefinition(6, Label = "Directory", Type = FieldType.Textbox, Advanced = true, HelpText = "Optional location to put downloads in, leave blank to use the default Transmission location")] + public string TvDirectory { get; set; } + + [FieldDefinition(7, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(TransmissionPriority), HelpText = "Priority to use when grabbing episodes that aired within the last 14 days")] public int RecentTvPriority { get; set; } - [FieldDefinition(7, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(TransmissionPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")] + [FieldDefinition(8, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(TransmissionPriority), HelpText = "Priority to use when grabbing episodes that aired over 14 days ago")] public int OlderTvPriority { get; set; } - [FieldDefinition(8, Label = "Use SSL", Type = FieldType.Checkbox)] + [FieldDefinition(9, Label = "Use SSL", Type = FieldType.Checkbox)] public bool UseSsl { get; set; } public NzbDroneValidationResult Validate()