ZonyLrcToolsX界面版
内核代码开源(C# – 部分代码)
Program.cs
using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Serilog;
using Serilog.Events;
using ZonyLrcTools.Cli.Commands;
using ZonyLrcTools.Cli.Commands.SubCommand;
using ZonyLrcTools.Cli.Infrastructure;
using ZonyLrcTools.Cli.Infrastructure.Logging;
using ZonyLrcTools.Common.Infrastructure.DependencyInject;
using ZonyLrcTools.Common.Infrastructure.Exceptions;
using ZonyLrcTools.Common.Infrastructure.Network;
// ReSharper disable ClassNeverInstantiated.Global
namespace ZonyLrcTools.Cli
{
[Command("lyric-tool")]
[Subcommand(typeof(DownloadCommand),
typeof(UtilityCommand))]
public class Program : ToolCommandBase
{
public static async Task Main(string[] args)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
ConfigureLogger();
ConfigureErrorMessage();
try
{
Log.Logger.Information("Starting...");
return await BuildHostedService(args);
}
catch (Exception ex)
{
return HandleException(ex);
}
finally
{
Log.CloseAndFlush();
}
}
#region > 程序初始化配置 < private static void ConfigureErrorMessage() => ErrorCodeHelper.LoadErrorMessage();
private static void ConfigureLogger()
{
Log.Logger = new LoggerConfiguration()
#if DEBUG
.MinimumLevel.Debug()
#else
.MinimumLevel.Information()
#endif
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.MinimumLevel.Override("System.Net.Http.HttpClient", LogEventLevel.Error)
.Enrich.FromLogContext()
.WriteTo.Async(c => c.Console(theme: CustomConsoleTheme.Code))
.WriteTo.Logger(lc =>
{
lc.Filter.ByIncludingOnly(warningLog => warningLog.Level == LogEventLevel.Warning)
.WriteTo.Async(c => c.File("Logs/warnings.txt"));
})
.WriteTo.Logger(lc =>
{
lc.Filter.ByIncludingOnly(errLog => errLog.Level == LogEventLevel.Error)
.WriteTo.Async(c => c.File("Logs/errors.txt"));
})
.CreateLogger();
}
private static Task BuildHostedService(string[] args)
{
return new HostBuilder()
.ConfigureLogging(builder => builder.AddSerilog())
.ConfigureHostConfiguration(builder =>
{
builder
.SetBasePath(AppDomain.CurrentDomain.BaseDirectory)
.AddYamlFile("config.yaml");
})
.ConfigureServices((_, services) =>
{
services.AddSingleton(PhysicalConsole.Singleton);
services.BeginAutoDependencyInject();
services.BeginAutoDependencyInject();
services.ConfigureConfiguration();
services.ConfigureToolService();
services.AddHostedService();
})
.RunCommandLineApplicationAsync(args);
}
private static int HandleException(Exception ex)
{
switch (ex)
{
case ErrorCodeException exception:
Log.Logger.Error(
$"出现了未处理的异常。\n错误代码: {exception.ErrorCode}\n错误信息: {ErrorCodeHelper.GetMessage(exception.ErrorCode)}\n原始信息:{exception.Message}\n调用栈:{exception.StackTrace}");
Environment.Exit(exception.ErrorCode);
return exception.ErrorCode;
case { } unknownException:
Log.Logger.Error($"出现了未处理的异常: {unknownException.Message}\n调用栈:\n{unknownException.StackTrace}");
Environment.Exit(-1);
return 1;
default:
return 1;
}
}
#endregion
}
}
DownloadCommand.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.DependencyInjection;
using ZonyLrcTools.Cli.Infrastructure.MusicScannerOptions;
using ZonyLrcTools.Common;
using ZonyLrcTools.Common.Album;
using ZonyLrcTools.Common.Lyrics;
using ZonyLrcTools.Common.MusicScanner;
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable MemberCanBePrivate.Global
namespace ZonyLrcTools.Cli.Commands.SubCommand
{
[Command("download", Description = "下载歌词文件或专辑图像。")]
public class DownloadCommand : ToolCommandBase
{
private readonly ILyricsDownloader _lyricsDownloader;
private readonly IAlbumDownloader _albumDownloader;
private readonly IMusicInfoLoader _musicInfoLoader;
private readonly IServiceProvider _serviceProvider;
public DownloadCommand(ILyricsDownloader lyricsDownloader,
IMusicInfoLoader musicInfoLoader,
IAlbumDownloader albumDownloader,
IServiceProvider serviceProvider)
{
_lyricsDownloader = lyricsDownloader;
_musicInfoLoader = musicInfoLoader;
_albumDownloader = albumDownloader;
_serviceProvider = serviceProvider;
}
#region > Options < [Option("-d|--dir", CommandOptionType.SingleValue, Description = "指定需要扫描的目录。")] [DirectoryExists] public string SongsDirectory { get; set; } [Option("-l|--lyric", CommandOptionType.NoValue, Description = "指定程序需要下载歌词文件。")] public bool DownloadLyric { get; set; } [Option("-a|--album", CommandOptionType.NoValue, Description = "指定程序需要下载专辑图像。")] public bool DownloadAlbum { get; set; } [Option("-n|--number", CommandOptionType.SingleValue, Description = "指定下载时候的线程数量。(默认值 1)")] public int ParallelNumber { get; set; } = 1; #endregion #region > Scanner Options <
[Option("-sc|--scanner", CommandOptionType.SingleValue, Description = "指定歌词文件扫描器,目前支持本地文件(local),网易云音乐(netease),csv 文件(csv),默认值为 local。")]
public string Scanner { get; set; } = "local";
[Option("-o|--output", Description = "指定歌词文件的输出路径。")]
public string OutputDirectory { get; set; } = "DownloadedLrc";
[Option("-p|--pattern", Description = "指定歌词文件的输出文件名模式。")]
public string OutputFileNamePattern { get; set; } = "{Artist} - {Name}.lrc";
[Option("-f|--file", Description = "指定 CSV 文件的路径。")]
public string CsvFilePath { get; set; }
[Option("-s|--song-list-id", Description = "指定网易云音乐歌单的 ID,如果有多个歌单,请使用 ';' 分割 ID。")]
public string SongListId { get; set; }
#endregion
protected override async Task OnExecuteAsync(CommandLineApplication app)
{
if (!DownloadAlbum && !DownloadLyric)
{
throw new ArgumentException("请至少指定一个下载选项,例如 -l(下载歌词) 或 -a(下载专辑图像)。");
}
if (DownloadLyric)
{
await _lyricsDownloader.DownloadAsync(await GetMusicInfosAsync(Scanner), ParallelNumber);
}
if (DownloadAlbum)
{
await _albumDownloader.DownloadAsync(await GetMusicInfosAsync(Scanner), ParallelNumber);
}
return 0;
}
ManualDownloadCommand.cs
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
namespace ZonyLrcTools.Cli.Commands.SubCommand;
[Command("manual", Description = "手动指定歌曲信息,然后下载对应的歌词数据。")]
public class ManualDownloadCommand : ToolCommandBase
{
private readonly ILogger _logger;
public ManualDownloadCommand(ILogger logger)
{
_logger = logger;
}
}
SearchCommand.cs
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
namespace ZonyLrcTools.Cli.Commands.SubCommand;
[Command("search", Description = "手动指定信息,用于搜索歌词数据。")]
public class SearchCommand : ToolCommandBase
{
private readonly ILogger _logger;
#region > Options <
public string Name { get; set; }
public string Artist { get; set; }
#endregion
public SearchCommand(ILogger logger)
{
_logger = logger;
}
protected override Task OnExecuteAsync(CommandLineApplication app)
{
return base.OnExecuteAsync(app);
}
}
UtilityCommand.cs
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using Microsoft.Extensions.Logging;
using MusicDecrypto.Library;
using ZonyLrcTools.Common.Infrastructure.IO;
using ZonyLrcTools.Common.Infrastructure.Threading;
using ZonyLrcTools.Common.MusicDecryption;
namespace ZonyLrcTools.Cli.Commands.SubCommand