@neteasecloudmusicapienhanced/api 4.30.1 → 4.30.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/public/cloud.html CHANGED
@@ -47,6 +47,59 @@
47
47
  text-decoration: underline;
48
48
  }
49
49
 
50
+ .mode-section {
51
+ margin-bottom: 24px;
52
+ padding: 16px;
53
+ background: #f9f9f9;
54
+ border-radius: 8px;
55
+ }
56
+
57
+ .mode-section label {
58
+ display: block;
59
+ font-size: 14px;
60
+ font-weight: 500;
61
+ color: #333;
62
+ margin-bottom: 12px;
63
+ }
64
+
65
+ .mode-options {
66
+ display: flex;
67
+ gap: 16px;
68
+ flex-wrap: wrap;
69
+ }
70
+
71
+ .mode-option {
72
+ display: flex;
73
+ align-items: flex-start;
74
+ gap: 8px;
75
+ cursor: pointer;
76
+ }
77
+
78
+ .mode-option input[type="radio"] {
79
+ margin-top: 3px;
80
+ }
81
+
82
+ .mode-option-text {
83
+ display: flex;
84
+ flex-direction: column;
85
+ }
86
+
87
+ .mode-option-title {
88
+ font-size: 14px;
89
+ color: #333;
90
+ }
91
+
92
+ .mode-option-desc {
93
+ font-size: 12px;
94
+ color: #999;
95
+ margin-top: 2px;
96
+ }
97
+
98
+ .mode-option input[type="radio"]:checked + .mode-option-text .mode-option-title {
99
+ color: #333;
100
+ font-weight: 500;
101
+ }
102
+
50
103
  .upload-section {
51
104
  margin-bottom: 32px;
52
105
  }
@@ -72,6 +125,11 @@
72
125
  display: none;
73
126
  }
74
127
 
128
+ .upload-btn.disabled {
129
+ background: #ccc;
130
+ cursor: not-allowed;
131
+ }
132
+
75
133
  .songs-list {
76
134
  list-style: none;
77
135
  }
@@ -99,6 +157,74 @@
99
157
  padding: 20px;
100
158
  color: #666;
101
159
  }
160
+
161
+ .progress-section {
162
+ margin-bottom: 24px;
163
+ display: none;
164
+ }
165
+
166
+ .progress-section.active {
167
+ display: block;
168
+ }
169
+
170
+ .progress-item {
171
+ margin-bottom: 12px;
172
+ padding: 12px;
173
+ background: #f9f9f9;
174
+ border-radius: 6px;
175
+ }
176
+
177
+ .progress-item .name {
178
+ font-size: 14px;
179
+ color: #333;
180
+ margin-bottom: 8px;
181
+ word-break: break-all;
182
+ }
183
+
184
+ .progress-item .status {
185
+ font-size: 12px;
186
+ color: #666;
187
+ margin-bottom: 6px;
188
+ }
189
+
190
+ .progress-bar {
191
+ height: 6px;
192
+ background: #e0e0e0;
193
+ border-radius: 3px;
194
+ overflow: hidden;
195
+ }
196
+
197
+ .progress-bar .fill {
198
+ height: 100%;
199
+ background: #333;
200
+ border-radius: 3px;
201
+ transition: width 0.3s ease;
202
+ width: 0%;
203
+ }
204
+
205
+ .progress-item.success .fill {
206
+ background: #4caf50;
207
+ }
208
+
209
+ .progress-item.error .fill {
210
+ background: #f44336;
211
+ }
212
+
213
+ .progress-item.error .status {
214
+ color: #f44336;
215
+ }
216
+
217
+ .info-text {
218
+ font-size: 12px;
219
+ color: #999;
220
+ margin-top: 8px;
221
+ }
222
+
223
+ .warning-text {
224
+ font-size: 12px;
225
+ color: #e65100;
226
+ margin-top: 8px;
227
+ }
102
228
  </style>
103
229
  </head>
104
230
 
@@ -107,13 +233,36 @@
107
233
  <h1>云盘上传</h1>
108
234
  <a href="/qrlogin-nocookie.html" class="login-link">还没登录?点击登录</a>
109
235
 
