external notifications are now based on Events.

This commit is contained in:
kay.one 2013-02-24 15:47:57 -08:00
commit 5fc25b6095
32 changed files with 542 additions and 619 deletions

View file

@ -0,0 +1,149 @@
using System;
using System.Linq;
using NLog;
using NzbDrone.Common.Eventing;
using NzbDrone.Core.Download;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.ExternalNotification
{
public abstract class ExternalNotificationBase
: IHandle<EpisodeGrabbedEvent>,
IHandle<EpisodeDownloadedEvent>,
IHandle<SeriesRenamedEvent>
{
private readonly IExternalNotificationRepository _externalNotificationRepository;
private readonly Logger _logger;
protected ExternalNotificationBase(IExternalNotificationRepository externalNotificationRepository, Logger logger)
{
_externalNotificationRepository = externalNotificationRepository;
_logger = logger;
}
public abstract string Name { get; }
public bool NotifyOnGrab
{
get
{
return GetEnableStatus(c => c.OnGrab);
}
set
{
SetEnableStatus(c => c.OnGrab = value);
}
}
public bool NotifyOnDownload
{
get
{
return GetEnableStatus(c => c.OnDownload);
}
set
{
SetEnableStatus(c => c.OnDownload = value);
}
}
public bool NotifyOnRename
{
get
{
return GetEnableStatus(c => c.OnRename);
}
set
{
SetEnableStatus(c => c.OnRename = value);
}
}
private void SetEnableStatus(Action<ExternalNotificationDefinition> updateAction)
{
var def = _externalNotificationRepository.Get(Name) ??
new ExternalNotificationDefinition { Name = Name };
updateAction(def);
_externalNotificationRepository.Upsert(def);
}
private bool GetEnableStatus(Func<ExternalNotificationDefinition, bool> readFunction)
{
var def = _externalNotificationRepository.Get(Name) ??
new ExternalNotificationDefinition { Name = Name };
return readFunction(def);
}
public void Handle(EpisodeGrabbedEvent message)
{
if (NotifyOnGrab)
{
try
{
_logger.Trace("Sending grab notification to {0}", Name);
OnGrab(message.ParseResult.GetDownloadTitle());
}
catch (Exception e)
{
_logger.WarnException("Couldn't send grab notification to " + Name, e);
}
}
}
public void Handle(EpisodeDownloadedEvent message)
{
if (NotifyOnDownload)
{
try
{
_logger.Trace("Sending download notification to {0}", Name);
OnDownload(message.ParseResult.GetDownloadTitle(), message.ParseResult.Series);
}
catch (Exception e)
{
_logger.WarnException("Couldn't send download notification to " + Name, e);
}
}
}
public void Handle(SeriesRenamedEvent message)
{
if (NotifyOnRename)
{
try
{
_logger.Trace("Sending rename notification to {0}", Name);
AfterRename(message.Series);
}
catch (Exception e)
{
_logger.WarnException("Couldn't send rename notification to " + Name, e);
}
}
}
protected virtual void OnGrab(string message)
{
}
protected virtual void OnDownload(string message, Series series)
{
}
protected virtual void AfterRename(Series series)
{
}
}
}

View file

@ -0,0 +1,14 @@
using System.Linq;
using NzbDrone.Core.Datastore;
using PetaPoco;
namespace NzbDrone.Core.ExternalNotification
{
public class ExternalNotificationDefinition : ModelBase
{
public string Name { get; set; }
public bool OnGrab { get; set; }
public bool OnDownload { get; set; }
public bool OnRename { get; set; }
}
}

View file

@ -0,0 +1,23 @@
using System.Linq;
using NzbDrone.Core.Datastore;
namespace NzbDrone.Core.ExternalNotification
{
public interface IExternalNotificationRepository : IBasicRepository<ExternalNotificationDefinition>
{
ExternalNotificationDefinition Get(string name);
}
public class ExternalNotificationRepository : BasicRepository<ExternalNotificationDefinition>, IExternalNotificationRepository
{
public ExternalNotificationRepository(IObjectDatabase objectDatabase)
: base(objectDatabase)
{
}
public ExternalNotificationDefinition Get(string name)
{
return Queryable.SingleOrDefault(c => c.Name.ToLower() == name.ToLower());
}
}
}

View file

