突破音乐限制:UnblockNeteaseMusic请求处理全解析
系统架构概览
UnblockNeteaseMusic通过拦截和转换网易云音乐请求,实现受限歌曲的播放功能。核心流程涉及请求拦截、SNI解析、元数据获取和多平台资源匹配。系统主要模块位于src/目录,包括请求处理server.js、SNI解析sni.js、钩子处理hook.js和资源匹配provider/模块。
核心模块关系
SNI解析:请求入口点
SNI(Server Name Indication)解析是系统处理HTTPS请求的第一个环节。sni.js模块通过解析TLS握手数据包,提取目标域名信息,实现对网易云音乐服务器的精准识别。
SNI解析关键代码
// [sni.js](https://link.gitcode.com/i/e261599ff5195fec5bda6185ade10414) 核心逻辑
module.exports = data => {
let end = data.length
let pointer = 5 + 1 + 3 + 2 + 32 // TLS握手包结构偏移
// 提取扩展字段
const extensionsLength = data.readInt16BE(pointer)
pointer += 2
const extensionsEnd = pointer + extensionsLength
// 查找SNI扩展
while (pointer + 4 <= end) {
const extensionType = data.readInt16BE(pointer)
const extensionSize = data.readInt16BE(pointer + 2)
pointer += 4
if (extensionType !== 0) { // 0表示SNI扩展类型
pointer += extensionSize
continue
}
// 提取服务器名称
const nameListLength = data.readInt16BE(pointer)
pointer += 2
// ...名称解析逻辑
return data.toString('ascii', pointer, pointer + nameLength)
}
return null
}
SNI解析结果会传递给TLS隧道处理,用于决定是否对请求进行拦截和转换。
请求处理流水线
服务器模块server.js实现了完整的请求处理流程,包括MITM(中间人)代理和TLS隧道两种模式。系统通过proxy.core对象定义了请求处理的核心逻辑。
关键处理阶段
- 请求保护:设置错误处理和连接管理proxy.protect
- 认证校验:处理代理授权proxy.authenticate
- 请求过滤:基于白名单和黑名单过滤请求proxy.filter
- 日志记录:输出请求处理日志proxy.log
- 请求转发:根据请求类型选择处理方式mitm/隧道
MITM模式处理流程
当系统识别到网易云音乐API请求时,会启动MITM模式,对请求和响应进行深度处理:
// [server.js](https://link.gitcode.com/i/195273f3a0e709acce35e6997ff1a68b) MITM请求处理
mitm: {
request: ctx => new Promise((resolve, reject) => {
const options = request.configure(req.method, url, req.headers)
ctx.proxyReq = request.create(url)(options)
.on('response', proxyRes => resolve(ctx.proxyRes = proxyRes))
.on('error', error => reject(ctx.error = error))
req.readable ? req.pipe(ctx.proxyReq) : ctx.proxyReq.end(req.body)
}),
response: ctx => {
proxyRes.on('error', () => proxy.abort(proxyRes.socket, 'proxyRes'))
res.writeHead(proxyRes.statusCode, proxyRes.headers)
proxyRes.readable ? proxyRes.pipe(res) : res.end(proxyRes.body)
}
}
钩子系统:请求转换核心
hook.js模块实现了对网易云音乐API请求的拦截和转换,是实现歌曲解锁的关键环节。系统通过定义目标主机和路径集合,精准匹配需要处理的API请求。
目标请求定义
// [hook.js](https://link.gitcode.com/i/4335c5e7b008a85f3ca49d75d8a6e701) 目标主机和路径定义
hook.target.host = new Set([
'music.163.com',
'interface.music.163.com',
'interface3.music.163.com',
'apm.music.163.com',
'apm3.music.163.com'
])
hook.target.path = new Set([
'/api/v3/playlist/detail',
'/api/v3/song/detail',
'/api/song/enhance/player/url',
'/api/song/enhance/player/url/v1',
'/api/song/enhance/download/url'
// ...其他API路径
])
请求处理流程
- 请求拦截:在hook.request.before中解析和转换请求
- 参数解密:对网易云音乐加密参数进行解密处理
- 响应处理:在hook.request.after中修改API响应
- 资源注入:将匹配到的第三方资源URL注入到响应中
元数据与资源匹配
当系统检测到歌曲播放请求时,会启动资源匹配流程,从第三方平台获取可用资源。这一过程主要由find.js和match.js模块协作完成。
元数据获取
find.js模块从网易云音乐API获取歌曲元数据,并进行标准化处理:
// [find.js](https://link.gitcode.com/i/fed3bb98be638945ea4a11031eb48546) 元数据处理
const find = id => {
return request('GET', 'https://music.163.com/api/song/detail?ids=[' + id + ']')
.then(response => response.json())
.then(jsonBody => {
const info = {
id: jsonBody.songs[0].id,
name: jsonBody.songs[0].name,
// 移除翻唱标记
.replace(/(\s*cover[::\s][^)]+)/i, '')
.replace(/\(\s*cover[::\s][^\)]+\)/i, ''),
artists: jsonBody.songs[0].artists.map(artist => ({
id: artist.id,
name: artist.name
}))
}
info.keyword = info.name + ' - ' + info.artists.map(a => a.name).join(' / ')
return info
})
}
多平台资源匹配
match.js模块实现了跨平台资源查找功能,目前支持QQ音乐、酷我、咪咕等多个平台:
// [match.js](https://link.gitcode.com/i/90617f83a4078c75c07dfd623f60c2b3) 资源匹配核心
const match = (id, source) => {
const candidate = (source || ['qq', 'kuwo', 'migu']).filter(name => name in provider)
return find(id)
.then(info => Promise.all(candidate.map(name =>
provider[name].check(info).catch(() => {}))))
.then(urls => Promise.all(urls.filter(url => url).map(url => check(url))))
.then(songs => {
songs = songs.filter(song => song.url)
return songs.length ? songs[0] : Promise.reject()
})
}
缓存系统:性能优化关键
为提高重复请求处理效率,系统实现了基于内存的缓存机制cache.js,对元数据和资源匹配结果进行缓存:
// [cache.js](https://link.gitcode.com/i/c2e1ed94e924b725df46e615a9eb99a9) 缓存实现
module.exports = (job, parameter, live = 30 * 60 * 1000) => {
const cache = job.cache ? job.cache : job.cache = {}
const key = parameter == null ? 'default' : parameter.toString()
if (!cache[key] || cache[key].expiration < Date.now()) {
cache[key] = {
expiration: Date.now() + live,
execution: job(parameter)
.then(result => done('resolve', result))
.catch(result => done('reject', result))
}
}
return cache[key].execution
}
缓存默认有效期为30分钟,可有效减少重复网络请求,提升系统响应速度。
总结与扩展
UnblockNeteaseMusic通过精巧的请求拦截和转换机制,实现了网易云音乐受限歌曲的播放功能。核心流程从SNI解析开始,经过多层过滤和转换,最终通过多平台资源匹配,为用户提供可用的音乐资源。
系统架构设计具有良好的可扩展性,可通过添加新的provider模块支持更多音乐平台。目前已实现的平台包括:
- QQ音乐:qq.js
- 酷我音乐:kuwo.js
- 咪咕音乐:migu.js
- 百度音乐:baidu.js
- YouTube:youtube.js
通过这种模块化设计,开发者可以轻松扩展系统功能,支持更多音乐平台和新的API特性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



