@neteasecloudmusicapienhanced/api 4.29.21 → 4.30.1

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.
@@ -5,45 +5,164 @@
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>二维码登录</title>
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
17
+ min-height: 100vh;
18
+ background: #f5f5f5;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: 20px;
23
+ }
24
+
25
+ .container {
26
+ background: white;
27
+ border-radius: 12px;
28
+ padding: 48px;
29
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
30
+ max-width: 450px;
31
+ width: 100%;
32
+ text-align: center;
33
+ }
34
+
35
+ h1 {
36
+ font-size: 24px;
37
+ font-weight: 600;
38
+ color: #333;
39
+ margin-bottom: 8px;
40
+ }
41
+
42
+ .subtitle {
43
+ font-size: 14px;
44
+ color: #666;
45
+ margin-bottom: 32px;
46
+ }
47
+
48
+ .qr-wrapper {
49
+ display: inline-block;
50
+ padding: 16px;
51
+ background: #f9f9f9;
52
+ border-radius: 8px;
53
+ margin-bottom: 24px;
54
+ }
55
+
56
+ #qrImg {
57
+ width: 200px;
58
+ height: 200px;
59
+ display: block;
60
+ }
61
+
62
+ .info {
63
+ text-align: left;
64
+ padding: 16px;
65
+ background: #f9f9f9;
66
+ border-radius: 6px;
67
+ font-family: 'Courier New', monospace;
68
+ font-size: 12px;
69
+ color: #666;
70
+ white-space: pre-wrap;
71
+ word-break: break-all;
72
+ max-height: 200px;
73
+ overflow-y: auto;
74
+ }
75
+
76
+ .status {
77
+ margin-top: 16px;
78
+ padding: 12px;
79
+ border-radius: 6px;
80
+ font-size: 14px;
81
+ font-weight: 500;
82
+ }
83
+
84
+ .status.waiting {
85
+ background: #fef3c7;
86
+ color: #92400e;
87
+ }
88
+
89
+ .status.success {
90
+ background: #d1fae5;
91
+ color: #065f46;
92
+ }
93
+
94
+ .status.error {
95
+ background: #fee2e2;
96
+ color: #991b1b;
97
+ }
98
+
99
+ .hint {
100
+ margin-top: 16px;
101
+ font-size: 13px;
102
+ color: #999;
103
+ }
104
+ </style>
8
105
  </head>
9
106
 
10
107
  <body>
11
- <img id="qrImg" />
12
- <div id="info" class="info"></div>
13
- <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js
14
- "></script>
15
- <script>
108
+ <div class="container">
109
+ <h1>二维码登录</h1>
110
+ <p class="subtitle">使用网易云音乐App扫描二维码登录</p>
111
+
112
+ <div class="qr-wrapper">
113
+ <img id="qrImg" src="" alt="二维码加载中..." />
114
+ </div>
115
+
116
+ <div id="status" class="status waiting">等待扫描...</div>
16
117
 
