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