diff --git a/README.md b/README.md
index de9f1ad..dafe687 100644
--- a/README.md
+++ b/README.md
@@ -69,6 +69,12 @@ macOS 和 Linux 用户请打开终端,切换到软件目录,一样执行命
例如获取地址 [https://music.163.com/#/playlist?id=158010361](https://music.163.com/#/playlist?id=158010361) 的歌单信息,那么歌单 ID 就应该传递 158010361。
+如果你需要获取多个歌单的歌曲数据,请在传递歌单 ID 时使用分号 `;` 指定多个 ID,例如下面的命令就是下载两个歌单的歌曲数据。
+
+```shell
+.\ZonyLrcTools.Cli.exe download -sc netease -o "D:\TempFiles" -s "7224428149;158010361" -l
+```
+
由于网易云音乐的限制,要想获取完整的歌单信息,必须扫码登录程序,还是以最上面的为例,我需要下载歌单内的歌词数据,就必须扫码之后程序才会执行。

diff --git a/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs b/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs
index 802c584..0fd0c61 100644
--- a/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs
+++ b/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs
@@ -37,11 +37,11 @@ public class NetEaseMusicSongListMusicScanner : ISingletonDependency
///
/// 从网易云歌单获取需要下载的歌曲列表,调用这个 API 需要用户登录,否则获取的歌单数据不全。
///
- /// 网易云音乐歌单的 ID。
+ /// 网易云音乐歌单的 ID。
/// 歌词文件的输出路径。
/// 输出的歌词文件格式,默认是 "{Artist} - {Title}.lrc" 的形式。
/// 返回获取到的歌曲列表。
- public async Task> GetMusicInfoFromNetEaseMusicSongListAsync(string songListId, string outputDirectory, string pattern)
+ public async Task> GetMusicInfoFromNetEaseMusicSongListAsync(string songListIds, string outputDirectory, string pattern)
{
if (string.IsNullOrEmpty(Cookie))
{
@@ -50,40 +50,52 @@ public class NetEaseMusicSongListMusicScanner : ISingletonDependency
CsrfToken = loginResponse.csrfToken ?? string.Empty;
}
- var secretKey = NetEaseMusicEncryptionHelper.CreateSecretKey(16);
- var encSecKey = NetEaseMusicEncryptionHelper.RsaEncode(secretKey);
- var response = await _warpHttpClient.PostAsync(
- $"{Host}/weapi/v6/playlist/detail?csrf_token=e5044820d8b66e14b8c31d39f9651a98", requestOption:
- request =>
- {
- request.Headers.Add("Cookie", Cookie);
- request.Content = new FormUrlEncodedContent(HandleRequest(new
- {
- csrf_token = CsrfToken,
- id = songListId,
- n = 1000,
- offset = 0,
- total = true,
- limit = 1000,
- }, secretKey, encSecKey));
- request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
- });
-
- if (response.Code != 200 || response.PlayList?.SongList == null)
+ async Task> GetMusicInfoBySongIdAsync(string songId)
{
- throw new ErrorCodeException(ErrorCodes.NotSupportedFileEncoding);
+ var secretKey = NetEaseMusicEncryptionHelper.CreateSecretKey(16);
+ var encSecKey = NetEaseMusicEncryptionHelper.RsaEncode(secretKey);
+ var response = await _warpHttpClient.PostAsync(
+ $"{Host}/weapi/v6/playlist/detail?csrf_token={CsrfToken}", requestOption:
+ request =>
+ {
+ request.Headers.Add("Cookie", Cookie);
+ request.Content = new FormUrlEncodedContent(HandleRequest(new
+ {
+ csrf_token = CsrfToken,
+ id = songId,
+ n = 1000,
+ offset = 0,
+ total = true,
+ limit = 1000,
+ }, secretKey, encSecKey));
+ request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
+ });
+
+ if (response.Code != 200 || response.PlayList?.SongList == null)
+ {
+ throw new ErrorCodeException(ErrorCodes.NotSupportedFileEncoding);
+ }
+
+ return response.PlayList.SongList
+ .Where(song => !string.IsNullOrEmpty(song.Name))
+ .Select(song =>
+ {
+ var artistName = song.Artists?.FirstOrDefault()?.Name ?? string.Empty;
+ var fakeFilePath = Path.Combine(outputDirectory, pattern.Replace("{Name}", song.Name).Replace("{Artist}", artistName));
+
+ return new MusicInfo(fakeFilePath, song.Name!, artistName);
+ }).ToList();
}
- return response.PlayList.SongList
- .Where(song => !string.IsNullOrEmpty(song.Name))
- .Select(song =>
- {
- var artistName = song.Artists?.FirstOrDefault()?.Name ?? string.Empty;
- var fakeFilePath = Path.Combine(outputDirectory, pattern.Replace("{Name}", song.Name).Replace("{Artist}", artistName));
+ var musicInfoList = new List();
+ foreach (var songListId in songListIds.Split(';'))
+ {
+ _logger.LogInformation("正在获取歌单 {SongListId} 的歌曲列表。", songListId);
+ var musicInfos = await GetMusicInfoBySongIdAsync(songListId);
+ musicInfoList.AddRange(musicInfos);
+ }
- var info = new MusicInfo(fakeFilePath, song.Name!, artistName);
- return info;
- }).ToList();
+ return musicInfoList;
}
///