Merge remote-tracking branch 'origin/develop' into develop

Leonardo Galli 7 years ago
commit d0174c7b7b

@ -115,10 +115,17 @@ Radarr is currently undergoing rapid development and pull requests are actively
> **Notice** > **Notice**
> Gulp must be running at all times while you are working with Radarr client source files. > Gulp must be running at all times while you are working with Radarr client source files.
### Build
* To build run `sh build.sh`
**Note:** Windows users must have bash available to do this. [cmder](http://cmder.net/) which is a console emulator for windows has bash as part of it's default installation.
### Development ### Development
* Open `NzbDrone.sln` in Visual Studio or run the build.sh script, if Mono is installed * Open `NzbDrone.sln` in Visual Studio or run the build.sh script, if Mono is installed
* Make sure `NzbDrone.Console` is set as the startup project * Make sure `NzbDrone.Console` is set as the startup project
* Run `build.sh` before running
### License ### License

@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
Port = 2222, Port = 2222,
Username = "admin", Username = "admin",
Password = "pass", Password = "pass",
TvCategory = "tv", MovieCategory = "movie",
RecentTvPriority = (int)NzbgetPriority.High RecentTvPriority = (int)NzbgetPriority.High
}; };
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
{ {
FileSizeLo = 1000, FileSizeLo = 1000,
RemainingSizeLo = 10, RemainingSizeLo = 10,
Category = "tv", Category = "movie",
NzbName = "Droned.1998.1080p.WEB-DL-DRONE", NzbName = "Droned.1998.1080p.WEB-DL-DRONE",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } } Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }
}; };
@ -46,7 +46,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_failed = new NzbgetHistoryItem _failed = new NzbgetHistoryItem
{ {
FileSizeLo = 1000, FileSizeLo = 1000,
Category = "tv", Category = "movie",
Name = "Droned.1998.1080p.WEB-DL-DRONE", Name = "Droned.1998.1080p.WEB-DL-DRONE",
DestDir = "somedirectory", DestDir = "somedirectory",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }, Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
@ -61,7 +61,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
_completed = new NzbgetHistoryItem _completed = new NzbgetHistoryItem
{ {
FileSizeLo = 1000, FileSizeLo = 1000,
Category = "tv", Category = "movie",
Name = "Droned.1998.1080p.WEB-DL-DRONE", Name = "Droned.1998.1080p.WEB-DL-DRONE",
DestDir = "/remote/mount/tv/Droned.1998.1080p.WEB-DL-DRONE", DestDir = "/remote/mount/tv/Droned.1998.1080p.WEB-DL-DRONE",
Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } }, Parameters = new List<NzbgetParameter> { new NzbgetParameter { Name = "drone", Value = "id" } },
@ -81,8 +81,8 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.NzbgetTests
}); });
var configItems = new Dictionary<string, string>(); var configItems = new Dictionary<string, string>();
configItems.Add("Category1.Name", "tv"); configItems.Add("Category1.Name", "movie");
configItems.Add("Category1.DestDir", @"/remote/mount/tv"); configItems.Add("Category1.DestDir", @"/remote/mount/movie");
Mocker.GetMock<INzbgetProxy>() Mocker.GetMock<INzbgetProxy>()
.Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>())) .Setup(v => v.GetConfig(It.IsAny<NzbgetSettings>()))

@ -36,7 +36,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
ApiKey = "5c770e3197e4fe763423ee7c392c25d1", ApiKey = "5c770e3197e4fe763423ee7c392c25d1",
Username = "admin", Username = "admin",
Password = "pass", Password = "pass",
TvCategory = "tv", MovieCategory = "movie",
RecentTvPriority = (int)SabnzbdPriority.High RecentTvPriority = (int)SabnzbdPriority.High
}; };
_queued = new SabnzbdQueue _queued = new SabnzbdQueue
@ -51,7 +51,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
Size = 1000, Size = 1000,
Sizeleft = 10, Sizeleft = 10,
Timeleft = TimeSpan.FromSeconds(10), Timeleft = TimeSpan.FromSeconds(10),
Category = "tv", Category = "movie",
Id = "sabnzbd_nzb12345", Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE" Title = "Droned.1998.1080p.WEB-DL-DRONE"
} }
@ -66,7 +66,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{ {
Status = SabnzbdDownloadStatus.Failed, Status = SabnzbdDownloadStatus.Failed,
Size = 1000, Size = 1000,
Category = "tv", Category = "movie",
Id = "sabnzbd_nzb12345", Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE" Title = "Droned.1998.1080p.WEB-DL-DRONE"
} }
@ -81,7 +81,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
{ {
Status = SabnzbdDownloadStatus.Completed, Status = SabnzbdDownloadStatus.Completed,
Size = 1000, Size = 1000,
Category = "tv", Category = "movie",
Id = "sabnzbd_nzb12345", Id = "sabnzbd_nzb12345",
Title = "Droned.1998.1080p.WEB-DL-DRONE", Title = "Droned.1998.1080p.WEB-DL-DRONE",
Storage = "/remote/mount/vv/Droned.1998.1080p.WEB-DL-DRONE" Storage = "/remote/mount/vv/Droned.1998.1080p.WEB-DL-DRONE"
@ -97,7 +97,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
}, },
Categories = new List<SabnzbdCategory> Categories = new List<SabnzbdCategory>
{ {
new SabnzbdCategory { Name = "tv", Dir = "vv" } new SabnzbdCategory { Name = "movie", Dir = "vv" }
} }
}; };
@ -111,7 +111,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
_fullStatus = new SabnzbdFullStatus _fullStatus = new SabnzbdFullStatus
{ {
CompleteDir = @"Y:\nzbget\root\complete".AsOsAgnostic() CompleteDir = @"Y:\sabnzbd\root\complete".AsOsAgnostic()
}; };
Mocker.GetMock<ISabnzbdProxy>() Mocker.GetMock<ISabnzbdProxy>()
@ -408,10 +408,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputPath.Should().Be(@"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic()); result.OutputPath.Should().Be(@"C:\sorted\somewhere\asdfasdf\asdfasdf.mkv".AsOsAgnostic());
} }
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")] [TestCase(@"Y:\sabnzbd\root", @"completed\downloads", @"vv", @"Y:\sabnzbd\root\completed\downloads", @"Y:\sabnzbd\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")] [TestCase(@"Y:\sabnzbd\root", @"completed", @"vv", @"Y:\sabnzbd\root\completed", @"Y:\sabnzbd\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")] [TestCase(@"/sabnzbd/root", @"completed/downloads", @"vv", @"/sabnzbd/root/completed/downloads", @"/sabnzbd/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")] [TestCase(@"/sabnzbd/root", @"completed", @"vv", @"/sabnzbd/root/completed", @"/sabnzbd/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_lt_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir) public void should_return_status_with_outputdir_for_version_lt_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{ {
_fullStatus.CompleteDir = null; _fullStatus.CompleteDir = null;
@ -429,10 +429,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
result.OutputRootFolders.First().Should().Be(fullCategoryDir); result.OutputRootFolders.First().Should().Be(fullCategoryDir);
} }
[TestCase(@"Y:\nzbget\root", @"completed\downloads", @"vv", @"Y:\nzbget\root\completed\downloads", @"Y:\nzbget\root\completed\downloads\vv")] [TestCase(@"Y:\sabnzbd\root", @"completed\downloads", @"vv", @"Y:\sabnzbd\root\completed\downloads", @"Y:\sabnzbd\root\completed\downloads\vv")]
[TestCase(@"Y:\nzbget\root", @"completed", @"vv", @"Y:\nzbget\root\completed", @"Y:\nzbget\root\completed\vv")] [TestCase(@"Y:\sabnzbd\root", @"completed", @"vv", @"Y:\sabnzbd\root\completed", @"Y:\sabnzbd\root\completed\vv")]
[TestCase(@"/nzbget/root", @"completed/downloads", @"vv", @"/nzbget/root/completed/downloads", @"/nzbget/root/completed/downloads/vv")] [TestCase(@"/sabnzbd/root", @"completed/downloads", @"vv", @"/sabnzbd/root/completed/downloads", @"/sabnzbd/root/completed/downloads/vv")]
[TestCase(@"/nzbget/root", @"completed", @"vv", @"/nzbget/root/completed", @"/nzbget/root/completed/vv")] [TestCase(@"/sabnzbd/root", @"completed", @"vv", @"/sabnzbd/root/completed", @"/sabnzbd/root/completed/vv")]
public void should_return_status_with_outputdir_for_version_gte_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir) public void should_return_status_with_outputdir_for_version_gte_2(string rootFolder, string completeDir, string categoryDir, string fullCompleteDir, string fullCategoryDir)
{ {
_fullStatus.CompleteDir = fullCompleteDir; _fullStatus.CompleteDir = fullCompleteDir;
@ -554,7 +554,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.SabnzbdTests
[Test] [Test]
public void should_test_failed_if_tv_sorting_default_category() public void should_test_failed_if_tv_sorting_default_category()
{ {
Subject.Definition.Settings.As<SabnzbdSettings>().TvCategory = null; Subject.Definition.Settings.As<SabnzbdSettings>().MovieCategory = null;
_config.Misc.enable_tv_sorting = true; _config.Misc.enable_tv_sorting = true;
_config.Misc.tv_categories = new[] { "Default" }; _config.Misc.tv_categories = new[] { "Default" };

@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Port = 2222, Port = 2222,
Username = "admin", Username = "admin",
Password = "pass", Password = "pass",
TvCategory = "tv" MovieCategory = "movie"
}; };
_queued = new UTorrentTorrent _queued = new UTorrentTorrent
@ -41,7 +41,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 1000, Remaining = 1000,
Progress = 0, Progress = 0,
Label = "tv", Label = "movie",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -54,7 +54,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 100, Remaining = 100,
Progress = 0.9, Progress = 0.9,
Label = "tv", Label = "movie",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -67,7 +67,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 100, Remaining = 100,
Progress = 0.9, Progress = 0.9,
Label = "tv", Label = "movie",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };
@ -80,7 +80,7 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.UTorrentTests
Size = 1000, Size = 1000,
Remaining = 0, Remaining = 0,
Progress = 1.0, Progress = 1.0,
Label = "tv", Label = "movie",
DownloadUrl = _downloadUrl, DownloadUrl = _downloadUrl,
RootDownloadPath = "somepath" RootDownloadPath = "somepath"
}; };

