merge: 同步 main(neapi 支持、v9.6.13 接口、cookie 解析修复)并解决冲突

This commit is contained in:
yukka-agent[bot]
2026-10-25 04:36:42 +00:00
40 changed files with 1440 additions and 397 deletions
+9
View File
@@ -0,0 +1,9 @@
// 首页轮播(v3)
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
clientType: query.clientType || 'android',
}
return request(`/api/banner/get/v3`, data, createOption(query, 'weapi'))
}
+13
View File
@@ -0,0 +1,13 @@
// 评论默认文案
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
threadId: query.threadId,
}
return request(
`/api/comment/default/text`,
data,
createOption(query, 'weapi'),
)
}
+11
View File
@@ -0,0 +1,11 @@
// 热评墙广场信息
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {}
return request(
`/api/comment/hotwall/today/squareinfo/get`,
data,
createOption(query, 'weapi'),
)
}
+15
View File
@@ -0,0 +1,15 @@
// 动态搜索
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
keyword: query.keyword || query.keywords || '',
limit: query.limit || 30,
offset: query.offset || 0,
}
return request(
`/api/event/search/list/get/v1`,
data,
createOption(query, 'weapi'),
)
}
+15
View File
@@ -0,0 +1,15 @@
// 乐迷团详情
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
groupId: query.groupId || query.id || '',
scene: query.scene || '',
}
return request(
'/api/social/fansgroup/bff/detail/get',
data,
createOption(query, 'eapi'),
)
}
+17
View File
@@ -0,0 +1,17 @@
// 乐迷团推荐笔记
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
artistSelf: query.artistSelf || '0',
fansGroupId: query.fansGroupId || query.groupId || '',
cursor: query.cursor || '0',
size: String(query.size || 10),
}
return request(
'/api/fans/group/feed/recommend/get',
data,
createOption(query, 'eapi'),
)
}
+14
View File
@@ -0,0 +1,14 @@
// 用户所处乐迷团详情
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
groupId: query.groupId || query.id || '',
}
return request(
'/api/social/fansgroup/bff/user/group/detail/get',
data,
createOption(query, 'eapi'),
)
}
+11
View File
@@ -0,0 +1,11 @@
// 获取当前登录用户加入的全部歌手乐迷团列表
const createOption = require('../util/option.js')
module.exports = (query, request) => {
return request(
'/api/social/fansgroup/bff/user/groups/get',
{},
createOption(query, 'eapi'),
)
}
+7 -2
View File
@@ -1,10 +1,15 @@
const QRCode = require('qrcode')
const { generateChainId } = require('../util/index')
const { generateChainId, getCookieHeader, hasCookie } = require('../util/index')
module.exports = (query) => {
return new Promise(async (resolve) => {
const platform = query.platform || 'pc'
const cookie = query.cookie || ''
const headerCookie = getCookieHeader(query.headers)
const cookie = hasCookie(query.cookie)
? query.cookie
: hasCookie(headerCookie)
? headerCookie
: ''
// 构建基础URL
let url = `https://music.163.com/login?codekey=${query.key}`
+11
View File
@@ -0,0 +1,11 @@
// 每日风格推荐场景配置列表获取
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {}
return request(
`/api/homepage/daily/song/config/get`,
data,
createOption(query, 'xeapi'),
)
}
+17
View File
@@ -0,0 +1,17 @@
// 每日风格推荐场景配置设置
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
tags: JSON.stringify({
tagIds: String(query.tags).split(',').map(Number),
categoryId: Number(query.category),
}),
}
console.log(data)
return request(
`/api/homepage/daily/song/tag/save`,
data,
createOption(query, 'xeapi'),
)
}
+11
View File
@@ -0,0 +1,11 @@
// 每日推荐风格歌曲
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {}
return request(
`/api/homepage/category/daily/song/list`,
data,
createOption(query, 'xeapi'),
)
}
+13
View File
@@ -0,0 +1,13 @@
// 每日推荐歌曲 - v1
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
ispush: query.ispush || false,
}
return request(
`/api/v3/discovery/recommend/songs`,
data,
createOption(query, 'xeapi'),
)
}
+48
View File
@@ -0,0 +1,48 @@
const { default: axios } = require('axios')
const { APP_CONF } = require('../util/config.json')
const { saveNeapiKey } = require('../util/neapiKey')
const { decodeConfig } = require('../util/neapiConfig')
const USER_AGENT =
'NeteaseMusic/9.5.61.260802021928(9005061);Dalvik/2.1.0 (Linux; U; Android 12; HBN-AL00 Build/cd737a2.0)'
module.exports = async (query, request) => {
const version = Number(query.version) || 0
const behavior = query.behavior === 'update' ? 'update' : 'open'
const res = await axios({
method: 'GET',
url: APP_CONF.apiDomain + '/api/gorilla/algorithm/record',
params: { version, behavior },
headers: { 'User-Agent': USER_AGENT },
proxy: false,
})
if (!res.data || res.data.code !== 200 || !res.data.data) {
throw new Error('neapi config request failed')
}
// file 为空表示本地已是最新,无需更新
const { file, circleTime } = res.data.data
const config = file
? saveNeapiKey(decodeConfig(Buffer.from(file, 'base64')), circleTime)
: null
// 只回版本与密钥偏移,密钥本身留在本地缓存
const keyOffsets = {}
if (config) {
keyOffsets.encrypt = config.keyBlob.indexOf(config.encryptKey)
keyOffsets.decrypt = config.keyBlob.indexOf(config.decryptKey)
}
return {
status: 200,
body: {
version: config ? config.version : res.data.data.version,
updated: Boolean(config),
circleTime,
keyOffsets,
},
cookie: [],
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ module.exports = async (query, request) => {
const res = await axios({
method: 'POST',
url: APP_CONF.apiDomain + '/api/gorilla/anti/crawler/security/key/get',
url: APP_CONF.apiDomain + '/api/bsr/sk/get',
headers: {
'User-Agent':
'NeteaseMusic/9.5.61.260802021928(9005061);Dalvik/2.1.0 (Linux; U; Android 12; HBN-AL00 Build/cd737a2.0)',
+10 -2
View File
@@ -1,18 +1,26 @@
// 听歌打卡
const createOption = require('../util/option.js')
const { getCookieHeader, hasCookie } = require('../util/index')
const { APP_CONF } = require('../util/config.json')
const DOMAIN = APP_CONF.clDomian
module.exports = async (query, request) => {
// 注入 os=osx 的 cookie
let cookie = query.cookie || ''
const headerCookie = getCookieHeader(query.headers)
let cookie = hasCookie(query.cookie)
? query.cookie
: hasCookie(headerCookie)
? headerCookie
: process.env.NETEASE_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 {
} else if (cookie) {
cookie = cookie + '; os=osx'
} else {
cookie = 'os=osx'
}
} else {
cookie = 'os=osx'
+7 -1
View File
@@ -13,6 +13,7 @@ const {
buildMetaJson,
doUpload,
} = require('../util/ncbl')
const { getCookieHeader, hasCookie } = require('../util/index')
module.exports = async (query, request) => {
// --- 参数校验 ---
@@ -32,7 +33,12 @@ module.exports = async (query, request) => {
const sourceName = query.source || 'list'
// --- 解析认证上下文 ---
const rawCookie = query.cookie || ''
const headerCookie = getCookieHeader(query.headers)
const rawCookie = hasCookie(query.cookie)
? query.cookie
: hasCookie(headerCookie)
? headerCookie
: process.env.NETEASE_COOKIE || ''
const cookieObj = parseCookie(rawCookie)
cookieObj.os = 'pc'
const ctx = extractContext(cookieObj)
+15
View File
@@ -0,0 +1,15 @@
// 按歌词搜索
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
keyword: query.keyword || query.keywords || '',
limit: query.limit || 30,
offset: query.offset || 0,
}
return request(
`/api/search/resource/lyric`,
data,
createOption(query, 'weapi'),
)
}
+16
View File
@@ -0,0 +1,16 @@
// 新版单曲搜索(分页)
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
keyword: query.keyword || query.keywords || '',
limit: query.limit || 30,
offset: query.offset || 0,
scene: query.scene || 'normal',
}
return request(
`/api/search/song/list/page`,
data,
createOption(query, 'weapi'),
)
}
+15
View File
@@ -0,0 +1,15 @@
// 搜索联想(App 移动端版:直hit歌曲卡 + 联想词 + 热搜/原唱标签)
// 注意:参数名为 keyword(传 s 会返回 HTTP 400 空体),
// 与 search_suggest 的旧版 /api/search/suggest/keyword 不同。
const createOption = require('../util/option.js')
module.exports = (query, request) => {
const data = {
keyword: query.keyword || query.keywords || '',
}
return request(
`/api/search/suggest/keyword/get`,
data,
createOption(query, 'weapi'),
)
}