网易云.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. function netease(packages) {
  2. const { axios, CryptoJs, qs, bigInt, dayjs } = packages;
  3. /** 内部的函数 */
  4. function a() {
  5. var d, e, b = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", c = "";
  6. for (d = 0; 16 > d; d += 1)
  7. e = Math.random() * b.length,
  8. e = Math.floor(e),
  9. c += b.charAt(e);
  10. return c
  11. }
  12. function b(a, b) {
  13. var c = CryptoJs.enc.Utf8.parse(b)
  14. , d = CryptoJs.enc.Utf8.parse("0102030405060708")
  15. , e = CryptoJs.enc.Utf8.parse(a)
  16. , f = CryptoJs.AES.encrypt(e, c, {
  17. iv: d,
  18. mode: CryptoJs.mode.CBC
  19. });
  20. return f.toString()
  21. }
  22. function c(text) {
  23. text = text.split('').reverse().join('');
  24. const d = '010001';
  25. const e = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7';
  26. const hexText = text.split('').map(_ => _.charCodeAt(0).toString(16)).join('');
  27. const res = bigInt(hexText, 16).modPow(bigInt(d, 16), bigInt(e, 16)).toString(16);
  28. return Array(256 - res.length).fill('0').join('').concat(res);
  29. }
  30. function getParamsAndEnc(text) {
  31. const first = b(text, '0CoJUm6Qyw8W8jud');
  32. const rand = a();
  33. const params = b(first, rand);
  34. const encSecKey = c(rand);
  35. return {
  36. params,
  37. encSecKey
  38. }
  39. }
  40. function formatMusicItem(_) {
  41. const album = _.al || _.album;
  42. return ({
  43. id: _.id,
  44. artwork: album.picUrl,
  45. title: _.name,
  46. artist: (_.ar || _.artists)[0].name,
  47. album: album.name
  48. })
  49. }
  50. function formatAlbumItem(_) {
  51. return ({
  52. id: _.id,
  53. artist: _.artist.name,
  54. title: _.name,
  55. artwork: _.picUrl,
  56. description: '',
  57. date: dayjs.unix(_.publishTime / 1000).format("YYYY-MM-DD"),
  58. });
  59. }
  60. function musicCanPlayFilter(_) {
  61. return ((_.fee === 0) || _.fee === 8) && _.privilege.st >= 0;
  62. }
  63. const pageSize = 30;
  64. async function searchBase(query, page, type) {
  65. const data = {
  66. 's': query,
  67. 'limit': pageSize,
  68. 'type': type,
  69. 'offset': (page - 1) * pageSize,
  70. 'csrf_token': ''
  71. }
  72. const pae = getParamsAndEnc(JSON.stringify(data));
  73. const paeData = qs.stringify(pae);
  74. const headers = {
  75. 'authority': 'music.163.com',
  76. 'user-agent':
  77. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
  78. 'content-type': 'application/x-www-form-urlencoded',
  79. 'accept': '*/*',
  80. 'origin': 'https://music.163.com',
  81. 'sec-fetch-site': 'same-origin',
  82. 'sec-fetch-mode': 'cors',
  83. 'sec-fetch-dest': 'empty',
  84. 'referer': 'https://music.163.com/search/',
  85. 'accept-language': 'zh-CN,zh;q=0.9',
  86. }
  87. const res = (await axios({
  88. method: 'post',
  89. url: 'https://music.163.com/weapi/cloudsearch/get/web?csrf_token=',
  90. headers,
  91. data: paeData
  92. })).data;
  93. return res;
  94. }
  95. async function searchMusic(query, page) {
  96. const res = await searchBase(query, page, 1);
  97. const songs = res.result.songs.filter(musicCanPlayFilter).map(formatMusicItem)
  98. return {
  99. isEnd: res.result.songCount <= page * pageSize,
  100. data: songs
  101. }
  102. }
  103. async function searchAlbum(query, page) {
  104. const res = await searchBase(query, page, 10);
  105. const albums = res.result.albums.map(formatAlbumItem)
  106. return {
  107. isEnd: res.result.albumCount <= page * pageSize,
  108. data: albums
  109. }
  110. }
  111. async function searchArtist(query, page) {
  112. const res = await searchBase(query, page, 100);
  113. const artists = res.result.artists.map(_ => ({
  114. name: _.name,
  115. id: _.id,
  116. avatar: _.img1v1Url,
  117. worksNum: _.albumSize
  118. }))
  119. return {
  120. isEnd: res.result.artistCount <= page * pageSize,
  121. data: artists
  122. }
  123. }
  124. async function getArtistWorks(artistItem, page, type) {
  125. const data = {
  126. 'csrf_token': ''
  127. }
  128. const pae = getParamsAndEnc(JSON.stringify(data));
  129. const paeData = qs.stringify(pae);
  130. const headers = {
  131. 'authority': 'music.163.com',
  132. 'user-agent':
  133. 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
  134. 'content-type': 'application/x-www-form-urlencoded',
  135. 'accept': '*/*',
  136. 'origin': 'https://music.163.com',
  137. 'sec-fetch-site': 'same-origin',
  138. 'sec-fetch-mode': 'cors',
  139. 'sec-fetch-dest': 'empty',
  140. 'referer': 'https://music.163.com/search/',
  141. 'accept-language': 'zh-CN,zh;q=0.9',
  142. }
  143. if (type === 'music') {
  144. const res = (await axios({
  145. method: 'post',
  146. url: `https://music.163.com/weapi/v1/artist/${artistItem.id}?csrf_token=`,
  147. headers,
  148. data: paeData
  149. })).data;
  150. return {
  151. isEnd: true,
  152. data: res.hotSongs.filter(musicCanPlayFilter).map(formatMusicItem)
  153. }
  154. } else if (type === 'album') {
  155. const res = (await axios({
  156. method: 'post',
  157. url: `https://music.163.com/weapi/artist/albums/${artistItem.id}?csrf_token=`,
  158. headers,
  159. data: paeData
  160. })).data;
  161. return {
  162. isEnd: true,
  163. data: res.hotAlbums.map(formatAlbumItem)
  164. }
  165. }
  166. }
  167. async function getLyric(musicItem) {
  168. const headers = {
  169. 'Referer': 'https://y.music.163.com/',
  170. 'Origin': 'https://y.music.163.com/',
  171. 'authority': 'music.163.com',
  172. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
  173. 'Content-Type': 'application/x-www-form-urlencoded',
  174. };
  175. const data = { id: musicItem.id, lv: -1, tv: -1, csrf_token: '' }
  176. const pae = getParamsAndEnc(JSON.stringify(data));
  177. const paeData = qs.stringify(pae);
  178. const result = (await axios({
  179. method: 'post',
  180. url: `https://interface.music.163.com/weapi/song/lyric?csrf_token=`,
  181. headers,
  182. data: paeData
  183. })).data;
  184. return {
  185. rawLrc: result.lrc.lyric
  186. }
  187. }
  188. async function getAlbumInfo(albumItem) {
  189. const headers = {
  190. 'Referer': 'https://y.music.163.com/',
  191. 'Origin': 'https://y.music.163.com/',
  192. 'authority': 'music.163.com',
  193. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
  194. 'Content-Type': 'application/x-www-form-urlencoded',
  195. };
  196. const data = { "resourceType": 3, "resourceId": albumItem.id, "limit": 15, "csrf_token": "" }
  197. const pae = getParamsAndEnc(JSON.stringify(data));
  198. const paeData = qs.stringify(pae);
  199. const res = (await axios({
  200. method: 'post',
  201. url: `https://interface.music.163.com/weapi/v1/album/${albumItem.id}?csrf_token=`,
  202. headers,
  203. data: paeData
  204. })).data;
  205. return {
  206. ...albumItem,
  207. description: res.album.description,
  208. musicList: (res.songs || []).filter(musicCanPlayFilter).map(formatMusicItem)
  209. }
  210. }
  211. async function getValidMusicItems(trackIds) {
  212. const headers = {
  213. 'Referer': 'https://y.music.163.com/',
  214. 'Origin': 'https://y.music.163.com/',
  215. 'authority': 'music.163.com',
  216. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
  217. 'Content-Type': 'application/x-www-form-urlencoded'
  218. };
  219. try {
  220. const data = { csrf_token: '', ids: `[${trackIds.join(',')}]`, level: 'standard', encodeType: 'flac' }
  221. const pae = getParamsAndEnc(JSON.stringify(data));
  222. const urlencoded = qs.stringify(pae);
  223. const res = (await axios({
  224. method: 'post',
  225. url: `https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token=`,
  226. headers,
  227. data: urlencoded
  228. })).data;
  229. const validTrackIds = res.data.filter(_ => _.url).map(_ => _.id);
  230. const songDetails = (await axios.get(`https://music.163.com/api/song/detail/?id=${validTrackIds[0]}&ids=[${validTrackIds.join(',')}]`, { headers })).data;
  231. const validMusicItems = songDetails.songs.filter(_ => ((_.fee === 0) || _.fee === 8)).map(formatMusicItem);
  232. return validMusicItems;
  233. } catch(e) {
  234. return []
  235. }
  236. }
  237. async function importMusicSheet(urlLike) {
  238. const matchResult = urlLike.match(/(?:https:\/\/y\.music\.163.com\/m\/playlist\?id=([0-9]+))|(?:https?:\/\/music\.163\.com\/playlist\/([0-9]+)\/.*)/);
  239. const id = matchResult[1] || matchResult[2];
  240. const headers = {
  241. 'Referer': 'https://y.music.163.com/',
  242. 'Origin': 'https://y.music.163.com/',
  243. 'authority': 'music.163.com',
  244. 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.135 Safari/537.36',
  245. };
  246. const sheetDetail = (await axios.get(`https://music.163.com/api/v3/playlist/detail?id=${id}&n=5000`, {
  247. headers
  248. })).data;
  249. const trackIds = sheetDetail.playlist.trackIds.map(_ => _.id);
  250. let result = [];
  251. let idx = 0;
  252. while((idx * 200) < trackIds.length) {
  253. const res = await getValidMusicItems(trackIds.slice(idx * 200, (idx + 1) * 200));
  254. result = result.concat(res);
  255. ++idx;
  256. }
  257. return result;
  258. }
  259. return {
  260. platform: '网易云',
  261. version: '0.0.6',
  262. srcUrl: 'https://gitee.com/maotoumao/MusicFreePlugins/raw/master/netease.js',
  263. cacheControl: 'no-store',
  264. async search(query, page, type) {
  265. if (type === 'music') {
  266. return await searchMusic(query, page);
  267. }
  268. if (type === 'album') {
  269. return await searchAlbum(query, page);
  270. }
  271. if (type === 'artist') {
  272. return await searchArtist(query, page);
  273. }
  274. },
  275. getMediaSource(musicItem) {
  276. return {
  277. url: `https://music.163.com/song/media/outer/url?id=${musicItem.id}.mp3`
  278. };
  279. },
  280. getAlbumInfo,
  281. getLyric,
  282. getArtistWorks,
  283. importMusicSheet
  284. }
  285. }