diff --git a/UmlautAdaptarr/Options/ArrOptions/ArrApplicationBaseOptions.cs b/UmlautAdaptarr/Options/ArrOptions/ArrApplicationBaseOptions.cs new file mode 100644 index 0000000..dc7df56 --- /dev/null +++ b/UmlautAdaptarr/Options/ArrOptions/ArrApplicationBaseOptions.cs @@ -0,0 +1,23 @@ +namespace UmlautAdaptarr.Options.ArrOptions +{ + /// + /// Base Options for ARR applications + /// + public class ArrApplicationBaseOptions + { + /// + /// Indicates whether the Arr application is enabled. + /// + public bool Enabled { get; set; } + + /// + /// The host of the ARR application. + /// + public string Host { get; set; } + + /// + /// The API key of the ARR application. + /// + public string ApiKey { get; set; } + } +} \ No newline at end of file diff --git a/UmlautAdaptarr/Options/ArrOptions/LidarrInstanceOptions.cs b/UmlautAdaptarr/Options/ArrOptions/LidarrInstanceOptions.cs new file mode 100644 index 0000000..d5c85e2 --- /dev/null +++ b/UmlautAdaptarr/Options/ArrOptions/LidarrInstanceOptions.cs @@ -0,0 +1,9 @@ +namespace UmlautAdaptarr.Options.ArrOptions +{ + /// + /// Lidarr Options + /// + public class LidarrInstanceOptions : ArrApplicationBaseOptions + { + } +} diff --git a/UmlautAdaptarr/Options/ArrOptions/ReadarrInstanceOptions.cs b/UmlautAdaptarr/Options/ArrOptions/ReadarrInstanceOptions.cs new file mode 100644 index 0000000..530e428 --- /dev/null +++ b/UmlautAdaptarr/Options/ArrOptions/ReadarrInstanceOptions.cs @@ -0,0 +1,9 @@ +namespace UmlautAdaptarr.Options.ArrOptions +{ + /// + /// Readarr Options + /// + public class ReadarrInstanceOptions : ArrApplicationBaseOptions + { + } +} diff --git a/UmlautAdaptarr/Options/ArrOptions/SonarrInstanceOptions.cs b/UmlautAdaptarr/Options/ArrOptions/SonarrInstanceOptions.cs new file mode 100644 index 0000000..cacc6c3 --- /dev/null +++ b/UmlautAdaptarr/Options/ArrOptions/SonarrInstanceOptions.cs @@ -0,0 +1,9 @@ +namespace UmlautAdaptarr.Options.ArrOptions +{ + /// + /// Sonarr Options + /// + public class SonarrInstanceOptions : ArrApplicationBaseOptions + { + } +} diff --git a/UmlautAdaptarr/Options/GlobalOptions.cs b/UmlautAdaptarr/Options/GlobalOptions.cs new file mode 100644 index 0000000..51452a5 --- /dev/null +++ b/UmlautAdaptarr/Options/GlobalOptions.cs @@ -0,0 +1,18 @@ +namespace UmlautAdaptarr.Options +{ + /// + /// Global options for the UmlautAdaptarr application. + /// + public class GlobalOptions + { + /// + /// The host of the UmlautAdaptarr API. + /// + public string UmlautAdaptarrApiHost { get; set; } + + /// + /// The User-Agent string used in HTTP requests. + /// + public string UserAgent { get; set; } + } +} \ No newline at end of file diff --git a/UmlautAdaptarr/Options/Proxy.cs b/UmlautAdaptarr/Options/Proxy.cs new file mode 100644 index 0000000..63aaec3 --- /dev/null +++ b/UmlautAdaptarr/Options/Proxy.cs @@ -0,0 +1,27 @@ +namespace UmlautAdaptarr.Options; + +/// +/// Represents options for proxy configuration. +/// +public class Proxy +{ + /// + /// Gets or sets a value indicating whether to use a proxy. + /// + public bool Enabled { get; set; } + + /// + /// Gets or sets the address of the proxy. + /// + public string? Address { get; set; } + + /// + /// Gets or sets the username for proxy authentication. + /// + public string? Username { get; set; } + + /// + /// Gets or sets the password for proxy authentication. + /// + public string? Password { get; set; } +} \ No newline at end of file diff --git a/UmlautAdaptarr/Options/ProxyOptions.cs b/UmlautAdaptarr/Options/ProxyOptions.cs new file mode 100644 index 0000000..1bea2c6 --- /dev/null +++ b/UmlautAdaptarr/Options/ProxyOptions.cs @@ -0,0 +1,32 @@ +namespace UmlautAdaptarr.Options; + +/// +/// Represents options for proxy configuration. +/// +public class ProxyOptions +{ + /// + /// Gets or sets a value indicating whether to use a proxy. + /// + public bool Enabled { get; set; } + + /// + /// Gets or sets the address of the proxy. + /// + public string? Address { get; set; } + + /// + /// Gets or sets the username for proxy authentication. + /// + public string? Username { get; set; } + + /// + /// Gets or sets the password for proxy authentication. + /// + public string? Password { get; set; } + + /// + /// Bypass Local Ip Addresses , Proxy will ignore local Ip Addresses + /// + public bool BypassOnLocal { get; set; } +} \ No newline at end of file diff --git a/UmlautAdaptarr/Program.cs b/UmlautAdaptarr/Program.cs index 5a0818e..4345904 100644 --- a/UmlautAdaptarr/Program.cs +++ b/UmlautAdaptarr/Program.cs @@ -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(); + handler.ConfigureProxy(proxyOptions); return handler; }); @@ -46,17 +50,18 @@ internal class Program builder.Services.AddControllers(); builder.Services.AddHostedService(); - builder.Services.AddSingleton(); + builder.AddTitleLookupService(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.AddSonarrSupport(); + builder.AddLidarrSupport(); + builder.AddReadarrSupport(); builder.Services.AddSingleton(); - builder.Services.AddSingleton(); + builder.AddProxyService(); var app = builder.Build(); + GlobalStaticLogger.Initialize(app.Services.GetService()!); app.UseHttpsRedirection(); app.UseAuthorization(); diff --git a/UmlautAdaptarr/Providers/LidarrClient.cs b/UmlautAdaptarr/Providers/LidarrClient.cs index de953f7..51411be 100644 --- a/UmlautAdaptarr/Providers/LidarrClient.cs +++ b/UmlautAdaptarr/Providers/LidarrClient.cs @@ -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 logger) : ArrClientBase() + ILogger logger, IOptions options) : ArrClientBase() { - private readonly string _lidarrHost = configuration.GetValue("LIDARR_HOST") ?? throw new ArgumentException("LIDARR_HOST environment variable must be set"); - private readonly string _lidarrApiKey = configuration.GetValue("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> 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>(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 diff --git a/UmlautAdaptarr/Providers/ReadarrClient.cs b/UmlautAdaptarr/Providers/ReadarrClient.cs index df60c88..608ac2c 100644 --- a/UmlautAdaptarr/Providers/ReadarrClient.cs +++ b/UmlautAdaptarr/Providers/ReadarrClient.cs @@ -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 options, ILogger logger) : ArrClientBase() { - private readonly string _readarrHost = configuration.GetValue("READARR_HOST") ?? throw new ArgumentException("READARR_HOST environment variable must be set"); - private readonly string _readarrApiKey = configuration.GetValue("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> 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>(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)}"); diff --git a/UmlautAdaptarr/Providers/SonarrClient.cs b/UmlautAdaptarr/Providers/SonarrClient.cs index 11cc622..82c218a 100644 --- a/UmlautAdaptarr/Providers/SonarrClient.cs +++ b/UmlautAdaptarr/Providers/SonarrClient.cs @@ -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 options, ILogger logger) : ArrClientBase() { - private readonly string _sonarrHost = configuration.GetValue("SONARR_HOST") ?? throw new ArgumentException("SONARR_HOST environment variable must be set"); - private readonly string _sonarrApiKey = configuration.GetValue("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("SONARR_HOST") ?? throw new ArgumentException("SONARR_HOST environment variable must be set"); + //private readonly string _sonarrApiKey = configuration.GetValue("SONARR_API_KEY") ?? throw new ArgumentException("SONARR_API_KEY environment variable must be set"); private readonly string _mediaType = "tv"; public override async Task> 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>(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(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(sonarrApiResponse); diff --git a/UmlautAdaptarr/Services/ArrSyncBackgroundService.cs b/UmlautAdaptarr/Services/ArrSyncBackgroundService.cs index bb689cf..f34714a 100644 --- a/UmlautAdaptarr/Services/ArrSyncBackgroundService.cs +++ b/UmlautAdaptarr/Services/ArrSyncBackgroundService.cs @@ -19,9 +19,6 @@ namespace UmlautAdaptarr.Services IConfiguration configuration, ILogger logger) : BackgroundService { - private readonly bool _sonarrEnabled = configuration.GetValue("SONARR_ENABLED"); - private readonly bool _lidarrEnabled = configuration.GetValue("LIDARR_ENABLED"); - private readonly bool _readarrEnabled = configuration.GetValue("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; diff --git a/UmlautAdaptarr/Services/ProxyService.cs b/UmlautAdaptarr/Services/ProxyService.cs index 6099ed4..95e9df8 100644 --- a/UmlautAdaptarr/Services/ProxyService.cs +++ b/UmlautAdaptarr/Services/ProxyService.cs @@ -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 _logger; private readonly IMemoryCache _cache; + private readonly GlobalOptions _options; private static readonly ConcurrentDictionary _lastRequestTimes = new(); private static readonly TimeSpan MINIMUM_DELAY_FOR_SAME_HOST = new(0, 0, 0, 1); - public ProxyService(IHttpClientFactory clientFactory, IConfiguration configuration, ILogger logger, IMemoryCache cache) + public ProxyService(IHttpClientFactory clientFactory, ILogger logger, IMemoryCache cache, IOptions 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) diff --git a/UmlautAdaptarr/Services/SearchItemLookupService.cs b/UmlautAdaptarr/Services/SearchItemLookupService.cs index 0cf0ef3..c70292c 100644 --- a/UmlautAdaptarr/Services/SearchItemLookupService.cs +++ b/UmlautAdaptarr/Services/SearchItemLookupService.cs @@ -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("SONARR_ENABLED"); - private readonly bool _lidarrEnabled = configuration.GetValue("LIDARR_ENABLED"); - private readonly bool _readarrEnabled = configuration.GetValue("READARR_ENABLED"); public async Task 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); } diff --git a/UmlautAdaptarr/Services/TitleApiService.cs b/UmlautAdaptarr/Services/TitleApiService.cs index c48988e..26733c2 100644 --- a/UmlautAdaptarr/Services/TitleApiService.cs +++ b/UmlautAdaptarr/Services/TitleApiService.cs @@ -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 logger) + public class TitleApiService(IHttpClientFactory clientFactory, ILogger logger, IOptions 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(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(titleApiResponse); diff --git a/UmlautAdaptarr/UmlautAdaptarr.csproj b/UmlautAdaptarr/UmlautAdaptarr.csproj index 5b1fa31..23722e0 100644 --- a/UmlautAdaptarr/UmlautAdaptarr.csproj +++ b/UmlautAdaptarr/UmlautAdaptarr.csproj @@ -9,6 +9,8 @@ + + diff --git a/UmlautAdaptarr/Utilities/GlobalStaticLogger.cs b/UmlautAdaptarr/Utilities/GlobalStaticLogger.cs new file mode 100644 index 0000000..e7fdbbe --- /dev/null +++ b/UmlautAdaptarr/Utilities/GlobalStaticLogger.cs @@ -0,0 +1,19 @@ +namespace UmlautAdaptarr.Utilities +{ + /// + /// 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. + /// + public static class GlobalStaticLogger + { + + public static ILogger Logger; + + /// + /// Initializes the GlobalStaticLogger with the provided logger factory. + /// + /// The ILoggerFactory instance used to create loggers. + public static void Initialize(ILoggerFactory loggerFactory) => Logger = loggerFactory.CreateLogger("GlobalStaticLogger"); + } +} diff --git a/UmlautAdaptarr/Utilities/ProxyExtension.cs b/UmlautAdaptarr/Utilities/ProxyExtension.cs new file mode 100644 index 0000000..6a448ba --- /dev/null +++ b/UmlautAdaptarr/Utilities/ProxyExtension.cs @@ -0,0 +1,53 @@ +using System; +using System.Net; +using UmlautAdaptarr.Options; + +namespace UmlautAdaptarr.Utilities +{ + /// + /// Extension methods for configuring proxies. + /// + public static class ProxyExtension + { + /// + /// Logger instance for logging proxy configurations. + /// + private static ILogger Logger = GlobalStaticLogger.Logger; + + /// + /// Configures the proxy settings for the provided HttpClientHandler instance. + /// + /// The HttpClientHandler instance to configure. + /// ProxyOptions options to be used for configuration. + /// The configured HttpClientHandler instance. + 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; + } + } +} \ No newline at end of file diff --git a/UmlautAdaptarr/Utilities/ServicesExtensions.cs b/UmlautAdaptarr/Utilities/ServicesExtensions.cs new file mode 100644 index 0000000..1ac3957 --- /dev/null +++ b/UmlautAdaptarr/Utilities/ServicesExtensions.cs @@ -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 +{ + /// + /// Extension methods for configuring services related to ARR Applications + /// + public static class ServicesExtensions + { + + /// + /// Adds a service with specified options and service to the service collection. + /// + /// The options type for the service. + /// The service type for the service. + /// The to configure the service collection. + /// The name of the configuration section containing service options. + /// The configured . + private static WebApplicationBuilder AddServiceWithOptions(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(); + if (options == null) + { + throw new InvalidOperationException($"{typeof(TService).Name} options could not be loaded from Configuration or ENV Variable."); + } + + builder.Services.Configure(builder.Configuration.GetSection(sectionName)); + builder.Services.AddSingleton(); + return builder; + } + + /// + /// Adds support for Sonarr with default options and client. + /// + /// The to configure the service collection. + /// The configured . + public static WebApplicationBuilder AddSonarrSupport(this WebApplicationBuilder builder) + { + return builder.AddServiceWithOptions("Sonarr"); + } + + /// + /// Adds support for Lidarr with default options and client. + /// + /// The to configure the service collection. + /// The configured . + public static WebApplicationBuilder AddLidarrSupport(this WebApplicationBuilder builder) + { + return builder.AddServiceWithOptions("Lidarr"); + } + + /// + /// Adds support for Readarr with default options and client. + /// + /// The to configure the service collection. + /// The configured . + public static WebApplicationBuilder AddReadarrSupport(this WebApplicationBuilder builder) + { + return builder.AddServiceWithOptions("Readarr"); + } + + /// + /// Adds a title lookup service to the service collection. + /// + /// The to configure the service collection. + /// The configured . + public static WebApplicationBuilder AddTitleLookupService(this WebApplicationBuilder builder) + { + return builder.AddServiceWithOptions("Settings"); + } + + /// + /// Adds a proxy service to the service collection. + /// + /// The to configure the service collection. + /// The configured . + public static WebApplicationBuilder AddProxyService(this WebApplicationBuilder builder) + { + return builder.AddServiceWithOptions("Settings"); + } + } + + +} diff --git a/UmlautAdaptarr/appsettings.json b/UmlautAdaptarr/appsettings.json index 7255729..32ae2bb 100644 --- a/UmlautAdaptarr/appsettings.json +++ b/UmlautAdaptarr/appsettings.json @@ -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 } }