Cadence
Cadence 是 Java 8 音乐数据客户端。它提供网易云音乐和 QQ 音乐的搜索、播放直链、歌词与二维码登录接口。
Cadence 只取数据,不播放音频,也不提供界面。SongUrl.url 应交给宿主自己的播放器。
源码位于 Cadence,采用 MIT 许可证。
引入
当前公开 tag 是 v0.1.1,通过 JitPack 获取:
repositories {
maven("https://jitpack.io")
}
dependencies {
implementation("com.github.FPSMasterTeam:Cadence:v0.1.1")
}源码包名仍是 top.fpsmaster.music.*。本地 publishToMavenLocal 使用另一组坐标:
top.fpsmaster:music-api:0.1.1库本身输出 Java 8 字节码。运行时还需要 Kotlin 标准库和 Gson;正常的 Gradle 依赖解析会带入它们。若宿主关闭传递依赖或将 Cadence 打进自己的 jar,需要自行保证这两个运行时依赖存在。
使用 MusicService
MusicService 是统一入口。调用方选择音乐来源,返回值使用同一组模型:
import top.fpsmaster.music.AudioQuality
import top.fpsmaster.music.MusicService
import top.fpsmaster.music.MusicSource
val music = MusicService()
val tracks = music.search(MusicSource.NETEASE, "搜索关键词")
val track = tracks.firstOrNull()
if (track != null) {
val song = music.getSongUrl(track, AudioQuality.STANDARD)
if (song.available) {
player.play(song.url!!)
} else {
logger.warn(song.reason ?: "没有可用直链")
}
}不要假设请求的音质一定可用。检查:
available:是否有直链。quality:实际返回的音质,可能低于请求值。isTrial:是否为试听片段。reason:不可用时的原因。
会员内容、地区限制和登录状态都可能让链接降级或为空。
调用音乐平台服务时应遵守对应平台条款,只使用自己的账户和获授权访问的内容。播放直链可能受时效和账户状态限制,不要记录后再次分发。
歌词
MusicService.getLyric(track) 已返回解析后的时间轴:
val lyric = music.getLyric(track)
for (line in lyric.lines) {
renderLine(
startMs = line.startMs,
text = line.text,
translation = line.translation
)
}网易云结果可能包含逐字时间:
for (word in line.words) {
highlight(word.text, word.startMs, word.durationMs)
}只需要离线解析已有文本时,直接使用 LyricParser:
import top.fpsmaster.music.lyric.LyricParser
val lines = LyricParser.parse(
lrc = lrcText,
translated = translatedText,
yrc = wordByWordText
)解析器支持标准 LRC、时间偏移、单行多时间戳、翻译对齐和网易云 YRC 逐字数据。它不发起网络请求。
二维码登录
二维码由宿主显示和轮询:
val qr = music.createQrCode(MusicSource.NETEASE)
showQrCode(qr.qrContent)
val state = music.checkQrCode(MusicSource.NETEASE, qr)
when (state) {
QrLoginState.WAITING -> showStatus("等待扫码")
QrLoginState.SCANNED -> showStatus("等待确认")
QrLoginState.CONFIRMED -> showStatus("登录成功")
QrLoginState.EXPIRED -> requestNewQrCode()
QrLoginState.ERROR -> showStatus("登录失败")
}网易云的 qrContent 是待编码为二维码的 URL。QQ 音乐的 qrContent 是 data URL。登录成功后,凭证写入对应的 NeteaseMusicApi 或 QQMusicApi 实例。
轮询应由宿主调度。不要在渲染线程中循环等待。
凭证存储
MusicCredentialStore 是可选工具。存储路径由宿主提供:
val store = MusicCredentialStore.inDir(appPrivateDataDir)
store.load()
music.netease.cookie = store.neteaseCookie
music.qq.musicid = store.qqMusicId
music.qq.musicKey = store.qqMusicKey登录成功后再调用 setNetease 或 setQq 保存当前实例中的凭证。示例不包含真实 Cookie。生产环境应使用用户私有目录,并按平台能力限制文件访问权限。不要把凭证写进日志、仓库或同步配置。
日志 SPI
Cadence 默认不输出日志。宿主可以替换 MusicLog.logger:
MusicLog.logger = object : MusicLogger {
override fun info(msg: String) {
appLogger.info(msg)
}
override fun error(msg: String, t: Throwable?) {
appLogger.error(msg, t)
}
}接入时避免记录请求凭证和完整响应头。
开发 Cadence
使用 JDK 17 或 21 运行仓库的 Gradle 9 Wrapper,不要用 JDK 8 启动 Gradle。编译产物仍是 Java 8 字节码。
git clone https://github.com/FPSMasterTeam/Cadence.git
cd Cadence
./gradlew build
./gradlew publishToMavenLocalbuild 会编译 Java 8 目标字节码并运行测试。修改 MusicService 或平台客户端时,至少覆盖空结果、不可用直链、过期二维码和异常响应。修改 LyricParser 时补充纯文本单元测试。
不要在使用文档中固化平台内部签名步骤。平台接口发生变化时,应在库内修复并保持 MusicService 的公共入口稳定。