118
+ <div id="info" class="info"></div>
119
+
120
+ <p class="hint">请打开网易云音乐App,扫描上方二维码完成登录</p>
121
+ </div>
122
+
123
+ <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
124
+ <script>
17
125
  async function login() {
18
126
  let timer
19
- let timestamp = Date.now()
127
+ const statusDiv = document.getElementById('status')
20
128
  const cookie = localStorage.getItem('cookie')
129
+
130
+ updateStatus('加载二维码...', 'waiting')
21
131
  getLoginStatus(cookie)
22
- const res = await axios({
23
- url: `/login/qr/key?timestamp=${Date.now()}`,
24
- })
25
- const key = res.data.data.unikey
26
- const res2 = await axios({
27
- url: `/login/qr/create?key=${key}&platform=web&qrimg=true&timestamp=${Date.now()}`,
28
- })
29
- document.querySelector('#qrImg').src = res2.data.data.qrimg
30
-
31
- timer = setInterval(async () => {
32
- const statusRes = await checkStatus(key)
33
- if (statusRes.code === 800) {
34
- alert('二维码已过期,请重新获取')
35
- clearInterval(timer)
36
- }
37
- if (statusRes.code === 803) {
38
- // 这一步会返回cookie
39
- clearInterval(timer)
40
- alert('授权登录成功')
41
- await getLoginStatus(statusRes.cookie)
42
- localStorage.setItem('cookie', statusRes.cookie)
43
- }
44
- }, 3000)
132
+
133
+ try {
134
+ const res = await axios({
135
+ url: `/login/qr/key?timestamp=${Date.now()}`,
136
+ })
137
+ const key = res.data.data.unikey
138
+
139
+ const res2 = await axios({
140
+ url: `/login/qr/create?key=${key}&platform=web&qrimg=true&timestamp=${Date.now()}`,
141
+ })
142
+ document.querySelector('#qrImg').src = res2.data.data.qrimg
143
+ updateStatus('请扫描二维码', 'waiting')
144
+
145
+ timer = setInterval(async () => {
146
+ const statusRes = await checkStatus(key)
147
+ if (statusRes.code === 800) {
148
+ updateStatus('二维码已过期,请刷新页面', 'error')
149
+ clearInterval(timer)
150
+ } else if (statusRes.code === 801) {
151
+ updateStatus('二维码已扫描,请在手机上确认', 'waiting')
152
+ } else if (statusRes.code === 802) {
153
+ updateStatus('登录成功,正在保存信息...', 'waiting')
154
+ } else if (statusRes.code === 803) {
155
+ clearInterval(timer)
156
+ updateStatus('授权登录成功!', 'success')
157
+ await getLoginStatus(statusRes.cookie)
158
+ localStorage.setItem('cookie', statusRes.cookie)
159
+ }
160
+ }, 3000)
161
+ } catch (error) {
162
+ console.error('登录失败:', error)
163
+ updateStatus('二维码加载失败,请刷新页面重试', 'error')
164
+ }
45
165
  }
46
- login()
47
166
 
48
167
  async function checkStatus(key) {
49
168
  const res = await axios({
@@ -51,22 +170,30 @@
51
170
  })
52
171
  return res.data
53
172
  }
173
+
54
174
  async function getLoginStatus(cookie = '') {
55
- const res = await axios({
56
- url: `/login/status?timestamp=${Date.now()}`,
57
- method: 'post',
58
- data: {
59
- cookie,
60
- },
61
- })
62
- document.querySelector('#info').innerText = JSON.stringify(res.data, null, 2)
175
+ try {
176
+ const res = await axios({
177
+ url: `/login/status?timestamp=${Date.now()}`,
178
+ method: 'post',
179
+ data: {
180
+ cookie,
181
+ },
182
+ })
183
+ document.querySelector('#info').textContent = JSON.stringify(res.data, null, 2)
184
+ } catch (error) {
185
+ console.error('获取登录状态失败:', error)
186
+ }
63
187
  }
