Ability to blacklist and rename indexer urls via services.
This commit is contained in:
parent
766520b851
commit
7b4cb4145d
|
@ -366,6 +366,7 @@
|
|||
<Compile Include="Qualities\QualityModelComparerFixture.cs" />
|
||||
<Compile Include="RootFolderTests\RootFolderServiceFixture.cs" />
|
||||
<Compile Include="SeriesStatsTests\SeriesStatisticsFixture.cs" />
|
||||
<Compile Include="SkyhookNotifications\SkyhookNotificationServiceFixture.cs" />
|
||||
<Compile Include="ThingiProvider\ProviderBaseFixture.cs" />
|
||||
<Compile Include="ThingiProviderTests\NullConfigFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeServiceTests\FindEpisodeByTitleFixture.cs" />
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Core.SkyhookNotifications;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Test.SkyhookNotifications
|
||||
{
|
||||
public class SkyhookNotificationServiceFixture : CoreTest<SkyhookNotificationService>
|
||||
{
|
||||
private static readonly Version _previousVersion = new Version(BuildInfo.Version.Major, BuildInfo.Version.Minor, BuildInfo.Version.Build, BuildInfo.Version.Revision - 1);
|
||||
private static readonly Version _currentVersion = BuildInfo.Version;
|
||||
private static readonly Version _nextVersion = new Version(BuildInfo.Version.Major, BuildInfo.Version.Minor, BuildInfo.Version.Build, BuildInfo.Version.Revision + 1);
|
||||
|
||||
private List<SkyhookNotification> _expiredNotifications;
|
||||
private List<SkyhookNotification> _currentNotifications;
|
||||
private List<SkyhookNotification> _futureNotifications;
|
||||
private List<SkyhookNotification> _urlNotifications;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_expiredNotifications = new List<SkyhookNotification>
|
||||
{
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 1,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Expired Notification",
|
||||
MaximumVersion = _previousVersion.ToString()
|
||||
}
|
||||
};
|
||||
|
||||
_currentNotifications = new List<SkyhookNotification>
|
||||
{
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 2,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Timeless current Notification"
|
||||
},
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 2,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Ending current Notification",
|
||||
MaximumVersion = _currentVersion.ToString()
|
||||
},
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 2,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Ending future Notification",
|
||||
MaximumVersion = _nextVersion.ToString()
|
||||
},
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 2,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Starting previous Notification",
|
||||
MinimumVersion = _previousVersion.ToString()
|
||||
},
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 2,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Starting current Notification",
|
||||
MinimumVersion = _currentVersion.ToString()
|
||||
}
|
||||
};
|
||||
|
||||
_futureNotifications = new List<SkyhookNotification>
|
||||
{
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 3,
|
||||
Type = SkyhookNotificationType.Notification,
|
||||
Title = "Future Notification",
|
||||
MinimumVersion = _nextVersion.ToString()
|
||||
}
|
||||
};
|
||||
|
||||
_urlNotifications = new List<SkyhookNotification>
|
||||
{
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 3,
|
||||
Type = SkyhookNotificationType.UrlBlacklist,
|
||||
Title = "Future Notification"
|
||||
},
|
||||
new SkyhookNotification
|
||||
{
|
||||
Id = 3,
|
||||
Type = SkyhookNotificationType.UrlReplace,
|
||||
Title = "Future Notification"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void GivenNotifications(List<SkyhookNotification> notifications)
|
||||
{
|
||||
Mocker.GetMock<ISkyhookNotificationProxy>()
|
||||
.Setup(v => v.GetNotifications())
|
||||
.Returns(notifications);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_return_expired_notifications()
|
||||
{
|
||||
GivenNotifications(_expiredNotifications);
|
||||
|
||||
Subject.GetUserNotifications().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_return_future_notifications()
|
||||
{
|
||||
GivenNotifications(_futureNotifications);
|
||||
|
||||
Subject.GetUserNotifications().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_current_notifications()
|
||||
{
|
||||
GivenNotifications(_currentNotifications);
|
||||
|
||||
Subject.GetUserNotifications().Should().HaveCount(_currentNotifications.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_return_user_notifications()
|
||||
{
|
||||
GivenNotifications(_currentNotifications);
|
||||
|
||||
Subject.GetUrlNotifications().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_return_url_notifications()
|
||||
{
|
||||
GivenNotifications(_urlNotifications);
|
||||
|
||||
Subject.GetUserNotifications().Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_return_url_notifications()
|
||||
{
|
||||
GivenNotifications(_urlNotifications);
|
||||
|
||||
Subject.GetUrlNotifications().Should().HaveCount(_urlNotifications.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_cache_api_result()
|
||||
{
|
||||
GivenNotifications(_urlNotifications);
|
||||
|
||||
Subject.GetUrlNotifications();
|
||||
Subject.GetUrlNotifications();
|
||||
|
||||
Mocker.GetMock<ISkyhookNotificationProxy>()
|
||||
.Verify(v => v.GetNotifications(), Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,7 +2,9 @@
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Composition;
|
||||
using NzbDrone.Common.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.SkyhookNotifications;
|
||||
using NzbDrone.Core.ThingiProvider;
|
||||
|
||||
namespace NzbDrone.Core.Indexers
|
||||
|
@ -15,17 +17,20 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
public class IndexerFactory : ProviderFactory<IIndexer, IndexerDefinition>, IIndexerFactory
|
||||
{
|
||||
private readonly ISubstituteIndexerUrl _substituteIndexerUrl;
|
||||
private readonly IIndexerStatusService _indexerStatusService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public IndexerFactory(IIndexerStatusService indexerStatusService,
|
||||
public IndexerFactory(ISubstituteIndexerUrl replaceIndexerUrl,
|
||||
IIndexerStatusService indexerStatusService,
|
||||
IIndexerRepository providerRepository,
|
||||
IEnumerable<IIndexer> providers,
|
||||
IContainer container,
|
||||
IContainer container,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
: base(providerRepository, providers, container, eventAggregator, logger)
|
||||
{
|
||||
_substituteIndexerUrl = replaceIndexerUrl;
|
||||
_indexerStatusService = indexerStatusService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
@ -50,7 +55,7 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
if (filterBlockedIndexers)
|
||||
{
|
||||
return FilterBlockedIndexers(enabledIndexers).ToList();
|
||||
return FilterBlockedIndexers(SubstituteIndexerUrls(enabledIndexers)).ToList();
|
||||
}
|
||||
|
||||
return enabledIndexers.ToList();
|
||||
|
@ -62,12 +67,31 @@ namespace NzbDrone.Core.Indexers
|
|||
|
||||
if (filterBlockedIndexers)
|
||||
{
|
||||
return FilterBlockedIndexers(enabledIndexers).ToList();
|
||||
return FilterBlockedIndexers(SubstituteIndexerUrls(enabledIndexers)).ToList();
|
||||
}
|
||||
|
||||
return enabledIndexers.ToList();
|
||||
}
|
||||
|
||||
private IEnumerable<IIndexer> SubstituteIndexerUrls(IEnumerable<IIndexer> indexers)
|
||||
{
|
||||
foreach (var indexer in indexers)
|
||||
{
|
||||
var settings = (IIndexerSettings)indexer.Definition.Settings;
|
||||
if (settings.BaseUrl.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
var newBaseUrl = _substituteIndexerUrl.SubstituteUrl(settings.BaseUrl);
|
||||
if (newBaseUrl != settings.BaseUrl)
|
||||
{
|
||||
_logger.Debug("Substituted indexer {0} url {1} with {2} since services blacklisted it.", indexer.Definition.Name, settings.BaseUrl, newBaseUrl);
|
||||
settings.BaseUrl = newBaseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
yield return indexer;
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<IIndexer> FilterBlockedIndexers(IEnumerable<IIndexer> indexers)
|
||||
{
|
||||
var blockedIndexers = _indexerStatusService.GetBlockedIndexers().ToDictionary(v => v.ProviderId, v => v);
|
||||
|
@ -85,4 +109,4 @@ namespace NzbDrone.Core.Indexers
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1063,6 +1063,11 @@
|
|||
<Compile Include="SeriesStats\SeriesStatistics.cs" />
|
||||
<Compile Include="SeriesStats\SeriesStatisticsRepository.cs" />
|
||||
<Compile Include="SeriesStats\SeriesStatisticsService.cs" />
|
||||
<Compile Include="SkyhookNotifications\SkyhookNotification.cs" />
|
||||
<Compile Include="SkyhookNotifications\SkyhookNotificationService.cs" />
|
||||
<Compile Include="SkyhookNotifications\SkyhookNotificationType.cs" />
|
||||
<Compile Include="SkyhookNotifications\SkyhookNotificationProxy.cs" />
|
||||
<Compile Include="SkyhookNotifications\SubstituteUrlService.cs" />
|
||||
<Compile Include="Tags\Tag.cs" />
|
||||
<Compile Include="Tags\TagRepository.cs" />
|
||||
<Compile Include="Tags\TagService.cs" />
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.SkyhookNotifications
|
||||
{
|
||||
public class SkyhookNotification
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string MinimumVersion { get; set; }
|
||||
public string MaximumVersion { get; set; }
|
||||
public SkyhookNotificationType Type { get; set; }
|
||||
public string Title { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string RegexMatch { get; set; }
|
||||
public string RegexReplace { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cloud;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Http;
|
||||
|
||||
namespace NzbDrone.Core.SkyhookNotifications
|
||||
{
|
||||
public interface ISkyhookNotificationProxy
|
||||
{
|
||||
List<SkyhookNotification> GetNotifications();
|
||||
}
|
||||
|
||||
public class SkyhookNotificationProxy : ISkyhookNotificationProxy
|
||||
{
|
||||
private readonly IHttpClient _httpClient;
|
||||
private readonly IHttpRequestBuilderFactory _requestBuilder;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public SkyhookNotificationProxy(IHttpClient httpClient, ISonarrCloudRequestBuilder requestBuilder, Logger logger)
|
||||
{
|
||||
_httpClient = httpClient;
|
||||
_requestBuilder = requestBuilder.Services;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<SkyhookNotification> GetNotifications()
|
||||
{
|
||||
var notificationsRequest = _requestBuilder.Create()
|
||||
.Resource("/notifications")
|
||||
.AddQueryParam("version", BuildInfo.Version)
|
||||
.AddQueryParam("os", OsInfo.Os.ToString().ToLowerInvariant())
|
||||
.Build();
|
||||
|
||||
try
|
||||
{
|
||||
var response = _httpClient.Get<List<SkyhookNotification>>(notificationsRequest);
|
||||
return response.Resource;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Warn(ex, "Failed to get information update from {0}", notificationsRequest.Url.Host);
|
||||
return new List<SkyhookNotification>();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
|
||||
namespace NzbDrone.Core.SkyhookNotifications
|
||||
{
|
||||
public interface ISkyhookNotificationService
|
||||
{
|
||||
List<SkyhookNotification> GetUserNotifications();
|
||||
List<SkyhookNotification> GetUrlNotifications();
|
||||
}
|
||||
|
||||
public class SkyhookNotificationService : ISkyhookNotificationService
|
||||
{
|
||||
private readonly ISkyhookNotificationProxy _proxy;
|
||||
private readonly Logger _logger;
|
||||
|
||||
private readonly ICached<List<SkyhookNotification>> _cache;
|
||||
|
||||
private readonly TimeSpan CacheExpiry = TimeSpan.FromHours(12);
|
||||
|
||||
public SkyhookNotificationService(ISkyhookNotificationProxy proxy, ICacheManager cacheManager, Logger logger)
|
||||
{
|
||||
_proxy = proxy;
|
||||
_logger = logger;
|
||||
|
||||
_cache = cacheManager.GetCache<List<SkyhookNotification>>(GetType());
|
||||
}
|
||||
|
||||
private List<SkyhookNotification> GetNotifications(string key)
|
||||
{
|
||||
var result = _cache.Find(key);
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
var all = _proxy.GetNotifications().Where(FilterVersion).ToList();
|
||||
|
||||
var user = all.Where(v => v.Type == SkyhookNotificationType.Notification).ToList();
|
||||
var url = all.Where(v => v.Type == SkyhookNotificationType.UrlBlacklist || v.Type == SkyhookNotificationType.UrlReplace).ToList();
|
||||
_cache.Set("all", all, CacheExpiry);
|
||||
_cache.Set("user", user, CacheExpiry);
|
||||
_cache.Set("url", url, CacheExpiry);
|
||||
}
|
||||
|
||||
return _cache.Find(key);
|
||||
}
|
||||
|
||||
public List<SkyhookNotification> GetUserNotifications()
|
||||
{
|
||||
return GetNotifications("user");
|
||||
}
|
||||
|
||||
public List<SkyhookNotification> GetUrlNotifications()
|
||||
{
|
||||
return GetNotifications("url");
|
||||
}
|
||||
|
||||
private bool FilterVersion(SkyhookNotification notification)
|
||||
{
|
||||
if (notification.MinimumVersion != null && BuildInfo.Version < Version.Parse(notification.MinimumVersion))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (notification.MaximumVersion != null && BuildInfo.Version > Version.Parse(notification.MaximumVersion))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace NzbDrone.Core.SkyhookNotifications
|
||||
{
|
||||
public enum SkyhookNotificationType
|
||||
{
|
||||
// Notification for the user alone.
|
||||
Notification = 1,
|
||||
|
||||
// Indexer urls matching the RegexMatch are automatically set to temporarily disabled and never contacted.
|
||||
UrlBlacklist = 2,
|
||||
|
||||
// Indexer urls matching the RegexMatch are replaced with RegexReplace.
|
||||
UrlReplace = 3
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace NzbDrone.Core.SkyhookNotifications
|
||||
{
|
||||
public interface ISubstituteIndexerUrl
|
||||
{
|
||||
string SubstituteUrl(string baseUrl);
|
||||
}
|
||||
|
||||
public class SubstituteUrlService : ISubstituteIndexerUrl
|
||||
{
|
||||
private readonly ISkyhookNotificationService _notificationService;
|
||||
|
||||
public SubstituteUrlService(ISkyhookNotificationService notificationService)
|
||||
{
|
||||
_notificationService = notificationService;
|
||||
}
|
||||
|
||||
public string SubstituteUrl(string baseUrl)
|
||||
{
|
||||
foreach (var action in _notificationService.GetUrlNotifications())
|
||||
{
|
||||
if (action.Type == SkyhookNotificationType.UrlBlacklist)
|
||||
{
|
||||
if (action.RegexMatch == null) continue;
|
||||
|
||||
if (Regex.IsMatch(baseUrl, action.RegexMatch))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else if (action.Type == SkyhookNotificationType.UrlReplace)
|
||||
{
|
||||
if (action.RegexMatch == null) continue;
|
||||
if (action.RegexReplace == null) continue;
|
||||
|
||||
if (Regex.IsMatch(baseUrl, action.RegexMatch))
|
||||
{
|
||||
return Regex.Replace(baseUrl, action.RegexMatch, action.RegexReplace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return baseUrl;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue