@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/module/cloud.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
1
|
const uploadPlugin = require('../plugins/songUpload')
|
|
2
|
-
const md5 = require('md5')
|
|
3
2
|
const createOption = require('../util/option.js')
|
|
4
3
|
const logger = require('../util/logger.js')
|
|
4
|
+
const {
|
|
5
|
+
isTempFile,
|
|
6
|
+
getFileSize,
|
|
7
|
+
getFileMd5,
|
|
8
|
+
cleanupTempFile,
|
|
9
|
+
getFileExtension,
|
|
10
|
+
sanitizeFilename,
|
|
11
|
+
} = require('../util/fileHelper')
|
|
12
|
+
|
|
5
13
|
let mm
|
|
6
14
|
module.exports = async (query, request) => {
|
|
7
15
|
mm = require('music-metadata')
|
|
8
|
-
|
|
9
|
-
// if (query.songFile.name.indexOf('flac') > -1) {
|
|
10
|
-
// ext = 'flac'
|
|
11
|
-
// }
|
|
12
|
-
if (query.songFile.name.includes('.')) {
|
|
13
|
-
ext = query.songFile.name.split('.').pop()
|
|
14
|
-
}
|
|
16
|
+
|
|
15
17
|
query.songFile.name = Buffer.from(query.songFile.name, 'latin1').toString(
|
|
16
18
|
'utf-8',
|
|
17
19
|
)
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
.replace(/\s/g, '')
|
|
21
|
-
.replace(/\./g, '_')
|
|
20
|
+
const ext = getFileExtension(query.songFile.name)
|
|
21
|
+
const filename = sanitizeFilename(query.songFile.name)
|
|
22
22
|
const bitrate = 999000
|
|
23
|
+
|
|
23
24
|
if (!query.songFile) {
|
|
24
25
|
return Promise.reject({
|
|
25
26
|
status: 500,
|
|
@@ -29,119 +30,135 @@ module.exports = async (query, request) => {
|
|
|
29
30
|
},
|
|
30
31
|
})
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
bitrate: String(bitrate),
|
|
41
|
-
ext: '',
|
|
42
|
-
length: query.songFile.size,
|
|
43
|
-
md5: query.songFile.md5,
|
|
44
|
-
songId: '0',
|
|
45
|
-
version: 1,
|
|
46
|
-
},
|
|
47
|
-
createOption(query),
|
|
48
|
-
)
|
|
49
|
-
let artist = ''
|
|
50
|
-
let album = ''
|
|
51
|
-
let songName = ''
|
|
33
|
+
|
|
34
|
+
const useTemp = isTempFile(query.songFile)
|
|
35
|
+
let fileSize = await getFileSize(query.songFile)
|
|
36
|
+
let fileMd5 = await getFileMd5(query.songFile)
|
|
37
|
+
|
|
38
|
+
query.songFile.md5 = fileMd5
|
|
39
|
+
query.songFile.size = fileSize
|
|
40
|
+
|
|
52
41
|
try {
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
42
|
+
const res = await request(
|
|
43
|
+
`/api/cloud/upload/check`,
|
|
44
|
+
{
|
|
45
|
+
bitrate: String(bitrate),
|
|
46
|
+
ext: '',
|
|
47
|
+
length: fileSize,
|
|
48
|
+
md5: fileMd5,
|
|
49
|
+
songId: '0',
|
|
50
|
+
version: 1,
|
|
51
|
+
},
|
|
52
|
+
createOption(query),
|
|
56
53
|
)
|
|
57
|
-
const info = metadata.common
|
|
58
54
|
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
let artist = ''
|
|
56
|
+
let album = ''
|
|
57
|
+
let songName = ''
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
let metadata
|
|
61
|
+
if (useTemp) {
|
|
62
|
+
metadata = await mm.parseFile(query.songFile.tempFilePath)
|
|
63
|
+
} else {
|
|
64
|
+
metadata = await mm.parseBuffer(
|
|
65
|
+
query.songFile.data,
|
|
66
|
+
query.songFile.mimetype,
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
const info = metadata.common
|
|
70
|
+
if (info.title) songName = info.title
|
|
71
|
+
if (info.album) album = info.album
|
|
72
|
+
if (info.artist) artist = info.artist
|
|
73
|
+
} catch (error) {
|
|
74
|
+
logger.info('元数据解析错误:', error.message)
|
|
61
75
|
}
|
|
62
|
-
|
|
63
|
-
|
|
76
|
+
|
|
77
|
+
const tokenRes = await request(
|
|
78
|
+
`/api/nos/token/alloc`,
|
|
79
|
+
{
|
|
80
|
+
bucket: '',
|
|
81
|
+
ext: ext,
|
|
82
|
+
filename: filename,
|
|
83
|
+
local: false,
|
|
84
|
+
nos_product: 3,
|
|
85
|
+
type: 'audio',
|
|
86
|
+
md5: fileMd5,
|
|
87
|
+
},
|
|
88
|
+
createOption(query),
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
if (!tokenRes.body.result || !tokenRes.body.result.resourceId) {
|
|
92
|
+
logger.error('Token分配失败:', tokenRes.body)
|
|
93
|
+
return Promise.reject({
|
|
94
|
+
status: 500,
|
|
95
|
+
body: {
|
|
96
|
+
code: 500,
|
|
97
|
+
msg: '获取上传token失败',
|
|
98
|
+
detail: tokenRes.body,
|
|
99
|
+
},
|
|
100
|
+
})
|
|
64
101
|
}
|
|
65
|
-
|
|
66
|
-
|
|
102
|
+
|
|
103
|
+
if (res.body.needUpload) {
|
|
104
|
+
logger.info('需要上传,开始上传流程...')
|
|
105
|
+
try {
|
|
106
|
+
const uploadInfo = await uploadPlugin(query, request)
|
|
107
|
+
logger.info('上传完成:', uploadInfo?.body?.result?.resourceId)
|
|
108
|
+
} catch (uploadError) {
|
|
109
|
+
logger.error('上传失败:', uploadError)
|
|
110
|
+
return Promise.reject(uploadError)
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
logger.info('文件已存在,跳过上传')
|
|
67
114
|
}
|
|
68
|
-
// if (metadata.native.ID3v1) {
|
|
69
|
-
// metadata.native.ID3v1.forEach((item) => {
|
|
70
|
-
// // logger.info(item.id, item.value)
|
|
71
|
-
// if (item.id === 'title') {
|
|
72
|
-
// songName = item.value
|
|
73
|
-
// }
|
|
74
|
-
// if (item.id === 'artist') {
|
|
75
|
-
// artist = item.value
|
|
76
|
-
// }
|
|
77
|
-
// if (item.id === 'album') {
|
|
78
|
-
// album = item.value
|
|
79
|
-
// }
|
|
80
|
-
// })
|
|
81
|
-
// // logger.info({
|
|
82
|
-
// // songName,
|
|
83
|
-
// // album,
|
|
84
|
-
// // songName,
|
|
85
|
-
// // })
|
|
86
|
-
// }
|
|
87
|
-
// logger.info({
|
|
88
|
-
// songName,
|
|
89
|
-
// album,
|
|
90
|
-
// songName,
|
|
91
|
-
// })
|
|
92
|
-
} catch (error) {
|
|
93
|
-
logger.info(error)
|
|
94
|
-
}
|
|
95
|
-
const tokenRes = await request(
|
|
96
|
-
`/api/nos/token/alloc`,
|
|
97
|
-
{
|
|
98
|
-
bucket: '',
|
|
99
|
-
ext: ext,
|
|
100
|
-
filename: filename,
|
|
101
|
-
local: false,
|
|
102
|
-
nos_product: 3,
|
|
103
|
-
type: 'audio',
|
|
104
|
-
md5: query.songFile.md5,
|
|
105
|
-
},
|
|
106
|
-
createOption(query),
|
|
107
|
-
)
|
|
108
115
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
116
|
+
const res2 = await request(
|
|
117
|
+
`/api/upload/cloud/info/v2`,
|
|
118
|
+
{
|
|
119
|
+
md5: fileMd5,
|
|
120
|
+
songid: res.body.songId,
|
|
121
|
+
filename: query.songFile.name,
|
|
122
|
+
song: songName || filename,
|
|
123
|
+
album: album || '未知专辑',
|
|
124
|
+
artist: artist || '未知艺术家',
|
|
125
|
+
bitrate: String(bitrate),
|
|
126
|
+
resourceId: tokenRes.body.result.resourceId,
|
|
127
|
+
},
|
|
128
|
+
createOption(query),
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if (res2.body.code !== 200) {
|
|
132
|
+
logger.error('云盘信息上传失败:', res2.body)
|
|
133
|
+
return Promise.reject({
|
|
134
|
+
status: res2.status || 500,
|
|
135
|
+
body: {
|
|
136
|
+
code: res2.body.code || 500,
|
|
137
|
+
msg: res2.body.msg || '上传云盘信息失败',
|
|
138
|
+
detail: res2.body,
|
|
139
|
+
},
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const res3 = await request(
|
|
144
|
+
`/api/cloud/pub/v2`,
|
|
145
|
+
{
|
|
146
|
+
songid: res2.body.songId,
|
|
147
|
+
},
|
|
148
|
+
createOption(query),
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
status: 200,
|
|
153
|
+
body: {
|
|
154
|
+
...res.body,
|
|
155
|
+
...res3.body,
|
|
156
|
+
},
|
|
157
|
+
cookie: res.cookie,
|
|
158
|
+
}
|
|
159
|
+
} finally {
|
|
160
|
+
if (useTemp) {
|
|
161
|
+
await cleanupTempFile(query.songFile.tempFilePath)
|
|
162
|
+
}
|
|
146
163
|
}
|
|
147
164
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
const createOption = require('../util/option.js')
|
|
2
|
+
|
|
3
|
+
module.exports = async (query, request) => {
|
|
4
|
+
const {
|
|
5
|
+
songId,
|
|
6
|
+
resourceId,
|
|
7
|
+
md5,
|
|
8
|
+
filename,
|
|
9
|
+
song,
|
|
10
|
+
artist,
|
|
11
|
+
album,
|
|
12
|
+
bitrate = 999000,
|
|
13
|
+
} = query
|
|
14
|
+
|
|
15
|
+
if (!songId || !resourceId || !md5 || !filename) {
|
|
16
|
+
return Promise.reject({
|
|
17
|
+
status: 400,
|
|
18
|
+
body: {
|
|
19
|
+
code: 400,
|
|
20
|
+
msg: '缺少必要参数: songId, resourceId, md5, filename',
|
|
21
|
+
},
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const songName = song || filename.replace(/\.[^.]+$/, '')
|
|
26
|
+
|
|
27
|
+
const res2 = await request(
|
|
28
|
+
`/api/upload/cloud/info/v2`,
|
|
29
|
+
{
|
|
30
|
+
md5: md5,
|
|
31
|
+
songid: songId,
|
|
32
|
+
filename: filename,
|
|
33
|
+
song: songName,
|
|
34
|
+
album: album || '未知专辑',
|
|
35
|
+
artist: artist || '未知艺术家',
|
|
36
|
+
bitrate: String(bitrate),
|
|
37
|
+
resourceId: resourceId,
|
|
38
|
+
},
|
|
39
|
+
createOption(query),
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if (res2.body.code !== 200) {
|
|
43
|
+
return Promise.reject({
|
|
44
|
+
status: res2.status || 500,
|
|
45
|
+
body: {
|
|
46
|
+
code: res2.body.code || 500,
|
|
47
|
+
msg: res2.body.msg || '上传云盘信息失败',
|
|
48
|
+
detail: res2.body,
|
|
49
|
+
},
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const res3 = await request(
|
|
54
|
+
`/api/cloud/pub/v2`,
|
|
55
|
+
{
|
|
56
|
+
songid: res2.body.songId,
|
|
57
|
+
},
|
|
58
|
+
createOption(query),
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
status: 200,
|
|
63
|
+
body: {
|
|
64
|
+
code: 200,
|
|
65
|
+
data: {
|
|
66
|
+
songId: res2.body.songId,
|
|
67
|
+
...res3.body,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
cookie: res2.cookie,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const { default: axios } = require('axios')
|
|
2
|
+
const createOption = require('../util/option.js')
|
|
3
|
+
|
|
4
|
+
module.exports = async (query, request) => {
|
|
5
|
+
const { md5, fileSize, filename, bitrate = 999000 } = query
|
|
6
|
+
|
|
7
|
+
if (!md5 || !fileSize || !filename) {
|
|
8
|
+
return Promise.reject({
|
|
9
|
+
status: 400,
|
|
10
|
+
body: {
|
|
11
|
+
code: 400,
|
|
12
|
+
msg: '缺少必要参数: md5, fileSize, filename',
|
|
13
|
+
},
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const ext = filename.includes('.') ? filename.split('.').pop() : 'mp3'
|
|
18
|
+
|
|
19
|
+
const checkRes = await request(
|
|
20
|
+
`/api/cloud/upload/check`,
|
|
21
|
+
{
|
|
22
|
+
bitrate: String(bitrate),
|
|
23
|
+
ext: '',
|
|
24
|
+
length: fileSize,
|
|
25
|
+
md5: md5,
|
|
26
|
+
songId: '0',
|
|
27
|
+
version: 1,
|
|
28
|
+
},
|
|
29
|
+
createOption(query),
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
const bucket = 'jd-musicrep-privatecloud-audio-public'
|
|
33
|
+
const tokenRes = await request(
|
|
34
|
+
`/api/nos/token/alloc`,
|
|
35
|
+
{
|
|
36
|
+
bucket: bucket,
|
|
37
|
+
ext: ext,
|
|
38
|
+
filename: filename
|
|
39
|
+
.replace(/\.[^.]+$/, '')
|
|
40
|
+
.replace(/\s/g, '')
|
|
41
|
+
.replace(/\./g, '_'),
|
|
42
|
+
local: false,
|
|
43
|
+
nos_product: 3,
|
|
44
|
+
type: 'audio',
|
|
45
|
+
md5: md5,
|
|
46
|
+
},
|
|
47
|
+
createOption(query, 'weapi'),
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
if (!tokenRes.body.result || !tokenRes.body.result.objectKey) {
|
|
51
|
+
return Promise.reject({
|
|
52
|
+
status: 500,
|
|
53
|
+
body: {
|
|
54
|
+
code: 500,
|
|
55
|
+
msg: '获取上传token失败',
|
|
56
|
+
detail: tokenRes.body,
|
|
57
|
+
},
|
|
58
|
+
})
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let lbs
|
|
62
|
+
try {
|
|
63
|
+
lbs = (
|
|
64
|
+
await axios({
|
|
65
|
+
method: 'get',
|
|
66
|
+
url: `https://wanproxy.127.net/lbs?version=1.0&bucketname=${bucket}`,
|
|
67
|
+
timeout: 10000,
|
|
68
|
+
})
|
|
69
|
+
).data
|
|
70
|
+
} catch (error) {
|
|
71
|
+
return Promise.reject({
|
|
72
|
+
status: 500,
|
|
73
|
+
body: {
|
|
74
|
+
code: 500,
|
|
75
|
+
msg: '获取上传服务器地址失败',
|
|
76
|
+
detail: error.message,
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (!lbs || !lbs.upload || !lbs.upload[0]) {
|
|
82
|
+
return Promise.reject({
|
|
83
|
+
status: 500,
|
|
84
|
+
body: {
|
|
85
|
+
code: 500,
|
|
86
|
+
msg: '获取上传服务器地址无效',
|
|
87
|
+
detail: lbs,
|
|
88
|
+
},
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
status: 200,
|
|
94
|
+
body: {
|
|
95
|
+
code: 200,
|
|
96
|
+
data: {
|
|
97
|
+
needUpload: checkRes.body.needUpload,
|
|
98
|
+
songId: checkRes.body.songId,
|
|
99
|
+
uploadToken: tokenRes.body.result.token,
|
|
100
|
+
objectKey: tokenRes.body.result.objectKey,
|
|
101
|
+
resourceId: tokenRes.body.result.resourceId,
|
|
102
|
+
uploadUrl: `${lbs.upload[0]}/${bucket}/${tokenRes.body.result.objectKey.replace(/\//g, '%2F')}?offset=0&complete=true&version=1.0`,
|
|
103
|
+
bucket: bucket,
|
|
104
|
+
md5: md5,
|
|
105
|
+
fileSize: fileSize,
|
|
106
|
+
filename: filename,
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
cookie: checkRes.cookie,
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// 对某一首歌曲发表评论
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const data = {
|
|
6
|
+
threadId: 'R_SO_4_' + query.id,
|
|
7
|
+
content: query.content,
|
|
8
|
+
resourceType: '0',
|
|
9
|
+
resourceId: '0',
|
|
10
|
+
expressionPicId: '-1',
|
|
11
|
+
bubbleId: '-1',
|
|
12
|
+
checkToken: '',
|
|
13
|
+
}
|
|
14
|
+
return request('/api/resource/comments/add', data, createOption(query))
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// 删除评论
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const data = {
|
|
6
|
+
commentId: query.cid,
|
|
7
|
+
threadId: 'R_SO_4_' + query.id,
|
|
8
|
+
}
|
|
9
|
+
return request(`/api/resource/comments/delete`, data, createOption(query))
|
|
10
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// 评论统计数据
|
|
2
|
+
// type: 0=歌曲 1=MV 2=歌单 3=专辑 4=电台节目 5=视频 6=动态 7=电台
|
|
3
|
+
// ids: 资源 ID 列表,多个用逗号分隔,如 "123,456"
|
|
4
|
+
const { resourceTypeMap } = require('../util/config.json')
|
|
5
|
+
const createOption = require('../util/option.js')
|
|
6
|
+
|
|
7
|
+
// 从 resourceTypeMap 的前缀值中提取网易云内部资源类型编号
|
|
8
|
+
// 例如 "R_SO_4_" -> "4", "A_DR_14_" -> "14"
|
|
9
|
+
const resourceTypeIdMap = Object.fromEntries(
|
|
10
|
+
Object.entries(resourceTypeMap).map(([key, prefix]) => [
|
|
11
|
+
key,
|
|
12
|
+
prefix.replace(/_$/, '').split('_').pop(),
|
|
13
|
+
]),
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
module.exports = (query, request) => {
|
|
17
|
+
const ids = String(query.ids || query.id || '')
|
|
18
|
+
.split(',')
|
|
19
|
+
.map((id) => id.trim())
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
|
|
22
|
+
return request(
|
|
23
|
+
`/api/resource/commentInfo/list`,
|
|
24
|
+
{
|
|
25
|
+
resourceType: resourceTypeIdMap[String(query.type || 0)],
|
|
26
|
+
resourceIds: JSON.stringify(ids),
|
|
27
|
+
},
|
|
28
|
+
createOption(query, 'weapi'),
|
|
29
|
+
)
|
|
30
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// 回复评论
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const data = {
|
|
6
|
+
threadId: query.id,
|
|
7
|
+
commentId: query.commentId,
|
|
8
|
+
content: query.content,
|
|
9
|
+
resourceType: '0',
|
|
10
|
+
resourceId: '0',
|
|
11
|
+
}
|
|
12
|
+
return request(`/api/v1/resource/comments/reply`, data, createOption(query))
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// 搜索建议pc端
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const data = {
|
|
6
|
+
keyword: query.keyword || '',
|
|
7
|
+
}
|
|
8
|
+
return request(
|
|
9
|
+
`/api/search/pc/suggest/keyword/get`,
|
|
10
|
+
data,
|
|
11
|
+
createOption(query),
|
|
12
|
+
)
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// 喜欢歌曲
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const like = query.like !== 'false'
|
|
6
|
+
const data = {
|
|
7
|
+
trackId: query.id,
|
|
8
|
+
userid: query.uid,
|
|
9
|
+
like: like,
|
|
10
|
+
}
|
|
11
|
+
return request(`/api/song/like`, data, createOption(query))
|
|
12
|
+
}
|
|
@@ -1,77 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
// 感谢来自GD Studio的开发API
|
|
3
|
-
// https://music.gdstudio.xyz/
|
|
4
|
-
|
|
5
|
-
const createOption = require('../util/option.js')
|
|
1
|
+
// 夹带私货的东西就不要放在这里了
|
|
6
2
|
|
|
7
3
|
module.exports = async (query, request) => {
|
|
8
|
-
|
|
9
|
-
const { id, br = '320' } = query
|
|
10
|
-
if (!id) {
|
|
11
|
-
return {
|
|
12
|
-
status: 400,
|
|
13
|
-
body: {
|
|
14
|
-
code: 400,
|
|
15
|
-
message: '缺少必要参数 id',
|
|
16
|
-
data: [],
|
|
17
|
-
},
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
const validBR = ['128', '192', '320', '740', '999']
|
|
21
|
-
// const covertBR = ['128000', '192000', '320000','740000', '999000']
|
|
22
|
-
if (!validBR.includes(br)) {
|
|
23
|
-
return {
|
|
24
|
-
status: 400,
|
|
25
|
-
body: {
|
|
26
|
-
code: 400,
|
|
27
|
-
message: '无效音质参数',
|
|
28
|
-
allowed_values: validBR,
|
|
29
|
-
data: [],
|
|
30
|
-
},
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const apiUrl = new URL('https://music-api.gdstudio.xyz/api.php')
|
|
35
|
-
apiUrl.searchParams.append('types', 'url')
|
|
36
|
-
apiUrl.searchParams.append('id', id)
|
|
37
|
-
apiUrl.searchParams.append('br', br)
|
|
38
|
-
|
|
39
|
-
const response = await fetch(apiUrl.toString())
|
|
40
|
-
if (!response.ok) throw new Error(`API 响应状态: ${response.status}`)
|
|
41
|
-
const result = await response.json()
|
|
42
|
-
|
|
43
|
-
// 代理逻辑
|
|
44
|
-
const useProxy = process.env.ENABLE_PROXY || false
|
|
45
|
-
const proxy = process.env.PROXY_URL
|
|
46
|
-
if (useProxy && result.url && result.url.includes('kuwo')) {
|
|
47
|
-
result.proxyUrl = proxy + result.url.replace(/^http:\/\//, 'http/')
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
status: 200,
|
|
52
|
-
body: {
|
|
53
|
-
code: 200,
|
|
54
|
-
message: '请求成功',
|
|
55
|
-
data: {
|
|
56
|
-
id,
|
|
57
|
-
br,
|
|
58
|
-
url: result.url,
|
|
59
|
-
...(proxy && result.proxyUrl ? { proxyUrl: result.proxyUrl } : {}),
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
|
-
}
|
|
63
|
-
} catch (error) {
|
|
64
|
-
console.error('Error in song_url_ncmget:', error)
|
|
65
|
-
return {
|
|
66
|
-
status: 500,
|
|
67
|
-
body: {
|
|
68
|
-
code: 500,
|
|
69
|
-
message: '服务器处理请求失败',
|
|
70
|
-
...(process.env.NODE_ENV === 'development'
|
|
71
|
-
? { error: error.message }
|
|
72
|
-
: {}),
|
|
73
|
-
data: [],
|
|
74
|
-
},
|
|
75
|
-
}
|
|
76
|
-
}
|
|
4
|
+
return { status: 200, body: { code: 200, data: [] } }
|
|
77
5
|
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// 获取客户端歌曲下载链接 - v1
|
|
2
|
+
// 此版本不再采用 br 作为音质区分的标准
|
|
3
|
+
// 而是采用 standard, exhigh, lossless, hires, jyeffect(高清环绕声), sky(沉浸环绕声), jymaster(超清母带) 进行音质判断
|
|
4
|
+
|
|
5
|
+
const createOption = require('../util/option.js')
|
|
6
|
+
module.exports = async (query, request) => {
|
|
7
|
+
const data = {
|
|
8
|
+
id: query.id,
|
|
9
|
+
immerseType: 'c51',
|
|
10
|
+
level: query.level,
|
|
11
|
+
}
|
|
12
|
+
const response = await request(
|
|
13
|
+
`/api/song/enhance/download/url/v1`,
|
|
14
|
+
data,
|
|
15
|
+
createOption(query),
|
|
16
|
+
)
|
|
17
|
+
let url = response?.body?.data?.[0]?.url
|
|
18
|
+
|
|
19
|
+
if (!url) {
|
|
20
|
+
const fallbackData = {
|
|
21
|
+
ids: `[${query.id}]`,
|
|
22
|
+
level: query.level,
|
|
23
|
+
encodeType: 'flac',
|
|
24
|
+
}
|
|
25
|
+
if (query.level === 'sky') {
|
|
26
|
+
fallbackData.immerseType = 'c51'
|
|
27
|
+
}
|
|
28
|
+
const fallback = await request(
|
|
29
|
+
`/api/song/enhance/player/url/v1`,
|
|
30
|
+
fallbackData,
|
|
31
|
+
createOption(query),
|
|
32
|
+
)
|
|
33
|
+
url = fallback?.body?.data?.[0]?.url
|
|
34
|
+
|
|
35
|
+
if (!url) {
|
|
36
|
+
return fallback
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return {
|
|
40
|
+
status: 302,
|
|
41
|
+
body: '',
|
|
42
|
+
cookie: fallback.cookie || [],
|
|
43
|
+
redirectUrl: url,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
status: 302,
|
|
49
|
+
body: '',
|
|
50
|
+
cookie: response.cookie || [],
|
|
51
|
+
redirectUrl: url,
|
|
52
|
+
}
|
|
53
|
+
}
|