在非ansi环境强制显示进度条等信息 (#327)
* 添加自定义Console,可强制以ansi模式输出 * 添加 `--force-ansi-console` 以在非ansi环境显示进度信息 * 添加用于移除ANSI颜色的 `--noansi` * 只去除颜色和指针移动 * 使用系统默认输出编码 * 不重复输出,修复错误的正则替换,补充一个过滤 * 移除在NoAnsi环境下的无用输出 * force console width to max * add escape sequence `\e[?25h` * remove spinner for HTTPLiveRecordManager.cs and SimpleDownloadManager.cs when `--noansi` * camelCase * rename variable * auto enable `--no-ansi` and `--force-ansi-console` when out/err redirected * avoid null reference * format code and clean up * capitalize word `ANSI` --------- Co-authored-by: RikaCelery <celeryfx@outlook.com>
This commit is contained in:
parent
5f131f13af
commit
1905f0503f
|
@ -0,0 +1,92 @@
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using Spectre.Console;
|
||||||
|
|
||||||
|
namespace N_m3u8DL_RE.Common.Log;
|
||||||
|
|
||||||
|
public class NonAnsiWriter : TextWriter
|
||||||
|
{
|
||||||
|
public override Encoding Encoding => Console.OutputEncoding;
|
||||||
|
|
||||||
|
private string lastOut = "";
|
||||||
|
|
||||||
|
public override void Write(char value)
|
||||||
|
{
|
||||||
|
Console.Write(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(string value)
|
||||||
|
{
|
||||||
|
if (lastOut == value)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lastOut = value;
|
||||||
|
RemoveAnsiEscapeSequences(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveAnsiEscapeSequences(string input)
|
||||||
|
{
|
||||||
|
// Use regular expression to remove ANSI escape sequences
|
||||||
|
string output = Regex.Replace(input, @"\x1B\[(\d+;?)+m", "");
|
||||||
|
output = Regex.Replace(output, @"\[\??\d+[AKlh]", "");
|
||||||
|
output = Regex.Replace(output,"[\r\n] +","");
|
||||||
|
if (string.IsNullOrWhiteSpace(output))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Console.Write(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A console capable of writing ANSI escape sequences.
|
||||||
|
/// </summary>
|
||||||
|
public static class CustomAnsiConsole
|
||||||
|
{
|
||||||
|
public static IAnsiConsole Console { get; set; } = AnsiConsole.Console;
|
||||||
|
|
||||||
|
public static void InitConsole(bool forceAnsi, bool noAnsiColor)
|
||||||
|
{
|
||||||
|
if (forceAnsi)
|
||||||
|
{
|
||||||
|
var ansiConsoleSettings = new AnsiConsoleSettings();
|
||||||
|
if (noAnsiColor)
|
||||||
|
{
|
||||||
|
ansiConsoleSettings.Out = new AnsiConsoleOutput(new NonAnsiWriter());
|
||||||
|
}
|
||||||
|
|
||||||
|
ansiConsoleSettings.Interactive = InteractionSupport.Yes;
|
||||||
|
ansiConsoleSettings.Ansi = AnsiSupport.Yes;
|
||||||
|
Console = AnsiConsole.Create(ansiConsoleSettings);
|
||||||
|
Console.Profile.Width = int.MaxValue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var ansiConsoleSettings = new AnsiConsoleSettings();
|
||||||
|
if (noAnsiColor)
|
||||||
|
{
|
||||||
|
ansiConsoleSettings.Out = new AnsiConsoleOutput(new NonAnsiWriter());
|
||||||
|
}
|
||||||
|
Console = AnsiConsole.Create(ansiConsoleSettings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the specified markup to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write.</param>
|
||||||
|
public static void Markup(string value)
|
||||||
|
{
|
||||||
|
Console.Markup(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes the specified markup, followed by the current line terminator, to the console.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The value to write.</param>
|
||||||
|
public static void MarkupLine(string value)
|
||||||
|
{
|
||||||
|
Console.MarkupLine(value);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,11 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var logDir = Path.GetDirectoryName(Environment.ProcessPath) + "/Logs";
|
var logDir = Path.GetDirectoryName(Environment.ProcessPath) + "/Logs";
|
||||||
if (!Directory.Exists(logDir)) { Directory.CreateDirectory(logDir); }
|
if (!Directory.Exists(logDir))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(logDir);
|
||||||
|
}
|
||||||
|
|
||||||
LogFilePath = Path.Combine(logDir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff") + ".log");
|
LogFilePath = Path.Combine(logDir, DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff") + ".log");
|
||||||
//若文件存在则加序号
|
//若文件存在则加序号
|
||||||
int index = 1;
|
int index = 1;
|
||||||
|
@ -49,11 +53,12 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
{
|
{
|
||||||
LogFilePath = Path.Combine(Path.GetDirectoryName(LogFilePath)!, $"{fileName}-{index++}.log");
|
LogFilePath = Path.Combine(Path.GetDirectoryName(LogFilePath)!, $"{fileName}-{index++}.log");
|
||||||
}
|
}
|
||||||
|
|
||||||
string now = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
string now = DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss");
|
||||||
string init = "LOG " + DateTime.Now.ToString("yyyy/MM/dd") + Environment.NewLine
|
string init = "LOG " + DateTime.Now.ToString("yyyy/MM/dd") + Environment.NewLine
|
||||||
+ "Save Path: " + Path.GetDirectoryName(LogFilePath) + Environment.NewLine
|
+ "Save Path: " + Path.GetDirectoryName(LogFilePath) + Environment.NewLine
|
||||||
+ "Task Start: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + Environment.NewLine
|
+ "Task Start: " + DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss") + Environment.NewLine
|
||||||
+ "Task CommandLine: " + Environment.CommandLine;
|
+ "Task CommandLine: " + Environment.CommandLine;
|
||||||
init += $"{Environment.NewLine}{Environment.NewLine}";
|
init += $"{Environment.NewLine}{Environment.NewLine}";
|
||||||
File.WriteAllText(LogFilePath, init, Encoding.UTF8);
|
File.WriteAllText(LogFilePath, init, Encoding.UTF8);
|
||||||
}
|
}
|
||||||
|
@ -74,13 +79,14 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
{
|
{
|
||||||
if (subWrite == "")
|
if (subWrite == "")
|
||||||
{
|
{
|
||||||
AnsiConsole.MarkupLine(write);
|
CustomAnsiConsole.MarkupLine(write);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AnsiConsole.Markup(write);
|
CustomAnsiConsole.Markup(write);
|
||||||
Console.WriteLine(subWrite);
|
Console.WriteLine(subWrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsWriteFile && File.Exists(LogFilePath))
|
if (IsWriteFile && File.Exists(LogFilePath))
|
||||||
{
|
{
|
||||||
var plain = write.RemoveMarkup() + subWrite.RemoveMarkup();
|
var plain = write.RemoveMarkup() + subWrite.RemoveMarkup();
|
||||||
|
@ -112,6 +118,7 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
{
|
{
|
||||||
data = VarsRepRegex().Replace(data, $"{ps[i]}", 1);
|
data = VarsRepRegex().Replace(data, $"{ps[i]}", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,6 +209,7 @@ namespace N_m3u8DL_RE.Common.Log
|
||||||
{
|
{
|
||||||
data = exception.ToString().EscapeMarkup();
|
data = exception.ToString().EscapeMarkup();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorMarkUp(data);
|
ErrorMarkUp(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
public static string customRangeFound { get => GetText("customRangeFound"); }
|
public static string customRangeFound { get => GetText("customRangeFound"); }
|
||||||
public static string customAdKeywordsFound { get => GetText("customAdKeywordsFound"); }
|
public static string customAdKeywordsFound { get => GetText("customAdKeywordsFound"); }
|
||||||
public static string customRangeInvalid { get => GetText("customRangeInvalid"); }
|
public static string customRangeInvalid { get => GetText("customRangeInvalid"); }
|
||||||
|
public static string consoleRedirected { get => GetText("consoleRedirected"); }
|
||||||
public static string autoBinaryMerge { get => GetText("autoBinaryMerge"); }
|
public static string autoBinaryMerge { get => GetText("autoBinaryMerge"); }
|
||||||
public static string autoBinaryMerge2 { get => GetText("autoBinaryMerge2"); }
|
public static string autoBinaryMerge2 { get => GetText("autoBinaryMerge2"); }
|
||||||
public static string autoBinaryMerge3 { get => GetText("autoBinaryMerge3"); }
|
public static string autoBinaryMerge3 { get => GetText("autoBinaryMerge3"); }
|
||||||
|
@ -55,6 +56,8 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); }
|
public static string cmd_customHLSKey { get => GetText("cmd_customHLSKey"); }
|
||||||
public static string cmd_customHLSIv { get => GetText("cmd_customHLSIv"); }
|
public static string cmd_customHLSIv { get => GetText("cmd_customHLSIv"); }
|
||||||
public static string cmd_Input { get => GetText("cmd_Input"); }
|
public static string cmd_Input { get => GetText("cmd_Input"); }
|
||||||
|
public static string cmd_forceAnsiConsole { get => GetText("cmd_forceAnsiConsole"); }
|
||||||
|
public static string cmd_noAnsiColor { get => GetText("cmd_noAnsiColor"); }
|
||||||
public static string cmd_keys { get => GetText("cmd_keys"); }
|
public static string cmd_keys { get => GetText("cmd_keys"); }
|
||||||
public static string cmd_keyText { get => GetText("cmd_keyText"); }
|
public static string cmd_keyText { get => GetText("cmd_keyText"); }
|
||||||
public static string cmd_loadKeyFailed { get => GetText("cmd_loadKeyFailed"); }
|
public static string cmd_loadKeyFailed { get => GetText("cmd_loadKeyFailed"); }
|
||||||
|
|
|
@ -22,6 +22,18 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
zhTW: "即時解密已被強制關閉",
|
zhTW: "即時解密已被強制關閉",
|
||||||
enUS: "Real-time decryption has been disabled"
|
enUS: "Real-time decryption has been disabled"
|
||||||
),
|
),
|
||||||
|
["cmd_forceAnsiConsole"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "强制认定终端为支持ANSI且可交互的终端",
|
||||||
|
zhTW: "強制認定終端為支援ANSI且可交往的終端",
|
||||||
|
enUS: "Force assuming the terminal is ANSI-compatible and interactive"
|
||||||
|
),
|
||||||
|
["cmd_noAnsiColor"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "去除ANSI颜色",
|
||||||
|
zhTW: "關閉ANSI顏色",
|
||||||
|
enUS: "Remove ANSI colors"
|
||||||
|
),
|
||||||
["customRangeWarn"] = new TextContainer
|
["customRangeWarn"] = new TextContainer
|
||||||
(
|
(
|
||||||
zhCN: "请注意,自定义下载范围有时会导致音画不同步",
|
zhCN: "请注意,自定义下载范围有时会导致音画不同步",
|
||||||
|
@ -46,6 +58,12 @@ namespace N_m3u8DL_RE.Common.Resource
|
||||||
zhTW: "用戶自定義下載範圍:",
|
zhTW: "用戶自定義下載範圍:",
|
||||||
enUS: "User customed range: "
|
enUS: "User customed range: "
|
||||||
),
|
),
|
||||||
|
["consoleRedirected"] = new TextContainer
|
||||||
|
(
|
||||||
|
zhCN: "输出被重定向, 将清除ANSI颜色",
|
||||||
|
zhTW: "輸出被重定向, 將清除ANSI顏色",
|
||||||
|
enUS: "Output is redirected, ANSI colors are cleared."
|
||||||
|
),
|
||||||
["processImageSub"] = new TextContainer
|
["processImageSub"] = new TextContainer
|
||||||
(
|
(
|
||||||
zhCN: "正在处理图形字幕",
|
zhCN: "正在处理图形字幕",
|
||||||
|
|
|
@ -53,6 +53,8 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
private readonly static Option<bool> AppendUrlParams = new(new string[] { "--append-url-params" }, description: ResString.cmd_appendUrlParams, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
private readonly static Option<bool> MP4RealTimeDecryption = new (new string[] { "--mp4-real-time-decryption" }, description: ResString.cmd_MP4RealTimeDecryption, getDefaultValue: () => false);
|
||||||
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
private readonly static Option<bool> UseShakaPackager = new (new string[] { "--use-shaka-packager" }, description: ResString.cmd_useShakaPackager, getDefaultValue: () => false);
|
||||||
|
private readonly static Option<bool> ForceAnsiConsole = new(new string[] { "--force-ansi-console" }, description: ResString.cmd_forceAnsiConsole);
|
||||||
|
private readonly static Option<bool> NoAnsiColor = new(new string[] { "--no-ansi-color" }, description: ResString.cmd_noAnsiColor);
|
||||||
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath) { ArgumentHelpName = "PATH" };
|
private readonly static Option<string?> DecryptionBinaryPath = new(new string[] { "--decryption-binary-path" }, description: ResString.cmd_decryptionBinaryPath) { ArgumentHelpName = "PATH" };
|
||||||
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath) { ArgumentHelpName = "PATH" };
|
private readonly static Option<string?> FFmpegBinaryPath = new(new string[] { "--ffmpeg-binary-path" }, description: ResString.cmd_ffmpegBinaryPath) { ArgumentHelpName = "PATH" };
|
||||||
private readonly static Option<string?> BaseUrl = new(new string[] { "--base-url" }, description: ResString.cmd_baseUrl);
|
private readonly static Option<string?> BaseUrl = new(new string[] { "--base-url" }, description: ResString.cmd_baseUrl);
|
||||||
|
@ -484,6 +486,8 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
var option = new MyOption
|
var option = new MyOption
|
||||||
{
|
{
|
||||||
Input = bindingContext.ParseResult.GetValueForArgument(Input),
|
Input = bindingContext.ParseResult.GetValueForArgument(Input),
|
||||||
|
ForceAnsiConsole = bindingContext.ParseResult.GetValueForOption(ForceAnsiConsole),
|
||||||
|
NoAnsiColor = bindingContext.ParseResult.GetValueForOption(NoAnsiColor),
|
||||||
LogLevel = bindingContext.ParseResult.GetValueForOption(LogLevel),
|
LogLevel = bindingContext.ParseResult.GetValueForOption(LogLevel),
|
||||||
AutoSelect = bindingContext.ParseResult.GetValueForOption(AutoSelect),
|
AutoSelect = bindingContext.ParseResult.GetValueForOption(AutoSelect),
|
||||||
SkipMerge = bindingContext.ParseResult.GetValueForOption(SkipMerge),
|
SkipMerge = bindingContext.ParseResult.GetValueForOption(SkipMerge),
|
||||||
|
@ -594,7 +598,7 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
|
|
||||||
var rootCommand = new RootCommand(VERSION_INFO)
|
var rootCommand = new RootCommand(VERSION_INFO)
|
||||||
{
|
{
|
||||||
Input, TmpDir, SaveDir, SaveName, BaseUrl, ThreadCount, DownloadRetryCount, AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
Input, TmpDir, SaveDir, SaveName, BaseUrl, ThreadCount, DownloadRetryCount, ForceAnsiConsole, NoAnsiColor,AutoSelect, SkipMerge, SkipDownload, CheckSegmentsCount,
|
||||||
BinaryMerge, UseFFmpegConcatDemuxer, DelAfterDone, NoDateInfo, NoLog, WriteMetaJson, AppendUrlParams, ConcurrentDownload, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
BinaryMerge, UseFFmpegConcatDemuxer, DelAfterDone, NoDateInfo, NoLog, WriteMetaJson, AppendUrlParams, ConcurrentDownload, Headers, /**SavePattern,**/ SubOnly, SubtitleFormat, AutoSubtitleFix,
|
||||||
FFmpegBinaryPath,
|
FFmpegBinaryPath,
|
||||||
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption,
|
LogLevel, UILanguage, UrlProcessorArgs, Keys, KeyTextFile, DecryptionBinaryPath, UseShakaPackager, MP4RealTimeDecryption,
|
||||||
|
|
|
@ -85,6 +85,14 @@ namespace N_m3u8DL_RE.CommandLine
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool BinaryMerge { get; set; }
|
public bool BinaryMerge { get; set; }
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
/// See: <see cref="CommandInvoker.ForceAnsiConsole"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool ForceAnsiConsole { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// See: <see cref="CommandInvoker.NoAnsiColor"/>.
|
||||||
|
/// </summary>
|
||||||
|
public bool NoAnsiColor { get; set; }
|
||||||
|
/// <summary>
|
||||||
/// See: <see cref="CommandInvoker.UseFFmpegConcatDemuxer"/>.
|
/// See: <see cref="CommandInvoker.UseFFmpegConcatDemuxer"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool UseFFmpegConcatDemuxer { get; set; }
|
public bool UseFFmpegConcatDemuxer { get; set; }
|
||||||
|
|
|
@ -197,11 +197,11 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic = new(); //速度计算
|
ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic = new(); //速度计算
|
||||||
ConcurrentDictionary<StreamSpec, bool?> Results = new();
|
ConcurrentDictionary<StreamSpec, bool?> Results = new();
|
||||||
|
|
||||||
var progress = AnsiConsole.Progress().AutoClear(true);
|
var progress = CustomAnsiConsole.Console.Progress().AutoClear(true);
|
||||||
progress.AutoRefresh = DownloaderConfig.MyOptions.LogLevel != LogLevel.OFF;
|
progress.AutoRefresh = DownloaderConfig.MyOptions.LogLevel != LogLevel.OFF;
|
||||||
|
|
||||||
//进度条的列定义
|
//进度条的列定义
|
||||||
progress.Columns(new ProgressColumn[]
|
var progressColumns = new ProgressColumn[]
|
||||||
{
|
{
|
||||||
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
||||||
new RecordingDurationColumn(RecordingDurDic), //时长显示
|
new RecordingDurationColumn(RecordingDurDic), //时长显示
|
||||||
|
@ -209,7 +209,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
new RecordingStatusColumn(),
|
new RecordingStatusColumn(),
|
||||||
new DownloadSpeedColumn(SpeedContainerDic), //速度计算
|
new DownloadSpeedColumn(SpeedContainerDic), //速度计算
|
||||||
new SpinnerColumn(),
|
new SpinnerColumn(),
|
||||||
});
|
};
|
||||||
|
if (DownloaderConfig.MyOptions.NoAnsiColor)
|
||||||
|
{
|
||||||
|
progressColumns = progressColumns.SkipLast(1).ToArray();
|
||||||
|
}
|
||||||
|
progress.Columns(progressColumns);
|
||||||
|
|
||||||
await progress.StartAsync(async ctx =>
|
await progress.StartAsync(async ctx =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -629,11 +629,11 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic = new(); //速度计算
|
ConcurrentDictionary<int, SpeedContainer> SpeedContainerDic = new(); //速度计算
|
||||||
ConcurrentDictionary<StreamSpec, bool?> Results = new();
|
ConcurrentDictionary<StreamSpec, bool?> Results = new();
|
||||||
|
|
||||||
var progress = AnsiConsole.Progress().AutoClear(true);
|
var progress = CustomAnsiConsole.Console.Progress().AutoClear(true);
|
||||||
progress.AutoRefresh = DownloaderConfig.MyOptions.LogLevel != LogLevel.OFF;
|
progress.AutoRefresh = DownloaderConfig.MyOptions.LogLevel != LogLevel.OFF;
|
||||||
|
|
||||||
//进度条的列定义
|
//进度条的列定义
|
||||||
progress.Columns(new ProgressColumn[]
|
var progressColumns = new ProgressColumn[]
|
||||||
{
|
{
|
||||||
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
||||||
new ProgressBarColumn(){ Width = 30 },
|
new ProgressBarColumn(){ Width = 30 },
|
||||||
|
@ -642,7 +642,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
new DownloadSpeedColumn(SpeedContainerDic), //速度计算
|
new DownloadSpeedColumn(SpeedContainerDic), //速度计算
|
||||||
new RemainingTimeColumn(),
|
new RemainingTimeColumn(),
|
||||||
new SpinnerColumn(),
|
new SpinnerColumn(),
|
||||||
});
|
};
|
||||||
|
if (DownloaderConfig.MyOptions.NoAnsiColor)
|
||||||
|
{
|
||||||
|
progressColumns = progressColumns.SkipLast(1).ToArray();
|
||||||
|
}
|
||||||
|
progress.Columns(progressColumns);
|
||||||
|
|
||||||
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !DownloaderConfig.MyOptions.UseShakaPackager
|
if (DownloaderConfig.MyOptions.MP4RealTimeDecryption && !DownloaderConfig.MyOptions.UseShakaPackager
|
||||||
&& DownloaderConfig.MyOptions.Keys != null && DownloaderConfig.MyOptions.Keys.Length > 0)
|
&& DownloaderConfig.MyOptions.Keys != null && DownloaderConfig.MyOptions.Keys.Length > 0)
|
||||||
|
|
|
@ -801,11 +801,11 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
await StreamingUtil.WriteMasterListAsync(SelectedSteams, saveName, saveDir);
|
await StreamingUtil.WriteMasterListAsync(SelectedSteams, saveName, saveDir);
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
var progress = AnsiConsole.Progress().AutoClear(true);
|
var progress = CustomAnsiConsole.Console.Progress().AutoClear(true);
|
||||||
progress.AutoRefresh = DownloaderConfig.MyOptions.LogLevel != LogLevel.OFF;
|
progress.AutoRefresh = DownloaderConfig.MyOptions.LogLevel != LogLevel.OFF;
|
||||||
|
|
||||||
//进度条的列定义
|
//进度条的列定义
|
||||||
progress.Columns(new ProgressColumn[]
|
var progressColumns = new ProgressColumn[]
|
||||||
{
|
{
|
||||||
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
new TaskDescriptionColumn() { Alignment = Justify.Left },
|
||||||
new RecordingDurationColumn(RecordedDurDic, RefreshedDurDic), //时长显示
|
new RecordingDurationColumn(RecordedDurDic, RefreshedDurDic), //时长显示
|
||||||
|
@ -813,7 +813,12 @@ namespace N_m3u8DL_RE.DownloadManager
|
||||||
new PercentageColumn(),
|
new PercentageColumn(),
|
||||||
new DownloadSpeedColumn(SpeedContainerDic), //速度计算
|
new DownloadSpeedColumn(SpeedContainerDic), //速度计算
|
||||||
new SpinnerColumn(),
|
new SpinnerColumn(),
|
||||||
});
|
};
|
||||||
|
if (DownloaderConfig.MyOptions.NoAnsiColor)
|
||||||
|
{
|
||||||
|
progressColumns = progressColumns.SkipLast(1).ToArray();
|
||||||
|
}
|
||||||
|
progress.Columns(progressColumns);
|
||||||
|
|
||||||
await progress.StartAsync(async ctx =>
|
await progress.StartAsync(async ctx =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace N_m3u8DL_RE
|
||||||
Console.CancelKeyPress += Console_CancelKeyPress;
|
Console.CancelKeyPress += Console_CancelKeyPress;
|
||||||
ServicePointManager.DefaultConnectionLimit = 1024;
|
ServicePointManager.DefaultConnectionLimit = 1024;
|
||||||
try { Console.CursorVisible = true; } catch { }
|
try { Console.CursorVisible = true; } catch { }
|
||||||
|
|
||||||
string loc = "en-US";
|
string loc = "en-US";
|
||||||
string currLoc = Thread.CurrentThread.CurrentUICulture.Name;
|
string currLoc = Thread.CurrentThread.CurrentUICulture.Name;
|
||||||
if (currLoc == "zh-CN" || currLoc == "zh-SG") loc = "zh-CN";
|
if (currLoc == "zh-CN" || currLoc == "zh-SG") loc = "zh-CN";
|
||||||
|
@ -70,6 +71,14 @@ namespace N_m3u8DL_RE
|
||||||
|
|
||||||
static async Task DoWorkAsync(MyOption option)
|
static async Task DoWorkAsync(MyOption option)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
if (Console.IsOutputRedirected || Console.IsErrorRedirected)
|
||||||
|
{
|
||||||
|
option.ForceAnsiConsole = true;
|
||||||
|
option.NoAnsiColor = true;
|
||||||
|
Logger.Info(ResString.consoleRedirected);
|
||||||
|
}
|
||||||
|
CustomAnsiConsole.InitConsole(option.ForceAnsiConsole, option.NoAnsiColor);
|
||||||
//检测更新
|
//检测更新
|
||||||
CheckUpdateAsync();
|
CheckUpdateAsync();
|
||||||
|
|
||||||
|
|
|
@ -135,7 +135,7 @@ namespace N_m3u8DL_RE.Util
|
||||||
prompt.Select(basicStreams.Concat(audios).Concat(subs).First());
|
prompt.Select(basicStreams.Concat(audios).Concat(subs).First());
|
||||||
|
|
||||||
//多选
|
//多选
|
||||||
var selectedStreams = AnsiConsole.Prompt(prompt);
|
var selectedStreams = CustomAnsiConsole.Console.Prompt(prompt);
|
||||||
|
|
||||||
return selectedStreams;
|
return selectedStreams;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue