BililiveRecorder/BililiveRecorder.ToolBox/ToolCommand.cs

163 lines
6.9 KiB
C#
Raw Normal View History

2021-04-14 23:46:24 +08:00
using System;
using System.CommandLine;
2022-06-07 22:41:09 +08:00
using System.CommandLine.NamingConventionBinder;
using System.CommandLine.Parsing;
using System.Linq;
2021-04-14 23:46:24 +08:00
using System.Threading.Tasks;
using BililiveRecorder.Flv.Pipeline;
2021-07-15 12:58:50 +08:00
using BililiveRecorder.ToolBox.Tool.Analyze;
2021-08-10 18:53:04 +08:00
using BililiveRecorder.ToolBox.Tool.DanmakuMerger;
2021-11-21 00:08:31 +08:00
using BililiveRecorder.ToolBox.Tool.DanmakuStartTime;
2021-07-15 12:58:50 +08:00
using BililiveRecorder.ToolBox.Tool.Export;
using BililiveRecorder.ToolBox.Tool.Fix;
2021-04-14 23:46:24 +08:00
using Newtonsoft.Json;
using Spectre.Console;
2021-04-14 23:46:24 +08:00
namespace BililiveRecorder.ToolBox
{
public class ToolCommand : Command
{
public ToolCommand() : base("tool", "Run Tools")
{
this.RegisterCommand<AnalyzeHandler, AnalyzeRequest, AnalyzeResponse>("analyze", null, c =>
{
c.Add(new Argument<string>("input", "example: input.flv"));
c.Add(new Option<ProcessingPipelineSettings?>(name: "--pipeline-settings", parseArgument: this.ParseProcessingPipelineSettings));
2021-04-14 23:46:24 +08:00
});
this.RegisterCommand<FixHandler, FixRequest, FixResponse>("fix", null, c =>
{
c.Add(new Argument<string>("input", "example: input.flv"));
c.Add(new Argument<string>("output-base", "example: output.flv"));
c.Add(new Option<ProcessingPipelineSettings?>(name: "--pipeline-settings", parseArgument: this.ParseProcessingPipelineSettings));
2021-04-14 23:46:24 +08:00
});
this.RegisterCommand<ExportHandler, ExportRequest, ExportResponse>("export", null, c =>
{
c.Add(new Argument<string>("input", "example: input.flv"));
c.Add(new Argument<string>("output", "example: output.xml or output.zip"));
2021-04-14 23:46:24 +08:00
});
2021-08-10 18:53:04 +08:00
2021-11-21 00:08:31 +08:00
this.RegisterCommand<DanmakuStartTimeHandler, DanmakuStartTimeRequest, DanmakuStartTimeResponse>("danmaku-start-time", null, c =>
{
c.Add(new Argument<string[]>("inputs", "example: 1.xml 2.xml ..."));
});
2021-08-10 18:53:04 +08:00
this.RegisterCommand<DanmakuMergerHandler, DanmakuMergerRequest, DanmakuMergerResponse>("danmaku-merge", null, c =>
{
c.Add(new Argument<string>("output", "example: output.xml"));
c.Add(new Argument<string[]>("inputs", "example: 1.xml 2.xml ..."));
2021-11-21 00:08:31 +08:00
c.Add(new Option<int[]?>("--offsets", "Use offsets provided instead of calculating from starttime attribute."));
2021-08-10 18:53:04 +08:00
});
2021-04-14 23:46:24 +08:00
}
private ProcessingPipelineSettings? ParseProcessingPipelineSettings(ArgumentResult result)
{
if (result.Tokens.Count == 0) return null;
try
{
return JsonConvert.DeserializeObject<ProcessingPipelineSettings>(result.Tokens.Single().Value);
}
catch (Exception)
{
result.ErrorMessage = "Pipeline settings must be a valid json string";
return null;
}
}
2021-04-14 23:46:24 +08:00
2021-04-19 18:20:14 +08:00
private void RegisterCommand<THandler, TRequest, TResponse>(string name, string? description, Action<Command> configure)
where THandler : ICommandHandler<TRequest, TResponse>
where TRequest : ICommandRequest<TResponse>
where TResponse : IResponseData
2021-04-14 23:46:24 +08:00
{
var cmd = new Command(name, description)
{
new Option<bool>("--json", "print result as json string"),
new Option<bool>("--json-indented", "print result as indented json string")
};
2021-04-19 18:20:14 +08:00
cmd.Handler = CommandHandler.Create((TRequest r, bool json, bool jsonIndented) => RunSubCommand<THandler, TRequest, TResponse>(r, json, jsonIndented));
2021-04-14 23:46:24 +08:00
configure(cmd);
this.Add(cmd);
}
2021-04-19 18:20:14 +08:00
private static async Task<int> RunSubCommand<THandler, TRequest, TResponse>(TRequest request, bool json, bool jsonIndented)
where THandler : ICommandHandler<TRequest, TResponse>
where TRequest : ICommandRequest<TResponse>
where TResponse : IResponseData
2021-04-14 23:46:24 +08:00
{
var isInteractive = !(json || jsonIndented);
2021-04-19 18:20:14 +08:00
var handler = Activator.CreateInstance<THandler>();
2021-04-14 23:46:24 +08:00
CommandResponse<TResponse>? response;
if (isInteractive)
2021-04-14 23:46:24 +08:00
{
response = await AnsiConsole
.Progress()
.Columns(new ProgressColumn[]
{
new TaskDescriptionColumn(),
new ProgressBarColumn(),
new PercentageColumn(),
new SpinnerColumn(Spinner.Known.Dots10),
})
.StartAsync(async ctx =>
{
var t = ctx.AddTask(handler.Name);
t.MaxValue = 1d;
2022-05-17 00:53:37 +08:00
#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously
var r = await handler.Handle(request, default, async p => t.Value = p).ConfigureAwait(false);
2022-05-17 00:53:37 +08:00
#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously
t.Value = 1d;
return r;
})
.ConfigureAwait(false);
2021-04-14 23:46:24 +08:00
}
else
{
response = await handler.Handle(request, default, null).ConfigureAwait(false);
}
if (isInteractive)
2021-04-14 23:46:24 +08:00
{
2021-04-19 18:20:14 +08:00
if (response.Status == ResponseStatus.OK)
{
response.Data?.PrintToConsole();
return 0;
2021-04-19 18:20:14 +08:00
}
else
{
2022-05-17 00:53:37 +08:00
AnsiConsole.Write(new FigletText("Error").Color(Color.Red));
var errorInfo = new Table
{
Border = TableBorder.Rounded
};
errorInfo.AddColumn(new TableColumn("Error Code").Centered());
errorInfo.AddColumn(new TableColumn("Error Message").Centered());
errorInfo.AddRow("[red]" + response.Status.ToString().EscapeMarkup() + "[/]", "[red]" + (response.ErrorMessage ?? string.Empty) + "[/]");
2022-05-17 00:53:37 +08:00
AnsiConsole.Write(errorInfo);
if (response.Exception is not null)
2022-05-17 00:53:37 +08:00
AnsiConsole.Write(new Panel(response.Exception.GetRenderable(ExceptionFormats.ShortenPaths | ExceptionFormats.ShowLinks))
{
Header = new PanelHeader("Exception Info"),
Border = BoxBorder.Rounded
});
return 1;
2021-04-19 18:20:14 +08:00
}
2021-04-14 23:46:24 +08:00
}
else
{
var json_str = JsonConvert.SerializeObject(response, jsonIndented ? Formatting.Indented : Formatting.None);
Console.WriteLine(json_str);
2021-04-14 23:46:24 +08:00
return response.Status == ResponseStatus.OK ? 0 : 1;
}
2021-04-14 23:46:24 +08:00
}
}
}