external notifications are now based on Events.

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

View File

@ -7,10 +7,10 @@ using FluentAssertions;
using NCrunch.Framework; using NCrunch.Framework;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Jobs; using NzbDrone.Core.Jobs;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Metadata; using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Test.Framework; using NzbDrone.Core.Test.Framework;
@ -115,12 +115,6 @@ namespace NzbDrone.Core.Test
kernel.Resolve<IIndexerService>().All().Select(c => c.Type).Should().BeEquivalentTo(indexers); kernel.Resolve<IIndexerService>().All().Select(c => c.Type).Should().BeEquivalentTo(indexers);
} }
[Test]
public void externalNotifiers_are_initialized()
{
kernel.Resolve<ExternalNotificationProvider>().All().Should().HaveSameCount(extNotifications);
}
[Test] [Test]
public void metadata_clients_are_initialized() public void metadata_clients_are_initialized()
{ {

View File

@ -9,6 +9,7 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Download; using NzbDrone.Core.Download;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
@ -117,16 +118,9 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
.Setup(s => s.FileExists(currentFilename)) .Setup(s => s.FileExists(currentFilename))
.Returns(true); .Returns(true);
Mocker.GetMock<ExternalNotificationProvider>()
.Setup(e => e.OnDownload("30 Rock - 1x01 - [WEBDL]", It.IsAny<Series>()));
//Act
var result = Mocker.Resolve<DiskScanProvider>().MoveEpisodeFile(file, true); var result = Mocker.Resolve<DiskScanProvider>().MoveEpisodeFile(file, true);
//Assert
result.Should().NotBeNull();
Mocker.GetMock<ExternalNotificationProvider>()
.Verify(e => e.OnDownload("30 Rock - 1x01 - [WEBDL]", It.IsAny<Series>()), Times.Once());
} }
[Test] [Test]
@ -172,13 +166,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
.Setup(e => e.CalculateFilePath(It.IsAny<Series>(), fakeEpisode.First().SeasonNumber, filename, ".mkv")) .Setup(e => e.CalculateFilePath(It.IsAny<Series>(), fakeEpisode.First().SeasonNumber, filename, ".mkv"))
.Returns(fi); .Returns(fi);
Mocker.GetMock<ExternalNotificationProvider>()
.Setup(e => e.OnDownload("30 Rock - 1x01 - [WEBDL]", It.IsAny<Series>()));
//Act
var result = Mocker.Resolve<DiskScanProvider>().MoveEpisodeFile(file, true); var result = Mocker.Resolve<DiskScanProvider>().MoveEpisodeFile(file, true);
//Assert
result.Should().BeNull(); result.Should().BeNull();
ExceptionVerification.ExpectedErrors(1); ExceptionVerification.ExpectedErrors(1);
} }

View File

@ -4,6 +4,7 @@ using FizzWare.NBuilder;
using FluentAssertions; using FluentAssertions;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;

View File

@ -11,6 +11,7 @@ using Moq;
using NUnit.Framework; using NUnit.Framework;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Model.Xbmc; using NzbDrone.Core.Model.Xbmc;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Providers.Core; using NzbDrone.Core.Providers.Core;

View File

@ -6,9 +6,9 @@ using Autofac.Core;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Indexers; using NzbDrone.Core.Indexers;
using NzbDrone.Core.Instrumentation; using NzbDrone.Core.Instrumentation;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Metadata; using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Providers.Search; using NzbDrone.Core.Providers.Search;
using PetaPoco; using PetaPoco;

View File

@ -0,0 +1,16 @@
using System.Linq;
using NzbDrone.Common.Eventing;
using NzbDrone.Core.Model;
namespace NzbDrone.Core.Download
{
public class EpisodeDownloadedEvent : IEvent
{
public EpisodeParseResult ParseResult { get; private set; }
public EpisodeDownloadedEvent(EpisodeParseResult parseResult)
{
ParseResult = parseResult;
}
}
}

View File

@ -0,0 +1,16 @@
using System.Linq;
using NzbDrone.Common.Eventing;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Download
{
public class SeriesRenamedEvent : IEvent
{
public Series Series { get; private set; }
public SeriesRenamedEvent(Series series)
{
Series = series;
}
}
}

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

