parent
5bcd1122e9
commit
e92e0c8e68
@ -1,20 +1,16 @@
|
||||
using Recyclarr.Cli.Pipelines.CustomFormat.Cache;
|
||||
using Recyclarr.Cli.Pipelines.CustomFormat.Models;
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.TrashGuide;
|
||||
using Recyclarr.TrashGuide.CustomFormat;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.CustomFormat;
|
||||
|
||||
public class CustomFormatPipelineContext : IPipelineContext
|
||||
internal class CustomFormatPipelineContext : PipelineContext
|
||||
{
|
||||
public string PipelineDescription => "Custom Format";
|
||||
public IReadOnlyCollection<SupportedServices> SupportedServiceTypes { get; } =
|
||||
[SupportedServices.Sonarr, SupportedServices.Radarr];
|
||||
public override string PipelineDescription => "Custom Format";
|
||||
|
||||
public IList<CustomFormatData> ConfigOutput { get; init; } = [];
|
||||
public IList<CustomFormatData> ApiFetchOutput { get; init; } = [];
|
||||
public CustomFormatTransactionData TransactionOutput { get; set; } = default!;
|
||||
public IReadOnlyCollection<string> InvalidFormats { get; set; } = default!;
|
||||
public CustomFormatCache Cache { get; set; } = default!;
|
||||
public CustomFormatTransactionData TransactionOutput { get; set; } = null!;
|
||||
public IReadOnlyCollection<string> InvalidFormats { get; set; } = null!;
|
||||
public CustomFormatCache Cache { get; set; } = null!;
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Common.Extensions;
|
||||
using Recyclarr.ServarrApi.CustomFormat;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
|
||||
|
||||
public class CustomFormatApiFetchPhase(ICustomFormatApiService api)
|
||||
: IApiFetchPipelinePhase<CustomFormatPipelineContext>
|
||||
internal class CustomFormatApiFetchPhase(ICustomFormatApiService api)
|
||||
: IPipelinePhase<CustomFormatPipelineContext>
|
||||
{
|
||||
public async Task Execute(CustomFormatPipelineContext context, CancellationToken ct)
|
||||
public async Task<bool> Execute(CustomFormatPipelineContext context, CancellationToken ct)
|
||||
{
|
||||
var result = await api.GetCustomFormats(ct);
|
||||
context.ApiFetchOutput.AddRange(result);
|
||||
context.Cache.RemoveStale(result);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,29 +0,0 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.CustomFormat.PipelinePhases;
|
||||
|
||||
internal class CustomFormatLogPhase(CustomFormatTransactionLogger cfLogger, ILogger log)
|
||||
: ILogPipelinePhase<CustomFormatPipelineContext>
|
||||
{
|
||||
// Returning 'true' means to exit. 'false' means to proceed.
|
||||
public bool LogConfigPhaseAndExitIfNeeded(CustomFormatPipelineContext context)
|
||||
{
|
||||
if (context.InvalidFormats.Count != 0)
|
||||
{
|
||||
log.Warning(
|
||||
"These Custom Formats do not exist in the guide and will be skipped: {Cfs}",
|
||||
context.InvalidFormats
|
||||
);
|
||||
}
|
||||
|
||||
// Do not exit when the config has zero custom formats. We still may need to delete old custom formats.
|
||||
return false;
|
||||
}
|
||||
|
||||
public void LogTransactionNotices(CustomFormatPipelineContext context) { }
|
||||
|
||||
public void LogPersistenceResults(CustomFormatPipelineContext context)
|
||||
{
|
||||
cfLogger.LogTransactions(context);
|
||||
}
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
[UsedImplicitly(ImplicitUseKindFlags.Assign, ImplicitUseTargetFlags.Members)]
|
||||
public class GenericPipelinePhases<TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
public required IConfigPipelinePhase<TContext> ConfigPhase { get; init; }
|
||||
public required ILogPipelinePhase<TContext> LogPhase { get; init; }
|
||||
public required IApiFetchPipelinePhase<TContext> ApiFetchPhase { get; init; }
|
||||
public required ITransactionPipelinePhase<TContext> TransactionPhase { get; init; }
|
||||
public required IPreviewPipelinePhase<TContext> PreviewPhase { get; init; }
|
||||
public required IApiPersistencePipelinePhase<TContext> ApiPersistencePhase { get; init; }
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
using Recyclarr.Cli.Console.Settings;
|
||||
using Recyclarr.Config.Models;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public class GenericSyncPipeline<TContext>(
|
||||
ILogger log,
|
||||
GenericPipelinePhases<TContext> phases,
|
||||
IServiceConfiguration config
|
||||
) : ISyncPipeline
|
||||
where TContext : IPipelineContext, new()
|
||||
{
|
||||
public async Task Execute(ISyncSettings settings, CancellationToken ct)
|
||||
{
|
||||
var context = new TContext();
|
||||
|
||||
log.Debug("Executing Pipeline: {Pipeline}", context.PipelineDescription);
|
||||
|
||||
if (!context.SupportedServiceTypes.Contains(config.ServiceType))
|
||||
{
|
||||
log.Debug(
|
||||
"Skipping this pipeline because it does not support service type {Service}",
|
||||
config.ServiceType
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await phases.ConfigPhase.Execute(context, ct);
|
||||
if (phases.LogPhase.LogConfigPhaseAndExitIfNeeded(context))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await phases.ApiFetchPhase.Execute(context, ct);
|
||||
phases.TransactionPhase.Execute(context);
|
||||
|
||||
phases.LogPhase.LogTransactionNotices(context);
|
||||
|
||||
if (settings.Preview)
|
||||
{
|
||||
phases.PreviewPhase.Execute(context);
|
||||
return;
|
||||
}
|
||||
|
||||
await phases.ApiPersistencePhase.Execute(context, ct);
|
||||
phases.LogPhase.LogPersistenceResults(context);
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface IApiFetchPipelinePhase<in TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
Task Execute(TContext context, CancellationToken ct);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface IApiPersistencePipelinePhase<in TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
Task Execute(TContext context, CancellationToken ct);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface IConfigPipelinePhase<in TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
Task Execute(TContext context, CancellationToken ct);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface ILogPipelinePhase<in TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
bool LogConfigPhaseAndExitIfNeeded(TContext context);
|
||||
void LogTransactionNotices(TContext context);
|
||||
void LogPersistenceResults(TContext context);
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using Recyclarr.TrashGuide;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface IPipelineContext
|
||||
{
|
||||
string PipelineDescription { get; }
|
||||
IReadOnlyCollection<SupportedServices> SupportedServiceTypes { get; }
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface IPreviewPipelinePhase<in TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
void Execute(TContext context);
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
namespace Recyclarr.Cli.Pipelines.Generic;
|
||||
|
||||
public interface ITransactionPipelinePhase<in TContext>
|
||||
where TContext : IPipelineContext
|
||||
{
|
||||
void Execute(TContext context);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
using Recyclarr.Cli.Console.Settings;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines;
|
||||
|
||||
internal class GenericSyncPipeline<TContext>(
|
||||
ILogger log,
|
||||
IReadOnlyCollection<IPipelinePhase<TContext>> phases
|
||||
) : ISyncPipeline
|
||||
where TContext : PipelineContext, new()
|
||||
{
|
||||
public async Task Execute(ISyncSettings settings, CancellationToken ct)
|
||||
{
|
||||
var context = new TContext { SyncSettings = settings };
|
||||
|
||||
log.Debug("Executing Pipeline: {Pipeline}", context.PipelineDescription);
|
||||
|
||||
foreach (var phase in phases)
|
||||
{
|
||||
if (!await phase.Execute(context, ct))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
namespace Recyclarr.Cli.Pipelines;
|
||||
|
||||
internal interface IPipelinePhase<in TContext>
|
||||
{
|
||||
Task<bool> Execute(TContext context, CancellationToken ct);
|
||||
}
|
@ -1,17 +1,13 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
using Recyclarr.TrashGuide;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming;
|
||||
|
||||
public class MediaNamingPipelineContext : IPipelineContext
|
||||
internal class MediaNamingPipelineContext : PipelineContext
|
||||
{
|
||||
public string PipelineDescription => "Media Naming";
|
||||
public IReadOnlyCollection<SupportedServices> SupportedServiceTypes { get; } =
|
||||
[SupportedServices.Sonarr, SupportedServices.Radarr];
|
||||
public override string PipelineDescription => "Media Naming";
|
||||
|
||||
public ProcessedNamingConfig ConfigOutput { get; set; } = default!;
|
||||
public MediaNamingDto ApiFetchOutput { get; set; } = default!;
|
||||
public MediaNamingDto TransactionOutput { get; set; } = default!;
|
||||
public ProcessedNamingConfig ConfigOutput { get; set; } = null!;
|
||||
public MediaNamingDto ApiFetchOutput { get; set; } = null!;
|
||||
public MediaNamingDto TransactionOutput { get; set; } = null!;
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
|
||||
public class MediaNamingApiFetchPhase(IMediaNamingApiService api)
|
||||
: IApiFetchPipelinePhase<MediaNamingPipelineContext>
|
||||
internal class MediaNamingApiFetchPhase(IMediaNamingApiService api)
|
||||
: IPipelinePhase<MediaNamingPipelineContext>
|
||||
{
|
||||
public async Task Execute(MediaNamingPipelineContext context, CancellationToken ct)
|
||||
public async Task<bool> Execute(MediaNamingPipelineContext context, CancellationToken ct)
|
||||
{
|
||||
context.ApiFetchOutput = await api.GetNaming(ct);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,41 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Notifications;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
|
||||
public class MediaNamingApiPersistencePhase(IMediaNamingApiService api)
|
||||
: IApiPersistencePipelinePhase<MediaNamingPipelineContext>
|
||||
internal class MediaNamingApiPersistencePhase(
|
||||
ILogger log,
|
||||
IMediaNamingApiService api,
|
||||
NotificationEmitter notificationEmitter
|
||||
) : IPipelinePhase<MediaNamingPipelineContext>
|
||||
{
|
||||
public async Task Execute(MediaNamingPipelineContext context, CancellationToken ct)
|
||||
public async Task<bool> Execute(MediaNamingPipelineContext context, CancellationToken ct)
|
||||
{
|
||||
await api.UpdateNaming(context.TransactionOutput, ct);
|
||||
LogPersistenceResults(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void LogPersistenceResults(MediaNamingPipelineContext context)
|
||||
{
|
||||
var differences = context.ApiFetchOutput switch
|
||||
{
|
||||
RadarrMediaNamingDto x => x.GetDifferences(context.TransactionOutput),
|
||||
SonarrMediaNamingDto x => x.GetDifferences(context.TransactionOutput),
|
||||
_ => throw new ArgumentException(
|
||||
"Unsupported configuration type in LogPersistenceResults method"
|
||||
),
|
||||
};
|
||||
|
||||
if (differences.Count != 0)
|
||||
{
|
||||
log.Information("Media naming has been updated");
|
||||
log.Debug("Naming differences: {Diff}", differences);
|
||||
notificationEmitter.SendStatistic("Media Naming Synced");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Information("Media naming is up to date!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,71 +0,0 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Notifications;
|
||||
using Recyclarr.ServarrApi.MediaNaming;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.MediaNaming.PipelinePhases;
|
||||
|
||||
public class MediaNamingLogPhase(ILogger log, NotificationEmitter notificationEmitter)
|
||||
: ILogPipelinePhase<MediaNamingPipelineContext>
|
||||
{
|
||||
// Returning 'true' means to exit. 'false' means to proceed.
|
||||
public bool LogConfigPhaseAndExitIfNeeded(MediaNamingPipelineContext context)
|
||||
{
|
||||
var config = context.ConfigOutput;
|
||||
|
||||
if (config.InvalidNaming.Count != 0)
|
||||
{
|
||||
foreach (var (topic, invalidValue) in config.InvalidNaming)
|
||||
{
|
||||
log.Error(
|
||||
"An invalid media naming format is specified for {Topic}: {Value}",
|
||||
topic,
|
||||
invalidValue
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
var differences = config.Dto switch
|
||||
{
|
||||
RadarrMediaNamingDto x => x.GetDifferences(new RadarrMediaNamingDto()),
|
||||
SonarrMediaNamingDto x => x.GetDifferences(new SonarrMediaNamingDto()),
|
||||
_ => throw new ArgumentException(
|
||||
"Unsupported configuration type in LogConfigPhase method"
|
||||
),
|
||||
};
|
||||
|
||||
if (differences.Count == 0)
|
||||
{
|
||||
log.Debug("No media naming changes to process");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void LogTransactionNotices(MediaNamingPipelineContext context) { }
|
||||
|
||||
public void LogPersistenceResults(MediaNamingPipelineContext context)
|
||||
{
|
||||
var differences = context.ApiFetchOutput switch
|
||||
{
|
||||
RadarrMediaNamingDto x => x.GetDifferences(context.TransactionOutput),
|
||||
SonarrMediaNamingDto x => x.GetDifferences(context.TransactionOutput),
|
||||
_ => throw new ArgumentException(
|
||||
"Unsupported configuration type in LogPersistenceResults method"
|
||||
),
|
||||
};
|
||||
|
||||
if (differences.Count != 0)
|
||||
{
|
||||
log.Information("Media naming has been updated");
|
||||
log.Debug("Naming differences: {Diff}", differences);
|
||||
notificationEmitter.SendStatistic("Media Naming Synced");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Information("Media naming is up to date!");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Recyclarr.Cli.Console.Settings;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines;
|
||||
|
||||
internal abstract class PipelineContext
|
||||
{
|
||||
public abstract string PipelineDescription { get; }
|
||||
|
||||
// Set from `GenericSyncPipeline.Execute()`. Not able to make this `required` because of the
|
||||
// `new()` constraint.
|
||||
public ISyncSettings SyncSettings { get; init; } = null!;
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
namespace Recyclarr.Cli.Pipelines;
|
||||
|
||||
internal abstract class PreviewPipelinePhase<T> : IPipelinePhase<T>
|
||||
where T : PipelineContext
|
||||
{
|
||||
public Task<bool> Execute(T context, CancellationToken ct)
|
||||
{
|
||||
if (!context.SyncSettings.Preview)
|
||||
{
|
||||
return Task.FromResult(true);
|
||||
}
|
||||
|
||||
RenderPreview(context);
|
||||
return Task.FromResult(false);
|
||||
}
|
||||
|
||||
protected abstract void RenderPreview(T context);
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
using Recyclarr.ServarrApi.QualityProfile;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualityProfile.Models;
|
||||
|
||||
public record QualityProfileServiceData(
|
||||
IReadOnlyList<QualityProfileDto> Profiles,
|
||||
QualityProfileDto Schema
|
||||
);
|
@ -1,20 +1,16 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Cli.Pipelines.QualityProfile.Models;
|
||||
using Recyclarr.ServarrApi.QualityProfile;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
|
||||
|
||||
public record QualityProfileServiceData(
|
||||
IReadOnlyList<QualityProfileDto> Profiles,
|
||||
QualityProfileDto Schema
|
||||
);
|
||||
|
||||
public class QualityProfileApiFetchPhase(IQualityProfileApiService api)
|
||||
: IApiFetchPipelinePhase<QualityProfilePipelineContext>
|
||||
internal class QualityProfileApiFetchPhase(IQualityProfileApiService api)
|
||||
: IPipelinePhase<QualityProfilePipelineContext>
|
||||
{
|
||||
public async Task Execute(QualityProfilePipelineContext context, CancellationToken ct)
|
||||
public async Task<bool> Execute(QualityProfilePipelineContext context, CancellationToken ct)
|
||||
{
|
||||
var profiles = await api.GetQualityProfiles(ct);
|
||||
var schema = await api.GetSchema(ct);
|
||||
context.ApiFetchOutput = new QualityProfileServiceData(profiles.AsReadOnly(), schema);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,15 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Cli.Pipelines.QualityProfile.Models;
|
||||
using Recyclarr.Common.FluentValidation;
|
||||
using Recyclarr.Notifications;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
|
||||
namespace Recyclarr.Cli.Pipelines.QualityProfile;
|
||||
|
||||
public class QualityProfileLogPhase(
|
||||
internal class QualityProfileLogger(
|
||||
ILogger log,
|
||||
ValidationLogger validationLogger,
|
||||
NotificationEmitter notificationEmitter
|
||||
) : ILogPipelinePhase<QualityProfilePipelineContext>
|
||||
)
|
||||
{
|
||||
public bool LogConfigPhaseAndExitIfNeeded(QualityProfilePipelineContext context)
|
||||
{
|
||||
if (!context.ConfigOutput.Any())
|
||||
{
|
||||
log.Debug("No Quality Profiles to process");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void LogTransactionNotices(QualityProfilePipelineContext context)
|
||||
{
|
||||
var transactions = context.TransactionOutput;
|
@ -1,23 +1,12 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Cli.Pipelines.QualityProfile.Models;
|
||||
using Recyclarr.Cli.Pipelines.QualityProfile.PipelinePhases;
|
||||
using Recyclarr.TrashGuide;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualityProfile;
|
||||
|
||||
[SuppressMessage(
|
||||
"Usage",
|
||||
"CA2227:Collection properties should be read only",
|
||||
Justification = "Context objects are similar to DTOs; for usability we want to assign not append"
|
||||
)]
|
||||
public class QualityProfilePipelineContext : IPipelineContext
|
||||
internal class QualityProfilePipelineContext : PipelineContext
|
||||
{
|
||||
public string PipelineDescription => "Quality Definition";
|
||||
public IReadOnlyCollection<SupportedServices> SupportedServiceTypes { get; } =
|
||||
[SupportedServices.Sonarr, SupportedServices.Radarr];
|
||||
public override string PipelineDescription => "Quality Profile";
|
||||
|
||||
public IList<ProcessedQualityProfileData> ConfigOutput { get; set; } = default!;
|
||||
public QualityProfileServiceData ApiFetchOutput { get; set; } = default!;
|
||||
public QualityProfileTransactionData TransactionOutput { get; set; } = default!;
|
||||
public IList<ProcessedQualityProfileData> ConfigOutput { get; set; } = null!;
|
||||
public QualityProfileServiceData ApiFetchOutput { get; set; } = null!;
|
||||
public QualityProfileTransactionData TransactionOutput { get; set; } = null!;
|
||||
}
|
||||
|
@ -1,8 +0,0 @@
|
||||
using Recyclarr.TrashGuide.QualitySize;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualitySize.Models;
|
||||
|
||||
public record ProcessedQualitySizeData(
|
||||
string Type,
|
||||
IReadOnlyCollection<QualityItemWithLimits> Qualities
|
||||
);
|
@ -1,13 +1,13 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.ServarrApi.QualityDefinition;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualitySize.PipelinePhases;
|
||||
|
||||
public class QualitySizeApiFetchPhase(IQualityDefinitionApiService api)
|
||||
: IApiFetchPipelinePhase<QualitySizePipelineContext>
|
||||
internal class QualitySizeApiFetchPhase(IQualityDefinitionApiService api)
|
||||
: IPipelinePhase<QualitySizePipelineContext>
|
||||
{
|
||||
public async Task Execute(QualitySizePipelineContext context, CancellationToken ct)
|
||||
public async Task<bool> Execute(QualitySizePipelineContext context, CancellationToken ct)
|
||||
{
|
||||
context.ApiFetchOutput = await api.GetQualityDefinition(ct);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,48 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Notifications;
|
||||
using Recyclarr.ServarrApi.QualityDefinition;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualitySize.PipelinePhases;
|
||||
|
||||
public class QualitySizeApiPersistencePhase(ILogger log, IQualityDefinitionApiService api)
|
||||
: IApiPersistencePipelinePhase<QualitySizePipelineContext>
|
||||
internal class QualitySizeApiPersistencePhase(
|
||||
ILogger log,
|
||||
IQualityDefinitionApiService api,
|
||||
NotificationEmitter notificationEmitter
|
||||
) : IPipelinePhase<QualitySizePipelineContext>
|
||||
{
|
||||
public async Task Execute(QualitySizePipelineContext context, CancellationToken ct)
|
||||
public async Task<bool> Execute(QualitySizePipelineContext context, CancellationToken ct)
|
||||
{
|
||||
var sizeData = context.TransactionOutput;
|
||||
if (sizeData.Count == 0)
|
||||
{
|
||||
log.Debug("No size data available to persist; skipping API call");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
await api.UpdateQualityDefinition(sizeData, ct);
|
||||
LogPersistenceResults(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void LogPersistenceResults(QualitySizePipelineContext context)
|
||||
{
|
||||
var qualityDefinitionName = context.QualitySizeType;
|
||||
|
||||
var totalCount = context.TransactionOutput.Count;
|
||||
if (totalCount > 0)
|
||||
{
|
||||
log.Information(
|
||||
"Total of {Count} sizes were synced for quality definition {Name}",
|
||||
totalCount,
|
||||
qualityDefinitionName
|
||||
);
|
||||
notificationEmitter.SendStatistic("Quality Sizes Synced", totalCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Information(
|
||||
"All sizes for quality definition {Name} are already up to date!",
|
||||
qualityDefinitionName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,51 +0,0 @@
|
||||
using Recyclarr.Cli.Pipelines.Generic;
|
||||
using Recyclarr.Notifications;
|
||||
|
||||
namespace Recyclarr.Cli.Pipelines.QualitySize.PipelinePhases;
|
||||
|
||||
public class QualitySizeLogPhase(ILogger log, NotificationEmitter notificationEmitter)
|
||||
: ILogPipelinePhase<QualitySizePipelineContext>
|
||||
{
|
||||
public bool LogConfigPhaseAndExitIfNeeded(QualitySizePipelineContext context)
|
||||
{
|
||||
if (context.ConfigError is not null)
|
||||
{
|
||||
log.Error(context.ConfigError);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (context.ConfigOutput is not { Qualities.Count: > 0 })
|
||||
{
|
||||
log.Debug("No Quality Definitions to process");
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void LogTransactionNotices(QualitySizePipelineContext context) { }
|
||||
|
||||
public void LogPersistenceResults(QualitySizePipelineContext context)
|
||||
{
|
||||
// Do not check ConfigOutput for null here since that is done for us in the LogConfigPhase method
|
||||
var qualityDefinitionName = context.ConfigOutput!.Type;
|
||||
|
||||
var totalCount = context.TransactionOutput.Count;
|
||||
if (totalCount > 0)
|
||||
{
|
||||
log.Information(
|
||||
"Total of {Count} sizes were synced for quality definition {Name}",
|
||||
totalCount,
|
||||
qualityDefinitionName
|
||||
);
|
||||
notificationEmitter.SendStatistic("Quality Sizes Synced", totalCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Information(
|
||||
"All sizes for quality definition {Name} are already up to date!",
|
||||
qualityDefinitionName
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue