using Common.Configuration.Arr; using Common.Configuration.DownloadClient; using Domain.Enums; using Domain.Models.Arr; using Domain.Models.Arr.Queue; using Infrastructure.Verticals.Arr; using Infrastructure.Verticals.DownloadClient; using Infrastructure.Verticals.DownloadRemover.Models; using Infrastructure.Verticals.Notifications; using MassTransit; using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Infrastructure.Verticals.Jobs; public abstract class GenericHandler : IHandler, IDisposable { protected readonly ILogger _logger; protected readonly DownloadClientConfig _downloadClientConfig; protected readonly SonarrConfig _sonarrConfig; protected readonly RadarrConfig _radarrConfig; protected readonly LidarrConfig _lidarrConfig; protected readonly IMemoryCache _cache; protected readonly IBus _messageBus; protected readonly ArrClientFactory _arrClientFactory; protected readonly ArrQueueIterator _arrArrQueueIterator; protected readonly IDownloadService _downloadService; protected readonly INotificationPublisher _notifier; protected GenericHandler( ILogger logger, IOptions downloadClientConfig, IOptions sonarrConfig, IOptions radarrConfig, IOptions lidarrConfig, IMemoryCache cache, IBus messageBus, ArrClientFactory arrClientFactory, ArrQueueIterator arrArrQueueIterator, DownloadServiceFactory downloadServiceFactory, INotificationPublisher notifier ) { _logger = logger; _downloadClientConfig = downloadClientConfig.Value; _sonarrConfig = sonarrConfig.Value; _radarrConfig = radarrConfig.Value; _lidarrConfig = lidarrConfig.Value; _cache = cache; _messageBus = messageBus; _arrClientFactory = arrClientFactory; _arrArrQueueIterator = arrArrQueueIterator; _downloadService = downloadServiceFactory.CreateDownloadClient(); _notifier = notifier; } public virtual async Task ExecuteAsync() { await _downloadService.LoginAsync(); await ProcessArrConfigAsync(_sonarrConfig, InstanceType.Sonarr); await ProcessArrConfigAsync(_radarrConfig, InstanceType.Radarr); await ProcessArrConfigAsync(_lidarrConfig, InstanceType.Lidarr); } public virtual void Dispose() { _downloadService.Dispose(); } protected abstract Task ProcessInstanceAsync(ArrInstance instance, InstanceType instanceType, ArrConfig config); protected async Task ProcessArrConfigAsync(ArrConfig config, InstanceType instanceType, bool throwOnFailure = false) { if (!config.Enabled) { return; } foreach (ArrInstance arrInstance in config.Instances) { try { await ProcessInstanceAsync(arrInstance, instanceType, config); } catch (Exception exception) { _logger.LogError(exception, "failed to clean {type} instance | {url}", instanceType, arrInstance.Url); if (throwOnFailure) { throw; } } } } protected async Task PublishQueueItemRemoveRequest( string downloadRemovalKey, InstanceType instanceType, ArrInstance instance, QueueRecord record, bool isPack, bool removeFromClient, DeleteReason deleteReason ) { if (instanceType is InstanceType.Sonarr) { QueueItemRemoveRequest removeRequest = new() { InstanceType = instanceType, Instance = instance, Record = record, SearchItem = (SonarrSearchItem)GetRecordSearchItem(instanceType, record, isPack), RemoveFromClient = removeFromClient, DeleteReason = deleteReason }; await _messageBus.Publish(removeRequest); } else { QueueItemRemoveRequest removeRequest = new() { InstanceType = instanceType, Instance = instance, Record = record, SearchItem = GetRecordSearchItem(instanceType, record, isPack), RemoveFromClient = removeFromClient, DeleteReason = deleteReason }; await _messageBus.Publish(removeRequest); } _cache.Set(downloadRemovalKey, true); _logger.LogInformation("item marked for removal | {title} | {url}", record.Title, instance.Url); } protected SearchItem GetRecordSearchItem(InstanceType type, QueueRecord record, bool isPack = false) { return type switch { InstanceType.Sonarr when _sonarrConfig.SearchType is SonarrSearchType.Episode && !isPack => new SonarrSearchItem { Id = record.EpisodeId, SeriesId = record.SeriesId, SearchType = SonarrSearchType.Episode }, InstanceType.Sonarr when _sonarrConfig.SearchType is SonarrSearchType.Episode && isPack => new SonarrSearchItem { Id = record.SeasonNumber, SeriesId = record.SeriesId, SearchType = SonarrSearchType.Season }, InstanceType.Sonarr when _sonarrConfig.SearchType is SonarrSearchType.Season => new SonarrSearchItem { Id = record.SeasonNumber, SeriesId = record.SeriesId, SearchType = SonarrSearchType.Series }, InstanceType.Sonarr when _sonarrConfig.SearchType is SonarrSearchType.Series => new SonarrSearchItem { Id = record.SeriesId }, InstanceType.Radarr => new SearchItem { Id = record.MovieId }, InstanceType.Lidarr => new SearchItem { Id = record.AlbumId }, _ => throw new NotImplementedException($"instance type {type} is not yet supported") }; } }