@ -4,7 +4,7 @@ using System.Linq;
using Growl.Connector; using Growl.Connector;
using NLog; using NLog;
namespace NzbDrone.Core.Providers namespace NzbDrone.Core.ExternalNotification
{ {
public class GrowlProvider public class GrowlProvider
{ {

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

@ -1,15 +1,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Xml.Linq; using System.Xml.Linq;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Providers.Core;
namespace NzbDrone.Core.Providers namespace NzbDrone.Core.ExternalNotification
{ {
public class PlexProvider public class PlexProvider
{ {
@ -51,6 +48,7 @@ namespace NzbDrone.Core.Providers
try try
{ {
logger.Trace("Sending Update Request to Plex Server");
var sections = GetSectionKeys(host); var sections = GetSectionKeys(host);
sections.ForEach(s => UpdateSection(host, s)); sections.ForEach(s => UpdateSection(host, s));
} }

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();
}
}
}
}

View File

@ -2,6 +2,9 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System; using System;
using NLog; using NLog;
using NzbDrone.Common.Eventing;
using NzbDrone.Core.Download;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
@ -12,23 +15,22 @@ namespace NzbDrone.Core.Jobs
{ {
private readonly MediaFileProvider _mediaFileProvider; private readonly MediaFileProvider _mediaFileProvider;
private readonly DiskScanProvider _diskScanProvider; private readonly DiskScanProvider _diskScanProvider;
private readonly ExternalNotificationProvider _externalNotificationProvider;
private readonly ISeriesService _seriesService; private readonly ISeriesService _seriesService;
private readonly MetadataProvider _metadataProvider; private readonly MetadataProvider _metadataProvider;
private readonly ISeriesRepository _seriesRepository; private readonly ISeriesRepository _seriesRepository;
private readonly IEventAggregator _eventAggregator;
private static readonly Logger logger = LogManager.GetCurrentClassLogger(); private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public RenameSeasonJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider, public RenameSeasonJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider, ISeriesService seriesService,
ExternalNotificationProvider externalNotificationProvider, ISeriesService seriesService, MetadataProvider metadataProvider, ISeriesRepository seriesRepository, IEventAggregator eventAggregator)
MetadataProvider metadataProvider, ISeriesRepository seriesRepository)
{ {
_mediaFileProvider = mediaFileProvider; _mediaFileProvider = mediaFileProvider;
_diskScanProvider = diskScanProvider; _diskScanProvider = diskScanProvider;
_externalNotificationProvider = externalNotificationProvider;
_seriesService = seriesService; _seriesService = seriesService;
_metadataProvider = metadataProvider; _metadataProvider = metadataProvider;
_seriesRepository = seriesRepository; _seriesRepository = seriesRepository;
_eventAggregator = eventAggregator;
} }
public string Name public string Name
@ -100,7 +102,8 @@ namespace NzbDrone.Core.Jobs
//Start AfterRename //Start AfterRename
var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, options.SeasonNumber); var message = String.Format("Renamed: Series {0}, Season: {1}", series.Title, options.SeasonNumber);
_externalNotificationProvider.AfterRename(message, series);
_eventAggregator.Publish(new SeriesRenamedEvent(series));
notification.CurrentMessage = String.Format("Rename completed for {0} Season {1}", series.Title, options.SeasonNumber); notification.CurrentMessage = String.Format("Rename completed for {0} Season {1}", series.Title, options.SeasonNumber);
} }

View File

@ -2,11 +2,11 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System; using System;
using NLog; using NLog;
using NzbDrone.Core.Datastore; using NzbDrone.Common.Eventing;
using NzbDrone.Core.Download;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Model.Notification; using NzbDrone.Core.Model.Notification;
using NzbDrone.Core.Providers; using NzbDrone.Core.Providers;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Jobs namespace NzbDrone.Core.Jobs
{ {
@ -14,23 +14,20 @@ namespace NzbDrone.Core.Jobs
{ {
private readonly MediaFileProvider _mediaFileProvider; private readonly MediaFileProvider _mediaFileProvider;
private readonly DiskScanProvider _diskScanProvider; private readonly DiskScanProvider _diskScanProvider;
private readonly ExternalNotificationProvider _externalNotificationProvider;
private readonly ISeriesService _seriesService;
private readonly MetadataProvider _metadataProvider; private readonly MetadataProvider _metadataProvider;
private readonly ISeriesRepository _seriesRepository; private readonly ISeriesRepository _seriesRepository;
private readonly IEventAggregator _eventAggregator;
private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
public RenameSeriesJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider, public RenameSeriesJob(MediaFileProvider mediaFileProvider, DiskScanProvider diskScanProvider,
ExternalNotificationProvider externalNotificationProvider, ISeriesService seriesService, MetadataProvider metadataProvider,ISeriesRepository seriesRepository,IEventAggregator eventAggregator)
MetadataProvider metadataProvider,ISeriesRepository seriesRepository)
{ {
_mediaFileProvider = mediaFileProvider; _mediaFileProvider = mediaFileProvider;
_diskScanProvider = diskScanProvider; _diskScanProvider = diskScanProvider;
_externalNotificationProvider = externalNotificationProvider;
_seriesService = seriesService;
_metadataProvider = metadataProvider; _metadataProvider = metadataProvider;
_seriesRepository = seriesRepository; _seriesRepository = seriesRepository;
_eventAggregator = eventAggregator;
} }
public string Name public string Name
@ -99,8 +96,7 @@ namespace NzbDrone.Core.Jobs
//Start AfterRename //Start AfterRename
var message = String.Format("Renamed: Series {0}", series.Title); _eventAggregator.Publish(new SeriesRenamedEvent(series));
_externalNotificationProvider.AfterRename(message, series);
notification.CurrentMessage = String.Format("Rename completed for {0}", series.Title); notification.CurrentMessage = String.Format("Rename completed for {0}", series.Title);
} }

View File

@ -260,7 +260,10 @@
<Compile Include="Datastore\PetaPoco\EpisodeSeasonRelator.cs" /> <Compile Include="Datastore\PetaPoco\EpisodeSeasonRelator.cs" />
<Compile Include="Datastore\PetaPoco\PetaPoco.cs" /> <Compile Include="Datastore\PetaPoco\PetaPoco.cs" />
<Compile Include="Datastore\SqlCeProxy.cs" /> <Compile Include="Datastore\SqlCeProxy.cs" />
<Compile Include="Download\EpisodeDownloadedEvent.cs" />
<Compile Include="Download\EpisodeGrabbedEvent.cs" /> <Compile Include="Download\EpisodeGrabbedEvent.cs" />
<Compile Include="Download\SeriesRenamedEvent.cs" />
<Compile Include="ExternalNotification\ExternalNotificationRepository.cs" />
<Compile Include="Fluent.cs" /> <Compile Include="Fluent.cs" />
<Compile Include="Helpers\Converters\EpochDateTimeConverter.cs" /> <Compile Include="Helpers\Converters\EpochDateTimeConverter.cs" />
<Compile Include="Helpers\SabnzbdQueueTimeConverter.cs" /> <Compile Include="Helpers\SabnzbdQueueTimeConverter.cs" />
@ -464,31 +467,28 @@
<Compile Include="Tv\EpisodeRepository.cs"> <Compile Include="Tv\EpisodeRepository.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotificationProvider.cs"> <Compile Include="ExternalNotification\ExternalNotificationBase.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\ExternalNotificationBase.cs"> <Compile Include="ExternalNotification\Growl.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\Growl.cs"> <Compile Include="ExternalNotification\Plex.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\Plex.cs"> <Compile Include="ExternalNotification\Prowl.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\Prowl.cs"> <Compile Include="ExternalNotification\Smtp.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\Smtp.cs"> <Compile Include="ExternalNotification\Twitter.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\Twitter.cs"> <Compile Include="ExternalNotification\Xbmc.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\ExternalNotification\Xbmc.cs"> <Compile Include="ExternalNotification\GrowlProvider.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Providers\GrowlProvider.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="History\HistoryService.cs"> <Compile Include="History\HistoryService.cs">
@ -521,7 +521,7 @@
<Compile Include="Providers\NotificationProvider.cs"> <Compile Include="Providers\NotificationProvider.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Providers\PlexProvider.cs" /> <Compile Include="ExternalNotification\PlexProvider.cs" />
<Compile Include="Providers\PostDownloadProvider.cs"> <Compile Include="Providers\PostDownloadProvider.cs">
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
@ -578,7 +578,7 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Indexers\NewznabDefinition.cs" /> <Compile Include="Indexers\NewznabDefinition.cs" />
<Compile Include="Repository\ExternalNotificationDefinition.cs" /> <Compile Include="ExternalNotification\ExternalNotificationDefinition.cs" />
<Compile Include="Jobs\JobDefinition.cs" /> <Compile Include="Jobs\JobDefinition.cs" />
<Compile Include="Indexers\Indexer.cs" /> <Compile Include="Indexers\Indexer.cs" />
<Compile Include="Model\EpisodeParseResult.cs" /> <Compile Include="Model\EpisodeParseResult.cs" />

View File

@ -4,7 +4,10 @@ using System.IO;
using System.Linq; using System.Linq;
using NLog; using NLog;
using NzbDrone.Common; using NzbDrone.Common;
using NzbDrone.Common.Eventing;
using NzbDrone.Core.Configuration; using NzbDrone.Core.Configuration;
using NzbDrone.Core.Download;
using NzbDrone.Core.ExternalNotification;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
@ -17,27 +20,26 @@ namespace NzbDrone.Core.Providers
private readonly DiskProvider _diskProvider; private readonly DiskProvider _diskProvider;
private readonly IEpisodeService _episodeService; private readonly IEpisodeService _episodeService;
private readonly MediaFileProvider _mediaFileProvider; private readonly MediaFileProvider _mediaFileProvider;
private readonly ExternalNotificationProvider _externalNotificationProvider;
private readonly SignalRProvider _signalRProvider; private readonly SignalRProvider _signalRProvider;
private readonly IConfigService _configService; private readonly IConfigService _configService;
private readonly RecycleBinProvider _recycleBinProvider; private readonly RecycleBinProvider _recycleBinProvider;
private readonly MediaInfoProvider _mediaInfoProvider; private readonly MediaInfoProvider _mediaInfoProvider;
private readonly ISeriesRepository _seriesRepository; private readonly ISeriesRepository _seriesRepository;
private readonly IEventAggregator _eventAggregator;
public DiskScanProvider(DiskProvider diskProvider, IEpisodeService episodeService, MediaFileProvider mediaFileProvider, public DiskScanProvider(DiskProvider diskProvider, IEpisodeService episodeService, MediaFileProvider mediaFileProvider,
ExternalNotificationProvider externalNotificationProvider,
SignalRProvider signalRProvider, IConfigService configService, SignalRProvider signalRProvider, IConfigService configService,
RecycleBinProvider recycleBinProvider, MediaInfoProvider mediaInfoProvider, ISeriesRepository seriesRepository) RecycleBinProvider recycleBinProvider, MediaInfoProvider mediaInfoProvider, ISeriesRepository seriesRepository, IEventAggregator eventAggregator)
{ {
_diskProvider = diskProvider; _diskProvider = diskProvider;
_episodeService = episodeService; _episodeService = episodeService;
_mediaFileProvider = mediaFileProvider; _mediaFileProvider = mediaFileProvider;
_externalNotificationProvider = externalNotificationProvider;
_signalRProvider = signalRProvider; _signalRProvider = signalRProvider;
_configService = configService; _configService = configService;
_recycleBinProvider = recycleBinProvider; _recycleBinProvider = recycleBinProvider;
_mediaInfoProvider = mediaInfoProvider; _mediaInfoProvider = mediaInfoProvider;
_seriesRepository = seriesRepository; _seriesRepository = seriesRepository;
_eventAggregator = eventAggregator;
} }
public DiskScanProvider() public DiskScanProvider()
@ -228,11 +230,10 @@ namespace NzbDrone.Core.Providers
parseResult.Quality = new QualityModel { Quality = episodeFile.Quality, Proper = episodeFile.Proper }; parseResult.Quality = new QualityModel { Quality = episodeFile.Quality, Proper = episodeFile.Proper };
parseResult.Episodes = episodes; parseResult.Episodes = episodes;
var message = parseResult.GetDownloadTitle();
if (newDownload) if (newDownload)
{ {
_externalNotificationProvider.OnDownload(message, series); _eventAggregator.Publish(new EpisodeDownloadedEvent(parseResult));
foreach (var episode in episodes) foreach (var episode in episodes)
_signalRProvider.UpdateEpisodeStatus(episode.OID, EpisodeStatusType.Ready, parseResult.Quality); _signalRProvider.UpdateEpisodeStatus(episode.OID, EpisodeStatusType.Ready, parseResult.Quality);

View File

@ -1,43 +0,0 @@
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public abstract class ExternalNotificationBase
{
protected readonly Logger _logger;
protected readonly IConfigService _configService;
protected ExternalNotificationBase(IConfigService configService)
{
_configService = configService;
_logger = LogManager.GetLogger(GetType().ToString());
}
/// <summary>
/// Gets the name for the notification provider
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Performs the on grab action
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
public abstract void OnGrab(string message);
/// <summary>
/// Performs the on download action
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
/// <param name = "series">The Series for the new download</param>
public abstract void OnDownload(string message, Series series);
/// <summary>
/// Performs the after rename action, this will be handled after all renaming for episode/season/series
/// </summary>
/// <param name = "message">The message to send to the receiver</param>
/// <param name = "series">The Series for the new download</param>
public abstract void AfterRename(string message, Series series);
}
}

View File

@ -1,77 +0,0 @@
using System;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public class Growl : ExternalNotificationBase
{
private readonly GrowlProvider _growlProvider;
public Growl(IConfigService configService, GrowlProvider growlProvider)
: base(configService)
{
_growlProvider = growlProvider;
}
public override string Name
{
get { return "Growl"; }
}
public override void OnGrab(string message)
{
try
{
if(_configService.GrowlNotifyOnGrab)
{
_logger.Trace("Sending Notification to Growl");
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);
}
}
catch (Exception ex)
{
_logger.WarnException(ex.Message, ex);
}
}
public override void OnDownload(string message, Series series)
{
try
{
if (_configService.GrowlNotifyOnDownload)
{
_logger.Trace("Sending Notification to Growl");
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);
}
}
catch (Exception ex)
{
_logger.WarnException(ex.Message, ex);
}
}
public override void AfterRename(string message, Series series)
{
}
}
}

