From 6b72f919b8be89d5a2161ba78b47be19e1d4615e Mon Sep 17 00:00:00 2001 From: real-zony Date: Sun, 23 Oct 2022 22:48:06 +0800 Subject: [PATCH] refactor: Refactor the code of the Download command. --- .../Commands/SubCommand/DownloadCommand.cs | 95 ++----------------- .../Album/AlbumDownloader.cs | 68 +++++++++++++ .../Album/IAlbumDownloader.cs | 27 ++---- .../Album/IAlbumProvider.cs | 21 ++++ ...Names.cs => InternalAlbumProviderNames.cs} | 2 +- ...mDownloader.cs => NetEaseAlbumProvider.cs} | 6 +- ...mDownloader.cs => QQMusicAlbumProvider.cs} | 6 +- .../Lyrics/ILyricsDownloader.cs | 2 +- ...yricsDownloader.cs => LyricsDownloader.cs} | 17 ++-- src/ZonyLrcTools.Common/MusicInfoLoader.cs | 26 ++++- .../Album/NetEaseAlbumDownloader_Tests.cs | 4 +- .../Album/QQMusicAlbumDownloaderTests.cs | 4 +- 12 files changed, 151 insertions(+), 127 deletions(-) create mode 100644 src/ZonyLrcTools.Common/Album/AlbumDownloader.cs create mode 100644 src/ZonyLrcTools.Common/Album/IAlbumProvider.cs rename src/ZonyLrcTools.Common/Album/{InternalAlbumDownloaderNames.cs => InternalAlbumProviderNames.cs} (89%) rename src/ZonyLrcTools.Common/Album/NetEase/{NetEaseAlbumDownloader.cs => NetEaseAlbumProvider.cs} (90%) rename src/ZonyLrcTools.Common/Album/QQMusic/{QQMusicAlbumDownloader.cs => QQMusicAlbumProvider.cs} (85%) rename src/ZonyLrcTools.Common/Lyrics/{DefaultLyricsDownloader.cs => LyricsDownloader.cs} (89%) diff --git a/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs b/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs index 089788b..47c9179 100644 --- a/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs +++ b/src/ZonyLrcTools.Cli/Commands/SubCommand/DownloadCommand.cs @@ -1,42 +1,29 @@ -using System.Collections.Generic; -using System.IO; -using System.Linq; using System.Threading.Tasks; using McMaster.Extensions.CommandLineUtils; -using Microsoft.Extensions.Options; using ZonyLrcTools.Common; using ZonyLrcTools.Common.Album; -using ZonyLrcTools.Common.Configuration; -using ZonyLrcTools.Common.Infrastructure.Exceptions; -using ZonyLrcTools.Common.Infrastructure.Extensions; -using ZonyLrcTools.Common.Infrastructure.IO; -using ZonyLrcTools.Common.Infrastructure.Logging; -using ZonyLrcTools.Common.Infrastructure.Threading; using ZonyLrcTools.Common.Lyrics; +// 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 IEnumerable _albumDownloaderList; - private readonly IWarpLogger _logger; - private readonly GlobalOptions _options; - - public DownloadCommand(IOptions options, - IEnumerable albumDownloaderList, - ILyricsDownloader lyricsDownloader, - IWarpLogger logger, - IMusicInfoLoader musicInfoLoader) + public DownloadCommand(ILyricsDownloader lyricsDownloader, + IMusicInfoLoader musicInfoLoader, + IAlbumDownloader albumDownloader) { - _albumDownloaderList = albumDownloaderList; _lyricsDownloader = lyricsDownloader; - _logger = logger; _musicInfoLoader = musicInfoLoader; - _options = options.Value; + _albumDownloader = albumDownloader; } #region > Options < @@ -65,72 +52,10 @@ namespace ZonyLrcTools.Cli.Commands.SubCommand if (DownloadAlbum) { - // await DownloadAlbumAsync( - // await LoadMusicInfoAsync( - // await ScanMusicFilesAsync())); + await _albumDownloader.DownloadAsync(await _musicInfoLoader.LoadAsync(SongsDirectory, ParallelNumber), ParallelNumber); } return 0; } - - private List RemoveExistLyricFiles(List filePaths) - { - if (!_options.Provider.Lyric.Config.IsSkipExistLyricFiles) - { - return filePaths; - } - - return filePaths - .Where(path => - { - if (!File.Exists(Path.ChangeExtension(path, ".lrc"))) - { - return true; - } - - _logger.WarnAsync($"已经存在歌词文件 {path},跳过。").GetAwaiter().GetResult(); - return false; - }) - .ToList(); - } - - #region > Ablum image download logic < - - private async ValueTask DownloadAlbumAsync(List musicInfos) - { - await _logger.InfoAsync("开始下载专辑图像数据..."); - - var downloader = _albumDownloaderList.FirstOrDefault(d => d.DownloaderName == InternalAlbumDownloaderNames.NetEase); - var warpTask = new WarpTask(ParallelNumber); - var warpTaskList = musicInfos.Select(info => - warpTask.RunAsync(() => Task.Run(async () => await DownloadAlbumTaskLogicAsync(downloader, info)))); - - await Task.WhenAll(warpTaskList); - - await _logger.InfoAsync($"专辑数据下载完成,成功: {musicInfos.Count(m => m.IsSuccessful)} 失败{musicInfos.Count(m => m.IsSuccessful == false)}。"); - } - - private async Task DownloadAlbumTaskLogicAsync(IAlbumDownloader downloader, MusicInfo info) - { - _logger.LogSuccessful(info); - - try - { - var album = await downloader.DownloadAsync(info.Name, info.Artist); - var filePath = Path.Combine(Path.GetDirectoryName(info.FilePath)!, $"{Path.GetFileNameWithoutExtension(info.FilePath)}.png"); - if (File.Exists(filePath) || album.Length <= 0) - { - return; - } - - await new FileStream(filePath, FileMode.Create).WriteBytesToFileAsync(album, 1024); - } - catch (ErrorCodeException ex) - { - _logger.LogWarningInfo(ex); - } - } - - #endregion } } \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/Album/AlbumDownloader.cs b/src/ZonyLrcTools.Common/Album/AlbumDownloader.cs new file mode 100644 index 0000000..715c2b7 --- /dev/null +++ b/src/ZonyLrcTools.Common/Album/AlbumDownloader.cs @@ -0,0 +1,68 @@ +using ZonyLrcTools.Common.Infrastructure.DependencyInject; +using ZonyLrcTools.Common.Infrastructure.Exceptions; +using ZonyLrcTools.Common.Infrastructure.Extensions; +using ZonyLrcTools.Common.Infrastructure.IO; +using ZonyLrcTools.Common.Infrastructure.Logging; +using ZonyLrcTools.Common.Infrastructure.Threading; + +namespace ZonyLrcTools.Common.Album; + +public class AlbumDownloader : IAlbumDownloader, ISingletonDependency +{ + private readonly IEnumerable _albumProviders; + + public IEnumerable AvailableProviders => new Lazy>(() => + { + return _albumProviders.Where(d => d.DownloaderName == InternalAlbumProviderNames.NetEase); + }).Value; + + private readonly IWarpLogger _logger; + + public AlbumDownloader(IEnumerable albumProviders, + IWarpLogger logger) + { + _albumProviders = albumProviders; + _logger = logger; + } + + public async Task DownloadAsync(List needDownloadMusicInfos, + int parallelCount = 2, + CancellationToken cancellationToken = default) + { + await _logger.InfoAsync("开始下载专辑图像数据..."); + + var provider = AvailableProviders.FirstOrDefault(d => d.DownloaderName == InternalAlbumProviderNames.NetEase); + if (provider == null) + { + return; + } + + var warpTask = new WarpTask(parallelCount); + var warpTaskList = needDownloadMusicInfos.Select(info => + warpTask.RunAsync(() => + Task.Run(async () => + { + _logger.LogSuccessful(info); + + try + { + var album = await provider.DownloadAsync(info.Name, info.Artist); + var filePath = Path.Combine(Path.GetDirectoryName(info.FilePath)!, $"{Path.GetFileNameWithoutExtension(info.FilePath)}.png"); + if (File.Exists(filePath) || album.Length <= 0) + { + return; + } + + await new FileStream(filePath, FileMode.Create).WriteBytesToFileAsync(album); + } + catch (ErrorCodeException ex) + { + _logger.LogWarningInfo(ex); + } + }, cancellationToken), cancellationToken)); + + await Task.WhenAll(warpTaskList); + + await _logger.InfoAsync($"专辑数据下载完成,成功: {needDownloadMusicInfos.Count(m => m.IsSuccessful)} 失败{needDownloadMusicInfos.Count(m => m.IsSuccessful == false)}。"); + } +} \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/Album/IAlbumDownloader.cs b/src/ZonyLrcTools.Common/Album/IAlbumDownloader.cs index bc64282..4619c35 100644 --- a/src/ZonyLrcTools.Common/Album/IAlbumDownloader.cs +++ b/src/ZonyLrcTools.Common/Album/IAlbumDownloader.cs @@ -1,21 +1,10 @@ -namespace ZonyLrcTools.Common.Album -{ - /// - /// 专辑封面下载器,用于匹配并下载歌曲的专辑封面。 - /// - public interface IAlbumDownloader - { - /// - /// 下载器的名称。 - /// - string DownloaderName { get; } +namespace ZonyLrcTools.Common.Album; - /// - /// 下载专辑封面。 - /// - /// 歌曲的名称。 - /// 歌曲的作者。 - /// 专辑封面的图像数据。 - ValueTask DownloadAsync(string songName, string artist); - } +public interface IAlbumDownloader +{ + Task DownloadAsync(List needDownloadMusicInfos, + int parallelCount = 2, + CancellationToken cancellationToken = default); + + IEnumerable AvailableProviders { get; } } \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/Album/IAlbumProvider.cs b/src/ZonyLrcTools.Common/Album/IAlbumProvider.cs new file mode 100644 index 0000000..6a10828 --- /dev/null +++ b/src/ZonyLrcTools.Common/Album/IAlbumProvider.cs @@ -0,0 +1,21 @@ +namespace ZonyLrcTools.Common.Album +{ + /// + /// 专辑封面下载器,用于匹配并下载歌曲的专辑封面。 + /// + public interface IAlbumProvider + { + /// + /// 下载器的名称。 + /// + string DownloaderName { get; } + + /// + /// 下载专辑封面。 + /// + /// 歌曲的名称。 + /// 歌曲的作者。 + /// 专辑封面的图像数据。 + ValueTask DownloadAsync(string songName, string artist); + } +} \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/Album/InternalAlbumDownloaderNames.cs b/src/ZonyLrcTools.Common/Album/InternalAlbumProviderNames.cs similarity index 89% rename from src/ZonyLrcTools.Common/Album/InternalAlbumDownloaderNames.cs rename to src/ZonyLrcTools.Common/Album/InternalAlbumProviderNames.cs index a690230..1c0b41d 100644 --- a/src/ZonyLrcTools.Common/Album/InternalAlbumDownloaderNames.cs +++ b/src/ZonyLrcTools.Common/Album/InternalAlbumProviderNames.cs @@ -3,7 +3,7 @@ /// /// 定义了程序默认提供的专辑图像下载器。 /// - public static class InternalAlbumDownloaderNames + public static class InternalAlbumProviderNames { /// /// 网易云音乐专辑图像下载器。 diff --git a/src/ZonyLrcTools.Common/Album/NetEase/NetEaseAlbumDownloader.cs b/src/ZonyLrcTools.Common/Album/NetEase/NetEaseAlbumProvider.cs similarity index 90% rename from src/ZonyLrcTools.Common/Album/NetEase/NetEaseAlbumDownloader.cs rename to src/ZonyLrcTools.Common/Album/NetEase/NetEaseAlbumProvider.cs index 9a62376..2d08c5c 100644 --- a/src/ZonyLrcTools.Common/Album/NetEase/NetEaseAlbumDownloader.cs +++ b/src/ZonyLrcTools.Common/Album/NetEase/NetEaseAlbumProvider.cs @@ -7,9 +7,9 @@ using ZonyLrcTools.Common.Lyrics.Providers.NetEase.JsonModel; namespace ZonyLrcTools.Common.Album.NetEase { - public class NetEaseAlbumDownloader : IAlbumDownloader, ITransientDependency + public class NetEaseAlbumProvider : IAlbumProvider, ITransientDependency { - public string DownloaderName => InternalAlbumDownloaderNames.NetEase; + public string DownloaderName => InternalAlbumProviderNames.NetEase; private readonly IWarpHttpClient _warpHttpClient; private readonly Action _defaultOption; @@ -18,7 +18,7 @@ namespace ZonyLrcTools.Common.Album.NetEase private const string GetMusicInfoApi = @"https://music.163.com/api/song/detail"; private const string DefaultReferer = @"https://music.163.com"; - public NetEaseAlbumDownloader(IWarpHttpClient warpHttpClient) + public NetEaseAlbumProvider(IWarpHttpClient warpHttpClient) { _warpHttpClient = warpHttpClient; _defaultOption = message => diff --git a/src/ZonyLrcTools.Common/Album/QQMusic/QQMusicAlbumDownloader.cs b/src/ZonyLrcTools.Common/Album/QQMusic/QQMusicAlbumProvider.cs similarity index 85% rename from src/ZonyLrcTools.Common/Album/QQMusic/QQMusicAlbumDownloader.cs rename to src/ZonyLrcTools.Common/Album/QQMusic/QQMusicAlbumProvider.cs index 001f9b3..b3fb1ed 100644 --- a/src/ZonyLrcTools.Common/Album/QQMusic/QQMusicAlbumDownloader.cs +++ b/src/ZonyLrcTools.Common/Album/QQMusic/QQMusicAlbumProvider.cs @@ -5,9 +5,9 @@ using ZonyLrcTools.Common.Lyrics.Providers.QQMusic.JsonModel; namespace ZonyLrcTools.Common.Album.QQMusic { - public class QQMusicAlbumDownloader : IAlbumDownloader, ITransientDependency + public class QQMusicAlbumProvider : IAlbumProvider, ITransientDependency { - public string DownloaderName => InternalAlbumDownloaderNames.QQ; + public string DownloaderName => InternalAlbumProviderNames.QQ; private readonly IWarpHttpClient _warpHttpClient; @@ -24,7 +24,7 @@ namespace ZonyLrcTools.Common.Album.QQMusic private const string SearchApi = "https://c.y.qq.com/soso/fcgi-bin/client_search_cp"; private const string DefaultReferer = "https://y.qq.com"; - public QQMusicAlbumDownloader(IWarpHttpClient warpHttpClient) + public QQMusicAlbumProvider(IWarpHttpClient warpHttpClient) { _warpHttpClient = warpHttpClient; } diff --git a/src/ZonyLrcTools.Common/Lyrics/ILyricsDownloader.cs b/src/ZonyLrcTools.Common/Lyrics/ILyricsDownloader.cs index d5a9da3..5a830e3 100644 --- a/src/ZonyLrcTools.Common/Lyrics/ILyricsDownloader.cs +++ b/src/ZonyLrcTools.Common/Lyrics/ILyricsDownloader.cs @@ -2,7 +2,7 @@ public interface ILyricsDownloader { - Task> DownloadAsync(List needDownloadMusicInfos, + Task DownloadAsync(List needDownloadMusicInfos, int parallelCount = 2, CancellationToken cancellationToken = default); diff --git a/src/ZonyLrcTools.Common/Lyrics/DefaultLyricsDownloader.cs b/src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs similarity index 89% rename from src/ZonyLrcTools.Common/Lyrics/DefaultLyricsDownloader.cs rename to src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs index ae466e5..8234b46 100644 --- a/src/ZonyLrcTools.Common/Lyrics/DefaultLyricsDownloader.cs +++ b/src/ZonyLrcTools.Common/Lyrics/LyricsDownloader.cs @@ -9,33 +9,33 @@ using ZonyLrcTools.Common.Infrastructure.Threading; namespace ZonyLrcTools.Common.Lyrics; -public class DefaultLyricsDownloader : ILyricsDownloader, ISingletonDependency +public class LyricsDownloader : ILyricsDownloader, ISingletonDependency { - private readonly IEnumerable _lyricDownloaderList; - private readonly GlobalOptions _options; + private readonly IEnumerable _lyricsProviders; private readonly IWarpLogger _logger; + private readonly GlobalOptions _options; public IEnumerable AvailableProviders => new Lazy>(() => { return _options.Provider.Lyric.Plugin .Where(op => op.Priority != -1) .OrderBy(op => op.Priority) - .Join(_lyricDownloaderList, + .Join(_lyricsProviders, op => op.Name, loader => loader.DownloaderName, - (op, loader) => loader); + (_, loader) => loader); }).Value; - public DefaultLyricsDownloader(IEnumerable lyricDownloaderList, + public LyricsDownloader(IEnumerable lyricsProviders, IOptions options, IWarpLogger logger) { - _lyricDownloaderList = lyricDownloaderList; + _lyricsProviders = lyricsProviders; _logger = logger; _options = options.Value; } - public async Task> DownloadAsync(List needDownloadMusicInfos, + public async Task DownloadAsync(List needDownloadMusicInfos, int parallelCount = 2, CancellationToken cancellationToken = default) { @@ -67,7 +67,6 @@ public class DefaultLyricsDownloader : ILyricsDownloader, ISingletonDependency await Task.WhenAll(downloadTasks); await _logger.InfoAsync($"歌词数据下载完成,成功: {needDownloadMusicInfos.Count(m => m.IsSuccessful)} 失败{needDownloadMusicInfos.Count(m => m.IsSuccessful == false)}。"); - return needDownloadMusicInfos; } private async Task DownloadAndWriteLyricsAsync(ILyricsProvider provider, MusicInfo info) diff --git a/src/ZonyLrcTools.Common/MusicInfoLoader.cs b/src/ZonyLrcTools.Common/MusicInfoLoader.cs index 8ab92c9..71948f9 100644 --- a/src/ZonyLrcTools.Common/MusicInfoLoader.cs +++ b/src/ZonyLrcTools.Common/MusicInfoLoader.cs @@ -1,5 +1,6 @@ using Microsoft.Extensions.Options; using ZonyLrcTools.Common.Configuration; +using ZonyLrcTools.Common.Infrastructure.DependencyInject; using ZonyLrcTools.Common.Infrastructure.Exceptions; using ZonyLrcTools.Common.Infrastructure.IO; using ZonyLrcTools.Common.Infrastructure.Logging; @@ -8,7 +9,7 @@ using ZonyLrcTools.Common.TagInfo; namespace ZonyLrcTools.Common; -public class MusicInfoLoader : IMusicInfoLoader +public class MusicInfoLoader : IMusicInfoLoader, ITransientDependency { private readonly IWarpLogger _logger; private readonly IFileScanner _fileScanner; @@ -30,7 +31,7 @@ public class MusicInfoLoader : IMusicInfoLoader int parallelCount = 2, CancellationToken cancellationToken = default) { - var files = (await _fileScanner.ScanMusicFilesAsync(dirPath, _options.SupportFileExtensions)).ToList(); + var files = RemoveExistLyricFiles(await _fileScanner.ScanMusicFilesAsync(dirPath, _options.SupportFileExtensions)); if (files.Count == 0) { @@ -66,4 +67,25 @@ public class MusicInfoLoader : IMusicInfoLoader return result; } + + private List RemoveExistLyricFiles(IEnumerable filePaths) + { + if (!_options.Provider.Lyric.Config.IsSkipExistLyricFiles) + { + return filePaths.ToList(); + } + + return filePaths + .Where(path => + { + if (!File.Exists(Path.ChangeExtension(path, ".lrc"))) + { + return true; + } + + _logger.WarnAsync($"已经存在歌词文件 {path},跳过。").GetAwaiter().GetResult(); + return false; + }) + .ToList(); + } } \ No newline at end of file diff --git a/tests/ZonyLrcTools.Tests/Infrastructure/Album/NetEaseAlbumDownloader_Tests.cs b/tests/ZonyLrcTools.Tests/Infrastructure/Album/NetEaseAlbumDownloader_Tests.cs index 8cdd31f..d1be96d 100644 --- a/tests/ZonyLrcTools.Tests/Infrastructure/Album/NetEaseAlbumDownloader_Tests.cs +++ b/tests/ZonyLrcTools.Tests/Infrastructure/Album/NetEaseAlbumDownloader_Tests.cs @@ -14,8 +14,8 @@ namespace ZonyLrcTools.Tests.Infrastructure.Album [Fact] public async Task DownloadDataAsync_Test() { - var downloader = ServiceProvider.GetRequiredService>() - .FirstOrDefault(x => x.DownloaderName == InternalAlbumDownloaderNames.NetEase); + var downloader = ServiceProvider.GetRequiredService>() + .FirstOrDefault(x => x.DownloaderName == InternalAlbumProviderNames.NetEase); downloader.ShouldNotBeNull(); var albumBytes = await downloader.DownloadAsync("东方红", null); diff --git a/tests/ZonyLrcTools.Tests/Infrastructure/Album/QQMusicAlbumDownloaderTests.cs b/tests/ZonyLrcTools.Tests/Infrastructure/Album/QQMusicAlbumDownloaderTests.cs index 529d863..37646d7 100644 --- a/tests/ZonyLrcTools.Tests/Infrastructure/Album/QQMusicAlbumDownloaderTests.cs +++ b/tests/ZonyLrcTools.Tests/Infrastructure/Album/QQMusicAlbumDownloaderTests.cs @@ -12,8 +12,8 @@ namespace ZonyLrcTools.Tests.Infrastructure.Album { public async Task DownloadDataAsync_Test() { - var downloader = ServiceProvider.GetRequiredService>() - .FirstOrDefault(x => x.DownloaderName == InternalAlbumDownloaderNames.QQ); + var downloader = ServiceProvider.GetRequiredService>() + .FirstOrDefault(x => x.DownloaderName == InternalAlbumProviderNames.QQ); downloader.ShouldNotBeNull(); var albumBytes = await downloader.DownloadAsync("东方红", null);