64
- </script>
65
- <style>
66
- .info {
67
- white-space: pre;
188
+
189
+ function updateStatus(message, type) {
190
+ const statusDiv = document.getElementById('status')
191
+ statusDiv.textContent = message
192
+ statusDiv.className = 'status ' + type
68
193
  }
69
- </style>
194
+
195
+ login()
196
+ </script>
70
197
  </body>
71
198
 
72
199
  </html>
@@ -5,44 +5,164 @@
5
5
  <meta charset="UTF-8" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>二维码登录</title>
8
+ <style>
9
+ * {
10
+ margin: 0;
11
+ padding: 0;
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
17
+ min-height: 100vh;
18
+ background: #f5f5f5;
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ padding: 20px;
23
+ }
24
+
25
+ .container {
26
+ background: white;
27
+ border-radius: 12px;
28
+ padding: 48px;
29
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
30
+ max-width: 450px;
31
+ width: 100%;
32
+ text-align: center;
33
+ }
34
+
35
+ h1 {
36
+ font-size: 24px;
37
+ font-weight: 600;
38
+ color: #333;
39
+ margin-bottom: 8px;
40
+ }
41
+
42
+ .subtitle {
43
+ font-size: 14px;
44
+ color: #666;
45
+ margin-bottom: 32px;
46
+ }
47
+
48
+ .qr-wrapper {
49
+ display: inline-block;
50
+ padding: 16px;
51
+ background: #f9f9f9;
52
+ border-radius: 8px;
53
+ margin-bottom: 24px;
54
+ }
55
+
56
+ #qrImg {
57
+ width: 200px;
58
+ height: 200px;
59
+ display: block;
60
+ }
61
+
62
+ .info {
63
+ text-align: left;
64
+ padding: 16px;
65
+ background: #f9f9f9;
66
+ border-radius: 6px;
67
+ font-family: 'Courier New', monospace;
68
+ font-size: 12px;
69
+ color: #666;
70
+ white-space: pre-wrap;
71
+ word-break: break-all;
72
+ max-height: 200px;
73
+ overflow-y: auto;
74
+ }
75
+
76
+ .status {
77
+ margin-top: 16px;
78
+ padding: 12px;
79
+ border-radius: 6px;
80
+ font-size: 14px;
81
+ font-weight: 500;
82
+ }
83
+
84
+ .status.waiting {
85
+ background: #fef3c7;
86
+ color: #92400e;
87
+ }
88
+
89
+ .status.success {
90
+ background: #d1fae5;
91
+ color: #065f46;
92
+ }
93
+
94
+ .status.error {
95
+ background: #fee2e2;
96
+ color: #991b1b;
97
+ }
98
+
99
+ .hint {
100
+ margin-top: 16px;
101
+ font-size: 13px;
102
+ color: #999;
103
+ }
104
+ </style>
8
105
  </head>
9
106
 
10
107
  <body>
11
- <img id="qrImg" />
12
- <div id="info" class="info"></div>
13
- <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js
14
- "></script>
108
+ <div class="container">
109
+ <h1>二维码登录</h1>
110
+ <p class="subtitle">使用网易云音乐App扫描二维码登录</p>
111
+
112
+ <div class="qr-wrapper">
113
+ <img id="qrImg" src="" alt="二维码加载中..." />
114
+ </div>
115
+
116
+ <div id="status" class="status waiting">等待扫描...</div>
117
+
118
+ <div id="info" class="info"></div>
119
+
120
+ <p class="hint">请打开网易云音乐App,扫描上方二维码完成登录</p>
121
+ </div>
122
+
123
+ <script src="https://fastly.jsdelivr.net/npm/axios@0.26.1/dist/axios.min.js"></script>
15
124
  <script>
16
125
  async function login() {
17
126
  let timer
18
- let timestamp = Date.now()
127
+ const statusDiv = document.getElementById('status')
19
128
  const cookie = localStorage.getItem('cookie')
129
+
130
+ updateStatus('加载二维码...', 'waiting')
20
131
  getLoginStatus(cookie)
21
- const res = await axios({
22
- url: `/login/qr/key?timestamp=${Date.now()}`,
23
- })
24
- const key = res.data.data.unikey
25
- const res2 = await axios({
26
- url: `/login/qr/create?key=${key}&platform=web&qrimg=true&timestamp=${Date.now()}&ua=pc`,
27
- })
28
- document.querySelector('#qrImg').src = res2.data.data.qrimg
29
-
30
- timer = setInterval(async () => {
31
- const statusRes = await checkStatus(key)
32
- if (statusRes.code === 800) {
33
- alert('二维码已过期,请重新获取')
34
- clearInterval(timer)
35
- }
36
- if (statusRes.code === 803) {
37
- // 这一步会返回cookie
38
- clearInterval(timer)
39
- alert('授权登录成功')
40
- await getLoginStatus(statusRes.cookie)
41
- localStorage.setItem('cookie', statusRes.cookie)
42
- }
43
- }, 3000)
132
+
133
+ try {
134
+ const res = await axios({
135
+ url: `/login/qr/key?timestamp=${Date.now()}`,
136
+ })
137
+ const key = res.data.data.unikey
138
+
139
+ const res2 = await axios({
140
+ url: `/login/qr/create?key=${key}&platform=web&qrimg=true&timestamp=${Date.now()}&ua=pc`,
141
+ })
142
+ document.querySelector('#qrImg').src = res2.data.data.qrimg
143
+ updateStatus('请扫描二维码', 'waiting')
144
+
145
+ timer = setInterval(async () => {
146
+ const statusRes = await checkStatus(key)
147
+ if (statusRes.code === 800) {
148
+ updateStatus('二维码已过期,请刷新页面', 'error')
149
+ clearInterval(timer)
150
+ } else if (statusRes.code === 801) {
151
+ updateStatus('二维码已扫描,请在手机上确认', 'waiting')
152
+ } else if (statusRes.code === 802) {
153
+ updateStatus('登录成功,正在保存信息...', 'waiting')
154
+ } else if (statusRes.code === 803) {
155
+ clearInterval(timer)
156
+ updateStatus('授权登录成功!', 'success')
157
+ await getLoginStatus(statusRes.cookie)
158
+ localStorage.setItem('cookie', statusRes.cookie)
159
+ }
160
+ }, 3000)
161
+ } catch (error) {
162
+ console.error('登录失败:', error)
163
+ updateStatus('二维码加载失败,请刷新页面重试', 'error')
164
+ }
44
165
  }