View File

@ -1,63 +0,0 @@
using System;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public class Plex : ExternalNotificationBase
{
private readonly PlexProvider _plexProvider;
public Plex(IConfigService configService, PlexProvider plexProvider)
: base(configService)
{
_plexProvider = plexProvider;
}
public override string Name
{
get { return "Plex"; }
}
public override void OnGrab(string message)
{
const string header = "NzbDrone [TV] - Grabbed";
if (_configService.PlexNotifyOnGrab)
{
_logger.Trace("Sending Notification to Plex Clients");
_plexProvider.Notify(header, message);
}
}
public override void OnDownload(string message, Series series)
{
const string header = "NzbDrone [TV] - Downloaded";
if (_configService.PlexNotifyOnDownload)
{
_logger.Trace("Sending Notification to Plex Clients");
_plexProvider.Notify(header, message);
}
UpdateIfEnabled();
}
public override void AfterRename(string message, Series series)
{
UpdateIfEnabled();
}
private void UpdateIfEnabled()
{
if (_configService.PlexUpdateLibrary)
{
_logger.Trace("Sending Update Request to Plex Server");
_plexProvider.UpdateLibrary();
}
}
}
}

View File

@ -1,75 +0,0 @@
using System;
using NLog;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
using Prowlin;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public class Prowl : ExternalNotificationBase
{
private readonly ProwlProvider _prowlProvider;
public Prowl(IConfigService configService, ProwlProvider prowlProvider)
: base(configService)
{
_prowlProvider = prowlProvider;
}
public override string Name
{
get { return "Prowl"; }
}
public override void OnGrab(string message)
{
try
{
if(_configService.GrowlNotifyOnGrab)
{
_logger.Trace("Sending Notification to Prowl");
const string title = "Episode Grabbed";
var apiKeys = _configService.ProwlApiKeys;
var priority = _configService.ProwlPriority;
_prowlProvider.SendNotification(title, message, apiKeys, (NotificationPriority)priority);
}
}
catch (Exception ex)
{
_logger.WarnException(ex.Message, ex);
}
}
public override void OnDownload(string message, Series series)
{
try
{
if (_configService.GrowlNotifyOnDownload)
{
_logger.Trace("Sending Notification to Prowl");
const string title = "Episode Downloaded";
var apiKeys = _configService.ProwlApiKeys;
var priority = _configService.ProwlPriority;
_prowlProvider.SendNotification(title, message, apiKeys, (NotificationPriority)priority);
}
}
catch (Exception ex)
{
_logger.WarnException(ex.Message, ex);
}
}
public override void AfterRename(string message, Series series)
{
}
}
}

