@neteasecloudmusicapienhanced/api 4.30.3 → 4.31.0
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 +1 -1
- package/module/dj_difm_all_style_channel.js +9 -0
- package/module/dj_difm_channel_subscribe.js +9 -0
- package/module/dj_difm_channel_unsubscribe.js +9 -0
- package/module/dj_difm_playing_tracks_list.js +11 -0
- package/module/dj_difm_subscribe_channels_get.js +13 -0
- package/package.json +14 -13
- package/public/docs/home.md +66 -0
- package/server.js +41 -4
- package/util/request.js +2 -0
package/README.MD
CHANGED
|
@@ -130,7 +130,7 @@ $ sudo docker run -d -p 3000:3000 ncm-api
|
|
|
130
130
|
|
|
131
131
|
| 变量名 | 默认值 | 说明 |
|
|
132
132
|
|----------------------------|--------------------------------------|----------------------------------------------------|
|
|
133
|
-
| **CORS_ALLOW_ORIGIN** | `*` |
|
|
133
|
+
| **CORS_ALLOW_ORIGIN** | `*` | 允许跨域请求的域名。可填写单个源,或使用逗号分隔多个源(例如 `https://a.com,https://b.com`)。 |
|
|
134
134
|
| **ENABLE_PROXY** | `false` | 是否启用反向代理功能。 |
|
|
135
135
|
| **PROXY_URL** | `https://your-proxy-url.com/?proxy=` | 代理服务地址。仅当 `ENABLE_PROXY=true` 时生效。 |
|
|
136
136
|
| **ENABLE_GENERAL_UNBLOCK** | `true` | 是否启用全局解灰(推荐开启)。开启后所有歌曲都尝试自动解锁。 |
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// DIFM电台 - 播放列表
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const data = {
|
|
6
|
+
limit: query.limit || 5,
|
|
7
|
+
source: query.source || 0,
|
|
8
|
+
channelId: query.channelId,
|
|
9
|
+
}
|
|
10
|
+
return request(`/api/dj/difm/playing/tracks/list`, data, createOption(query))
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// DIFM电台 - 收藏列表
|
|
2
|
+
|
|
3
|
+
const createOption = require('../util/option.js')
|
|
4
|
+
module.exports = (query, request) => {
|
|
5
|
+
const data = {
|
|
6
|
+
sources: query.sources || '[0]',
|
|
7
|
+
}
|
|
8
|
+
return request(
|
|
9
|
+
`/api/dj/difm/subscribe/channels/get/v2`,
|
|
10
|
+
data,
|
|
11
|
+
createOption(query),
|
|
12
|
+
)
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neteasecloudmusicapienhanced/api",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.31.0",
|
|
4
4
|
"description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"dev": "nodemon app.js",
|
|
@@ -65,14 +65,15 @@
|
|
|
65
65
|
"data"
|
|
66
66
|
],
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@neteasecloudmusicapienhanced/unblockmusic-utils": "^0.2.
|
|
69
|
-
"axios": "^1.13.
|
|
68
|
+
"@neteasecloudmusicapienhanced/unblockmusic-utils": "^0.2.4",
|
|
69
|
+
"axios": "^1.13.6",
|
|
70
70
|
"crypto-js": "^4.2.0",
|
|
71
71
|
"dotenv": "^17.3.1",
|
|
72
72
|
"express": "^5.2.1",
|
|
73
73
|
"express-fileupload": "^1.5.2",
|
|
74
|
-
"
|
|
75
|
-
"
|
|
74
|
+
"gzip": "^0.1.0",
|
|
75
|
+
"music-metadata": "^11.12.3",
|
|
76
|
+
"node-forge": "^1.4.0",
|
|
76
77
|
"pac-proxy-agent": "^7.2.0",
|
|
77
78
|
"qrcode": "^1.5.4",
|
|
78
79
|
"safe-decode-uri-component": "^1.2.1",
|
|
@@ -81,22 +82,22 @@
|
|
|
81
82
|
"yargs": "^18.0.0"
|
|
82
83
|
},
|
|
83
84
|
"devDependencies": {
|
|
84
|
-
"@eslint/eslintrc": "^3.3.
|
|
85
|
-
"@eslint/js": "^9.39.
|
|
85
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
86
|
+
"@eslint/js": "^9.39.4",
|
|
86
87
|
"@types/express": "^5.0.6",
|
|
87
88
|
"@types/express-fileupload": "^1.5.1",
|
|
88
89
|
"@types/mocha": "^10.0.10",
|
|
89
|
-
"@types/node": "25.0
|
|
90
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
91
|
-
"@typescript-eslint/parser": "^8.
|
|
92
|
-
"eslint": "^9.39.
|
|
90
|
+
"@types/node": "25.5.0",
|
|
91
|
+
"@typescript-eslint/eslint-plugin": "^8.57.2",
|
|
92
|
+
"@typescript-eslint/parser": "^8.57.2",
|
|
93
|
+
"eslint": "^9.39.4",
|
|
93
94
|
"eslint-config-prettier": "^10.1.8",
|
|
94
95
|
"eslint-plugin-html": "^8.1.4",
|
|
95
96
|
"eslint-plugin-prettier": "^5.5.5",
|
|
96
|
-
"globals": "^
|
|
97
|
+
"globals": "^17.4.0",
|
|
97
98
|
"husky": "^9.1.7",
|
|
98
99
|
"intelli-espower-loader": "^1.1.0",
|
|
99
|
-
"lint-staged": "^16.
|
|
100
|
+
"lint-staged": "^16.4.0",
|
|
100
101
|
"mocha": "^11.7.5",
|
|
101
102
|
"nodemon": "^3.1.14",
|
|
102
103
|
"pkg": "^5.8.1",
|
package/public/docs/home.md
CHANGED
|
@@ -5143,6 +5143,72 @@ let data = encodeURIComponent(
|
|
|
5143
5143
|
|
|
5144
5144
|
**调用例子 :** `/comment/reply?id=2058263032&commentId=123456789&content=我也觉得这首歌很棒!`
|
|
5145
5145
|
|
|
5146
|
+
### DIFM电台 - 分类
|
|
5147
|
+
|
|
5148
|
+
说明: 调用此接口, 获取DIFM电台分类
|
|
5149
|
+
|
|
5150
|
+
**必选参数 :**
|
|
5151
|
+
|
|
5152
|
+
`sources`: 来源列表, 0: 最嗨电音 1: 古典电台 2: 爵士电台
|
|
5153
|
+
|
|
5154
|
+
**接口地址:** `/dj/difm/all/style/channel`
|
|
5155
|
+
|
|
5156
|
+
**调用例子:** `/dj/difm/all/style/channel?sources=[0]`
|
|
5157
|
+
|
|
5158
|
+
### DIFM电台 - 收藏列表
|
|
5159
|
+
|
|
5160
|
+
说明: 调用此接口, 获取DIFM电台收藏列表
|
|
5161
|
+
|
|
5162
|
+
**必选参数 :**
|
|
5163
|
+
|
|
5164
|
+
`sources`: 来源列表, 0: 最嗨电音 1: 古典电台 2: 爵士电台
|
|
5165
|
+
|
|
5166
|
+
**接口地址:** `/dj/difm/subscribe/channels/get`
|
|
5167
|
+
|
|
5168
|
+
**调用例子:** `/dj/difm/subscribe/channels/get?sources=[0]`
|
|
5169
|
+
|
|
5170
|
+
### DIFM电台 - 收藏频道
|
|
5171
|
+
|
|
5172
|
+
说明: 调用此接口, 可收藏DIFM频道
|
|
5173
|
+
|
|
5174
|
+
**必选参数 :**
|
|
5175
|
+
|
|
5176
|
+
`id`: 频道id
|
|
5177
|
+
|
|
5178
|
+
**接口地址:** `/dj/difm/channel/subscribe`
|
|
5179
|
+
|
|
5180
|
+
**调用例子:** `/dj/difm/channel/subscribe?id=1`
|
|
5181
|
+
|
|
5182
|
+
### DIFM电台 - 取消收藏频道
|
|
5183
|
+
|
|
5184
|
+
说明: 调用此接口, 可取消收藏DIFM频道
|
|
5185
|
+
|
|
5186
|
+
**必选参数 :**
|
|
5187
|
+
|
|
5188
|
+
`id`: 频道id
|
|
5189
|
+
|
|
5190
|
+
**接口地址:** `/dj/difm/channel/unsubscribe`
|
|
5191
|
+
|
|
5192
|
+
**调用例子:** `/dj/difm/channel/unsubscribe?id=1`
|
|
5193
|
+
|
|
5194
|
+
### DIFM电台 - 播放列表
|
|
5195
|
+
|
|
5196
|
+
说明: 调用此接口, 获取DIFM播放列表
|
|
5197
|
+
|
|
5198
|
+
**必选参数 :**
|
|
5199
|
+
|
|
5200
|
+
`source`: 来源, 0: 最嗨电音 1: 古典电台 2: 爵士电台
|
|
5201
|
+
|
|
5202
|
+
`channelId`: 频道id
|
|
5203
|
+
|
|
5204
|
+
**可选参数 :**
|
|
5205
|
+
|
|
5206
|
+
`limit`: 返回数量, 默认为 5
|
|
5207
|
+
|
|
5208
|
+
**接口地址:** `/dj/difm/playing/tracks/list`
|
|
5209
|
+
|
|
5210
|
+
**调用例子:** `/dj/difm/playing/tracks/list?source=0&channelId=1012`
|
|
5211
|
+
|
|
5146
5212
|
## 离线访问此文档
|
|
5147
5213
|
|
|
5148
5214
|
此文档同时也是 Progressive Web Apps(PWA), 加入了 serviceWorker, 可离线访问
|
package/server.js
CHANGED
|
@@ -127,15 +127,45 @@ async function checkVersion() {
|
|
|
127
127
|
})
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
function parseCorsAllowOrigins(corsAllowOrigin) {
|
|
131
|
+
if (!corsAllowOrigin) {
|
|
132
|
+
return null
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const origins = corsAllowOrigin
|
|
136
|
+
.split(',')
|
|
137
|
+
.map((origin) => origin.trim())
|
|
138
|
+
.filter(Boolean)
|
|
139
|
+
|
|
140
|
+
return origins.length > 0 ? origins : null
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function getCorsAllowOrigin(allowOrigins, requestOrigin) {
|
|
144
|
+
if (!allowOrigins) {
|
|
145
|
+
return requestOrigin || '*'
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (allowOrigins.includes('*')) {
|
|
149
|
+
return '*'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (requestOrigin && allowOrigins.includes(requestOrigin)) {
|
|
153
|
+
return requestOrigin
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return null
|
|
157
|
+
}
|
|
158
|
+
|
|
130
159
|
/**
|
|
131
160
|
* Construct the server of NCM API.
|
|
132
161
|
*
|
|
133
162
|
* @param {ModuleDefinition[]} [moduleDefs] Customized module definitions [advanced]
|
|
134
163
|
* @returns {Promise<import("express").Express>} The server instance.
|
|
135
164
|
*/
|
|
136
|
-
async function
|
|
165
|
+
async function constructServer(moduleDefs) {
|
|
137
166
|
const app = express()
|
|
138
167
|
const { CORS_ALLOW_ORIGIN } = process.env
|
|
168
|
+
const allowOrigins = parseCorsAllowOrigins(CORS_ALLOW_ORIGIN)
|
|
139
169
|
app.set('trust proxy', true)
|
|
140
170
|
|
|
141
171
|
/**
|
|
@@ -147,10 +177,17 @@ async function consturctServer(moduleDefs) {
|
|
|
147
177
|
*/
|
|
148
178
|
app.use((req, res, next) => {
|
|
149
179
|
if (req.path !== '/' && !req.path.includes('.')) {
|
|
180
|
+
const corsAllowOrigin = getCorsAllowOrigin(
|
|
181
|
+
allowOrigins,
|
|
182
|
+
req.headers.origin,
|
|
183
|
+
)
|
|
184
|
+
const shouldSetVaryHeader = corsAllowOrigin && corsAllowOrigin !== '*'
|
|
150
185
|
res.set({
|
|
151
186
|
'Access-Control-Allow-Credentials': true,
|
|
152
|
-
|
|
153
|
-
|
|
187
|
+
...(corsAllowOrigin
|
|
188
|
+
? { 'Access-Control-Allow-Origin': corsAllowOrigin }
|
|
189
|
+
: {}),
|
|
190
|
+
...(shouldSetVaryHeader ? { Vary: 'Origin' } : {}),
|
|
154
191
|
'Access-Control-Allow-Headers': 'X-Requested-With,Content-Type',
|
|
155
192
|
'Access-Control-Allow-Methods': 'PUT,POST,GET,DELETE,OPTIONS',
|
|
156
193
|
'Content-Type': 'application/json; charset=utf-8',
|
|
@@ -359,7 +396,7 @@ async function serveNcmApi(options) {
|
|
|
359
396
|
)
|
|
360
397
|
}
|
|
361
398
|
})
|
|
362
|
-
const constructServerSubmission =
|
|
399
|
+
const constructServerSubmission = constructServer(options.moduleDefs)
|
|
363
400
|
|
|
364
401
|
const [_, app] = await Promise.all([
|
|
365
402
|
checkVersionSubmission,
|
package/util/request.js
CHANGED
|
@@ -240,6 +240,7 @@ const createRequest = (uri, data, options) => {
|
|
|
240
240
|
headers['User-Agent'] = options.ua || chooseUserAgent('api', 'iphone')
|
|
241
241
|
|
|
242
242
|
if (crypto === 'eapi') {
|
|
243
|
+
// headers['x-aeapi'] = true // 服务器会使用gzip压缩返回值
|
|
243
244
|
data.header = header
|
|
244
245
|
data.e_r = toBoolean(
|
|
245
246
|
options.e_r !== undefined
|
|
@@ -323,6 +324,7 @@ const createRequest = (uri, data, options) => {
|
|
|
323
324
|
if (crypto === 'eapi' && data.e_r) {
|
|
324
325
|
answer.body = encrypt.eapiResDecrypt(
|
|
325
326
|
body.toString('hex').toUpperCase(),
|
|
327
|
+
headers['x-aeapi'],
|
|
326
328
|
)
|
|
327
329
|
} else {
|
|
328
330
|
answer.body =
|