45
- login()
46
166
 
47
167
  async function checkStatus(key) {
48
168
  const res = await axios({
@@ -50,22 +170,30 @@
50
170
  })
51
171
  return res.data
52
172
  }
173
+
53
174
  async function getLoginStatus(cookie = '') {
54
- const res = await axios({
55
- url: `/login/status?timestamp=${Date.now()}&ua=pc`,
56
- method: 'post',
57
- data: {
58
- cookie,
59
- },
60
- })
61
- document.querySelector('#info').innerText = JSON.stringify(res.data, null, 2)
175
+ try {
176
+ const res = await axios({
177
+ url: `/login/status?timestamp=${Date.now()}&ua=pc`,
178
+ method: 'post',
179
+ data: {
180
+ cookie,
181
+ },
182
+ })
183
+ document.querySelector('#info').textContent = JSON.stringify(res.data, null, 2)
184
+ } catch (error) {
185
+ console.error('获取登录状态失败:', error)
186
+ }
62
187
  }
63
- </script>
64
- <style>
65
- .info {
66
- white-space: pre;
188
+
189
+ function updateStatus(message, type) {
190
+ const statusDiv = document.getElementById('status')
191
+ statusDiv.textContent = message
192
+ statusDiv.className = 'status ' + type
67
193
  }
68
- </style>
194
+
195
+ login()
196
+ </script>
69
197
  </body>
70
198
 
71
199
  </html>
@@ -5,79 +5,136 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>音乐解灰测试</title>
7
7
  <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
8
14
  body {
9
- font-family: Arial, sans-serif;
10
- max-width: 800px;
11
- margin: 20px auto;
12
- padding: 0 20px;
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
+ min-height: 100vh;
17
+ background: #f5f5f5;
18
+ padding: 20px;
13
19
  }
20
+
14
21
  .container {
15
- background-color: #f5f5f5;
16
- padding: 20px;
17
- border-radius: 8px;
22
+ max-width: 800px;
23
+ margin: 0 auto;
24
+ background: white;
25
+ border-radius: 12px;
26
+ padding: 32px;
27
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
28
+ }
29
+
30
+ h1 {
31
+ font-size: 24px;
32
+ font-weight: 600;
33
+ color: #333;
34
+ margin-bottom: 24px;
18
35
  }
36
+
19
37
  .form-group {
20
- margin-bottom: 15px;
38
+ margin-bottom: 20px;
39
+ }
40
+
41
+ label {
42
+ display: block;
43
+ font-size: 14px;
44
+ font-weight: 500;
45
+ color: #555;
46
+ margin-bottom: 8px;
21
47
  }
22
- .source-options {
23
- display: flex;
24
- flex-wrap: wrap;
25
- gap: 10px;
26
- margin-bottom: 15px;
48
+
49
+ input {
50
+ width: 100%;
51
+ padding: 12px 14px;
52
+ border: 1px solid #ddd;
53
+ border-radius: 6px;
54
+ font-size: 15px;
55
+ outline: none;
27
56
  }
28
- .source-option {
29
- display: flex;
30
- align-items: center;
31
- gap: 5px;
57
+
58
+ input:focus {
59
+ border-color: #333;
32
60
  }
61
+
33
62
  button {
34
- background-color: #4CAF50;
63
+ background: #333;
35
64
  color: white;
36
- padding: 10px 20px;
65
+ padding: 14px 28px;
37
66
  border: none;
38
- border-radius: 4px;
67
+ border-radius: 6px;
68
+ font-size: 15px;
69
+ font-weight: 500;
39
70
  cursor: pointer;
71
+ transition: background 0.2s ease;
40
72
  }
73
+
41
74
  button:hover {
42
- background-color: #45a049;
75
+ background: #555;
76
+ }
77
+
78
+ button:disabled {
79
+ background: #999;
80
+ cursor: not-allowed;
43
81
  }
82
+
44
83
  #result {
45
- margin-top: 20px;
46
- padding: 10px;
47
- border: 1px solid #ddd;
48
- border-radius: 4px;
84
+ margin-top: 24px;
85
+ padding: 16px;
86
+ background: #f9f9f9;
87
+ border-radius: 6px;
88
+ border: 1px solid #eee;
89
+ font-family: 'Courier New', monospace;
90
+ font-size: 13px;
49
91
  white-space: pre-wrap;
92
+ word-break: break-all;
93
+ min-height: 100px;
94
+ }
95
+
96
+ .hint {
97
+ font-size: 12px;
98
+ color: #999;
99
+ margin-top: 4px;
50
100
  }
51
101
  </style>
52
102
  </head>
53
103
  <body>
54
104
  <div class="container">
55
105
  <h1>音乐解灰测试</h1>
106
+
56
107
  <div class="form-group">
57
- <label for="songId">音乐 ID:</label>
58
- <input type="number" id="songId" placeholder="请输入音乐ID" required>
108
+ <label for="songId">音乐 ID</label>
109
+ <input type="number" id="songId" placeholder="请输入音乐ID" />
110
+ <div class="hint">例如: 1372188635</div>
59
111
  </div>
112
+
60
113
  <div class="form-group">
61
- <label for="sources">音源列表:</label>
62
- <input type="text" id="sources" placeholder="请输入音源(非必填)">
114
+ <label for="sources">音源列表(可选)</label>
115
+ <input type="text" id="sources" placeholder="请输入音源" />
116
+ <div class="hint">例如: kuwo, kugou, migu</div>
63
117
  </div>
64
- <button onclick="testSong()">开始测试</button>
118
+
119
+ <button id="testBtn" onclick="testSong()">开始测试</button>
120
+
65
121
  <div id="result"></div>
66
122
  </div>
67
123
 
68
124
  <script>
69
125
  async function testSong() {
70
126
  const songId = document.getElementById('songId').value;
127
+ const sources = document.getElementById('sources').value;
128
+ const testBtn = document.getElementById('testBtn');
129
+ const resultDiv = document.getElementById('result');
130
+
71
131
  if (!songId) {
72
132
  alert('请输入音乐ID');
73
133
  return;
74
134
  }
75
135
 
76
- const sources = document.getElementById('sources').value;
77
-
78
-
79
-
80
- const resultDiv = document.getElementById('result');
136
+ testBtn.disabled = true;
137
+ testBtn.textContent = '测试中...';
81
138
  resultDiv.textContent = '正在请求...';
82
139
 
83
140
  try {
@@ -86,6 +143,9 @@
86
143
  resultDiv.textContent = JSON.stringify(data, null, 2);
87
144
  } catch (error) {
88
145
  resultDiv.textContent = `请求失败: ${error.message}`;
146
+ } finally {
147
+ testBtn.disabled = false;
148
+ testBtn.textContent = '开始测试';
89
149
  }
90
150
  }
91
151
  </script>