236
+ <div class="mode-section">
237
+ <label>上传模式</label>
238
+ <div class="mode-options">
239
+ <label class="mode-option">
240
+ <input type="radio" name="uploadMode" value="direct" checked />
241
+ <span class="mode-option-text">
242
+ <span class="mode-option-title">客户端直传</span>
243
+ <span class="mode-option-desc">文件直接上传到云存储,支持大文件,适合 Vercel 等平台</span>
244
+ </span>
245
+ </label>
246
+ <label class="mode-option">
247
+ <input type="radio" name="uploadMode" value="proxy" />
248
+ <span class="mode-option-text">
249
+ <span class="mode-option-title">后端代理</span>
250
+ <span class="mode-option-desc">文件通过服务器转发,更简洁,需要服务器支持大文件</span>
251
+ </span>
252
+ </label>
253
+ </div>
254
+ </div>
255
+
110
256
  <div class="upload-section">
111
- <label class="upload-btn">
257
+ <label class="upload-btn" id="uploadBtn">
112
258
  选择文件(支持多选)
113
259
  <input id="file" type="file" multiple accept="audio/*" />
114
260
  </label>
261
+ <p class="info-text" id="modeInfo">支持大文件上传,文件将直接传输到云存储服务器</p>
115
262
  </div>
116
263
 
264
+ <div id="progressSection" class="progress-section"></div>
265
+
117
266
  <div id="app">
118
267
  <div v-if="loading" class="loading">加载中...</div>
119
268
  <ul v-else-if="songs.length > 0" class="songs-list">
@@ -127,6 +276,7 @@
127
276
 
128
277
  <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
129
278
  <script src="https://fastly.jsdelivr.net/npm/vue@3"></script>
279
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jsmediatags/3.9.5/jsmediatags.min.js"></script>
130
280
  <script>
131
281
  const app = Vue.createApp({
132
282
  data() {
@@ -157,55 +307,272 @@
157
307
  },
158
308
  }).mount('#app')
159
309
 
160
- const fileUpdateTime = {}
161
- let fileLength = 0
310
+ let isUploading = false
311
+ let uploadMode = 'direct'
312
+ const progressSection = document.getElementById('progressSection')
313
+ const uploadBtn = document.getElementById('uploadBtn')
314
+ const fileInput = document.querySelector('input[type="file"]')
315
+ const modeInfo = document.getElementById('modeInfo')
316
+
317
+ document.querySelectorAll('input[name="uploadMode"]').forEach(radio => {
318
+ radio.addEventListener('change', function() {
319
+ uploadMode = this.value
320
+ if (uploadMode === 'direct') {
321
+ modeInfo.textContent = '支持大文件上传,文件将直接传输到云存储服务器'
322
+ modeInfo.className = 'info-text'
323
+ } else {
324
+ modeInfo.textContent = '文件将通过服务器转发,服务器需支持大文件上传(Vercel 限制 4.5MB)'
325
+ modeInfo.className = 'warning-text'
326
+ }
327
+ })
328
+ })
162
329
 
163
330
  function main() {
164
- document
165
- .querySelector('input[type="file"]')
166
- .addEventListener('change', function (e) {
167
- const files = this.files
168
- if (files.length === 0) return
169
-
170
- fileLength = files.length
171
- for (let i = 0; i < files.length; i++) {
172
- upload(files[i], i + 1)
173
- }
174
- })
331
+ fileInput.addEventListener('change', function (e) {
332
+ const files = this.files
333
+ if (files.length === 0) return
334
+ if (isUploading) return
335
+
336
+ uploadFilesSequentially(Array.from(files))
337
+ this.value = ''
338
+ })
175
339
  }
176
340
  main()
177
341
 
