From 9a029225e1dc0bdf1f4c1f89782b06e24fc4f8d1 Mon Sep 17 00:00:00 2001 From: real-zony Date: Fri, 17 Feb 2023 23:05:32 +0800 Subject: [PATCH] chore: Working... --- .../SubCommand/ManualDownloadCommand.cs | 15 +++ .../NetEaseMusicSongListMusicScanner.cs | 109 ++++++++++++++++++ .../QQMusicSongListMusicScanner.cs | 5 + .../NetEaseMusicSongListMusicScannerTests.cs | 5 + 4 files changed, 134 insertions(+) create mode 100644 src/ZonyLrcTools.Cli/Commands/SubCommand/ManualDownloadCommand.cs create mode 100644 src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs create mode 100644 src/ZonyLrcTools.Common/MusicScanner/QQMusicSongListMusicScanner.cs create mode 100644 tests/ZonyLrcTools.Tests/MusicScanner/NetEaseMusicSongListMusicScannerTests.cs diff --git a/src/ZonyLrcTools.Cli/Commands/SubCommand/ManualDownloadCommand.cs b/src/ZonyLrcTools.Cli/Commands/SubCommand/ManualDownloadCommand.cs new file mode 100644 index 0000000..a629ac5 --- /dev/null +++ b/src/ZonyLrcTools.Cli/Commands/SubCommand/ManualDownloadCommand.cs @@ -0,0 +1,15 @@ +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; + } +} \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs b/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs new file mode 100644 index 0000000..f9b02c4 --- /dev/null +++ b/src/ZonyLrcTools.Common/MusicScanner/NetEaseMusicSongListMusicScanner.cs @@ -0,0 +1,109 @@ +using System.Security.Cryptography; +using System.Text; +using ZonyLrcTools.Common.Infrastructure.DependencyInject; + +namespace ZonyLrcTools.Common.MusicScanner; + +public class NetEaseMusicSongListMusicScanner : ITransientDependency +{ +} + +public interface INetEaseMusicSongListMusicScanner +{ +} + +/// +/// +/// +/// +/// Reference github links: +/// https://github.com/Quandong-Zhang/easynet-playlist-downloader/blob/main/main.py +/// https://github.com/mos9527/pyncm/blob/master/pyncm/apis/login.py +/// +public class NetEaseMusicSessionManager : INetEaseMusicSongListMusicScanner, ISingletonDependency +{ +} + +public class NetEaseCrypto +{ + private readonly (long, long) WEAPI_RSA_PUBKEY = ( + Convert.ToInt64( + "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7", + 16), + Convert.ToInt64("10001", 16) // textbook rsa without padding + ); + + private const string Base62 = "PJArHa0dpwhvMNYqKnTbitWfEmosQ9527ZBx46IXUgOzD81VuSFyckLRljG3eC"; + private const string Base64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + private const string WEAPI_AES_KEY = "0CoJUm6Qyw8W8jud"; // cbc + private const string WEAPI_AES_IV = "0102030405060708"; // cbc + private const string LINUXAPI_AES_KEY = "rFgB&h#%2?^eDg:Q"; // ecb + private const string EAPI_DIGEST_SALT = "nobody%(url)suse%(text)smd5forencrypt"; + private const string EAPI_DATA_SALT = "%(url)s-36cd479b6b5-%(text)s-36cd479b6b5-%(digest)s"; + private const string EAPI_AES_KEY = "e82ckenh8dichen8"; // ecb + + public string WeApiEncrypt(string @params, string aesKey2 = null) + { + aesKey2 ??= RandomString(16); + // 1st go,encrypt the text with aes_key and aes_iv. + @params = AesEncrypt(@params, WEAPI_AES_KEY, WEAPI_AES_IV, CipherMode.CBC); + // 2nd go,encrypt the ENCRYPTED text again,with the 2nd key and aes_iv. + @params = AesEncrypt(@params, aesKey2, WEAPI_AES_IV); + // 3rd go,generate RSA encrypted encSecKey. + var encSecKey = HexDigest(RsaEncrypt(aesKey2, WEAPI_RSA_PUBKEY.Item1, WEAPI_RSA_PUBKEY.Item2)); + return $"params={@params}&encSecKey={encSecKey}"; + } + + public string AesEncrypt(string data, string key, string iv, CipherMode mode = CipherMode.CBC) + { + using (var aes = Aes.Create()) + { + aes.Key = Encoding.UTF8.GetBytes(key); + aes.IV = Encoding.UTF8.GetBytes(iv); + aes.Mode = mode; + aes.Padding = PaddingMode.PKCS7; + using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV)) + { + var plainBytes = System.Text.Encoding.UTF8.GetBytes(Pkcs7Pad(data)); + var encryptedBytes = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length); + return Convert.ToBase64String(encryptedBytes); + } + } + } + + private string Pkcs7Pad(string data, int bs = 16) + { + var padding = bs - data.Length % bs; + return data + new string((char)padding, padding); + } + + private string RandomString(int length, string chars = Base62) + { + var random = new Random(); + return string.Join("", Enumerable.Range(0, length).Select(_ => chars[random.Next(chars.Length)])); + } + + private string HexDigest(byte[] data) + { + return string.Join("", data.Select(b => b.ToString("X2"))); + } + + static byte[] RsaEncrypt(string data, long n, long e, bool reverse = true) + { + var m = reverse ? data.Reverse() : data; + var mBytes = Encoding.UTF8.GetBytes(string.Join("", m)); + var mHex = BitConverter.ToString(mBytes).Replace("-", string.Empty); + var mInt = int.Parse(mHex, System.Globalization.NumberStyles.HexNumber); + var r = (int)Math.Pow(mInt, e) % n; + return BitConverter.GetBytes(r); + } + + static string HexCompose(string hex) + { + return BitConverter.ToString(Enumerable.Range(0, hex.Length) + .Where(x => x % 2 == 0) + .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) + .ToArray()); + } +} \ No newline at end of file diff --git a/src/ZonyLrcTools.Common/MusicScanner/QQMusicSongListMusicScanner.cs b/src/ZonyLrcTools.Common/MusicScanner/QQMusicSongListMusicScanner.cs new file mode 100644 index 0000000..573d80c --- /dev/null +++ b/src/ZonyLrcTools.Common/MusicScanner/QQMusicSongListMusicScanner.cs @@ -0,0 +1,5 @@ +// namespace ZonyLrcTools.Common.MusicScanner; +// +// public class QQMusicSongListMusicScanner : IMusicScanner +// { +// } \ No newline at end of file diff --git a/tests/ZonyLrcTools.Tests/MusicScanner/NetEaseMusicSongListMusicScannerTests.cs b/tests/ZonyLrcTools.Tests/MusicScanner/NetEaseMusicSongListMusicScannerTests.cs new file mode 100644 index 0000000..968100d --- /dev/null +++ b/tests/ZonyLrcTools.Tests/MusicScanner/NetEaseMusicSongListMusicScannerTests.cs @@ -0,0 +1,5 @@ +namespace ZonyLrcTools.Tests.MusicScanner; + +public class NetEaseMusicSongListMusicScannerTests : TestBase +{ +} \ No newline at end of file