Compare commits

..

No commits in common. "60ee927e3224ab675679d023065225af11bdc693" and "6fc4231142e2a91913cdf54f27cc9722391e30c0" have entirely different histories.

6 changed files with 20 additions and 104 deletions

View File

@ -1,23 +0,0 @@
# Agent Instructions for NeteaseCloudMusicApiEnhanced
## Quick Start
- **Package Manager**: Use `pnpm` (not npm or yarn).
- **Node Version**: Requires Node.js 18 or later.
## Developer Commands
- **Install dependencies**: `pnpm i`
- **Start server**: `pnpm start` or `node app.js`
- **Start dev server**: `pnpm dev` (uses nodemon)
- **Run tests**: `pnpm test` (uses Mocha)
- **Linting**: `pnpm lint` (check) or `pnpm lint-fix` (auto-fix)
## Architecture & Entrypoints
- **Executable Server**: `app.js` is the main entrypoint for running the API server.
- **Module Exports**: `main.js` is the entrypoint when the project is imported as a Node.js dependency.
- **API Endpoints**: Located in the `module/` directory. Each file typically corresponds to an API route.
- **Core Utilities**: Request handling, encryption, and core utilities are found in the `util/` directory.
## Important Gotchas & Quirks
- **Environment Variables**: The server defaults to port 3000 but can be overridden with the `PORT` environment variable.
- **Proxy Variables**: Be very careful with proxy environment variables (`http_proxy`, `https_proxy`, `no_proxy`). The request library (like axios) will automatically pick these up. If they point to an unavailable proxy (especially common in Docker environments), requests will fail silently or throw connection errors.
- **Code Style**: The project uses ESLint and Prettier. Always run `pnpm lint-fix` before committing changes to ensure formatting consistency.

View File