@ -0,0 +1,48 @@
using System.Linq;
using System;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.ExternalNotification
{
public class Growl : ExternalNotificationBase
{
private readonly IConfigService _configService;
private readonly GrowlProvider _growlProvider;
public Growl(IExternalNotificationRepository repository, IConfigService configService, GrowlProvider growlProvider, Logger logger)
: base(repository, logger)
{
_configService = configService;
_growlProvider = growlProvider;
}
public override string Name
{
get { return "Growl"; }
}
protected override void OnGrab(string message)
{
const string title = "Episode Grabbed";
var growlHost = _configService.GrowlHost.Split(':');
var host = growlHost[0];
var port = Convert.ToInt32(growlHost[1]);
_growlProvider.SendNotification(title, message, "GRAB", host, port, _configService.GrowlPassword);
}
protected override void OnDownload(string message, Series series)
{
const string title = "Episode Downloaded";
var growlHost = _configService.GrowlHost.Split(':');
var host = growlHost[0];
var port = Convert.ToInt32(growlHost[1]);
_growlProvider.SendNotification(title, message, "DOWNLOAD", host, port, _configService.GrowlPassword);
}
}
}

View file

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Growl.Connector;
using NLog;
namespace NzbDrone.Core.ExternalNotification
{
public class GrowlProvider
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly Application _growlApplication = new Application("NzbDrone");
private GrowlConnector _growlConnector;
private List<NotificationType> _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<NotificationType> GetNotificationTypes()
{
var notificationTypes = new List<NotificationType>();
notificationTypes.Add(new NotificationType("TEST", "Test"));
notificationTypes.Add(new NotificationType("GRAB", "Episode Grabbed"));
notificationTypes.Add(new NotificationType("DOWNLOAD", "Episode Complete"));
return notificationTypes;
}
}
}

View file

@ -0,0 +1,51 @@
using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.ExternalNotification
{
public class Plex : ExternalNotificationBase
{
private readonly IConfigService _configService;
private readonly PlexProvider _plexProvider;
public Plex(IConfigService configService, IExternalNotificationRepository repository, PlexProvider plexProvider, Logger logger)
: base(repository, logger)
{
_configService = configService;
_plexProvider = plexProvider;
}
public override string Name
{
get { return "Plex"; }
}
protected override void OnGrab(string message)
{
const string header = "NzbDrone [TV] - Grabbed";
_plexProvider.Notify(header, message);
}
protected override void OnDownload(string message, Series series)
{
const string header = "NzbDrone [TV] - Downloaded";
_plexProvider.Notify(header, message);
UpdateIfEnabled();
}
protected override void AfterRename( Series series)
{
UpdateIfEnabled();
}
private void UpdateIfEnabled()
{
if (_configService.PlexUpdateLibrary)
{
_plexProvider.UpdateLibrary();
}
}
}
}

View file

@ -0,0 +1,104 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using NLog;
using NzbDrone.Common;
using NzbDrone.Core.Configuration;
namespace NzbDrone.Core.ExternalNotification
{
public class PlexProvider
{
private readonly HttpProvider _httpProvider;
private readonly IConfigService _configService;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public PlexProvider(HttpProvider httpProvider, IConfigService configService)
{
_httpProvider = httpProvider;
_configService = configService;
}
public PlexProvider()
{
}
public virtual void Notify(string header, string message)
{
//Foreach plex client send a notification
foreach(var host in _configService.PlexClientHosts.Split(','))
{
try
{
var command = String.Format("ExecBuiltIn(Notification({0}, {1}))", header, message);
SendCommand(host.Trim(), command, _configService.PlexUsername, _configService.PlexPassword);
}
catch(Exception ex)
{
logger.WarnException("Failed to send notification to Plex Client: " + host.Trim(), ex);
}
}
}
public virtual void UpdateLibrary()
{
var host = _configService.PlexServerHost;
try
{
logger.Trace("Sending Update Request to Plex Server");
var sections = GetSectionKeys(host);
sections.ForEach(s => UpdateSection(host, s));
}
catch(Exception ex)
{
logger.WarnException("Failed to Update Plex host: " + host, ex);
throw;
}
}
public List<int> GetSectionKeys(string host)
{
logger.Trace("Getting sections from Plex host: {0}", host);
var url = String.Format("http://{0}/library/sections", host);
var xmlStream = _httpProvider.DownloadStream(url, null);
var xDoc = XDocument.Load(xmlStream);
var mediaContainer = xDoc.Descendants("MediaContainer").FirstOrDefault();
var directories = mediaContainer.Descendants("Directory").Where(x => x.Attribute("type").Value == "show");
return directories.Select(d => Int32.Parse(d.Attribute("key").Value)).ToList();
}
public void UpdateSection(string host, int key)
{
logger.Trace("Updating Plex host: {0}, Section: {1}", host, key);
var url = String.Format("http://{0}/library/sections/{1}/refresh", host, key);
_httpProvider.DownloadString(url);
}
public virtual string SendCommand(string host, string command, string username, string password)
{
var url = String.Format("http://{0}/xbmcCmds/xbmcHttp?command={1}", host, command);
if (!String.IsNullOrEmpty(username))
{
return _httpProvider.DownloadString(url, username, password);
}
return _httpProvider.DownloadString(url);
}
public virtual void TestNotification(string hosts, string username, string password)
{
foreach (var host in hosts.Split(','))
{
logger.Trace("Sending Test Notifcation to XBMC Host: {0}", host);
var command = String.Format("ExecBuiltIn(Notification({0}, {1}))", "Test Notification", "Success! Notifications are setup correctly");
SendCommand(host.Trim(), command, _configService.PlexUsername, _configService.PlexPassword);
}
}
}
}

