diff --git a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj index 27c9875a0..29f1ff7b5 100644 --- a/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj +++ b/NzbDrone.Core.Test/NzbDrone.Core.Test.csproj @@ -80,6 +80,7 @@ + diff --git a/NzbDrone.Core.Test/ProviderTests/GrowlProviderTest.cs b/NzbDrone.Core.Test/ProviderTests/GrowlProviderTest.cs new file mode 100644 index 000000000..a7586aa7f --- /dev/null +++ b/NzbDrone.Core.Test/ProviderTests/GrowlProviderTest.cs @@ -0,0 +1,73 @@ +using System; +using AutoMoq; +using FizzWare.NBuilder; +using FluentAssertions; +using Moq; +using NUnit.Framework; +using NzbDrone.Core.Model; +using NzbDrone.Core.Providers; +using NzbDrone.Core.Repository; +using NzbDrone.Core.Repository.Quality; +using NzbDrone.Core.Test.Framework; + +// ReSharper disable InconsistentNaming + +namespace NzbDrone.Core.Test.ProviderTests +{ + [Explicit] + [TestFixture] + public class GrowlProviderTest : TestBase + { + [Test] + public void Register_should_add_new_application_to_local_growl_instance() + { + //Setup + var mocker = new AutoMoqer(MockBehavior.Strict); + + //Act + mocker.Resolve().Register("localhost", 23053, ""); + + //Assert + mocker.VerifyAllMocks(); + } + + [Test] + public void TestNotification_should_send_a_message_to_local_growl_instance() + { + //Setup + var mocker = new AutoMoqer(MockBehavior.Strict); + + //Act + mocker.Resolve().TestNotification("localhost", 23053, ""); + + //Assert + mocker.VerifyAllMocks(); + } + + [Test] + public void OnGrab_should_send_a_message_to_local_growl_instance() + { + //Setup + var mocker = new AutoMoqer(MockBehavior.Strict); + + //Act + mocker.Resolve().SendNotification("Episode Grabbed", "Series Title - 1x05 - Episode Title", "GRAB", "localhost", 23053, ""); + + //Assert + mocker.VerifyAllMocks(); + } + + [Test] + public void OnDownload_should_send_a_message_to_local_growl_instance() + { + //Setup + var mocker = new AutoMoqer(MockBehavior.Strict); + + //Act + mocker.Resolve().SendNotification("Episode Downloaded", "Series Title - 1x05 - Episode Title", "DOWNLOAD", "localhost", 23053, ""); + + //Assert + mocker.VerifyAllMocks(); + } + } +} \ No newline at end of file diff --git a/NzbDrone.Core/CentralDispatch.cs b/NzbDrone.Core/CentralDispatch.cs index 276551bf1..2e950e7af 100644 --- a/NzbDrone.Core/CentralDispatch.cs +++ b/NzbDrone.Core/CentralDispatch.cs @@ -35,7 +35,6 @@ namespace NzbDrone.Core } } - public static void InitializeApp() { BindKernel(); @@ -107,6 +106,7 @@ namespace NzbDrone.Core _kernel.Bind().To(); _kernel.Bind().To(); _kernel.Bind().To(); + _kernel.Bind().To(); var notifiers = _kernel.GetAll(); _kernel.Get().InitializeNotifiers(notifiers.ToList()); diff --git a/NzbDrone.Core/NzbDrone.Core.csproj b/NzbDrone.Core/NzbDrone.Core.csproj index fe08841d8..999ed1f31 100644 --- a/NzbDrone.Core/NzbDrone.Core.csproj +++ b/NzbDrone.Core/NzbDrone.Core.csproj @@ -125,6 +125,12 @@ False ..\Libraries\Exceptioneer.WindowsFormsClient.dll + + ..\packages\Growl.0.6\lib\Growl.Connector.dll + + + ..\packages\Growl.0.6\lib\Growl.CoreLibrary.dll + ..\packages\DotNetZip.1.9.1.8\lib\net20\Ionic.Zip.dll @@ -221,8 +227,10 @@ + + @@ -352,6 +360,10 @@ NzbDrone.Common + + + + diff --git a/NzbDrone.Core/NzbDrone.ico b/NzbDrone.Core/NzbDrone.ico new file mode 100644 index 000000000..1d6e4d3f4 Binary files /dev/null and b/NzbDrone.Core/NzbDrone.ico differ diff --git a/NzbDrone.Core/Providers/Core/ConfigProvider.cs b/NzbDrone.Core/Providers/Core/ConfigProvider.cs index a10bccc6d..10a8df3e0 100644 --- a/NzbDrone.Core/Providers/Core/ConfigProvider.cs +++ b/NzbDrone.Core/Providers/Core/ConfigProvider.cs @@ -338,6 +338,32 @@ namespace NzbDrone.Core.Providers.Core set { SetValue("TwitterAccessTokenSecret", value); } } + public virtual Boolean GrowlNotifyOnGrab + { + get { return GetValueBoolean("GrowlNotifyOnGrab"); } + + set { SetValue("GrowlNotifyOnGrab", value); } + } + + public virtual Boolean GrowlNotifyOnDownload + { + get { return GetValueBoolean("GrowlNotifyOnDownload"); } + + set { SetValue("GrowlNotifyOnDownload", value); } + } + + public virtual string GrowlHost + { + get { return GetValue("GrowlHost", String.Empty); } + set { SetValue("GrowlHost", value); } + } + + public virtual string GrowlPassword + { + get { return GetValue("GrowlPassword", String.Empty); } + set { SetValue("GrowlPassword", value); } + } + private string GetValue(string key) { return GetValue(key, String.Empty); diff --git a/NzbDrone.Core/Providers/ExternalNotification/Growl.cs b/NzbDrone.Core/Providers/ExternalNotification/Growl.cs new file mode 100644 index 000000000..d4e887dd2 --- /dev/null +++ b/NzbDrone.Core/Providers/ExternalNotification/Growl.cs @@ -0,0 +1,78 @@ +using System; +using NLog; +using NzbDrone.Core.Providers.Core; +using NzbDrone.Core.Repository; + +namespace NzbDrone.Core.Providers.ExternalNotification +{ + public class Growl : ExternalNotificationBase + { + private readonly GrowlProvider _growlProvider; + + private readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + public Growl(ConfigProvider configProvider, GrowlProvider growlProvider) + : base(configProvider) + { + _growlProvider = growlProvider; + } + + public override string Name + { + get { return "Growl"; } + } + + public override void OnGrab(string message) + { + try + { + if(_configProvider.GrowlNotifyOnGrab) + { + _logger.Trace("Sending Notification to Growl"); + const string title = "Episode Grabbed"; + + var growlHost = _configProvider.GrowlHost.Split(':'); + var host = growlHost[0]; + var port = Convert.ToInt32(growlHost[1]); + + _growlProvider.SendNotification(title, message, host, "GRAB", port, _configProvider.GrowlPassword); + } + } + + catch (Exception ex) + { + Logger.WarnException(ex.Message, ex); + throw; + } + } + + public override void OnDownload(string message, Series series) + { + try + { + if (_configProvider.GrowlNotifyOnDownload) + { + _logger.Trace("Sending Notification to Growl"); + const string title = "Episode Downloaded"; + + var growlHost = _configProvider.GrowlHost.Split(':'); + var host = growlHost[0]; + var port = Convert.ToInt32(growlHost[1]); + + _growlProvider.SendNotification(title, message, host, "DOWNLOAD", port, _configProvider.GrowlPassword); + } + } + + catch (Exception ex) + { + Logger.WarnException(ex.Message, ex); + throw; + } + } + + public override void OnRename(string message, Series series) + { + + } + } +} diff --git a/NzbDrone.Core/Providers/GrowlProvider.cs b/NzbDrone.Core/Providers/GrowlProvider.cs new file mode 100644 index 000000000..cc1dd44db --- /dev/null +++ b/NzbDrone.Core/Providers/GrowlProvider.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Growl.Connector; +using NLog; + +namespace NzbDrone.Core.Providers +{ + public class GrowlProvider + { + private readonly Logger Logger = LogManager.GetCurrentClassLogger(); + + private readonly Application _growlApplication = new Application("NzbDrone"); + private GrowlConnector _growlConnector; + private List _notificationTypes; + + public GrowlProvider() + { + _notificationTypes = GetNotificationTypes(); + _growlApplication.Icon = "https://github.com/NzbDrone/NzbDrone/raw/master/NzbDrone.Core/NzbDrone.jpg"; + } + + public virtual void Register(string hostname, int port, string password) + { + Logger.Trace("Registering NzbDrone with Growl host: {0}:{1}", hostname, port); + _growlConnector = new GrowlConnector(password, hostname, port); + _growlConnector.Register(_growlApplication, _notificationTypes.ToArray()); + } + + public virtual void TestNotification(string hostname, int port, string password) + { + const string title = "Test Notification"; + const string message = "This is a test message from NzbDrone"; + + SendNotification(title, message, "TEST", hostname, port, password); + } + + public virtual void SendNotification(string title, string message, string notificationTypeName, string hostname, int port, string password) + { + var notificationType = _notificationTypes.Single(n => n.Name == notificationTypeName); + + var notification = new Notification("NzbDrone", notificationType.Name, DateTime.Now.Ticks.ToString(), title, message); + + _growlConnector = new GrowlConnector(password, hostname, port); + + Logger.Trace("Sending Notification to: {0}:{1}", hostname, port); + _growlConnector.Notify(notification); + } + + private List GetNotificationTypes() + { + var notificationTypes = new List(); + notificationTypes.Add(new NotificationType("TEST", "Test")); + notificationTypes.Add(new NotificationType("GRAB", "Episode Grabbed")); + notificationTypes.Add(new NotificationType("DOWNLOAD", "Episode Complete")); + + return notificationTypes; + } + } +} diff --git a/NzbDrone.Core/Providers/Xbmc/ResourceManager.cs b/NzbDrone.Core/Providers/Xbmc/ResourceManager.cs index 0e8e7c548..7a9daefd2 100644 --- a/NzbDrone.Core/Providers/Xbmc/ResourceManager.cs +++ b/NzbDrone.Core/Providers/Xbmc/ResourceManager.cs @@ -37,7 +37,7 @@ public static System.Drawing.Bitmap GetIconAsImage(string Name) { - System.IO.Stream stm = typeof(ResourceManager).Assembly.GetManifestResourceStream(string.Format("{0}.Icons.{1}.ico", typeof(ResourceManager).Namespace, Name)); + System.IO.Stream stm = typeof(ResourceManager).Assembly.GetManifestResourceStream(string.Format("NzbDrone.Core.{0}.ico", Name)); if (stm == null) return null; System.Drawing.Bitmap bmp; using (System.Drawing.Icon ico = new System.Drawing.Icon(stm)) diff --git a/NzbDrone.Core/license.txt b/NzbDrone.Core/license.txt new file mode 100644 index 000000000..630a2961e --- /dev/null +++ b/NzbDrone.Core/license.txt @@ -0,0 +1,25 @@ +Growl.NET GNTP Connector Library +----------------------------------------------- +Copyright (c) 2008 - Growl for Windows +All rights reserved + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + diff --git a/NzbDrone.Core/packages.config b/NzbDrone.Core/packages.config index 4d4c07386..0bdd610cd 100644 --- a/NzbDrone.Core/packages.config +++ b/NzbDrone.Core/packages.config @@ -1,6 +1,7 @@  + diff --git a/packages/Growl.0.6/Growl.0.6.nupkg b/packages/Growl.0.6/Growl.0.6.nupkg new file mode 100644 index 000000000..1d89eddd5 Binary files /dev/null and b/packages/Growl.0.6/Growl.0.6.nupkg differ diff --git a/packages/Growl.0.6/content/GrowlHelper.cs.pp b/packages/Growl.0.6/content/GrowlHelper.cs.pp new file mode 100644 index 000000000..b833b8cca --- /dev/null +++ b/packages/Growl.0.6/content/GrowlHelper.cs.pp @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using Growl.Connector; +using Growl.CoreLibrary; + +namespace $rootnamespace$ +{ + class GrowlHelper + { + public static void simpleGrowl(string title, string message = "") + { + GrowlConnector simpleGrowl = new GrowlConnector(); + Growl.Connector.Application thisApp = new Growl.Connector.Application(System.Windows.Forms.Application.ProductName); + NotificationType simpleGrowlType = new NotificationType("SIMPLEGROWL"); + simpleGrowl.Register(thisApp, new NotificationType[] { simpleGrowlType }); + Notification myGrowl = new Notification(System.Windows.Forms.Application.ProductName, "SIMPLEGROWL", title, title, message); + simpleGrowl.Notify(myGrowl); + } + } +} diff --git a/packages/Growl.0.6/content/license.txt b/packages/Growl.0.6/content/license.txt new file mode 100644 index 000000000..630a2961e --- /dev/null +++ b/packages/Growl.0.6/content/license.txt @@ -0,0 +1,25 @@ +Growl.NET GNTP Connector Library +----------------------------------------------- +Copyright (c) 2008 - Growl for Windows +All rights reserved + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH +DAMAGE. + diff --git a/packages/Growl.0.6/lib/Growl.Connector.dll b/packages/Growl.0.6/lib/Growl.Connector.dll new file mode 100644 index 000000000..01c0c59f6 Binary files /dev/null and b/packages/Growl.0.6/lib/Growl.Connector.dll differ diff --git a/packages/Growl.0.6/lib/Growl.CoreLibrary.dll b/packages/Growl.0.6/lib/Growl.CoreLibrary.dll new file mode 100644 index 000000000..ca1545cff Binary files /dev/null and b/packages/Growl.0.6/lib/Growl.CoreLibrary.dll differ