@ -1,40 +1,8 @@
// 听歌打卡
const createOption = require('../util/option.js')
module.exports = async (query, request) => {
// 注入 os=osx 的 cookie
let cookie = query.cookie || ''
if (typeof cookie === 'object') {
cookie = Object.assign({ os: 'osx' }, cookie)
} else if (typeof cookie === 'string') {
if (cookie.indexOf('os=') > -1) {
cookie = cookie.replace(/os=[^;]+/g, 'os=osx')
} else {
cookie = cookie + '; os=osx'
}
} else {
cookie = 'os=osx'
}
query.cookie = cookie
// 1) startplay → 进「最近播放」
const startplayData = {
logs: JSON.stringify([
{
action: 'startplay',
json: {
id: query.id,
type: 'song',
mainsite: '1',
mainsiteWeb: '1',
content: `id=${query.sourceid}`,
},
},
]),
}
// 2) play → 涨「听歌排行」计数
const playData = {
module.exports = (query, request) => {
const data = {
logs: JSON.stringify([
{
action: 'play',
@ -47,30 +15,12 @@ module.exports = async (query, request) => {
type: 'song',
wifi: 0,
source: 'list',
mainsite: '1',
mainsiteWeb: '1',
content: `id=${query.sourceid}`,
mainsite: 1,
content: '',
},
},
]),
}
const option = createOption(query, 'eapi')
option.domain = 'https://clientlog.music.163.com'
// 发送两次请求
const res1 = await request(`/api/feedback/weblog`, startplayData, option)
const res2 = await request(`/api/feedback/weblog`, playData, option)
return {
status: 200,
body: {
code: 200,
data: 'success',
details: {
startplay: res1.body,
play: res2.body,
},
},
}
return request(`/api/feedback/weblog`, data, createOption(query, 'weapi'))
}

View File

@ -1,6 +1,6 @@
{
"name": "@neteasecloudmusicapienhanced/api",
"version": "4.35.2",
"version": "4.35.1",
"description": "全网最全的网易云音乐API接口 || A revival project for NeteaseCloudMusicApi Node.js Services (Half Refactor & Enhanced) || 网易云音乐 API 备份 + 增强 || 本项目自原版v4.28.0版本后开始自行维护",
"scripts": {
"dev": "nodemon app.js",

View File

@ -10,7 +10,6 @@ const { cookieToJson } = require('./util/index')
const fileUpload = require('express-fileupload')
const decode = require('safe-decode-uri-component')
const logger = require('./util/logger.js')
const { APP_CONF } = require('./util/config.json')
/**
* The version check result.
@ -300,15 +299,15 @@ async function constructServer(moduleDefs) {
)
try {
let usedCrypto = ''
const moduleResponse = await moduleDef.module(query, (...params) => {
// 参数注入客户端IP
const obj = [...params]
const options = obj[2] || {}
usedCrypto = options.crypto || ''
let ip = ''
if (options.randomCNIP) {
ip = global.cnIp
// logger.info('Using random Chinese IP for request:', ip)
} else {
ip = req.ip
@ -318,6 +317,7 @@ async function constructServer(moduleDefs) {
if (ip == '::1') {
ip = global.cnIp
}
// logger.info('Requested from ip:', ip)
}
obj[2] = {
@ -327,10 +327,7 @@ async function constructServer(moduleDefs) {
return request(...obj)
})
const displayCrypto = usedCrypto || (APP_CONF.encrypt ? 'eapi' : 'api')
logger.info(
`Request Success: [${displayCrypto}] ${decode(req.originalUrl)}`,
)
logger.info(`Request Success: ${decode(req.originalUrl)}`)
// 夹带私货部分如果开启了通用解锁并且是获取歌曲URL的接口则尝试解锁如果需要的话ヾ(≧▽≦*)o
if (
@ -425,7 +422,7 @@ async function serveNcmApi(options) {
options.checkVersion &&
checkVersion().then(({ npmVersion, ourVersion, status }) => {
if (status == VERSION_CHECK_RESULT.NOT_LATEST) {
logger.warn(
logger.info(
`最新版本: ${npmVersion}, 当前版本: ${ourVersion}, 请及时更新`,
)
}
@ -447,9 +444,11 @@ async function serveNcmApi(options) {
`)
logger.info(
`Server started successfully @ http://${host ? host : 'localhost'}:${port}`,
)
logger.info(`
- Server started successfully @ http://${host ? host : 'localhost'}:${port}
- Environment: ${process.env.NODE_ENV || 'development'}
- Node Version: ${process.version}
- Process ID: ${process.pid}`)
})
return appExt

View File

@ -62,9 +62,9 @@ const chinaIPRanges = (function loadChinaIPRanges() {
// attach total for convenience
arr.totalCount = total
// logger.info(
// `Loaded ${arr.length} Chinese IP ranges from china_ip_ranges.txt, total ${total} IPs`,
// )
logger.info(
`Loaded ${arr.length} Chinese IP ranges from china_ip_ranges.txt, total ${total} IPs`,
)
return arr
} catch (error) {
logger.error('Failed to load china_ip_ranges.txt:', error.message)

View File

@ -88,12 +88,6 @@ const osMap = {
osver: '16.2',
channel: 'distribution',
},
osx: {
os: 'osx',
appver: '3.1.10.5100',
osver: '15.5',
channel: 'netease',
},
}
// 预先定义userAgentMap
@ -312,11 +306,7 @@ const createRequest = (uri, data, options) => {
if (cookie.MUSIC_A) header['MUSIC_A'] = cookie.MUSIC_A
headers['Cookie'] = createHeaderCookie(header)
headers['User-Agent'] =
options.ua ||
(cookie.os === 'osx'
? 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36'
: chooseUserAgent('api', 'iphone'))
headers['User-Agent'] = options.ua || chooseUserAgent('api', 'iphone')
if (crypto === 'eapi') {
// headers['x-aeapi'] = true // 服务器会使用gzip压缩返回值