View file

@ -0,0 +1,48 @@
using System.Linq;
using System;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Tv;
using Prowlin;
namespace NzbDrone.Core.ExternalNotification
{
public class Prowl : ExternalNotificationBase
{
private readonly IConfigService _configService;
private readonly ProwlProvider _prowlProvider;
public Prowl(IConfigService configService, IExternalNotificationRepository repository, ProwlProvider prowlProvider, Logger logger)
: base(repository, logger)
{
_configService = configService;
_prowlProvider = prowlProvider;
}
public override string Name
{
get { return "Prowl"; }
}
protected override void OnGrab(string message)
{
const string title = "Episode Grabbed";
var apiKeys = _configService.ProwlApiKeys;
var priority = _configService.ProwlPriority;
_prowlProvider.SendNotification(title, message, apiKeys, (NotificationPriority)priority);
}
protected override void OnDownload(string message, Series series)
{
const string title = "Episode Downloaded";
var apiKeys = _configService.ProwlApiKeys;
var priority = _configService.ProwlPriority;
_prowlProvider.SendNotification(title, message, apiKeys, (NotificationPriority)priority);
}
}
}

View file

@ -0,0 +1,39 @@
using System.Linq;
using System;
using NLog;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.ExternalNotification
{
public class Smtp : ExternalNotificationBase
{
private readonly SmtpProvider _smtpProvider;
public Smtp(IExternalNotificationRepository repository, SmtpProvider smtpProvider, Logger logger)
: base(repository, logger)
{
_smtpProvider = smtpProvider;
}
public override string Name
{
get { return "SMTP"; }
}
protected override void OnGrab(string message)
{
const string subject = "NzbDrone [TV] - Grabbed";
var body = String.Format("{0} sent to SABnzbd queue.", message);
_smtpProvider.SendEmail(subject, body);
}
protected override void OnDownload(string message, Series series)
{
const string subject = "NzbDrone [TV] - Downloaded";
var body = String.Format("{0} Downloaded and sorted.", message);
_smtpProvider.SendEmail(subject, body);
}
}
}

View file

@ -0,0 +1,35 @@
using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.ExternalNotification
{
public class Twitter : ExternalNotificationBase
{
private readonly TwitterProvider _twitterProvider;
public Twitter(IExternalNotificationRepository repository, TwitterProvider twitterProvider, Logger logger)
: base(repository, logger)
{
_twitterProvider = twitterProvider;
}
public override string Name
{
get { return "Twitter"; }
}
protected override void OnGrab(string message)
{
_twitterProvider.SendTweet("Download Started: " + message);
}
protected override void OnDownload(string message, Series series)
{
_twitterProvider.SendTweet("Download Completed: " + message);
}
}
}

View file

@ -0,0 +1,59 @@
using System.Linq;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Providers;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.ExternalNotification
{
public class Xbmc : ExternalNotificationBase
{
private readonly IConfigService _configService;
private readonly XbmcProvider _xbmcProvider;
public Xbmc(IConfigService configService, IExternalNotificationRepository repository, XbmcProvider xbmcProvider, Logger logger)
: base(repository, logger)
{
_configService = configService;
_xbmcProvider = xbmcProvider;
}
public override string Name
{
get { return "XBMC"; }
}
protected override void OnGrab(string message)
{
const string header = "NzbDrone [TV] - Grabbed";
_xbmcProvider.Notify(header, message);
}
protected override void OnDownload(string message, Series series)
{
const string header = "NzbDrone [TV] - Downloaded";
_xbmcProvider.Notify(header, message);
UpdateAndClean(series);
}
protected override void AfterRename(Series series)
{
UpdateAndClean(series);
}
private void UpdateAndClean(Series series)
{
if (_configService.XbmcUpdateLibrary)
{
_xbmcProvider.Update(series);
}
if (_configService.XbmcCleanLibrary)
{
_xbmcProvider.Clean();
}
}
}
}