@neteasecloudmusicapienhanced/api 4.30.1 → 4.30.3
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/README.MD +48 -23
- package/data/china_ip_ranges.txt +4147 -0
- package/module/cloud.js +136 -119
- package/module/cloud_upload_complete.js +72 -0
- package/module/cloud_upload_token.js +111 -0
- package/module/comment_add.js +15 -0
- package/module/comment_delete.js +10 -0
- package/module/comment_info_list.js +30 -0
- package/module/comment_reply.js +13 -0
- package/module/search_suggest_pc.js +13 -0
- package/module/song_like.js +12 -0
- package/module/song_url_ncmget.js +2 -74
- package/module/song_url_v1_302.js +53 -0
- package/module/user_followeds.js +1 -1
- package/module/voice_upload.js +36 -22
- package/module/voicelist_my_created.js +13 -0
- package/module/voicelist_search.js +6 -9
- package/package.json +19 -25
- package/plugins/songUpload.js +67 -19
- package/plugins/upload.js +5 -7
- package/public/cloud.html +406 -39
- package/public/docs/home.md +232 -9
- package/public/docs/index.html +1 -1
- package/public/docs/logo.svg +6 -0
- package/public/docs/netease.png +0 -0
- package/public/index.html +29 -4
- package/public/static/docs.png +0 -0
- package/server.js +43 -18
- package/util/fileHelper.js +88 -0
- package/util/index.js +55 -52
- package/data/ChineseIPGenerate.csv +0 -26
- package/public/docs/ncmapireborn.png +0 -0
- /package/public/static/{screenshot1.png → module_test.png} +0 -0
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
|
-
|
|
161
|
-
let
|
|
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
|
-
|
|
165
|
-
.
|
|
166
|
-
.
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
|
179
|
-
|
|
180
|
-
|
|
342
|
+
async function uploadFilesSequentially(files) {
|
|
343
|
+
isUploading = true
|
|
344
|
+
uploadBtn.classList.add('disabled')
|
|
345
|
+
progressSection.classList.add('active')
|
|
346
|
+
progressSection.innerHTML = ''
|
|
181
347
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
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
|
-
|
|
205
|
-
|
|
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>
|