View File

@ -1,53 +0,0 @@
using System;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public class Smtp: ExternalNotificationBase
{
private readonly SmtpProvider _smtpProvider;
public Smtp(IConfigService configService, SmtpProvider smtpProvider)
: base(configService)
{
_smtpProvider = smtpProvider;
}
public override string Name
{
get { return "SMTP"; }
}
public override void OnGrab(string message)
{
const string subject = "NzbDrone [TV] - Grabbed";
var body = String.Format("{0} sent to SABnzbd queue.", message);
if (_configService.SmtpNotifyOnGrab)
{
_logger.Trace("Sending SMTP Notification");
_smtpProvider.SendEmail(subject, body);
}
}
public override void OnDownload(string message, Series series)
{
const string subject = "NzbDrone [TV] - Downloaded";
var body = String.Format("{0} Downloaded and sorted.", message);
if (_configService.SmtpNotifyOnDownload)
{
_logger.Trace("Sending SMTP Notification");
_smtpProvider.SendEmail(subject, body);
}
}
public override void AfterRename(string message, Series series)
{
}
}
}

View File

@ -1,47 +0,0 @@
using System;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public class Twitter : ExternalNotificationBase
{
private readonly TwitterProvider _twitterProvider;
public Twitter(IConfigService configService, TwitterProvider twitterProvider)
: base(configService)
{
_twitterProvider = twitterProvider;
}
public override string Name
{
get { return "Twitter"; }
}
public override void OnGrab(string message)
{
if (_configService.TwitterNotifyOnGrab)
{
_logger.Trace("Sending Notification to Twitter (On Grab)");
_twitterProvider.SendTweet("Download Started: " + message);
}
}
public override void OnDownload(string message, Series series)
{
if (_configService.TwitterNotifyOnDownload)
{
_logger.Trace("Sending Notification to Twitter (On Grab)");
_twitterProvider.SendTweet("Download Completed: " + message);
}
}
public override void AfterRename(string message, Series series)
{
}
}
}

