using OF_DL.Models.Downloads;
using OF_DL.Services;
using Spectre.Console;
namespace OF_DL.CLI;
///
/// Spectre.Console implementation of IDownloadEventHandler.
/// Handles all CLI-specific display logic for downloads.
///
public class SpectreDownloadEventHandler : IDownloadEventHandler
{
public CancellationToken CancellationToken { get; } = CancellationToken.None;
public async Task WithStatusAsync(string statusMessage, Func> work)
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
await AnsiConsole.Status()
.StartAsync($"[red]{Markup.Escape(statusMessage)}[/]",
async ctx =>
{
try
{
SpectreStatusReporter reporter = new(ctx);
T result = await work(reporter);
tcs.TrySetResult(result);
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return await tcs.Task;
}
public async Task WithProgressAsync(string description, long maxValue, bool showSize,
Func> work)
{
TaskCompletionSource tcs = new(TaskCreationOptions.RunContinuationsAsynchronously);
await AnsiConsole.Progress()
.Columns(GetProgressColumns(showSize))
.StartAsync(async ctx =>
{
try
{
ProgressTask task = ctx.AddTask($"[red]{Markup.Escape(description)}[/]", false);
task.MaxValue = maxValue;
task.StartTask();
SpectreProgressReporter progressReporter = new(task);
T result = await work(progressReporter);
tcs.TrySetResult(result);
task.StopTask();
}
catch (Exception ex)
{
tcs.TrySetException(ex);
}
});
return await tcs.Task;
}
public void OnContentFound(string contentType, int mediaCount, int objectCount) =>
AnsiConsole.Markup($"[red]Found {mediaCount} Media from {objectCount} {Markup.Escape(contentType)}\n[/]");
public void OnNoContentFound(string contentType) =>
AnsiConsole.Markup($"[red]Found 0 {Markup.Escape(contentType)}\n[/]");
public void OnDownloadComplete(string contentType, DownloadResult result) =>
AnsiConsole.Markup(
$"[red]{Markup.Escape(contentType)} Media Already Downloaded: {result.ExistingDownloads} New {Markup.Escape(contentType)} Media Downloaded: {result.NewDownloads}[/]\n");
public void OnUserStarting(string username) =>
AnsiConsole.Markup($"[red]\nScraping Data for {Markup.Escape(username)}\n[/]");
public void OnUserComplete(string username, CreatorDownloadResult result)
{
AnsiConsole.Markup("\n");
AnsiConsole.Write(new BreakdownChart()
.FullSize()
.AddItem("Paid Posts", result.PaidPostCount, Color.Red)
.AddItem("Posts", result.PostCount, Color.Blue)
.AddItem("Archived", result.ArchivedCount, Color.Green)
.AddItem("Streams", result.StreamsCount, Color.Purple)
.AddItem("Stories", result.StoriesCount, Color.Yellow)
.AddItem("Highlights", result.HighlightsCount, Color.Orange1)
.AddItem("Messages", result.MessagesCount, Color.LightGreen)
.AddItem("Paid Messages", result.PaidMessagesCount, Color.Aqua));
AnsiConsole.Markup("\n");
}
public void OnPurchasedTabUserComplete(string username, int paidPostCount, int paidMessagesCount)
{
AnsiConsole.Markup("\n");
AnsiConsole.Write(new BreakdownChart()
.FullSize()
.AddItem("Paid Posts", paidPostCount, Color.Red)
.AddItem("Paid Messages", paidMessagesCount, Color.Aqua));
AnsiConsole.Markup("\n");
}
public void OnScrapeComplete(TimeSpan elapsed) =>
AnsiConsole.Markup($"[green]Scrape Completed in {elapsed.TotalMinutes:0.00} minutes\n[/]");
public void OnMessage(string message) => AnsiConsole.Markup($"[red]{Markup.Escape(message)}\n[/]");
private static ProgressColumn[] GetProgressColumns(bool showScrapeSize)
{
List progressColumns;
if (showScrapeSize)
{
progressColumns =
[
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new DownloadedColumn(),
new RemainingTimeColumn()
];
}
else
{
progressColumns =
[
new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn()
];
}
return progressColumns.ToArray();
}
}