Add Proxy Support, Add IOptions Pattern, Add Extensions Method
Currently Changes Http / Https proxy support has been added , To disguise the Ip address or if a proxy service is required IOptions pattern has been implemented. Better options handling Extensions methods have been implemented to make Program.cs smaller Added a global logger for static and extension methods appsettings.json now contains "default" data for the applications and proxy settings. The Docker variables are also specified above it. This also fixes the bug that you have to set all variables, although you only want to use Sonarr, for example
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
namespace UmlautAdaptarr.Options.ArrOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Base Options for ARR applications
|
||||
/// </summary>
|
||||
public class ArrApplicationBaseOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Indicates whether the Arr application is enabled.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The host of the ARR application.
|
||||
/// </summary>
|
||||
public string Host { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The API key of the ARR application.
|
||||
/// </summary>
|
||||
public string ApiKey { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace UmlautAdaptarr.Options.ArrOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Lidarr Options
|
||||
/// </summary>
|
||||
public class LidarrInstanceOptions : ArrApplicationBaseOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace UmlautAdaptarr.Options.ArrOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Readarr Options
|
||||
/// </summary>
|
||||
public class ReadarrInstanceOptions : ArrApplicationBaseOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace UmlautAdaptarr.Options.ArrOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Sonarr Options
|
||||
/// </summary>
|
||||
public class SonarrInstanceOptions : ArrApplicationBaseOptions
|
||||
{
|
||||
}
|
||||
}
|
||||
18
UmlautAdaptarr/Options/GlobalOptions.cs
Normal file
18
UmlautAdaptarr/Options/GlobalOptions.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace UmlautAdaptarr.Options
|
||||
{
|
||||
/// <summary>
|
||||
/// Global options for the UmlautAdaptarr application.
|
||||
/// </summary>
|
||||
public class GlobalOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// The host of the UmlautAdaptarr API.
|
||||
/// </summary>
|
||||
public string UmlautAdaptarrApiHost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The User-Agent string used in HTTP requests.
|
||||
/// </summary>
|
||||
public string UserAgent { get; set; }
|
||||
}
|
||||
}
|
||||
27
UmlautAdaptarr/Options/Proxy.cs
Normal file
27
UmlautAdaptarr/Options/Proxy.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
namespace UmlautAdaptarr.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents options for proxy configuration.
|
||||
/// </summary>
|
||||
public class Proxy
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to use a proxy.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the address of the proxy.
|
||||
/// </summary>
|
||||
public string? Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the username for proxy authentication.
|
||||
/// </summary>
|
||||
public string? Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the password for proxy authentication.
|
||||
/// </summary>
|
||||
public string? Password { get; set; }
|
||||
}
|
||||
32
UmlautAdaptarr/Options/ProxyOptions.cs
Normal file
32
UmlautAdaptarr/Options/ProxyOptions.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
namespace UmlautAdaptarr.Options;
|
||||
|
||||
/// <summary>
|
||||
/// Represents options for proxy configuration.
|
||||
/// </summary>
|
||||
public class ProxyOptions
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether to use a proxy.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the address of the proxy.
|
||||
/// </summary>
|
||||
public string? Address { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the username for proxy authentication.
|
||||
/// </summary>
|
||||
public string? Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the password for proxy authentication.
|
||||
/// </summary>
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Bypass Local Ip Addresses , Proxy will ignore local Ip Addresses
|
||||
/// </summary>
|
||||
public bool BypassOnLocal { get; set; }
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Net;
|
||||
using UmlautAdaptarr.Options;
|
||||
using UmlautAdaptarr.Providers;
|
||||
using UmlautAdaptarr.Routing;
|
||||
using UmlautAdaptarr.Services;
|
||||
using UmlautAdaptarr.Utilities;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
@@ -24,6 +26,8 @@ internal class Program
|
||||
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate | DecompressionMethods.Brotli
|
||||
};
|
||||
|
||||
var proxyOptions = configuration.GetSection("Proxy").Get<ProxyOptions>();
|
||||
handler.ConfigureProxy(proxyOptions);
|
||||
return handler;
|
||||
});
|
||||
|
||||
@@ -46,17 +50,18 @@ internal class Program
|
||||
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddHostedService<ArrSyncBackgroundService>();
|
||||
builder.Services.AddSingleton<TitleApiService>();
|
||||
builder.AddTitleLookupService();
|
||||
builder.Services.AddSingleton<SearchItemLookupService>();
|
||||
builder.Services.AddSingleton<TitleMatchingService>();
|
||||
builder.Services.AddSingleton<SonarrClient>();
|
||||
builder.Services.AddSingleton<LidarrClient>();
|
||||
builder.Services.AddSingleton<ReadarrClient>();
|
||||
builder.AddSonarrSupport();
|
||||
builder.AddLidarrSupport();
|
||||
builder.AddReadarrSupport();
|
||||
builder.Services.AddSingleton<CacheService>();
|
||||
builder.Services.AddSingleton<ProxyService>();
|
||||
builder.AddProxyService();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
GlobalStaticLogger.Initialize(app.Services.GetService<ILoggerFactory>()!);
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
app.UseAuthorization();
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UmlautAdaptarr.Models;
|
||||
using UmlautAdaptarr.Options.ArrOptions;
|
||||
using UmlautAdaptarr.Services;
|
||||
using UmlautAdaptarr.Utilities;
|
||||
|
||||
@@ -12,10 +14,9 @@ namespace UmlautAdaptarr.Providers
|
||||
IConfiguration configuration,
|
||||
CacheService cacheService,
|
||||
IMemoryCache cache,
|
||||
ILogger<LidarrClient> logger) : ArrClientBase()
|
||||
ILogger<LidarrClient> logger, IOptions<LidarrInstanceOptions> options) : ArrClientBase()
|
||||
{
|
||||
private readonly string _lidarrHost = configuration.GetValue<string>("LIDARR_HOST") ?? throw new ArgumentException("LIDARR_HOST environment variable must be set");
|
||||
private readonly string _lidarrApiKey = configuration.GetValue<string>("LIDARR_API_KEY") ?? throw new ArgumentException("LIDARR_API_KEY environment variable must be set");
|
||||
public LidarrInstanceOptions LidarrOptions { get; } = options.Value;
|
||||
private readonly string _mediaType = "audio";
|
||||
|
||||
public override async Task<IEnumerable<SearchItem>> FetchAllItemsAsync()
|
||||
@@ -25,7 +26,7 @@ namespace UmlautAdaptarr.Providers
|
||||
|
||||
try
|
||||
{
|
||||
var lidarrArtistsUrl = $"{_lidarrHost}/api/v1/artist?apikey={_lidarrApiKey}";
|
||||
var lidarrArtistsUrl = $"{LidarrOptions.Host}/api/v1/artist?apikey={LidarrOptions.ApiKey}";
|
||||
logger.LogInformation($"Fetching all artists from Lidarr: {UrlUtilities.RedactApiKey(lidarrArtistsUrl)}");
|
||||
var artistsApiResponse = await httpClient.GetStringAsync(lidarrArtistsUrl);
|
||||
var artists = JsonConvert.DeserializeObject<List<dynamic>>(artistsApiResponse);
|
||||
@@ -40,7 +41,7 @@ namespace UmlautAdaptarr.Providers
|
||||
{
|
||||
var artistId = (int)artist.id;
|
||||
|
||||
var lidarrAlbumUrl = $"{_lidarrHost}/api/v1/album?artistId={artistId}&apikey={_lidarrApiKey}";
|
||||
var lidarrAlbumUrl = $"{LidarrOptions.Host}/api/v1/album?artistId={artistId}&apikey={LidarrOptions.ApiKey}";
|
||||
|
||||
// TODO add caching here
|
||||
// Disable cache for now as it can result in problems when adding new albums that aren't displayed on the artists page initially
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UmlautAdaptarr.Models;
|
||||
using UmlautAdaptarr.Options.ArrOptions;
|
||||
using UmlautAdaptarr.Services;
|
||||
using UmlautAdaptarr.Utilities;
|
||||
|
||||
@@ -12,10 +14,11 @@ namespace UmlautAdaptarr.Providers
|
||||
IConfiguration configuration,
|
||||
CacheService cacheService,
|
||||
IMemoryCache cache,
|
||||
IOptions<ReadarrInstanceOptions> options,
|
||||
ILogger<ReadarrClient> logger) : ArrClientBase()
|
||||
{
|
||||
private readonly string _readarrHost = configuration.GetValue<string>("READARR_HOST") ?? throw new ArgumentException("READARR_HOST environment variable must be set");
|
||||
private readonly string _readarrApiKey = configuration.GetValue<string>("READARR_API_KEY") ?? throw new ArgumentException("READARR_API_KEY environment variable must be set");
|
||||
|
||||
public ReadarrInstanceOptions ReadarrOptions { get; } = options.Value;
|
||||
private readonly string _mediaType = "book";
|
||||
|
||||
public override async Task<IEnumerable<SearchItem>> FetchAllItemsAsync()
|
||||
@@ -25,7 +28,7 @@ namespace UmlautAdaptarr.Providers
|
||||
|
||||
try
|
||||
{
|
||||
var readarrAuthorUrl = $"{_readarrHost}/api/v1/author?apikey={_readarrApiKey}";
|
||||
var readarrAuthorUrl = $"{ReadarrOptions.Host}/api/v1/author?apikey={ReadarrOptions.ApiKey}";
|
||||
logger.LogInformation($"Fetching all authors from Readarr: {UrlUtilities.RedactApiKey(readarrAuthorUrl)}");
|
||||
var authorApiResponse = await httpClient.GetStringAsync(readarrAuthorUrl);
|
||||
var authors = JsonConvert.DeserializeObject<List<dynamic>>(authorApiResponse);
|
||||
@@ -40,7 +43,7 @@ namespace UmlautAdaptarr.Providers
|
||||
{
|
||||
var authorId = (int)author.id;
|
||||
|
||||
var readarrBookUrl = $"{_readarrHost}/api/v1/book?authorId={authorId}&apikey={_readarrApiKey}";
|
||||
var readarrBookUrl = $"{ReadarrOptions.Host}/api/v1/book?authorId={authorId}&apikey={ReadarrOptions.ApiKey}";
|
||||
|
||||
// TODO add caching here
|
||||
logger.LogInformation($"Fetching all books from authorId {authorId} from Readarr: {UrlUtilities.RedactApiKey(readarrBookUrl)}");
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using UmlautAdaptarr.Models;
|
||||
using UmlautAdaptarr.Options.ArrOptions;
|
||||
using UmlautAdaptarr.Services;
|
||||
using UmlautAdaptarr.Utilities;
|
||||
|
||||
@@ -9,10 +11,12 @@ namespace UmlautAdaptarr.Providers
|
||||
IHttpClientFactory clientFactory,
|
||||
IConfiguration configuration,
|
||||
TitleApiService titleService,
|
||||
IOptions<SonarrInstanceOptions> options,
|
||||
ILogger<SonarrClient> logger) : ArrClientBase()
|
||||
{
|
||||
private readonly string _sonarrHost = configuration.GetValue<string>("SONARR_HOST") ?? throw new ArgumentException("SONARR_HOST environment variable must be set");
|
||||
private readonly string _sonarrApiKey = configuration.GetValue<string>("SONARR_API_KEY") ?? throw new ArgumentException("SONARR_API_KEY environment variable must be set");
|
||||
public SonarrInstanceOptions SonarrOptions { get; } = options.Value;
|
||||
//private readonly string _sonarrHost = configuration.GetValue<string>("SONARR_HOST") ?? throw new ArgumentException("SONARR_HOST environment variable must be set");
|
||||
//private readonly string _sonarrApiKey = configuration.GetValue<string>("SONARR_API_KEY") ?? throw new ArgumentException("SONARR_API_KEY environment variable must be set");
|
||||
private readonly string _mediaType = "tv";
|
||||
|
||||
public override async Task<IEnumerable<SearchItem>> FetchAllItemsAsync()
|
||||
@@ -22,7 +26,7 @@ namespace UmlautAdaptarr.Providers
|
||||
|
||||
try
|
||||
{
|
||||
var sonarrUrl = $"{_sonarrHost}/api/v3/series?includeSeasonImages=false&apikey={_sonarrApiKey}";
|
||||
var sonarrUrl = $"{SonarrOptions.Host}/api/v3/series?includeSeasonImages=false&apikey={SonarrOptions.ApiKey}";
|
||||
logger.LogInformation($"Fetching all items from Sonarr: {UrlUtilities.RedactApiKey(sonarrUrl)}");
|
||||
var response = await httpClient.GetStringAsync(sonarrUrl);
|
||||
var shows = JsonConvert.DeserializeObject<List<dynamic>>(response);
|
||||
@@ -71,7 +75,7 @@ namespace UmlautAdaptarr.Providers
|
||||
|
||||
try
|
||||
{
|
||||
var sonarrUrl = $"{_sonarrHost}/api/v3/series?tvdbId={externalId}&includeSeasonImages=false&apikey={_sonarrApiKey}";
|
||||
var sonarrUrl = $"{SonarrOptions.Host}/api/v3/series?tvdbId={externalId}&includeSeasonImages=false&apikey={SonarrOptions.ApiKey}";
|
||||
logger.LogInformation($"Fetching item by external ID from Sonarr: {UrlUtilities.RedactApiKey(sonarrUrl)}");
|
||||
var response = await httpClient.GetStringAsync(sonarrUrl);
|
||||
var shows = JsonConvert.DeserializeObject<dynamic>(response);
|
||||
@@ -123,7 +127,7 @@ namespace UmlautAdaptarr.Providers
|
||||
return null;
|
||||
}
|
||||
|
||||
var sonarrUrl = $"{_sonarrHost}/api/v3/series?tvdbId={tvdbId}&includeSeasonImages=false&apikey={_sonarrApiKey}";
|
||||
var sonarrUrl = $"{SonarrOptions.Host}/api/v3/series?tvdbId={tvdbId}&includeSeasonImages=false&apikey={SonarrOptions.ApiKey}";
|
||||
var sonarrApiResponse = await httpClient.GetStringAsync(sonarrUrl);
|
||||
var shows = JsonConvert.DeserializeObject<dynamic>(sonarrApiResponse);
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ namespace UmlautAdaptarr.Services
|
||||
IConfiguration configuration,
|
||||
ILogger<ArrSyncBackgroundService> logger) : BackgroundService
|
||||
{
|
||||
private readonly bool _sonarrEnabled = configuration.GetValue<bool>("SONARR_ENABLED");
|
||||
private readonly bool _lidarrEnabled = configuration.GetValue<bool>("LIDARR_ENABLED");
|
||||
private readonly bool _readarrEnabled = configuration.GetValue<bool>("READARR_ENABLED");
|
||||
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
|
||||
{
|
||||
logger.LogInformation("ArrSyncBackgroundService is starting.");
|
||||
@@ -62,17 +59,17 @@ namespace UmlautAdaptarr.Services
|
||||
try
|
||||
{
|
||||
var success = true;
|
||||
if (_readarrEnabled)
|
||||
if (readarrClient.ReadarrOptions.Enabled)
|
||||
{
|
||||
var syncSuccess = await FetchItemsFromReadarrAsync();
|
||||
success = success && syncSuccess;
|
||||
}
|
||||
if (_sonarrEnabled)
|
||||
if (sonarrClient.SonarrOptions.Enabled)
|
||||
{
|
||||
var syncSuccess = await FetchItemsFromSonarrAsync();
|
||||
success = success && syncSuccess;
|
||||
}
|
||||
if (_lidarrEnabled)
|
||||
if (lidarrClient.LidarrOptions.Enabled)
|
||||
{
|
||||
var syncSuccess = await FetchItemsFromLidarrAsync();
|
||||
success = success && syncSuccess;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using System.Collections.Concurrent;
|
||||
using Microsoft.Extensions.Options;
|
||||
using UmlautAdaptarr.Options;
|
||||
using UmlautAdaptarr.Utilities;
|
||||
|
||||
namespace UmlautAdaptarr.Services
|
||||
@@ -10,15 +12,18 @@ namespace UmlautAdaptarr.Services
|
||||
private readonly string _userAgent;
|
||||
private readonly ILogger<ProxyService> _logger;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly GlobalOptions _options;
|
||||
private static readonly ConcurrentDictionary<string, DateTimeOffset> _lastRequestTimes = new();
|
||||
private static readonly TimeSpan MINIMUM_DELAY_FOR_SAME_HOST = new(0, 0, 0, 1);
|
||||
|
||||
public ProxyService(IHttpClientFactory clientFactory, IConfiguration configuration, ILogger<ProxyService> logger, IMemoryCache cache)
|
||||
public ProxyService(IHttpClientFactory clientFactory, ILogger<ProxyService> logger, IMemoryCache cache, IOptions<GlobalOptions> options)
|
||||
{
|
||||
_options = options.Value;
|
||||
_httpClient = clientFactory.CreateClient("HttpClient") ?? throw new ArgumentNullException(nameof(clientFactory));
|
||||
_userAgent = configuration["Settings:UserAgent"] ?? throw new ArgumentException("UserAgent must be set in appsettings.json");
|
||||
_userAgent = _options.UserAgent ?? throw new ArgumentException("UserAgent must be set in appsettings.json");
|
||||
_logger = logger;
|
||||
_cache = cache;
|
||||
|
||||
}
|
||||
|
||||
private static async Task EnsureMinimumDelayAsync(string targetUri)
|
||||
|
||||
@@ -6,12 +6,8 @@ namespace UmlautAdaptarr.Services
|
||||
public class SearchItemLookupService(CacheService cacheService,
|
||||
SonarrClient sonarrClient,
|
||||
ReadarrClient readarrClient,
|
||||
LidarrClient lidarrClient,
|
||||
IConfiguration configuration)
|
||||
LidarrClient lidarrClient)
|
||||
{
|
||||
private readonly bool _sonarrEnabled = configuration.GetValue<bool>("SONARR_ENABLED");
|
||||
private readonly bool _lidarrEnabled = configuration.GetValue<bool>("LIDARR_ENABLED");
|
||||
private readonly bool _readarrEnabled = configuration.GetValue<bool>("READARR_ENABLED");
|
||||
public async Task<SearchItem?> GetOrFetchSearchItemByExternalId(string mediaType, string externalId)
|
||||
{
|
||||
// Attempt to get the item from the cache first
|
||||
@@ -26,20 +22,20 @@ namespace UmlautAdaptarr.Services
|
||||
switch (mediaType)
|
||||
{
|
||||
case "tv":
|
||||
if (_sonarrEnabled)
|
||||
if (sonarrClient.SonarrOptions.Enabled)
|
||||
{
|
||||
fetchedItem = await sonarrClient.FetchItemByExternalIdAsync(externalId);
|
||||
}
|
||||
break;
|
||||
case "audio":
|
||||
if (_lidarrEnabled)
|
||||
if (lidarrClient.LidarrOptions.Enabled)
|
||||
{
|
||||
fetchedItem = await lidarrClient.FetchItemByExternalIdAsync(externalId);
|
||||
fetchedItem = cacheService.GetSearchItemByExternalId(mediaType, externalId);
|
||||
}
|
||||
break;
|
||||
case "book":
|
||||
if (_readarrEnabled)
|
||||
if (readarrClient.ReadarrOptions.Enabled)
|
||||
{
|
||||
await readarrClient.FetchItemByExternalIdAsync(externalId);
|
||||
fetchedItem = cacheService.GetSearchItemByExternalId(mediaType, externalId);
|
||||
@@ -70,7 +66,7 @@ namespace UmlautAdaptarr.Services
|
||||
switch (mediaType)
|
||||
{
|
||||
case "tv":
|
||||
if (_sonarrEnabled)
|
||||
if (sonarrClient.SonarrOptions.Enabled)
|
||||
{
|
||||
fetchedItem = await sonarrClient.FetchItemByTitleAsync(title);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
using Newtonsoft.Json;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using UmlautAdaptarr.Options;
|
||||
using UmlautAdaptarr.Utilities;
|
||||
|
||||
namespace UmlautAdaptarr.Services
|
||||
{
|
||||
public class TitleApiService(IHttpClientFactory clientFactory, IConfiguration configuration, ILogger<TitleApiService> logger)
|
||||
public class TitleApiService(IHttpClientFactory clientFactory, ILogger<TitleApiService> logger, IOptions<GlobalOptions> options)
|
||||
{
|
||||
private readonly string _umlautAdaptarrApiHost = configuration["Settings:UmlautAdaptarrApiHost"]
|
||||
?? throw new ArgumentException("UmlautAdaptarrApiHost must be set in appsettings.json");
|
||||
public GlobalOptions Options { get; } = options.Value;
|
||||
|
||||
private DateTime lastRequestTime = DateTime.MinValue;
|
||||
|
||||
private async Task EnsureMinimumDelayAsync()
|
||||
@@ -28,7 +30,7 @@ namespace UmlautAdaptarr.Services
|
||||
await EnsureMinimumDelayAsync();
|
||||
|
||||
var httpClient = clientFactory.CreateClient();
|
||||
var titleApiUrl = $"{_umlautAdaptarrApiHost}/tvshow_german.php?tvdbid={externalId}";
|
||||
var titleApiUrl = $"{Options.UmlautAdaptarrApiHost}/tvshow_german.php?tvdbid={externalId}";
|
||||
logger.LogInformation($"TitleApiService GET {UrlUtilities.RedactApiKey(titleApiUrl)}");
|
||||
var response = await httpClient.GetStringAsync(titleApiUrl);
|
||||
var titleApiResponseData = JsonConvert.DeserializeObject<dynamic>(response);
|
||||
@@ -74,7 +76,7 @@ namespace UmlautAdaptarr.Services
|
||||
|
||||
var httpClient = clientFactory.CreateClient();
|
||||
var tvdbCleanTitle = title.Replace("ß", "ss");
|
||||
var titleApiUrl = $"{_umlautAdaptarrApiHost}/tvshow_german.php?title={tvdbCleanTitle}";
|
||||
var titleApiUrl = $"{Options.UmlautAdaptarrApiHost}/tvshow_german.php?title={tvdbCleanTitle}";
|
||||
logger.LogInformation($"TitleApiService GET {UrlUtilities.RedactApiKey(titleApiUrl)}");
|
||||
var titleApiResponse = await httpClient.GetStringAsync(titleApiUrl);
|
||||
var titleApiResponseData = JsonConvert.DeserializeObject<dynamic>(titleApiResponse);
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="8.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
19
UmlautAdaptarr/Utilities/GlobalStaticLogger.cs
Normal file
19
UmlautAdaptarr/Utilities/GlobalStaticLogger.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
namespace UmlautAdaptarr.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Service for providing a static logger to log errors and information.
|
||||
/// The GlobalStaticLogger is designed to provide a static logger that can be used to log errors and information.
|
||||
/// It facilitates logging for both static classes and extension methods.
|
||||
/// </summary>
|
||||
public static class GlobalStaticLogger
|
||||
{
|
||||
|
||||
public static ILogger Logger;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the GlobalStaticLogger with the provided logger factory.
|
||||
/// </summary>
|
||||
/// <param name="loggerFactory">The ILoggerFactory instance used to create loggers.</param>
|
||||
public static void Initialize(ILoggerFactory loggerFactory) => Logger = loggerFactory.CreateLogger("GlobalStaticLogger");
|
||||
}
|
||||
}
|
||||
53
UmlautAdaptarr/Utilities/ProxyExtension.cs
Normal file
53
UmlautAdaptarr/Utilities/ProxyExtension.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using UmlautAdaptarr.Options;
|
||||
|
||||
namespace UmlautAdaptarr.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for configuring proxies.
|
||||
/// </summary>
|
||||
public static class ProxyExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Logger instance for logging proxy configurations.
|
||||
/// </summary>
|
||||
private static ILogger Logger = GlobalStaticLogger.Logger;
|
||||
|
||||
/// <summary>
|
||||
/// Configures the proxy settings for the provided HttpClientHandler instance.
|
||||
/// </summary>
|
||||
/// <param name="handler">The HttpClientHandler instance to configure.</param>
|
||||
/// <param name="proxyOptions">ProxyOptions options to be used for configuration.</param>
|
||||
/// <returns>The configured HttpClientHandler instance.</returns>
|
||||
public static HttpClientHandler ConfigureProxy(this HttpClientHandler handler, ProxyOptions? proxyOptions)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (proxyOptions != null && proxyOptions.Enabled)
|
||||
{
|
||||
Logger.LogInformation("Use Proxy {0}", proxyOptions.Address);
|
||||
handler.UseProxy = true;
|
||||
handler.Proxy = new WebProxy(proxyOptions.Address, proxyOptions.BypassOnLocal);
|
||||
|
||||
if (!string.IsNullOrEmpty(proxyOptions.Username) && !string.IsNullOrEmpty(proxyOptions.Password))
|
||||
{
|
||||
Logger.LogInformation("Use Proxy Credentials from User {0}", proxyOptions.Username);
|
||||
handler.DefaultProxyCredentials =
|
||||
new NetworkCredential(proxyOptions.Username, proxyOptions.Password);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger.LogDebug("No proxy was set");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error occurred while configuring proxy, no Proxy will be used!");
|
||||
}
|
||||
|
||||
return handler;
|
||||
}
|
||||
}
|
||||
}
|
||||
96
UmlautAdaptarr/Utilities/ServicesExtensions.cs
Normal file
96
UmlautAdaptarr/Utilities/ServicesExtensions.cs
Normal file
@@ -0,0 +1,96 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using UmlautAdaptarr.Options;
|
||||
using UmlautAdaptarr.Options.ArrOptions;
|
||||
using UmlautAdaptarr.Providers;
|
||||
using UmlautAdaptarr.Services;
|
||||
|
||||
namespace UmlautAdaptarr.Utilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Extension methods for configuring services related to ARR Applications
|
||||
/// </summary>
|
||||
public static class ServicesExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Adds a service with specified options and service to the service collection.
|
||||
/// </summary>
|
||||
/// <typeparam name="TOptions">The options type for the service.</typeparam>
|
||||
/// <typeparam name="TService">The service type for the service.</typeparam>
|
||||
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to configure the service collection.</param>
|
||||
/// <param name="sectionName">The name of the configuration section containing service options.</param>
|
||||
/// <returns>The configured <see cref="WebApplicationBuilder"/>.</returns>
|
||||
private static WebApplicationBuilder AddServiceWithOptions<TOptions, TService>(this WebApplicationBuilder builder, string sectionName)
|
||||
where TOptions : class
|
||||
where TService : class
|
||||
{
|
||||
if (builder.Services == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder), "Service collection is null.");
|
||||
}
|
||||
|
||||
var options = builder.Configuration.GetSection(sectionName).Get<TOptions>();
|
||||
if (options == null)
|
||||
{
|
||||
throw new InvalidOperationException($"{typeof(TService).Name} options could not be loaded from Configuration or ENV Variable.");
|
||||
}
|
||||
|
||||
builder.Services.Configure<TOptions>(builder.Configuration.GetSection(sectionName));
|
||||
builder.Services.AddSingleton<TService>();
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds support for Sonarr with default options and client.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to configure the service collection.</param>
|
||||
/// <returns>The configured <see cref="WebApplicationBuilder"/>.</returns>
|
||||
public static WebApplicationBuilder AddSonarrSupport(this WebApplicationBuilder builder)
|
||||
{
|
||||
return builder.AddServiceWithOptions<SonarrInstanceOptions, SonarrClient>("Sonarr");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds support for Lidarr with default options and client.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to configure the service collection.</param>
|
||||
/// <returns>The configured <see cref="WebApplicationBuilder"/>.</returns>
|
||||
public static WebApplicationBuilder AddLidarrSupport(this WebApplicationBuilder builder)
|
||||
{
|
||||
return builder.AddServiceWithOptions<LidarrInstanceOptions, LidarrClient>("Lidarr");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds support for Readarr with default options and client.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to configure the service collection.</param>
|
||||
/// <returns>The configured <see cref="WebApplicationBuilder"/>.</returns>
|
||||
public static WebApplicationBuilder AddReadarrSupport(this WebApplicationBuilder builder)
|
||||
{
|
||||
return builder.AddServiceWithOptions<ReadarrInstanceOptions, ReadarrClient>("Readarr");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a title lookup service to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to configure the service collection.</param>
|
||||
/// <returns>The configured <see cref="WebApplicationBuilder"/>.</returns>
|
||||
public static WebApplicationBuilder AddTitleLookupService(this WebApplicationBuilder builder)
|
||||
{
|
||||
return builder.AddServiceWithOptions<GlobalOptions, TitleApiService>("Settings");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a proxy service to the service collection.
|
||||
/// </summary>
|
||||
/// <param name="builder">The <see cref="WebApplicationBuilder"/> to configure the service collection.</param>
|
||||
/// <returns>The configured <see cref="WebApplicationBuilder"/>.</returns>
|
||||
public static WebApplicationBuilder AddProxyService(this WebApplicationBuilder builder)
|
||||
{
|
||||
return builder.AddServiceWithOptions<GlobalOptions, ProxyService>("Settings");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -13,8 +13,51 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
// Settings__UserAgent=UmlautAdaptarr/1.0
|
||||
// Settings__UmlautAdaptarrApiHost=https://umlautadaptarr.pcjones.de/api/v1
|
||||
"Settings": {
|
||||
"UserAgent": "UmlautAdaptarr/1.0",
|
||||
"UmlautAdaptarrApiHost": "https://umlautadaptarr.pcjones.de/api/v1"
|
||||
},
|
||||
"Sonarr": {
|
||||
// Docker Environment Variables:
|
||||
// - Sonarr__Enabled: true (set to false to disable)
|
||||
// - Sonarr__Host: your_sonarr_host_url
|
||||
// - Sonarr__ApiKey: your_sonarr_api_key
|
||||
"Enabled": false,
|
||||
"Host": "your_sonarr_host_url",
|
||||
"ApiKey": "your_sonarr_api_key"
|
||||
},
|
||||
"Lidarr": {
|
||||
// Docker Environment Variables:
|
||||
// - Lidarr__Enabled: true (set to false to disable)
|
||||
// - Lidarr__Host: your_lidarr_host_url
|
||||
// - Lidarr__ApiKey: your_lidarr_api_key
|
||||
"Enabled": false,
|
||||
"Host": "your_lidarr_host_url",
|
||||
"ApiKey": "your_lidarr_api_key"
|
||||
},
|
||||
"Readarr": {
|
||||
// Docker Environment Variables:
|
||||
// - Readarr__Enabled: true (set to false to disable)
|
||||
// - Readarr__Host: your_readarr_host_url
|
||||
// - Readarr__ApiKey: your_readarr_api_key
|
||||
"Enabled": false,
|
||||
"Host": "your_readarr_host_url",
|
||||
"ApiKey": "your_readarr_api_key"
|
||||
},
|
||||
|
||||
// Docker Environment Variables:
|
||||
// - Proxy__Enabled: true (set to false to disable)
|
||||
// - Proxy__Address: http://yourproxyaddress:port
|
||||
// - Proxy__Username: your_proxy_username
|
||||
// - Proxy__Password: your_proxy_password
|
||||
// - Proxy__BypassOnLocal: true (set to false to not bypass local IP addresses)
|
||||
"Proxy": {
|
||||
"Enabled": false,
|
||||
"Address": "http://yourproxyaddress:port",
|
||||
"Username": "your_proxy_username",
|
||||
"Password": "your_proxy_password",
|
||||
"BypassOnLocal": true
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user