@ -1,4 +1,4 @@
using System; using System;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents) protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
{ {
var category = Settings.TvCategory; // TODO: Update this to MovieCategory? var category = Settings.MovieCategory;
var priority = Settings.RecentTvPriority; var priority = Settings.RecentTvPriority;
@ -204,7 +204,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public override IEnumerable<DownloadClientItem> GetItems() public override IEnumerable<DownloadClientItem> GetItems()
{ {
return GetQueue().Concat(GetHistory()).Where(downloadClientItem => downloadClientItem.Category == Settings.TvCategory); return GetQueue().Concat(GetHistory()).Where(downloadClientItem => downloadClientItem.Category == Settings.MovieCategory);
} }
public override void RemoveItem(string downloadId, bool deleteData) public override void RemoveItem(string downloadId, bool deleteData)
@ -221,7 +221,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{ {
var config = _proxy.GetConfig(Settings); var config = _proxy.GetConfig(Settings);
var category = GetCategories(config).FirstOrDefault(v => v.Name == Settings.TvCategory); var category = GetCategories(config).FirstOrDefault(v => v.Name == Settings.MovieCategory);
var status = new DownloadClientStatus var status = new DownloadClientStatus
{ {
@ -283,7 +283,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
if (Version.Parse(version) < Version.Parse("12.0")) if (Version.Parse(version) < Version.Parse("12.0"))
{ {
return new ValidationFailure(string.Empty, "Nzbget version too low, need 12.0 or higher"); return new ValidationFailure(string.Empty, "NZBGet version too low, need 12.0 or higher");
} }
} }
catch (Exception ex) catch (Exception ex)
@ -304,12 +304,12 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var config = _proxy.GetConfig(Settings); var config = _proxy.GetConfig(Settings);
var categories = GetCategories(config); var categories = GetCategories(config);
if (!Settings.TvCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.TvCategory)) if (!Settings.MovieCategory.IsNullOrWhiteSpace() && !categories.Any(v => v.Name == Settings.MovieCategory))
{ {
return new NzbDroneValidationFailure("TvCategory", "Category does not exist") return new NzbDroneValidationFailure("MovieCategory", "Category does not exist")
{ {
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
DetailedDescription = "The Category your entered doesn't exist in NzbGet. Go to NzbGet to create it." DetailedDescription = "The category you entered doesn't exist in NZBGet. Go to NZBGet to create it."
}; };
} }
@ -323,10 +323,10 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var keepHistory = config.GetValueOrDefault("KeepHistory"); var keepHistory = config.GetValueOrDefault("KeepHistory");
if (keepHistory == "0") if (keepHistory == "0")
{ {
return new NzbDroneValidationFailure(string.Empty, "NzbGet setting KeepHistory should be greater than 0") return new NzbDroneValidationFailure(string.Empty, "NZBGet setting KeepHistory should be greater than 0")
{ {
InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/", Settings.Host, Settings.Port),
DetailedDescription = "NzbGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads." DetailedDescription = "NZBGet setting KeepHistory is set to 0. Which prevents Radarr from seeing completed downloads."
}; };
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using NLog; using NLog;
@ -88,7 +88,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
var editResult = EditQueue("GroupSetParameter", 0, "drone=" + droneId, item.NzbId, settings); var editResult = EditQueue("GroupSetParameter", 0, "drone=" + droneId, item.NzbId, settings);
if (editResult) if (editResult)
{ {
_logger.Debug("Nzbget download drone parameter set to: {0}", droneId); _logger.Debug("NZBGet download drone parameter set to: {0}", droneId);
} }
return droneId; return droneId;
@ -114,7 +114,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
if (editResult) if (editResult)
{ {
_logger.Debug("Nzbget download drone parameter set to: {0}", droneId); _logger.Debug("NZBGet download drone parameter set to: {0}", droneId);
} }
return droneId; return droneId;
@ -175,7 +175,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{ {
if (!EditQueue("GroupFinalDelete", 0, "", queueItem.NzbId, settings)) if (!EditQueue("GroupFinalDelete", 0, "", queueItem.NzbId, settings))
{ {
_logger.Warn("Failed to remove item from nzbget queue, {0} [{1}]", queueItem.NzbName, queueItem.NzbId); _logger.Warn("Failed to remove item from NZBGet, {0} [{1}]", queueItem.NzbName, queueItem.NzbId);
} }
} }
@ -183,13 +183,13 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{ {
if (!EditQueue("HistoryDelete", 0, "", historyItem.Id, settings)) if (!EditQueue("HistoryDelete", 0, "", historyItem.Id, settings))
{ {
_logger.Warn("Failed to remove item from nzbget history, {0} [{1}]", historyItem.Name, historyItem.Id); _logger.Warn("Failed to remove item from NZBGet history, {0} [{1}]", historyItem.Name, historyItem.Id);
} }
} }
else else
{ {
_logger.Warn("Unable to remove item from nzbget, Unknown ID: {0}", id); _logger.Warn("Unable to remove item from NZBGet, Unknown ID: {0}", id);
return; return;
} }
} }
@ -235,21 +235,21 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{ {
if (ex.Response.StatusCode == HttpStatusCode.Unauthorized) if (ex.Response.StatusCode == HttpStatusCode.Unauthorized)
{ {
throw new DownloadClientException("Authentication failed for NzbGet, please check your settings", ex); throw new DownloadClientException("Authentication failed for NZBGet, please check your settings", ex);
} }
throw new DownloadClientException("Unable to connect to NzbGet. " + ex.Message, ex); throw new DownloadClientException("Unable to connect to NZBGet. " + ex.Message, ex);
} }
catch (WebException ex) catch (WebException ex)
{ {
throw new DownloadClientException("Unable to connect to NzbGet. " + ex.Message, ex); throw new DownloadClientException("Unable to connect to NZBGet. " + ex.Message, ex);
} }
var result = Json.Deserialize<JsonRpcResponse<T>>(response.Content); var result = Json.Deserialize<JsonRpcResponse<T>>(response.Content);
if (result.Error != null) if (result.Error != null)
{ {
throw new DownloadClientException("Error response received from nzbget: {0}", result.Error.ToString()); throw new DownloadClientException("Error response received from NZBGet: {0}", result.Error.ToString());
} }
return result.Result; return result.Result;

@ -1,4 +1,4 @@
namespace NzbDrone.Core.Download.Clients.Nzbget namespace NzbDrone.Core.Download.Clients.Nzbget
{ {
public class NzbgetResponse<T> public class NzbgetResponse<T>
{ {

@ -1,4 +1,4 @@
using FluentValidation; using FluentValidation;
using NzbDrone.Core.Annotations; using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -14,7 +14,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
RuleFor(c => c.Username).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Password)); RuleFor(c => c.Username).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Password));
RuleFor(c => c.Password).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Username)); RuleFor(c => c.Password).NotEmpty().When(c => !string.IsNullOrWhiteSpace(c.Username));
RuleFor(c => c.TvCategory).NotEmpty().WithMessage("A category is recommended").AsWarning(); RuleFor(c => c.MovieCategory).NotEmpty().WithMessage("A category is recommended").AsWarning();
} }
} }
@ -26,7 +26,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
{ {
Host = "localhost"; Host = "localhost";
Port = 6789; Port = 6789;
TvCategory = "Movies"; MovieCategory = "Movies";
Username = "nzbget"; Username = "nzbget";
Password = "tegbzn6789"; Password = "tegbzn6789";
RecentTvPriority = (int)NzbgetPriority.Normal; RecentTvPriority = (int)NzbgetPriority.Normal;
@ -46,7 +46,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
public string Password { get; set; } public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")] [FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; } public string MovieCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")] [FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(NzbgetPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")]
public int RecentTvPriority { get; set; } public int RecentTvPriority { get; set; }
@ -57,7 +57,7 @@ namespace NzbDrone.Core.Download.Clients.Nzbget
[FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)] [FieldDefinition(7, Label = "Use SSL", Type = FieldType.Checkbox)]
public bool UseSsl { get; set; } public bool UseSsl { get; set; }
[FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NzbGet version 16.0")] [FieldDefinition(8, Label = "Add Paused", Type = FieldType.Checkbox, HelpText = "This option requires at least NZBGet version 16.0")]
public bool AddPaused { get; set; } public bool AddPaused { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()

@ -21,7 +21,7 @@ namespace NzbDrone.Core.Download.Clients.QBittorrent
public QBittorrentSettings() public QBittorrentSettings()
{ {
Host = "localhost"; Host = "localhost";
Port = 9091; Port = 8080;
MovieCategory = "radarr"; MovieCategory = "radarr";
} }

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents) protected override string AddFromNzbFile(RemoteMovie remoteMovie, string filename, byte[] fileContents)
{ {
var category = Settings.TvCategory; var category = Settings.MovieCategory;
var priority = Settings.RecentTvPriority; var priority = Settings.RecentTvPriority;
var response = _proxy.DownloadNzb(fileContents, filename, category, priority, Settings); var response = _proxy.DownloadNzb(fileContents, filename, category, priority, Settings);
@ -119,7 +119,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
try try
{ {
sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings.TvCategory, Settings); sabHistory = _proxy.GetHistory(0, _configService.DownloadClientHistoryLimit, Settings.MovieCategory, Settings);
} }
catch (DownloadClientException ex) catch (DownloadClientException ex)
{ {
@ -200,7 +200,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{ {
foreach (var downloadClientItem in GetQueue().Concat(GetHistory())) foreach (var downloadClientItem in GetQueue().Concat(GetHistory()))
{ {
if (downloadClientItem.Category == Settings.TvCategory || downloadClientItem.Category == "*" && Settings.TvCategory.IsNullOrWhiteSpace()) if (downloadClientItem.Category == Settings.MovieCategory || downloadClientItem.Category == "*" && Settings.MovieCategory.IsNullOrWhiteSpace())
{ {
yield return downloadClientItem; yield return downloadClientItem;
} }
@ -254,7 +254,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var config = _proxy.GetConfig(Settings); var config = _proxy.GetConfig(Settings);
var categories = GetCategories(config).ToArray(); var categories = GetCategories(config).ToArray();
var category = categories.FirstOrDefault(v => v.Name == Settings.TvCategory); var category = categories.FirstOrDefault(v => v.Name == Settings.MovieCategory);
if (category == null) if (category == null)
{ {
@ -366,7 +366,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
if (rawVersion.Equals("develop", StringComparison.InvariantCultureIgnoreCase)) if (rawVersion.Equals("develop", StringComparison.InvariantCultureIgnoreCase))
{ {
return new NzbDroneValidationFailure("Version", "Sabnzbd develop version, assuming version 1.1.0 or higher.") return new NzbDroneValidationFailure("Version", "SABnzbd develop version, assuming version 1.1.0 or higher.")
{ {
IsWarning = true, IsWarning = true,
DetailedDescription = "Radarr may not be able to support new features added to SABnzbd when running develop versions." DetailedDescription = "Radarr may not be able to support new features added to SABnzbd when running develop versions."
@ -419,10 +419,10 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
var config = _proxy.GetConfig(Settings); var config = _proxy.GetConfig(Settings);
if (config.Misc.pre_check && !HasVersion(1, 1)) if (config.Misc.pre_check && !HasVersion(1, 1))
{ {
return new NzbDroneValidationFailure("", "Disable 'Check before download' option in Sabnbzd") return new NzbDroneValidationFailure("", "Disable 'Check before download' option in SABnzbd")
{ {
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/switches/", Settings.Host, Settings.Port),
DetailedDescription = "Using Check before download affects Radarr ability to track new downloads. Also Sabnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective." DetailedDescription = "Using Check before download affects Radarr ability to track new downloads. Also SABnzbd recommends 'Abort jobs that cannot be completed' instead since it's more effective."
}; };
} }
@ -432,52 +432,52 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
private ValidationFailure TestCategory() private ValidationFailure TestCategory()
{ {
var config = _proxy.GetConfig(Settings); var config = _proxy.GetConfig(Settings);
var category = GetCategories(config).FirstOrDefault((SabnzbdCategory v) => v.Name == Settings.TvCategory); var category = GetCategories(config).FirstOrDefault((SabnzbdCategory v) => v.Name == Settings.MovieCategory);
if (category != null) if (category != null)
{ {
if (category.Dir.EndsWith("*")) if (category.Dir.EndsWith("*"))
{ {
return new NzbDroneValidationFailure("TvCategory", "Enable Job folders") return new NzbDroneValidationFailure("MovieCategory", "Enable Job folders")
{ {
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
DetailedDescription = "Radarr prefers each download to have a separate folder. With * appended to the Folder/Path Sabnzbd will not create these job folders. Go to Sabnzbd to fix it." DetailedDescription = "Radarr prefers each download to have a separate folder. With * appended to the Folder/Path SABnzbd will not create these job folders. Go to SABnzbd to fix it."
}; };
} }
} }
else else
{ {
if (!Settings.TvCategory.IsNullOrWhiteSpace()) if (!Settings.MovieCategory.IsNullOrWhiteSpace())
{ {
return new NzbDroneValidationFailure("TvCategory", "Category does not exist") return new NzbDroneValidationFailure("MovieCategory", "Category does not exist")
{ {
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/categories/", Settings.Host, Settings.Port),
DetailedDescription = "The Category your entered doesn't exist in Sabnzbd. Go to Sabnzbd to create it." DetailedDescription = "The category you entered doesn't exist in SABnzbd. Go to SABnzbd to create it."
}; };
} }
} }
if (config.Misc.enable_tv_sorting && ContainsCategory(config.Misc.tv_categories, Settings.TvCategory)) if (config.Misc.enable_tv_sorting && ContainsCategory(config.Misc.tv_categories, Settings.MovieCategory))
{ {
return new NzbDroneValidationFailure("TvCategory", "Disable TV Sorting") return new NzbDroneValidationFailure("MovieCategory", "Disable TV Sorting")
{ {
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd TV Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it." DetailedDescription = "You must disable SABnzbd TV Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
}; };
} }
if (config.Misc.enable_movie_sorting && ContainsCategory(config.Misc.movie_categories, Settings.TvCategory)) if (config.Misc.enable_movie_sorting && ContainsCategory(config.Misc.movie_categories, Settings.MovieCategory))
{ {
return new NzbDroneValidationFailure("TvCategory", "Disable Movie Sorting") return new NzbDroneValidationFailure("MovieCategory", "Disable Movie Sorting")
{ {
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd Movie Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it." DetailedDescription = "You must disable SABnzbd Movie Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
}; };
} }
if (config.Misc.enable_date_sorting && ContainsCategory(config.Misc.date_categories, Settings.TvCategory)) if (config.Misc.enable_date_sorting && ContainsCategory(config.Misc.date_categories, Settings.MovieCategory))
{ {
return new NzbDroneValidationFailure("TvCategory", "Disable Date Sorting") return new NzbDroneValidationFailure("MovieCategory", "Disable Date Sorting")
{ {
InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port), InfoLink = string.Format("http://{0}:{1}/sabnzbd/config/sorting/", Settings.Host, Settings.Port),
DetailedDescription = "You must disable Sabnzbd Date Sorting for the category Radarr uses to prevent import issues. Go to Sabnzbd to fix it." DetailedDescription = "You must disable SABnzbd Date Sorting for the category Radarr uses to prevent import issues. Go to SABnzbd to fix it."
}; };
} }

@ -1,4 +1,4 @@
using FluentValidation; using FluentValidation;
using NzbDrone.Core.Annotations; using NzbDrone.Core.Annotations;
using NzbDrone.Core.ThingiProvider; using NzbDrone.Core.ThingiProvider;
using NzbDrone.Core.Validation; using NzbDrone.Core.Validation;
@ -24,7 +24,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
.WithMessage("Password is required when API key is not configured") .WithMessage("Password is required when API key is not configured")
.When(c => string.IsNullOrWhiteSpace(c.ApiKey)); .When(c => string.IsNullOrWhiteSpace(c.ApiKey));
RuleFor(c => c.TvCategory).NotEmpty() RuleFor(c => c.MovieCategory).NotEmpty()
.WithMessage("A category is recommended") .WithMessage("A category is recommended")
.AsWarning(); .AsWarning();
} }
@ -38,7 +38,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
{ {
Host = "localhost"; Host = "localhost";
Port = 8080; Port = 8080;
TvCategory = "movies"; MovieCategory = "movies";
RecentTvPriority = (int)SabnzbdPriority.Default; RecentTvPriority = (int)SabnzbdPriority.Default;
OlderTvPriority = (int)SabnzbdPriority.Default; OlderTvPriority = (int)SabnzbdPriority.Default;
} }
@ -59,7 +59,7 @@ namespace NzbDrone.Core.Download.Clients.Sabnzbd
public string Password { get; set; } public string Password { get; set; }
[FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")] [FieldDefinition(5, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; } public string MovieCategory { get; set; }
[FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")] [FieldDefinition(6, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(SabnzbdPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")]
public int RecentTvPriority { get; set; } public int RecentTvPriority { get; set; }

@ -1,4 +1,4 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Collections.Generic; using System.Collections.Generic;
using NzbDrone.Common.Disk; using NzbDrone.Common.Disk;
@ -49,7 +49,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink) protected override string AddFromMagnetLink(RemoteMovie remoteMovie, string hash, string magnetLink)
{ {
_proxy.AddTorrentFromUrl(magnetLink, Settings); _proxy.AddTorrentFromUrl(magnetLink, Settings);
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings); _proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode(); /*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
@ -59,13 +59,15 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
_proxy.MoveTorrentToTopInQueue(hash, Settings); _proxy.MoveTorrentToTopInQueue(hash, Settings);
}*/ }*/
_proxy.SetState(hash, (UTorrentState)Settings.IntialState, Settings);
return hash; return hash;
} }
protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent) protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string hash, string filename, byte[] fileContent)
{ {
_proxy.AddTorrentFromFile(filename, fileContent, Settings); _proxy.AddTorrentFromFile(filename, fileContent, Settings);
_proxy.SetTorrentLabel(hash, Settings.TvCategory, Settings); _proxy.SetTorrentLabel(hash, Settings.MovieCategory, Settings);
/*var isRecentEpisode = remoteEpisode.IsRecentEpisode(); /*var isRecentEpisode = remoteEpisode.IsRecentEpisode();
@ -75,6 +77,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
_proxy.MoveTorrentToTopInQueue(hash, Settings); _proxy.MoveTorrentToTopInQueue(hash, Settings);
}*/ }*/
_proxy.SetState(hash, (UTorrentState)Settings.IntialState, Settings);
return hash; return hash;
} }
@ -86,7 +90,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
try try
{ {
var cacheKey = string.Format("{0}:{1}:{2}", Settings.Host, Settings.Port, Settings.TvCategory); var cacheKey = string.Format("{0}:{1}:{2}", Settings.Host, Settings.Port, Settings.MovieCategory);
var cache = _torrentCache.Find(cacheKey); var cache = _torrentCache.Find(cacheKey);
var response = _proxy.GetTorrents(cache == null ? null : cache.CacheID, Settings); var response = _proxy.GetTorrents(cache == null ? null : cache.CacheID, Settings);
@ -123,7 +127,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
foreach (var torrent in torrents) foreach (var torrent in torrents)
{ {
if (torrent.Label != Settings.TvCategory) if (torrent.Label != Settings.MovieCategory)
{ {
continue; continue;
} }
@ -205,7 +209,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
if (config.GetValueOrDefault("dir_add_label") == "true") if (config.GetValueOrDefault("dir_add_label") == "true")
{ {
destDir = destDir + Settings.TvCategory; destDir = destDir + Settings.MovieCategory;
} }
} }

@ -22,6 +22,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
void RemoveTorrent(string hash, bool removeData, UTorrentSettings settings); void RemoveTorrent(string hash, bool removeData, UTorrentSettings settings);
void SetTorrentLabel(string hash, string label, UTorrentSettings settings); void SetTorrentLabel(string hash, string label, UTorrentSettings settings);
void MoveTorrentToTopInQueue(string hash, UTorrentSettings settings); void MoveTorrentToTopInQueue(string hash, UTorrentSettings settings);
void SetState(string hash, UTorrentState state, UTorrentSettings settings);
} }
public class UTorrentProxy : IUTorrentProxy public class UTorrentProxy : IUTorrentProxy
@ -157,6 +158,15 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
ProcessRequest(requestBuilder, settings); ProcessRequest(requestBuilder, settings);
} }
public void SetState(string hash, UTorrentState state, UTorrentSettings settings)
{
var requestBuilder = BuildRequest(settings)
.AddQueryParam("action", state.ToString().ToLowerInvariant())
.AddQueryParam("hash", hash);
ProcessRequest(requestBuilder, settings);
}
private HttpRequestBuilder BuildRequest(UTorrentSettings settings) private HttpRequestBuilder BuildRequest(UTorrentSettings settings)
{ {
var requestBuilder = new HttpRequestBuilder(false, settings.Host, settings.Port) var requestBuilder = new HttpRequestBuilder(false, settings.Host, settings.Port)

@ -11,7 +11,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
{ {
RuleFor(c => c.Host).ValidHost(); RuleFor(c => c.Host).ValidHost();
RuleFor(c => c.Port).InclusiveBetween(1, 65535); RuleFor(c => c.Port).InclusiveBetween(1, 65535);
RuleFor(c => c.TvCategory).NotEmpty(); RuleFor(c => c.MovieCategory).NotEmpty();
} }
} }
@ -22,8 +22,8 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
public UTorrentSettings() public UTorrentSettings()
{ {
Host = "localhost"; Host = "localhost";
Port = 9091; Port = 8080;
TvCategory = "radarr"; MovieCategory = "radarr";
} }
[FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)] [FieldDefinition(0, Label = "Host", Type = FieldType.Textbox)]
@ -39,7 +39,7 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
public string Password { get; set; } public string Password { get; set; }
[FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")] [FieldDefinition(4, Label = "Category", Type = FieldType.Textbox, HelpText = "Adding a category specific to Radarr avoids conflicts with unrelated downloads, but it's optional")]
public string TvCategory { get; set; } public string MovieCategory { get; set; }
[FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")] [FieldDefinition(5, Label = "Recent Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing releases that aired within the last 14 days")]
public int RecentTvPriority { get; set; } public int RecentTvPriority { get; set; }
@ -47,6 +47,9 @@ namespace NzbDrone.Core.Download.Clients.UTorrent
[FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing releases that aired over 14 days ago")] [FieldDefinition(6, Label = "Older Priority", Type = FieldType.Select, SelectOptions = typeof(UTorrentPriority), HelpText = "Priority to use when grabbing releases that aired over 14 days ago")]
public int OlderTvPriority { get; set; } public int OlderTvPriority { get; set; }
[FieldDefinition(7, Label = "Initial State", Type = FieldType.Select, SelectOptions = typeof(UTorrentState), HelpText = "Initial state for torrents added to uTorrent")]
public int IntialState { get; set; }
public NzbDroneValidationResult Validate() public NzbDroneValidationResult Validate()
{ {
return new NzbDroneValidationResult(Validator.Validate(this)); return new NzbDroneValidationResult(Validator.Validate(this));

@ -0,0 +1,10 @@
namespace NzbDrone.Core.Download.Clients.UTorrent
{
public enum UTorrentState
{
Start = 0,
ForceStart = 1,
Pause = 2,
Stop = 3
}
}

@ -1,4 +1,4 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.IO; using System.IO;
@ -31,6 +31,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
{ {
var movie = message.Movie; var movie = message.Movie;
var remoteMovie = message.RemoteMovie; var remoteMovie = message.RemoteMovie;
var quality = message.Quality;
var environmentVariables = new StringDictionary(); var environmentVariables = new StringDictionary();
environmentVariables.Add("Radarr_EventType", "Grab"); environmentVariables.Add("Radarr_EventType", "Grab");
@ -42,6 +43,8 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer); environmentVariables.Add("Radarr_Release_Indexer", remoteMovie.Release.Indexer);
environmentVariables.Add("Radarr_Release_Size", remoteMovie.Release.Size.ToString()); environmentVariables.Add("Radarr_Release_Size", remoteMovie.Release.Size.ToString());
environmentVariables.Add("Radarr_Release_ReleaseGroup", remoteMovie.ParsedMovieInfo.ReleaseGroup ?? string.Empty); environmentVariables.Add("Radarr_Release_ReleaseGroup", remoteMovie.ParsedMovieInfo.ReleaseGroup ?? string.Empty);
environmentVariables.Add("Radarr_Release_Quality", quality.Quality.Name);
environmentVariables.Add("Radarr_Release_QualityVersion", quality.Revision.Version.ToString());
ExecuteScript(environmentVariables); ExecuteScript(environmentVariables);
} }
@ -54,6 +57,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
var environmentVariables = new StringDictionary(); var environmentVariables = new StringDictionary();
environmentVariables.Add("Radarr_EventType", "Download"); environmentVariables.Add("Radarr_EventType", "Download");
environmentVariables.Add("Radarr_IsUpgrade", message.OldMovieFiles.Any().ToString());
environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString()); environmentVariables.Add("Radarr_Movie_Id", movie.Id.ToString());
environmentVariables.Add("Radarr_Movie_Title", movie.Title); environmentVariables.Add("Radarr_Movie_Title", movie.Title);
environmentVariables.Add("Radarr_Movie_Path", movie.Path); environmentVariables.Add("Radarr_Movie_Path", movie.Path);
@ -69,6 +73,11 @@ namespace NzbDrone.Core.Notifications.CustomScript
environmentVariables.Add("Radarr_MovieFile_SourcePath", sourcePath); environmentVariables.Add("Radarr_MovieFile_SourcePath", sourcePath);
environmentVariables.Add("Radarr_MovieFile_SourceFolder", Path.GetDirectoryName(sourcePath)); environmentVariables.Add("Radarr_MovieFile_SourceFolder", Path.GetDirectoryName(sourcePath));
if (message.OldMovieFiles.Any())
{
environmentVariables.Add("Radarr_DeletedRelativePaths", string.Join("|", message.OldMovieFiles.Select(e => e.RelativePath)));
environmentVariables.Add("Radarr_DeletedPaths", string.Join("|", message.OldMovieFiles.Select(e => Path.Combine(movie.Path, e.RelativePath))));
}
ExecuteScript(environmentVariables); ExecuteScript(environmentVariables);
} }

@ -1,35 +1,64 @@

using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using FluentValidation.Results; using FluentValidation.Results;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Validation;
namespace NzbDrone.Core.Notifications.Webhook namespace NzbDrone.Core.Notifications.Webhook
{ {
public class Webhook : NotificationBase<WebhookSettings> public class Webhook : NotificationBase<WebhookSettings>
{ {
private readonly IWebhookService _service; private readonly IWebhookProxy _proxy;
public Webhook(IWebhookService service) public Webhook(IWebhookProxy proxy)
{ {
_service = service; _proxy = proxy;
} }
public override string Link => "https://github.com/Radarr/Radarr/wiki/Webhook"; public override string Link => "https://github.com/Radarr/Radarr/wiki/Webhook";
public override void OnGrab(GrabMessage message) public override void OnGrab(GrabMessage message)
{ {
_service.OnGrab(message.Movie, message.RemoteMovie, message.Quality, Settings); var remoteMovie = message.RemoteMovie;
var quality = message.Quality;
var payload = new WebhookGrabPayload
{
EventType = "Grab",
Movie = new WebhookMovie(message.Movie),
RemoteMovie = new WebhookRemoteMovie(remoteMovie),
Release = new WebhookRelease(quality, remoteMovie)
};
_proxy.SendWebhook(payload, Settings);
} }
public override void OnDownload(DownloadMessage message) public override void OnDownload(DownloadMessage message)
{ {
_service.OnDownload(message.Movie, message.MovieFile, Settings); var movieFile = message.MovieFile;
var payload = new WebhookImportPayload
{
EventType = "Download",
Movie = new WebhookMovie(message.Movie),
RemoteMovie = new WebhookRemoteMovie(message.Movie),
MovieFile = new WebhookMovieFile(movieFile),
IsUpgrade = message.OldMovieFiles.Any()
};
_proxy.SendWebhook(payload, Settings);
} }
public override void OnMovieRename(Movie movie) public override void OnMovieRename(Movie movie)
{ {
_service.OnRename(movie, Settings); var payload = new WebhookPayload
{
EventType = "Rename",
Movie = new WebhookMovie(movie)
};
_proxy.SendWebhook(payload, Settings);
} }
public override void OnRename(Series series) public override void OnRename(Series series)
@ -42,9 +71,51 @@ namespace NzbDrone.Core.Notifications.Webhook
{ {
var failures = new List<ValidationFailure>(); var failures = new List<ValidationFailure>();
failures.AddIfNotNull(_service.Test(Settings)); failures.AddIfNotNull(SendWebhookTest());
return new ValidationResult(failures); return new ValidationResult(failures);
} }
private ValidationFailure SendWebhookTest()
{
try
{
var payload = new WebhookGrabPayload
{
EventType = "Test",
Movie = new WebhookMovie
{
Id = 1,
Title = "Test Title",
FilePath = "C:\\testpath",
ReleaseDate = "1970-01-01"
},
RemoteMovie = new WebhookRemoteMovie
{
TmdbId = 1234,
ImdbId = "5678",
Title = "Test title",
Year = 1970
},
Release = new WebhookRelease
{
Indexer = "Test Indexer",
Quality = "Test Quality",
QualityVersion = 1,
ReleaseGroup = "Test Group",
ReleaseTitle = "Test Title",
Size = 9999999
}
};
_proxy.SendWebhook(payload, Settings);
}
catch (WebhookException ex)
{
return new NzbDroneValidationFailure("Url", ex.Message);
}
return null;
}
} }
} }

@ -1,32 +0,0 @@
using NzbDrone.Core.Tv;
using System;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookEpisode
{
public WebhookEpisode() { }
public WebhookEpisode(Episode episode)
{
Id = episode.Id;
SeasonNumber = episode.SeasonNumber;
EpisodeNumber = episode.EpisodeNumber;
Title = episode.Title;
AirDate = episode.AirDate;
AirDateUtc = episode.AirDateUtc;
}
public int Id { get; set; }
public int EpisodeNumber { get; set; }
public int SeasonNumber { get; set; }
public string Title { get; set; }
public string AirDate { get; set; }
public DateTime? AirDateUtc { get; set; }
public string Quality { get; set; }
public int QualityVersion { get; set; }
public string ReleaseGroup { get; set; }
public string SceneName { get; set; }
}
}

@ -0,0 +1,8 @@
namespace NzbDrone.Core.Notifications.Webhook
{
class WebhookGrabPayload : WebhookPayload
{
public WebhookRemoteMovie RemoteMovie { get; set; }
public WebhookRelease Release { get; set; }
}
}

@ -0,0 +1,9 @@
namespace NzbDrone.Core.Notifications.Webhook
{
class WebhookImportPayload : WebhookPayload
{
public WebhookRemoteMovie RemoteMovie { get; set; }
public WebhookMovieFile MovieFile { get; set; }
public bool IsUpgrade { get; set; }
}
}

@ -1,8 +1,10 @@
namespace NzbDrone.Core.Notifications.Webhook using NzbDrone.Common.Http;
namespace NzbDrone.Core.Notifications.Webhook
{ {
public enum WebhookMethod public enum WebhookMethod
{ {
POST = RestSharp.Method.POST, POST = HttpMethod.POST,
PUT = RestSharp.Method.PUT PUT = HttpMethod.PUT
} }
} }

@ -9,6 +9,7 @@ namespace NzbDrone.Core.Notifications.Webhook
public int Id { get; set; } public int Id { get; set; }
public string Title { get; set; } public string Title { get; set; }
public string FilePath { get; set; } public string FilePath { get; set; }
public string ReleaseDate { get; set; }
public WebhookMovie() { } public WebhookMovie() { }
@ -16,12 +17,11 @@ namespace NzbDrone.Core.Notifications.Webhook
{ {
Id = movie.Id; Id = movie.Id;
Title = movie.Title; Title = movie.Title;
ReleaseDate = movie.PhysicalReleaseDate().ToString("yyyy-MM-dd");
} }
public WebhookMovie(Movie movie, MovieFile movieFile) public WebhookMovie(Movie movie, MovieFile movieFile) : this(movie)
{ {
Id = movie.Id;
Title = movie.Title;
FilePath = Path.Combine(movie.Path, movieFile.RelativePath); FilePath = Path.Combine(movie.Path, movieFile.RelativePath);
} }
} }

@ -0,0 +1,28 @@
using NzbDrone.Core.MediaFiles;
namespace NzbDrone.Core.Notifications.Webhook
{
class WebhookMovieFile
{
public WebhookMovieFile() { }
public WebhookMovieFile(MovieFile movieFile)
{
Id = movieFile.Id;
RelativePath = movieFile.RelativePath;
Path = movieFile.Path;
Quality = movieFile.Quality.Quality.Name;
QualityVersion = movieFile.Quality.Revision.Version;
ReleaseGroup = movieFile.ReleaseGroup;
SceneName = movieFile.SceneName;
}
public int Id { get; set; }
public string RelativePath { get; set; }
public string Path { get; set; }
public string Quality { get; set; }
public int QualityVersion { get; set; }
public string ReleaseGroup { get; set; }
public string SceneName { get; set; }
}
}

@ -1,11 +1,8 @@
using System.Collections.Generic;
namespace NzbDrone.Core.Notifications.Webhook namespace NzbDrone.Core.Notifications.Webhook
{ {
public class WebhookPayload public class WebhookPayload
{ {
public string EventType { get; set; } public string EventType { get; set; }
public WebhookMovie Movie { get; set; } public WebhookMovie Movie { get; set; }
public WebhookRemoteMovie RemoteMovie { get; set; }
} }
} }

@ -0,0 +1,41 @@
using NzbDrone.Common.Http;
using NzbDrone.Common.Serializer;
using NzbDrone.Core.Rest;
namespace NzbDrone.Core.Notifications.Webhook
{
public interface IWebhookProxy
{
void SendWebhook(WebhookPayload payload, WebhookSettings settings);
}
class WebhookProxy : IWebhookProxy
{
private readonly IHttpClient _httpClient;
public WebhookProxy(IHttpClient httpClient)
{
_httpClient = httpClient;
}
public void SendWebhook(WebhookPayload body, WebhookSettings settings)
{
try
{
var request = new HttpRequestBuilder(settings.Url)
.Accept(HttpAccept.Json)
.Build();
request.Method = (HttpMethod)settings.Method;
request.Headers.ContentType = "application/json";
request.SetContent(body.ToJson());
_httpClient.Execute(request);
}
catch (RestException ex)
{
throw new WebhookException("Unable to post to webhook: {0}", ex, ex.Message);
}
}
}
}

@ -0,0 +1,27 @@
using NzbDrone.Core.Parser.Model;
using NzbDrone.Core.Qualities;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookRelease
{
public WebhookRelease() { }
public WebhookRelease(QualityModel quality, RemoteMovie remoteMovie)
{
Quality = quality.Quality.Name;
QualityVersion = quality.Revision.Version;
ReleaseGroup = remoteMovie.ParsedMovieInfo.ReleaseGroup;
ReleaseTitle = remoteMovie.Release.Title;
Indexer = remoteMovie.Release.Indexer;
Size = remoteMovie.Release.Size;
}
public string Quality { get; set; }
public int QualityVersion { get; set; }
public string ReleaseGroup { get; set; }
public string ReleaseTitle { get; set; }
public string Indexer { get; set; }
public long Size { get; set; }
}
}

@ -1,22 +0,0 @@
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Notifications.Webhook
{
public class WebhookSeries
{
public int Id { get; set; }
public string Title { get; set; }
public string Path { get; set; }
public int TvdbId { get; set; }
public WebhookSeries() { }
public WebhookSeries(Series series)
{
Id = series.Id;
Title = series.Title;
Path = series.Path;
TvdbId = series.TvdbId;
}
}
}

@ -1,103 +0,0 @@
using FluentValidation.Results;
using NzbDrone.Core.MediaFiles;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Validation;
using NzbDrone.Core.Rest;
using RestSharp;
using NzbDrone.Core.Qualities;
using NzbDrone.Core.Parser.Model;
using System.Collections.Generic;
namespace NzbDrone.Core.Notifications.Webhook
{
public interface IWebhookService
{
void OnDownload(Movie movie, MovieFile movieFile, WebhookSettings settings);
void OnRename(Movie movie, WebhookSettings settings);
void OnGrab(Movie movie, RemoteMovie remoteMovie, QualityModel quality, WebhookSettings settings);
ValidationFailure Test(WebhookSettings settings);
}
public class WebhookService : IWebhookService
{
public void OnDownload(Movie movie, MovieFile movieFile, WebhookSettings settings)
{
var payload = new WebhookPayload
{
EventType = "Download",
Movie = new WebhookMovie(movie, movieFile),
RemoteMovie = new WebhookRemoteMovie(movie)
};
NotifyWebhook(payload, settings);
}
public void OnRename(Movie movie, WebhookSettings settings)
{
var payload = new WebhookPayload
{
EventType = "Rename",
Movie = new WebhookMovie(movie)
};
NotifyWebhook(payload, settings);
}
public void OnGrab(Movie movie, RemoteMovie remoteMovie, QualityModel quality, WebhookSettings settings)
{
var payload = new WebhookPayload
{
EventType = "Grab",
Movie = new WebhookMovie(movie),
RemoteMovie = new WebhookRemoteMovie(remoteMovie)
};
NotifyWebhook(payload, settings);
}
public void NotifyWebhook(WebhookPayload body, WebhookSettings settings)
{
try {
var client = RestClientFactory.BuildClient(settings.Url);
var request = new RestRequest((Method) settings.Method);
request.RequestFormat = DataFormat.Json;
request.AddBody(body);
client.ExecuteAndValidate(request);
}
catch (RestException ex)
{
throw new WebhookException("Unable to post to webhook: {0}", ex, ex.Message);
}
}
public ValidationFailure Test(WebhookSettings settings)
{
try
{
NotifyWebhook(
new WebhookPayload
{
EventType = "Test",
Movie = new WebhookMovie()
{
Id = 1,
Title = "Test Title",
FilePath = "C:\\testpath",
},
RemoteMovie = new WebhookRemoteMovie(){
ImdbId = "tt012345",
Title = "My Awesome Movie!"
}
},
settings
);
}
catch (WebhookException ex)
{
return new NzbDroneValidationFailure("Url", ex.Message);
}
return null;
}
}
}

@ -556,6 +556,7 @@
<Compile Include="Download\Clients\uTorrent\UTorrentProxy.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentProxy.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentResponse.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentResponse.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentSettings.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentSettings.cs" />
<Compile Include="Download\Clients\uTorrent\UtorrentState.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentTorrent.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentTorrent.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentTorrentCache.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentTorrentCache.cs" />
<Compile Include="Download\Clients\uTorrent\UTorrentTorrentStatus.cs" /> <Compile Include="Download\Clients\uTorrent\UTorrentTorrentStatus.cs" />
@ -985,14 +986,16 @@
<Compile Include="Notifications\Telegram\TelegramSettings.cs" /> <Compile Include="Notifications\Telegram\TelegramSettings.cs" />
<Compile Include="Notifications\Twitter\OAuthToken.cs" /> <Compile Include="Notifications\Twitter\OAuthToken.cs" />
<Compile Include="Notifications\Twitter\TwitterException.cs" /> <Compile Include="Notifications\Twitter\TwitterException.cs" />
<Compile Include="Notifications\Webhook\WebhookEpisode.cs" />
<Compile Include="Notifications\Webhook\WebhookException.cs" /> <Compile Include="Notifications\Webhook\WebhookException.cs" />
<Compile Include="Notifications\Webhook\WebhookGrabPayload.cs" />
<Compile Include="Notifications\Webhook\WebhookImportPayload.cs" />
<Compile Include="Notifications\Webhook\WebhookMethod.cs" /> <Compile Include="Notifications\Webhook\WebhookMethod.cs" />
<Compile Include="Notifications\Webhook\WebhookMovieFile.cs" />
<Compile Include="Notifications\Webhook\WebhookPayload.cs" /> <Compile Include="Notifications\Webhook\WebhookPayload.cs" />
<Compile Include="Notifications\Webhook\WebhookSeries.cs" /> <Compile Include="Notifications\Webhook\WebhookProxy.cs" />
<Compile Include="Notifications\Webhook\WebhookRelease.cs" />
<Compile Include="Notifications\Webhook\WebhookMovie.cs" /> <Compile Include="Notifications\Webhook\WebhookMovie.cs" />
<Compile Include="Notifications\Webhook\WebhookRemoteMovie.cs" /> <Compile Include="Notifications\Webhook\WebhookRemoteMovie.cs" />
<Compile Include="Notifications\Webhook\WebhookService.cs" />
<Compile Include="Notifications\Webhook\WebhookSettings.cs" /> <Compile Include="Notifications\Webhook\WebhookSettings.cs" />
<Compile Include="Notifications\Webhook\Webhook.cs" /> <Compile Include="Notifications\Webhook\Webhook.cs" />
<Compile Include="Organizer\NamingConfigRepository.cs" /> <Compile Include="Organizer\NamingConfigRepository.cs" />
@ -1390,4 +1393,4 @@
<Target Name="AfterBuild"> <Target Name="AfterBuild">
</Target> </Target>
--> -->
</Project> </Project>

@ -1,27 +1,27 @@
using FluentValidation.Validators; using FluentValidation.Validators;
using NzbDrone.Common.Extensions; using NzbDrone.Common.Extensions;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Validation.Paths namespace NzbDrone.Core.Validation.Paths
{ {
public class MoviePathValidator : PropertyValidator public class MoviePathValidator : PropertyValidator
{ {
private readonly IMovieService _seriesService; private readonly IMovieService _moviesService;
public MoviePathValidator(IMovieService seriesService) public MoviePathValidator(IMovieService moviesService)
: base("Path is already configured for another series") : base("Path is already configured for another movie")
{ {
_seriesService = seriesService; _moviesService = moviesService;
} }
protected override bool IsValid(PropertyValidatorContext context) protected override bool IsValid(PropertyValidatorContext context)
{ {
if (context.PropertyValue == null) return true; if (context.PropertyValue == null) return true;
dynamic instance = context.ParentContext.InstanceToValidate; dynamic instance = context.ParentContext.InstanceToValidate;
var instanceId = (int)instance.Id; var instanceId = (int)instance.Id;
return (!_seriesService.GetAllMovies().Exists(s => s.Path.PathEquals(context.PropertyValue.ToString()) && s.Id != instanceId)); return (!_moviesService.GetAllMovies().Exists(s => s.Path.PathEquals(context.PropertyValue.ToString()) && s.Id != instanceId));
} }
} }
} }

@ -41,8 +41,7 @@
.help-inline { .help-inline {
display : inline-block; display : inline-block;
margin-top : 8px; padding-left : 0px;
padding-left : 0;
@media (max-width: @screen-xs-max) { @media (max-width: @screen-xs-max) {
margin-left: 0; margin-left: 0;

@ -1,7 +1,7 @@
.hotkeys-modal { .hotkeys-modal {
h3 { h3 {
margin-top : 0; margin-top : 0;
margin-botton : 0; margin-bottom : 0;
} }
.hotkey-group { .hotkey-group {
@ -20,4 +20,4 @@
font-size : 22px; font-size : 22px;
} }
} }
} }

@ -86,7 +86,7 @@ var Collection = PageableCollection.extend({
return {}; return {};
} }
if (this.state.pageSize == -1) { if (this.state.pageSize === -1) {
return this.state; return this.state;
} }
@ -98,7 +98,7 @@ var Collection = PageableCollection.extend({
}, },
parseRecords : function(resp) { parseRecords : function(resp) {
if (resp && this.mode !== 'client' && this.state.pageSize != 0 && this.state.pageSize != -1) { if (resp && this.mode !== 'client' && this.state.pageSize !== 0 && this.state.pageSize !== -1) {
return resp.records; return resp.records;
} }
@ -252,7 +252,7 @@ var Collection = PageableCollection.extend({
}, },
add : function(model, options) { add : function(model, options) {
if (this.length >= this.state.pageSize && this.state.pageSize != -1) { if (this.length >= this.state.pageSize && this.state.pageSize !== -1) {
return; return;
} }
this.origAdd.call(this, model, options); this.origAdd.call(this, model, options);

@ -1,4 +1,8 @@
<div id="x-toolbar"/> <div id="x-toolbar"/>
<div class="alert alert-warning alert-dismissable">
<a href="#" class="close" data-dismiss="alert" aria-label="close">&times;</a>
If the log viewer table does not load, please disable your adblocker and refresh the page.
</div>
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<div id="x-grid" class="table-responsive"/> <div id="x-grid" class="table-responsive"/>

Loading…
Cancel
Save