178
- function upload(file, currentIndex) {
179
- var formData = new FormData()
180
- formData.append('songFile', file)
342
+ async function uploadFilesSequentially(files) {
343
+ isUploading = true
344
+ uploadBtn.classList.add('disabled')
345
+ progressSection.classList.add('active')
346
+ progressSection.innerHTML = ''
181
347
 
182
- axios({
183
- method: 'post',
184
- url: `/cloud?time=${Date.now()}&cookie=${localStorage.getItem('cookie')}`,
185
- headers: {
186
- 'Content-Type': 'multipart/form-data',
187
- },
188
- data: formData,
189
- })
190
- .then((res) => {
191
- console.log(`${file.name} 上传成功`)
192
- if (currentIndex >= fileLength) {
193
- console.log('所有文件上传完毕')
194
- }
195
- app.getData()
348
+ for (let i = 0; i < files.length; i++) {
349
+ if (uploadMode === 'direct') {
350
+ await uploadFileDirect(files[i], i + 1, files.length)
351
+ } else {
352
+ await uploadFileProxy(files[i], i + 1, files.length)
353
+ }
354
+ }
355
+
356
+ isUploading = false
357
+ uploadBtn.classList.remove('disabled')
358
+ app.getData()
359
+ }
360
+
361
+ function createProgressItem(file, index, total) {
362
+ const item = document.createElement('div')
363
+ item.className = 'progress-item'
364
+ item.id = `progress-${index}`
365
+ item.innerHTML = `
366
+ <div class="name">${file.name} (${formatSize(file.size)})</div>
367
+ <div class="status">准备中...</div>
368
+ <div class="progress-bar"><div class="fill"></div></div>
369
+ `
370
+ progressSection.appendChild(item)
371
+ return item
372
+ }
373
+
374
+ function updateProgress(index, status, percent, isError = false) {
375
+ const item = document.getElementById(`progress-${index}`)
376
+ if (!item) return
377
+ item.querySelector('.status').textContent = status
378
+ item.querySelector('.fill').style.width = `${percent}%`
379
+ if (isError) {
380
+ item.classList.add('error')
381
+ } else if (percent >= 100) {
382
+ item.classList.add('success')
383
+ }
384
+ }
385
+
386
+ function formatSize(bytes) {
387
+ if (bytes < 1024) return bytes + ' B'
388
+ if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
389
+ return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
390
+ }
391
+
392
+ async function uploadFileProxy(file, index, total) {
393
+ createProgressItem(file, index, total)
394
+
395
+ try {
396
+ updateProgress(index, '上传中...', 10)
397
+
398
+ const formData = new FormData()
399
+ formData.append('songFile', file)
400
+
401
+ await axios({
402
+ method: 'post',
403
+ url: `/cloud?time=${Date.now()}&cookie=${localStorage.getItem('cookie')}`,
404
+ headers: {
405
+ 'Content-Type': 'multipart/form-data',
406
+ },
407
+ data: formData,
408
+ onUploadProgress: (progressEvent) => {
409
+ const percent = Math.round((progressEvent.loaded / progressEvent.total) * 90) + 10
410
+ updateProgress(index, `上传中... ${Math.round(progressEvent.loaded / progressEvent.total * 100)}%`, Math.min(percent, 100))
411
+ },
412
+ timeout: 600000,
196
413
  })
197
- .catch((err) => {
198
- console.error(`${file.name} 上传失败:`, err)
199
- fileUpdateTime[file.name] = (fileUpdateTime[file.name] || 0) + 1
200
- if (fileUpdateTime[file.name] >= 4) {
201
- console.error(`文件 ${file.name} 上传失败次数过多,已停止重试`)
202
- return
414
+
415
+ updateProgress(index, '上传完成!', 100)
416
+
417
+ } catch (err) {
418
+ console.error(`${file.name} 上传失败:`, err)
419
+ const errorMsg = err.response?.data?.msg || err.message || '未知错误'
420
+ if (err.response?.status === 413 || errorMsg.includes('PAYLOAD_TOO_LARGE')) {
421
+ updateProgress(index, '文件过大,请切换到客户端直传模式', 0, true)
422
+ } else {
423
+ updateProgress(index, `上传失败: ${errorMsg}`, 0, true)
424
+ }
425
+ }
426
+ }
427
+
428
+ async function calculateMD5(file) {
429
+ return new Promise((resolve, reject) => {
430
+ const chunkSize = 2 * 1024 * 1024
431
+ const chunks = Math.ceil(file.size / chunkSize)
432
+ let currentChunk = 0
433
+ const spark = new SparkMD5.ArrayBuffer()
434
+ const reader = new FileReader()
435
+
436
+ reader.onload = (e) => {
437
+ spark.append(e.target.result)
438
+ currentChunk++
439
+ if (currentChunk < chunks) {
440
+ loadNext()
203
441
  } else {
204
- console.error(`${file.name} 上传失败 ${fileUpdateTime[file.name]} 次,正在重试...`)
205
- upload(file, currentIndex)
442
+ resolve(spark.end())
443
+ }
444
+ }
445
+
446
+ reader.onerror = () => reject(reader.error)
447
+
448
+ function loadNext() {
449
+ const start = currentChunk * chunkSize
450
+ const end = Math.min(start + chunkSize, file.size)
451
+ reader.readAsArrayBuffer(file.slice(start, end))
452
+ }
453
+
454
+ loadNext()
455
+ })
456
+ }
457
+
458
+ async function parseMediaTags(file) {
459
+ return new Promise((resolve) => {
460
+ jsmediatags.read(file, {
461
+ onSuccess: function(tag) {
462
+ resolve({
463
+ title: tag.tags.title || null,
464
+ artist: tag.tags.artist || null,
465
+ album: tag.tags.album || null,
466
+ })
467
+ },
468
+ onError: function() {
469
+ resolve({ title: null, artist: null, album: null })
206
470
  }
207
471
  })
472
+ })
473
+ }
474
+
475
+ async function uploadFileDirect(file, index, total) {
476
+ createProgressItem(file, index, total)
477
+
478
+ try {
479
+ updateProgress(index, '计算文件MD5...', 5)
480
+
481
+ const md5 = await calculateMD5(file)
482
+ const fileSize = file.size
483
+ const filename = file.name
484
+
485
+ updateProgress(index, '解析音频元数据...', 8)
486
+
487
+ const mediaTags = await parseMediaTags(file)
488
+
489
+ updateProgress(index, '获取上传凭证...', 10)
490
+
491
+ const tokenRes = await axios({
492
+ method: 'post',
493
+ url: `/cloud/upload/token?time=${Date.now()}`,
494
+ data: {
495
+ cookie: localStorage.getItem('cookie'),
496
+ md5: md5,
497
+ fileSize: fileSize,
498
+ filename: filename,
499
+ },
500
+ })
501
+
502
+ if (tokenRes.data.code !== 200) {
503
+ throw new Error(tokenRes.data.msg || '获取上传凭证失败')
504
+ }
505
+
506
+ const tokenData = tokenRes.data.data
507
+
508
+ if (!tokenData.needUpload) {
509
+ updateProgress(index, '文件已存在,直接导入云盘...', 80)
510
+ await completeUpload(tokenData, file, mediaTags)
511
+ updateProgress(index, '上传完成!', 100)
512
+ return
513
+ }
514
+
515
+ updateProgress(index, '开始上传到云存储...', 15)
516
+
517
+ await axios({
518
+ method: 'post',
519
+ url: tokenData.uploadUrl,
520
+ headers: {
521
+ 'x-nos-token': tokenData.uploadToken,
522
+ 'Content-MD5': md5,
523
+ 'Content-Type': 'audio/mpeg',
524
+ 'Content-Length': String(fileSize),
525
+ },
526
+ data: file,
527
+ onUploadProgress: (progressEvent) => {
528
+ const percent = Math.round((progressEvent.loaded / progressEvent.total) * 70) + 15
529
+ updateProgress(index, `上传中... ${Math.round(progressEvent.loaded / progressEvent.total * 100)}%`, Math.min(percent, 85))
530
+ },
531
+ maxContentLength: Infinity,
532
+ maxBodyLength: Infinity,
533
+ timeout: 600000,
534
+ })
535
+
536
+ updateProgress(index, '上传完成,正在导入云盘...', 90)
537
+
538
+ await completeUpload(tokenData, file, mediaTags)
539
+
540
+ updateProgress(index, '上传完成!', 100)
541
+
542
+ } catch (err) {
543
+ console.error(`${file.name} 上传失败:`, err)
544
+ const errorMsg = err.response?.data?.msg || err.message || '未知错误'
545
+ updateProgress(index, `上传失败: ${errorMsg}`, 0, true)
546
+ }
547
+ }
548
+
549
+ async function completeUpload(tokenData, file, mediaTags = {}) {
550
+ const songName = mediaTags.title || file.name.replace(/\.[^.]+$/, '')
551
+ const artist = mediaTags.artist || '未知艺术家'
552
+ const album = mediaTags.album || '未知专辑'
553
+
554
+ const completeRes = await axios({
555
+ method: 'post',
556
+ url: `/cloud/upload/complete?time=${Date.now()}`,
557
+ data: {
558
+ cookie: localStorage.getItem('cookie'),
559
+ songId: tokenData.songId,
560
+ resourceId: tokenData.resourceId,
561
+ md5: tokenData.md5,
562
+ filename: file.name,
563
+ song: songName,
564
+ artist: artist,
565
+ album: album,
566
+ },
567
+ })
568
+
569
+ if (completeRes.data.code !== 200) {
570
+ throw new Error(completeRes.data.msg || '导入云盘失败')
571
+ }
572
+
573
+ return completeRes.data
208
574
  }
209
575
  </script>
576
+ <script src="https://fastly.jsdelivr.net/npm/spark-md5@3.0.2/spark-md5.min.js"></script>
210
577
  </body>
211
578
  </html>
@@ -2,6 +2,8 @@
2
2
 
3
3
  网易云音乐 NodeJS API Enhanced
4
4
 
5
+ 最后更新于: 2026.2.15
6
+
5
7
  ## 灵感来自
6
8
 
7
9
  [disoul/electron-cloud-music](https://github.com/disoul/electron-cloud-music)
@@ -1684,6 +1686,62 @@ tags: 歌单标签
1684
1686
 
1685
1687
  **调用例子 :** `/comment/video?id=89ADDE33C0AAE8EC14B99F6750DB954D`
1686
1688
 
1689
+ ### 评论统计数据
1690
+
1691
+ 说明 : 调用此接口 , 传入资源类型和资源 id 列表 , 可批量获取对应资源的评论统计数据 ( 不需要登录 )
1692
+
1693
+ **必选参数 :**
1694
+
1695
+ `type`: 数字 , 资源类型 , 对应以下类型
1696
+
1697
+ ```
1698
+ 0: 歌曲
1699
+
1700
+ 1: mv
1701
+
1702
+ 2: 歌单
1703
+
1704
+ 3: 专辑
1705
+
1706
+ 4: 电台节目
1707
+
1708
+ 5: 视频
1709
+
1710
+ 6: 动态
1711
+
1712
+ 7: 电台
1713
+ ```
1714
+
1715
+ `ids`: 资源 id 列表 , 多个 id 用逗号分隔 , 如 `186016,347230`
1716
+
1717
+ **接口地址 :** `/comment/info/list`
1718
+
1719
+ **调用例子 :** `/comment/info/list?type=0&ids=186016,347230`
1720
+
1721
+ **返回数据 :**
1722
+
1723
+ ```json
1724
+ {
1725
+ "data": [
1726
+ {
1727
+ "latestLikedUsers": null,
1728
+ "liked": false,
1729
+ "comments": null,
1730
+ "resourceType": 4,
1731
+ "resourceId": 186016,
1732
+ "commentUpgraded": false,
1733
+ "musicianSaidCount": 0,
1734
+ "commentCountDesc": "100w+",
1735
+ "likedCount": 347,
1736
+ "commentCount": 1970844,
1737
+ "shareCount": 109721,
1738
+ "threadId": "R_SO_4_186016"
1739
+ }
1740
+ ],
1741
+ "code": 200
1742
+ }
1743
+ ```
1744
+
1687
1745
  ### 热门评论
1688
1746
 
1689
1747
  说明 : 调用此接口 , 传入 type, 资源 id 可获得对应资源热门评论 ( 不需要登录 )
@@ -2766,7 +2824,7 @@ type : 地区
2766
2824
 
2767
2825
  参考: https://github.com/neteasecloudmusicapienhanced/api-enhanced/blob/main/public/cloud.html
2768
2826
 
2769
- 访问地址: http://localhost:3000/cloud.html)
2827
+ 访问地址: http://localhost:3000/cloud.html
2770
2828
 
2771
2829
  支持命令行调用,参考 module_example 目录下`song_upload.js`
2772
2830
 
@@ -2774,6 +2832,78 @@ type : 地区
2774
2832
 
2775
2833
  **调用例子 :** `/cloud`
2776
2834
 
2835
+ #### 上传模式说明
2836
+
2837
+ 云盘上传支持两种模式:
2838
+
2839
+ **1. 后端代理模式 (默认)**
2840
+
2841
+ 文件通过服务器转发到云存储,调用简单,但受服务器限制:
2842
+
2843
+ - Vercel Serverless Functions 限制请求体大小为 4.5MB
2844
+ - 自建服务器需配置足够大的请求体限制
2845
+
2846
+ **2. 客户端直传模式 (推荐用于 Vercel)**
2847
+
2848
+ 文件直接从客户端上传到云存储服务器,绕过服务器限制:
2849
+
2850
+ - 支持大文件上传
2851
+ - 适合 Vercel、Netlify 等有请求体限制的平台
2852
+ - 需要前端配合实现
2853
+
2854
+ #### 客户端直传相关接口
2855
+
2856
+ **获取上传凭证**
2857
+
2858
+ **接口地址 :** `/cloud/upload/token`
2859
+
2860
+ **必选参数 :**
2861
+
2862
+ - `cookie`: 网易云音乐 Cookie (在请求体中传递)
2863
+ - `md5`: 文件 MD5 值
2864
+ - `fileSize`: 文件大小(字节)
2865
+ - `filename`: 文件名
2866
+
2867
+ **返回数据 :**
2868
+
2869
+ ```json
2870
+ {
2871
+ "code": 200,
2872
+ "data": {
2873
+ "needUpload": true,
2874
+ "songId": "...",
2875
+ "uploadToken": "...",
2876
+ "uploadUrl": "...",
2877
+ "resourceId": "..."
2878
+ }
2879
+ }
2880
+ ```
2881
+
2882
+ **完成上传导入**
2883
+
2884
+ **接口地址 :** `/cloud/upload/complete`
2885
+
2886
+ **必选参数 :**
2887
+
2888
+ - `cookie`: 网易云音乐 Cookie (在请求体中传递)
2889
+ - `songId`: 歌曲 ID
2890
+ - `resourceId`: 资源 ID
2891
+ - `md5`: 文件 MD5
2892
+ - `filename`: 文件名
2893
+
2894
+ **可选参数 :**
2895
+
2896
+ - `song`: 歌曲名
2897
+ - `artist`: 艺术家
2898
+ - `album`: 专辑名
2899
+
2900
+ #### 客户端直传流程
2901
+
2902
+ 1. 客户端计算文件 MD5
2903
+ 2. 调用 `/cloud/upload/token` 获取上传凭证
2904
+ 3. 如果 `needUpload` 为 true,直接 PUT 文件到 `uploadUrl`
2905
+ 4. 调用 `/cloud/upload/complete` 完成导入
2906
+
2777
2907
  ### 云盘歌曲信息匹配纠正
2778
2908
 
2779
2909
  说明 : 登录后调用此接口,可对云盘歌曲信息匹配纠正,如需取消匹配,asid 需要传 0
@@ -2790,6 +2920,7 @@ type : 地区
2790
2920
  **调用例子 :** `/cloud/match?uid=32953014&sid=aaa&asid=bbb` `/cloud/match?uid=32953014&sid=bbb&asid=0`
2791
2921
 
2792
2922
  ### 获取云盘歌词
2923
+
2793
2924
  说明: 调用此接口, 获取云盘歌曲的歌词,歌词来自此文件的音乐元数据`LYRICS`标签。
2794
2925
 
2795
2926
  **可选参数 :**
@@ -4883,12 +5014,11 @@ let data = encodeURIComponent(
4883
5014
 
4884
5015
  **调用例子:** `/vip/sign/info`
4885
5016
 
4886
-
4887
5017
  ### 用户的创建歌单列表
4888
5018
 
4889
5019
  说明 : 调用此接口, 传入用户id, 获取用户的创建歌单列表
4890
5020
 
4891
- **必选参数 :**
5021
+ **必选参数 :**
4892
5022
 
4893
5023
  `uid`: 用户 id
4894
5024
 
@@ -4906,7 +5036,7 @@ let data = encodeURIComponent(
4906
5036
 
4907
5037
  说明 : 调用此接口, 传入用户id, 获取用户的收藏歌单列表
4908
5038
 
4909
- **必选参数 :**
5039
+ **必选参数 :**
4910
5040
 
4911
5041
  `uid`: 用户 id
4912
5042
 
@@ -5,7 +5,7 @@
5
5
  <meta name="KEYWords" contect="网易云音乐,网易云音乐 api,网易云音乐 nodejs,网易云音乐 node.js">
6
6
  <meta name="description" content="网易云音乐 NodeJS API Enhanced">
7
7
  <title>网易云音乐 NodeJS API Enhanced</title>
8
- <link rel="icon" href="favicon.ico">
8
+ <link rel="icon" href="netease.png">
9
9
  <meta name="description" content="Description">
10
10
  <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
11
11
  <meta name="referrer" content="never">