View File

@ -1,68 +0,0 @@
using System;
using NzbDrone.Core.Configuration;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Providers.Core;
using NzbDrone.Core.Repository;
namespace NzbDrone.Core.Providers.ExternalNotification
{
public class Xbmc : ExternalNotificationBase
{
private readonly XbmcProvider _xbmcProvider;
public Xbmc(IConfigService configService, XbmcProvider xbmcProvider)
: base(configService)
{
_xbmcProvider = xbmcProvider;
}
public override string Name
{
get { return "XBMC"; }
}
public override void OnGrab(string message)
{
const string header = "NzbDrone [TV] - Grabbed";
if (_configService.XbmcNotifyOnGrab)
{
_logger.Trace("Sending Notification to XBMC");
_xbmcProvider.Notify(header, message);
}
}
public override void OnDownload(string message, Series series)
{
const string header = "NzbDrone [TV] - Downloaded";
if (_configService.XbmcNotifyOnDownload)
{
_logger.Trace("Sending Notification to XBMC");
_xbmcProvider.Notify(header, message);
}
UpdateAndClean(series);
}
public override void AfterRename(string message, Series series)
{
UpdateAndClean(series);
}
private void UpdateAndClean(Series series)
{
if (_configService.XbmcUpdateLibrary)
{
_logger.Trace("Sending Update Request to XBMC");
_xbmcProvider.Update(series);
}
if (_configService.XbmcCleanLibrary)
{
_logger.Trace("Sending Clean DB Request to XBMC");
_xbmcProvider.Clean();
}
}
}
}

