mStream 6.32.0 API 使用详解

mStream 6.32.0 REST API 使用详解:257 个操作的 openapi 全景、JWT 认证实测,以及曲库/媒体/播放列表/评分/扫描/分享/用户管理七大域逐端点 curl 实录

mStreammStream音乐流媒体自托管媒体服务器Nodejs2026/10/29

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)实测通过。

一、环境信息

二、前置条件

  1. 服务已部署并可访问(部署见《mStream 6.32.0 Docker Compose 部署指南》)。探活:
curl -s http://localhost:8155/api/v1/ping -w '\nHTTP %{http_code}\n'

实测输出:

HTTP 200
  1. 准备一个管理员 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...
  1. (可选)本机解析 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/ping1探活

按 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 再触发下一批操作是稳妥做法。

八、参考链接

  1. openapi.yaml(API 权威契约,随源码发布):https://github.com/IrosTheBeggar/mStream/blob/master/docs/openapi.yaml
  2. mStream 官方仓库:https://github.com/IrosTheBeggar/mStream
  3. 站内延伸:《mStream 6.32.0 介绍与选型指南》、《mStream 6.32.0 Docker Compose 部署指南》、《mStream 6.32.0 配置参数详解》