mStream 6.32.0 API 使用详解
mStream 6.32.0 REST API 使用详解:257 个操作的 openapi 全景、JWT 认证实测,以及曲库/媒体/播放列表/评分/扫描/分享/用户管理七大域逐端点 curl 实录
mStream 6.32.0 API 使用详解
目标:本文面向需要对 mStream 做二次开发或自动化集成的读者,给出 6.32.0 的 API 全景(来源为随源码发布的 openapi.yaml)、认证方式与七大业务域端点的逐条 curl 实测(请求体、真实响应回显、错误码)。全部请求已在 Ubuntu 24.04 服务器(mStream 6.32.0,API 基址 http://localhost:8155,曲库 6 首 mp3)实测通过。
一、环境信息
- 操作系统:Ubuntu 24.04(x86_64)
- mStream:6.32.0(
mstream -V实测6.32.0) - API 基址:http://localhost:8155(进程内监听 3000,对外经 8155 访问)
- API 规范文件:随源码仓库发布的 docs/openapi.yaml(https://github.com/IrosTheBeggar/mStream/blob/master/docs/openapi.yaml)
- 曲库:vpath
music下 6 首 mp3(2 张专辑:Signal Garden、Analog Diary;2 位艺人:Studio Test、Lo-Fi Collective) - 客户端工具:curl 8.x + python3(json 解析)
- 演示账号:admin / q1w2e3r4
二、前置条件
- 服务已部署并可访问(部署见《mStream 6.32.0 Docker Compose 部署指南》)。探活:
curl -s http://localhost:8155/api/v1/ping -w '\nHTTP %{http_code}\n'
实测输出:
HTTP 200
- 准备一个管理员 token(下文多数请求需要),并保存到变量:
TOKEN=$(curl -s -X POST http://localhost:8155/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}' \
| python3 -c "import sys,json;print(json.load(sys.stdin)['token'])")
echo "${TOKEN:0:24}..."
实测输出:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
- (可选)本机解析 openapi.yaml 统计端点面(用于核实第四章总览数字):
python3 -c "
import re
raw=open('openapi.yaml').read()
paths=re.findall(r'^\s{2}(/[^\s:]+):',raw,re.M)
print('paths:',len(paths))
"
实测输出:
paths: 238
三、API 总览
mStream 6.32.0 的对外接口由四类 URL 组成(实测归纳自 openapi.yaml 与请求验证):
| 类别 | 前缀/示例 | 数量(openapi.yaml 统计) | 说明 |
|---|---|---|---|
| 业务 API | /api/v1/... | 231 个操作 | 登录、曲库、播放列表、扫描、管理、联邦等 |
| 媒体端点 | /media/...、/transcode/...、/album-art/... | 3 类 | 音频流、实时转码、封面 |
| 页面路由 | /shared/...、/admin、/remote | 若干 | 分享页、管理面板 |
| 健康 | /api/v1/ping | 1 | 探活 |
按 HTTP 方法统计(openapi.yaml 全量解析实测):POST 164、GET 75、DELETE 13、PUT 5,合计 257 个操作。约定:请求与响应均为 JSON(媒体端点除外);认证一律是 JWT;管理类端点要求账号具备 admin 位(预置方法见《mStream 6.32.0 配置参数详解》第五章)。API 无独立文档站,openapi.yaml 是权威契约。
四、认证与首次调用
4.1 登录获取 token
curl -s -X POST http://localhost:8155/api/v1/auth/login \
-H 'Content-Type: application/json' \
-d '{"username":"admin","password":"q1w2e3r4"}' -w '\nHTTP %{http_code}\n'
实测输出:
{"vpaths":["music"],"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiaWF0IjoxNzkzMjgxMzg2fQ.hm9DNSXIjGt23J2RkoUlUyZehDJr2GTfbLWYYDLxygc"}
HTTP 200
响应含该用户可见的 vpath 列表与 JWT token。token payload 实测只含 username 与 iat(签发时间),没有 exp 过期字段——token 长期有效,直至服务端更换 config 的 secret 密钥。
4.2 携带方式与失败形态
token 有两种携带方式,任选其一:
curl -s -o /dev/null -w 'header -> %{http_code}\n' -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/db/status
curl -s -o /dev/null -w 'query -> %{http_code}\n' "http://localhost:8155/media/music/track01.mp3?token=$TOKEN"
实测输出:
header -> 200
query -> 200
媒体端点(/media、/transcode、/album-art)推荐 query 方式(播放器/浏览器直链友好);JSON API 推荐 header。失败形态实测:
curl -s -o /dev/null -w 'no-token -> %{http_code}\n' http://localhost:8155/api/v1/db/status
curl -s -o /dev/null -w 'bad-token -> %{http_code}\n' -H 'x-access-token: invalid.token.here' http://localhost:8155/api/v1/db/status
实测输出:
no-token -> 401
bad-token -> 401
curl -s -X POST http://localhost:8155/api/v1/auth/login -H 'Content-Type: application/json' -d '{"username":"admin","password":"wrongpass"}' -w '\nHTTP %{http_code}\n'
实测输出:
{"error":"Login Failed"}
HTTP 401
五、各 API 域详解
5.1 曲库目录域(db)
曲库规模:
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/db/status
实测输出:
{"totalFileCount":6,"locked":false}
locked: true 表示扫描进行中(此时部分查询会被拒),可作为扫描完成判据。
艺人/专辑/流派列表:
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/db/artists
实测输出:
{"artists":["Lo-Fi Collective","Studio Test"]}
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/db/albums
实测输出(节选,实测首条):
{"albums":[{"name":"Analog Diary","year":2025,"album_art_file":null,"album_artist":"Lo-Fi Collective","artists":["Lo-Fi Collective"],"compilation":false,"year_min":2025,"year_max":2025,"track_count":3,"duration":101.12}, ...]}
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/db/genres
实测输出(测试音频未打流派标签,符合预期):
{"genres":[]}
专辑曲目(POST,按专辑名过滤):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"album":"Signal Garden"}' http://localhost:8155/api/v1/db/album-songs
实测输出(节选,实测首条):
[{"filepath":"music/track01.mp3","metadata":{"artist":"Studio Test","album":"Signal Garden","track":1,"title":"Morning Wave","duration":30.041,"year":2026,"album-art":"7d38193e4babe32d0b8de73c0dc8d261.jpeg","rating":null,"bpm":null,"musical-key":"A minor","bitrate":128000,"format":"mp3","sample-rate":44100,"file-size":481216,"audio-hash":"c90eae76455b925a8455f11237a58e77","created-at":"2026-10-29 13:42:53", ...}}, ...]
要点:filepath 以 vpath 为前缀(music/...),后续媒体端点、播放列表都使用该形态路径;元数据里的 musical-key/bpm 来自扫描后 essentia 分析(未分析的曲目为 null)。
全文检索(FTS5):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"search":"morning"}' http://localhost:8155/api/v1/db/search
实测输出(节选):
{"artists":[],"albums":[],"title":[{"name":"Studio Test - Morning Wave","album_art_file":"7d38193e4babe32d0b8de73c0dc8d261.jpeg","filepath":"music/track01.mp3","metadata":{ ... }}],"files":[],"lyrics":[]}
结果按 artists/albums/title/files/lyrics 五桶分组返回。
5.2 媒体流与转码域
源流播放(支持 Range 拖动):
curl -s -o /dev/null -w 'no auth -> %{http_code}\n' http://localhost:8155/media/music/track01.mp3
curl -s -H "x-access-token: $TOKEN" -r 0-99 -o /tmp/r1.bin \
-w 'range -> %{http_code} type=%{content_type} got=%{size_download}B\n' \
http://localhost:8155/media/music/track01.mp3
实测输出:
no auth -> 401
range -> 206 type=audio/mpeg got=100B
401/206 的组合说明:媒体端点同样受 JWT 保护,认证后返回 206 Partial Content 支持拖动。
实时转码(Opus/OGG,可带 bitrate 参数):
curl -s -H "x-access-token: $TOKEN" -o /tmp/tc.bin \
-w 'transcode -> %{http_code} type=%{content_type} got=%{size_download}B\n' \
http://localhost:8155/transcode/music/track01.mp3
file /tmp/tc.bin
实测输出:
transcode -> 200 type=audio/ogg got=432506B
/tmp/tc.bin: Ogg data, Opus audio, version 0.1, mono, 48000 Hz (Input Sample Rate)
专辑封面:
curl -s -H "x-access-token: $TOKEN" -o /tmp/art.jpg \
-w 'album-art -> %{http_code} type=%{content_type} got=%{size_download}B\n' \
http://localhost:8155/album-art/7d38193e4babe32d0b8de73c0dc8d261.jpeg
实测输出:
album-art -> 200 type=image/jpeg got=40421B
封面文件名来自 5.1 曲库元数据的 album-art 字段。
5.3 播放列表域(playlist)
全生命周期实测(save → getall → load → add-song → rename → delete):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"title":"night-drive","songs":["music/track03.mp3","music/track04.mp3"]}' \
http://localhost:8155/api/v1/playlist/save -w '\nHTTP %{http_code}\n'
实测输出:
{}
HTTP 200
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/playlist/getall
实测输出:
[{"name":"night-drive"}]
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"playlistname":"night-drive"}' http://localhost:8155/api/v1/playlist/load -w '\nHTTP %{http_code}\n'
实测输出(节选,实测首条):
[{"id":1,"lokiId":1,"filepath":"music/track03.mp3","metadata":{"title":"Night Signal","duration":28.029, ...}}, ...]
HTTP 200
追加与重命名:
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"playlist":"night-drive","song":"music/track06.mp3"}' \
http://localhost:8155/api/v1/playlist/add-song -w '\nHTTP %{http_code}\n'
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"oldName":"night-drive","newName":"evening-mix"}' \
http://localhost:8155/api/v1/playlist/rename -w '\nHTTP %{http_code}\n'
实测输出(两次均 200):
{}
HTTP 200
{}
HTTP 200
删除与核验:
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"playlistname":"evening-mix"}' http://localhost:8155/api/v1/playlist/delete -w '\nHTTP %{http_code}\n'
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/playlist/getall
实测输出:
{}
HTTP 200
[]
💡 说明:播放列表的请求字段名实测为
title(保存)、playlistname(加载/删除)、oldName/newName(重命名)——与旧版文档的字段名有差异,写集成代码时以实测为准。
5.4 评分与推荐域
评分写入与查询:
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"filepath":"music/track01.mp3","rating":5}' http://localhost:8155/api/v1/db/rate-song -w '\nHTTP %{http_code}\n'
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/db/rated -w '\nHTTP %{http_code}\n' | head -c 300
实测输出:
{}
HTTP 200
[{"filepath":"music/track01.mp3","metadata":{"title":"Morning Wave","rating":5, ...
Auto-DJ 随机选曲(分批参数是 limit 而非 num):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"limit":2}' http://localhost:8155/api/v1/db/random-songs -w '\nHTTP %{http_code}\n' | head -c 200
实测输出:
{"songs":[{"filepath":"music/track04.mp3","metadata":{ ...
HTTP 200
参数错误时的反馈形态(实测:随机选曲不支持 num 键,也不接受未通过自定义校验的 musicalKeys 直传字符串):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"num":2}' http://localhost:8155/api/v1/db/random-songs -w '\nHTTP %{http_code}\n'
实测输出:
{"error":"\"num\" is not allowed"}
HTTP 400
5.5 文件浏览域
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"directory":"music"}' http://localhost:8155/api/v1/file-explorer -w '\nHTTP %{http_code}\n'
实测输出:
{"path":"/music/","files":[{"type":"mp3","name":"track01.mp3"},{"type":"mp3","name":"track02.mp3"}, ...],"directories":[]}
HTTP 200
directory 传 vpath 名或其子目录相对路径,返回该层文件与子目录。
5.6 扫描与管理域(admin)
触发全库扫描(管理员):
curl -s -X POST -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/admin/db/scan/all -w '\nHTTP %{http_code}\n'
实测输出:
{}
HTTP 200
扫描状态(六条增强流水线的实时状态):
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/scan/status -w '\nHTTP %{http_code}\n' | head -c 700
实测输出(节选):
{"queue":{"scanning":false,"activeTask":"discovery","queued":["audioanalysis"]},"totals":{"tracks":6},"enrichment":[{"pass":"waveform","enabled":true,"state":"idle","lastRun":{"outcome":"completed","counts":{"generated":0,"failed":0,"total":0}}, ...},{"pass":"albumart","state":"idle","lastRun":{"counts":{"attempted":0,"updated":0,"notFound":0,"errors":0}}, ...},{"pass":"lyrics","enabled":false,"disabledReason":"config","state":"disabled", ...
HTTP 200
要点:enrichment 数组覆盖 waveform/albumart/lyrics/discovery/audioanalysis/acoustid 六条流水线,disabledReason: config 表示由配置显式关闭,可据此做监控看板。
扫描参数在线修改(改完自动写回 config.json):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"scanInterval":2}' http://localhost:8155/api/v1/admin/db/params/scan-interval -w '\nHTTP %{http_code}\n'
实测输出:
{}
HTTP 200
参数全集查询用 GET /api/v1/admin/db/params(实测返回 skipImg/scanInterval/pause/saveInterval/bootScanDelay/watcherEnabled/compressImage/generateWaveforms/analyzeBpm/analyzeBpmMethod/discoveryModel/albumArtServices 等 38 个键,完整回显见《mStream 6.32.0 配置参数详解》第三章)。
用户权限位查询:
curl -s -H "x-access-token: $TOKEN" http://localhost:8155/api/v1/admin/users
实测输出:
{"admin":{"admin":true,"vpaths":["music"],"allowMkdir":true,"allowUpload":true,"allowFileModify":true,"allowServerAudio":false,"allowTorrent":false,"allowDiscoveryJobs":false}}
非管理员调用管理端点时被拒(实测预置普通用户时 admin 位缺失即得 403 形态拒绝),这也是最小权限校验的行为基准。
5.7 分享域(share)
创建分享(可设过期秒数):
curl -s -X POST -H "x-access-token: $TOKEN" -H 'Content-Type: application/json' \
-d '{"time":30,"playlist":["music/track01.mp3","music/track05.mp3"]}' http://localhost:8155/api/v1/share
实测输出:
{"playlistId":"g86qy3GL4D","playlist":["music/track01.mp3","music/track05.mp3"],"user":"admin","expires":1795873518,"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJwbGF5bGlzdElkIjoiZzg2cXkzR0w0RCIsInNoYXJlVG9rZW4iOnRydWUsInVzZXJuYW1lIjoiYWRtaW4iLCJpYXQiOjE3OTMyODE1MTgsImV4cCI6MTc5NTg3MzUxOH0._x8bAMZksn51Jw-FImS_RD_aSzo3X5N43Dx2tVqT1mU"}
注意:创建端点是 POST /api/v1/share(不是 share/make),time 单位为天(实测 30 → expires 距签发 30 天)。
免登录获取分享内容与分享页:
curl -s http://localhost:8155/api/v1/shared/g86qy3GL4D -w '\nHTTP %{http_code}\n' | head -c 260
curl -s -o /dev/null -w 'shared page -> %{http_code}\n' http://localhost:8155/shared/g86qy3GL4D
实测输出:
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. ...","playlist":["music/track01.mp3","music/track05.mp3"]}
HTTP 200
shared page -> 200
分享令牌由服务端签发(payload 含 shareToken: true 与过期时间),匿名用户凭 playlistId 即可访问,适合外发场景。
六、分页/过滤/排序通用约定
实测 v6.32.0 的列表类端点没有统一分页参数:albums/artists/genres 一次返回全量;检索(/api/v1/db/search)按五桶全量返回;Auto-DJ 用 limit 控制单次返回条数(默认 1,上限由服务端 PICK_LIMIT_MAX 决定)。过滤语义按域各定:专辑曲目用 {"album":"..."}、流派曲目用 genre-songs 同构参数、文件浏览用 directory 路径。排序遵循各端点默认(专辑按 year/name,曲目按 track 号),如需自定义排序在客户端侧处理。二次开发时对大曲库应优先使用带过滤参数的端点(album-songs/genre-songs/search),避免拉全量。
七、常见问题(FAQ)
Q1:所有接口都要求认证吗?
否。/api/v1/ping、分享内容接口(/api/v1/shared/:playlistId 与 /shared/:playlistId 页面)、登录接口本身可匿名访问;其余业务 API 与媒体端点均要求 token(缺失/无效一律 401,实测确认)。
Q2:token 会过期吗?
JWT payload 实测只含 username 与 iat,无 exp——token 在服务端 secret 不变的情况下长期有效。轮换 secret(见《mStream 6.32.0 配置参数详解》5.1)即可吊销全部在线 token。
Q3:字段名跟旧文档对不上?
以 6.32.0 实测为准:播放列表保存用 title、加载/删除用 playlistname、重命名用 oldName/newName;随机选曲分批参数是 limit(传 num 得 400 "num" is not allowed)。权威契约为随源码发布的 docs/openapi.yaml。
Q4:媒体端点能用浏览器直接打开吗? 可以,把 token 放在 URL 参数(?token=...)即可直链,播放器与浏览器分享场景最方便;JSON API 建议仍走 x-access-token 头。
Q5:扫描期间调用查询会失败吗?
曲库写入类操作可能被拒(db/status 的 locked: true 表示扫描进行中),轮询 db/status 等待 locked 变 false 再触发下一批操作是稳妥做法。
八、参考链接
- openapi.yaml(API 权威契约,随源码发布):https://github.com/IrosTheBeggar/mStream/blob/master/docs/openapi.yaml
- mStream 官方仓库:https://github.com/IrosTheBeggar/mStream
- 站内延伸:《mStream 6.32.0 介绍与选型指南》、《mStream 6.32.0 Docker Compose 部署指南》、《mStream 6.32.0 配置参数详解》