網易雲和QQ音樂api
最近有點閒,聽歌的時候遇見好聽的想下載卻遇到尷尬的事,版權!唉,知道我幹什麼了吧
網易雲音樂
獲取排行榜中的歌曲列表
https://music.163.com/discover/toplist?id=
引數id:左側分類的id,比如雲音樂熱歌榜:3778678
獲取具體歌曲連結
http://music.163.com/weapi/song/enhance/player/url?csrf_token=&ids=xxx&br=999000
引數:ids:歌曲id集合,br歌曲位元速率
獲取歌詞:
http://music.163.com/weapi/song/lyric?csrf_token=&id=xxx&os=pc&lv-1&kv=-1&tv=-1
引數:id:歌曲id
網易雲的引數先經過JSON序列化然後進行加密,所有加密程式碼:
需要用到的一些Head及引數:
#region 屬性 private string _MODULUS = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7View Code"; private string _NONCE = "0CoJUm6Qyw8W8jud"; private string _PUBKEY = "010001"; private string _VI = "0102030405060708"; private string _USERAGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"; private string_COOKIE = "os=pc;osver=Microsoft-Windows-10-Professional-build-16299.125-64bit;appver=2.0.3.131777;channel=netease;__remember_me=true"; private string _REFERER = "http://music.163.com/"; // use keygen in c# private string _secretKey; private string _encSecKey; #endregion
加密方法:
private string CreateSecretKey(int length) { var str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; var r = ""; var rnd = new Random(); for (int i = 0; i < length; i++) { r += str[rnd.Next(0, str.Length)]; } return r; } private Dictionary<string, string> Prepare(string raw) { Dictionary<string, string> data = new Dictionary<string, string>(); data["params"] = AESEncode(raw, _NONCE); data["params"] = AESEncode(data["params"], _secretKey); data["encSecKey"] = _encSecKey; return data; } private string RSAEncode(string text) { string srtext = new string(text.Reverse().ToArray()); ; var a = BCHexDec(BitConverter.ToString(Encoding.Default.GetBytes(srtext)).Replace("-", "")); var b = BCHexDec(_PUBKEY); var c = BCHexDec(_MODULUS); var key = BigInteger.ModPow(a, b, c).ToString("x"); key = key.PadLeft(256, '0'); if (key.Length > 256) return key.Substring(key.Length - 256, 256); else return key; } private BigInteger BCHexDec(string hex) { BigInteger dec = new BigInteger(0); int len = hex.Length; for (int i = 0; i < len; i++) { dec += BigInteger.Multiply(new BigInteger(Convert.ToInt32(hex[i].ToString(), 16)), BigInteger.Pow(new BigInteger(16), len - i - 1)); } return dec; } private string AESEncode(string secretData, string secret = "TA3YiYCfY2dDJQgg") { byte[] encrypted; byte[] IV = Encoding.UTF8.GetBytes(_VI); using (var aes = Aes.Create()) { aes.Key = Encoding.UTF8.GetBytes(secret); aes.IV = IV; aes.Mode = CipherMode.CBC; using (var encryptor = aes.CreateEncryptor()) { using (var stream = new MemoryStream()) { using (var cstream = new CryptoStream(stream, encryptor, CryptoStreamMode.Write)) { using (var sw = new StreamWriter(cstream)) { sw.Write(secretData); } encrypted = stream.ToArray(); } } } } return Convert.ToBase64String(encrypted); } private string CURL(string url, Dictionary<string, string> parms, string method = "POST") { string result; using (var wc = new WebClient()) { wc.Headers.Add(HttpRequestHeader.ContentType, "application/x-www-form-urlencoded"); wc.Headers.Add(HttpRequestHeader.Referer, _REFERER); wc.Headers.Add(HttpRequestHeader.UserAgent, _USERAGENT); wc.Headers.Add(HttpRequestHeader.Cookie, _COOKIE); var reqparm = new System.Collections.Specialized.NameValueCollection(); foreach (var keyPair in parms) { reqparm.Add(keyPair.Key, keyPair.Value); } byte[] responsebytes = wc.UploadValues(url, method, reqparm); result = Encoding.UTF8.GetString(responsebytes); } return result; }View Code
獲取歌曲詳情呼叫方法:
public DetailResult Detail(long song_id) { string url = "http://music.163.com/weapi/v3/song/detail?csrf_token="; var data = new Dictionary<string, string> { { "c", "[" + JsonConvert.SerializeObject(new Dictionary<string, string> { //神tm 加密的json裡套json mdzz (說不定一次可以查多首歌?) { "id", song_id.ToString() } }) + "]" }, {"csrf_token",""}, }; string raw = CURL(url, Prepare(JsonConvert.SerializeObject(data))); var deserialedObj = JsonConvert.DeserializeObject<DetailResult>(raw); return deserialedObj; }View Code
QQ音樂
獲取排行榜類別
https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_opt.fcg?page=index&format=html&tpl=macv4&v8debug=1
獲取排行榜中的歌曲
https://c.y.qq.com/v8/fcg-bin/fcg_v8_toplist_cp.fcg?tpl=3&page=detail&date={update_key}&topid={Id}&type=top&song_begin=0&song_num=30}&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0
引數:id:排行榜的類別id,song_num 每頁顯示的條數
獲取歌曲連結
https://u.y.qq.com/cgi-bin/musicu.fcg?-=getplaysongvkey7202785251801513&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data=%7B%22req%22%3A%7B%22module%22%3A%22CDN.SrfCdnDispatchServer%22%2C%22method%22%3A%22GetCdnDispatch%22%2C%22param%22%3A%7B%22guid%22%3A%229756534816%22%2C%22calltype%22%3A0%2C%22userip%22%3A%22%22%7D%7D%2C%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%226541487400%22%2C%22songmid%22%3A%5B%22{mid}%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%220%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A0%2C%22format%22%3A%22json%22%2C%22ct%22%3A20%2C%22cv%22%3A0%7D%7D
引數:mid:歌曲的mid
private string GetSongUrl(string mid) { var url = $"https://u.y.qq.com/cgi-bin/musicu.fcg?-=getplaysongvkey7202785251801513&g_tk=5381&loginUin=0&hostUin=0&format=json&inCharset=utf8&outCharset=utf-8¬ice=0&platform=yqq.json&needNewCode=0&data=%7B%22req%22%3A%7B%22module%22%3A%22CDN.SrfCdnDispatchServer%22%2C%22method%22%3A%22GetCdnDispatch%22%2C%22param%22%3A%7B%22guid%22%3A%229756534816%22%2C%22calltype%22%3A0%2C%22userip%22%3A%22%22%7D%7D%2C%22req_0%22%3A%7B%22module%22%3A%22vkey.GetVkeyServer%22%2C%22method%22%3A%22CgiGetVkey%22%2C%22param%22%3A%7B%22guid%22%3A%226541487400%22%2C%22songmid%22%3A%5B%22{mid}%22%5D%2C%22songtype%22%3A%5B0%5D%2C%22uin%22%3A%220%22%2C%22loginflag%22%3A1%2C%22platform%22%3A%2220%22%7D%7D%2C%22comm%22%3A%7B%22uin%22%3A0%2C%22format%22%3A%22json%22%2C%22ct%22%3A20%2C%22cv%22%3A0%7D%7D"; WebClient client = new WebClient(); client.Encoding = Encoding.UTF8; var result = client.DownloadString(url); }View Code
獲取歌詞:
https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid={songmid}&g_tk=5381
引數:songmid:歌曲id
var url = $"https://c.y.qq.com/lyric/fcgi-bin/fcg_query_lyric_new.fcg?songmid={songmid}&g_tk=5381"; WebClient client = new WebClient(); client.Headers.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.110 Safari/537.36"); client.Headers.Add("Accept", "*/*"); client.Headers.Add("Referer", "https://y.qq.com/portal/player.html"); client.Headers.Add("Accept-Language", "zh-CN,zh;q=0.8"); client.Headers.Add("Cookie", "tvfe_boss_uuid=c3db0dcc4d677c60; pac_uid=1_2728578956; qq_slist_autoplay=on; ts_refer=ADTAGh5_playsong; RK=pKOOKi2f1O; pgv_pvi=8927113216; o_cookie=2728578956; pgv_pvid=5107924810; ptui_loginuin=2728578956; ptcz=897c17d7e17ae9009e018ebf3f818355147a3a26c6c67a63ae949e24758baa2d; pt2gguin=o2728578956; pgv_si=s5715204096; qqmusic_fromtag=66; yplayer_open=1; ts_last=y.qq.com/portal/player.html; ts_uid=996779984; yq_index=0"); client.Headers.Add("Host", "c.y.qq.com"); var result = client.DownloadString(url); result = result.Substring(result.IndexOf('(') + 1); result = result.Substring(0, result.LastIndexOf(')')); var data = JsonConvert.DeserializeObject<dynamic>(result);View Code
歌詞是經過base64進行加密的,所以獲取後需要進行base64解密
/// <summary> /// Base64解碼 /// </summary> /// <param name="Message"></param> /// <returns></returns> public static string Base64Decode(string Message) { if ((Message.Length % 4) != 0) { throw new ArgumentException("不是正確的BASE64編碼,請檢查。", "Message"); } if (!System.Text.RegularExpressions.Regex.IsMatch(Message, "^[A-Z0-9/+=]*$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)) { throw new ArgumentException("包含不正確的BASE64編碼,請檢查。", "Message"); } string Base64Code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; int page = Message.Length / 4; System.Collections.ArrayList outMessage = new System.Collections.ArrayList(page * 3); char[] message = Message.ToCharArray(); for (int i = 0; i < page; i++) { byte[] instr = new byte[4]; instr[0] = (byte)Base64Code.IndexOf(message[i * 4]); instr[1] = (byte)Base64Code.IndexOf(message[i * 4 + 1]); instr[2] = (byte)Base64Code.IndexOf(message[i * 4 + 2]); instr[3] = (byte)Base64Code.IndexOf(message[i * 4 + 3]); byte[] outstr = new byte[3]; outstr[0] = (byte)((instr[0] << 2) ^ ((instr[1] & 0x30) >> 4)); if (instr[2] != 64) { outstr[1] = (byte)((instr[1] << 4) ^ ((instr[2] & 0x3c) >> 2)); } else { outstr[2] = 0; } if (instr[3] != 64) { outstr[2] = (byte)((instr[2] << 6) ^ instr[3]); } else { outstr[2] = 0; } outMessage.Add(outstr[0]); if (outstr[1] != 0) outMessage.Add(outstr[1]); if (outstr[2] != 0) outMessage.Add(outstr[2]); } byte[] outbyte = (byte[])outMessage.ToArray(Type.GetType("System.Byte")); return Encoding.UTF8.GetString(outbyte); }View Code
完整專案地址:Demo