View File

@ -1,114 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NLog;
using NzbDrone.Common.Eventing;
using NzbDrone.Core.Download;
using NzbDrone.Core.Tv;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Repository;
using PetaPoco;
namespace NzbDrone.Core.Providers
{
public class ExternalNotificationProvider : IHandle<EpisodeGrabbedEvent>
{
private static readonly Logger Logger = LogManager.GetCurrentClassLogger();
private readonly IDatabase _database;
private IList<ExternalNotificationBase> _notifiers;
public ExternalNotificationProvider(IDatabase database, IEnumerable<ExternalNotificationBase> notifiers)
{
_database = database;
_notifiers = notifiers.ToList();
InitializeNotifiers(_notifiers);
}
public ExternalNotificationProvider()
{
}
public virtual List<ExternalNotificationDefinition> All()
{
return _database.Fetch<ExternalNotificationDefinition>();
}
public virtual void SaveSettings(ExternalNotificationDefinition settings)
{
if (settings.Id == 0)
{
Logger.Debug("Adding External Notification definition for {0}", settings.Name);
_database.Insert(settings);
}
else
{
Logger.Debug("Updating External Notification definition for {0}", settings.Name);
_database.Update(settings);
}
}
public virtual ExternalNotificationDefinition GetSettings(Type type)
{
return _database.SingleOrDefault<ExternalNotificationDefinition>("WHERE ExternalNotificationProviderType = @0", type.ToString());
}
public virtual IList<ExternalNotificationBase> GetEnabledExternalNotifiers()
{
var all = All();
return _notifiers.Where(i => all.Exists(c => c.ExternalNotificationProviderType == i.GetType().ToString() && c.Enable)).ToList();
}
private void InitializeNotifiers(IList<ExternalNotificationBase> notifiers)
{
Logger.Debug("Initializing notifiers. Count {0}", notifiers.Count);
_notifiers = notifiers;
var currentNotifiers = All();
foreach (var notificationProvider in notifiers)
{
ExternalNotificationBase externalNotificationProviderLocal = notificationProvider;
if (!currentNotifiers.Exists(c => c.ExternalNotificationProviderType == externalNotificationProviderLocal.GetType().ToString()))
{
var settings = new ExternalNotificationDefinition
{
Enable = false,
ExternalNotificationProviderType = externalNotificationProviderLocal.GetType().ToString(),
Name = externalNotificationProviderLocal.Name
};
SaveSettings(settings);
}
}
}
public virtual void OnDownload(string message, Series series)
{
foreach (var notifier in _notifiers.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.OnDownload(message, series);
}
}
public virtual void AfterRename(string message, Series series)
{
foreach (var notifier in _notifiers.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.AfterRename(message, series);
}
}
public void Handle(EpisodeGrabbedEvent message)
{
foreach (var notifier in _notifiers.Where(i => GetSettings(i.GetType()).Enable))
{
notifier.OnGrab(message.ParseResult.GetDownloadTitle());
}
}
}
}

View File

@ -5,7 +5,6 @@ using NLog;
using NzbDrone.Core.Datastore; using NzbDrone.Core.Datastore;
using NzbDrone.Core.Tv; using NzbDrone.Core.Tv;
using NzbDrone.Core.Model; using NzbDrone.Core.Model;
using NzbDrone.Core.Providers.ExternalNotification;
using NzbDrone.Core.Providers.Metadata; using NzbDrone.Core.Providers.Metadata;
using NzbDrone.Core.Repository; using NzbDrone.Core.Repository;
using PetaPoco; using PetaPoco;

View File

@ -1,17 +0,0 @@
using PetaPoco;
namespace NzbDrone.Core.Repository
{
[TableName("ExternalNotificationDefinitions")]
[PrimaryKey("Id", autoIncrement = true)]
public class ExternalNotificationDefinition
{
public int Id { get; set; }
public bool Enable { get; set; }
public string ExternalNotificationProviderType { get; set; }
public string Name { get; set; }
}
}