Wristhyme开发文档
示例网站公网音乐 API 已关闭。接口示例供阅读,自建部署后使用。
本页目录

协议与数据模型

文档首页

独立部署说明:文中官方域名为原服务示例,实际使用配置的实例域名;后台ADMIN_ORIGIN要求HTTPS且包含实际非默认端口。可信代理通过TRUSTED_PROXY_IPS显式配置,内部服务/数据路径也已环境化,详见部署文档。初次实例不带旧数据库/密钥/默认插件或原音源启停策略。

1. HTTP 约定

  • 公开和管理接口基地址均为 https://wristhyme.tolike.cn,路径区分大小写。
  • 音乐元数据读取为 GET,查询参数采用 URL 编码;不要把中文、ref 或歌单链接手工拼接进 URL。
  • 写入接口为 POST,JSON 根必须是对象,Content-Type: application/json,须提供一个明确的 Content-Length。设备与后台实现拒绝 Transfer-Encoding 分块上传。
  • 成功 JSON 没有统一 data 外层,也不是所有接口都返回 ok;按各接口实际结构解析。
  • 网关 JSON 通常为 application/json; charset=utf-8;音频是二进制,不可调用 JSON 解析器。
  • 网关/后台通常返回 Cache-Control: no-store、X-Content-Type-Options: nosniff、Referrer-Policy: no-referrer、X-Frame-Options: DENY 及 CSP。静态发布文件遵循反向代理的缓存策略。
  • 不存在通用的 Bearer/JWT/API Key 鉴权。不要给音乐请求携带管理员 Cookie、内部密钥或平台登录凭证。
  • 当前代码没有通用 CORS/OPTIONS 支持。原生客户端可访问,浏览器建议同源调用;不能假定跨域前端能直接使用。
  • 没有统一 HEAD 支持,也没有公共 PUT/PATCH/DELETE 合同。Python 默认处理可能返回 HTML 501,而非 JSON 错误。
  • 查询解析只使用同名参数的首个值,空值可能被忽略;因此不要依赖重复参数或空参数来表达列表。
  • 未知查询字段不一定被拒绝,但不能据此声称支持该功能。

可选客户端身份头

头 格式 用途
X-Wristhyme-Device 32 位小写十六进制 ID + . + 64 位小写十六进制签名 已自愿注册实例的统计及设备封禁识别
X-Wristhyme-Version 字符串,观察逻辑最多保留 32 字符 应用版本
X-Wristhyme-Variant 字符串,最多保留 16 字符 如 phone、watch、desktop、ios
Range 单个 bytes=start-end 范围 仅音频流请求

设备头不是管理员身份,也不证明物理设备或自然人身份。客户端只应向本站 HTTPS /api/ 发送设备凭证,并阻止跨站重定向。

X-Real-IP 由可信反向代理覆盖,仅特定代理地址受信任;不要依靠客户端伪造此头改变限流或封禁。服务端不信任任意 X-Forwarded-For。

2. 标识与有效期

字段 含义 生命周期
source.id 客户端可选音源目录 ID,可为自定义别名 后台可改名、启停、删除自定义项
source.backend / song.source 实际平台身份,例如 netease 歌曲协议必须保留真实平台,不能替换为别名
song.key 服务器已知歌曲的短期索引,当前生成算法为 SHA256 前 32 位小写 hex 写入歌曲缓存后 21600 秒;最多 1200 条,可能提前淘汰;重启丢失
song.ref 可恢复歌曲的签名引用 无内置时间戳过期;依赖签名密钥、合法结构和音源仍启用
plugin.id 脚本原始字节 SHA256 的前 16 位小写 hex 内容变化会改变 ID;目录启停影响可用性
0000000000000000 跟随后台默认插件的稳定别名 每次解析映射至当时有效默认,非真实脚本 ID
ticket 插件解析后的随机音频访问票据 3600 秒;最多 512 条,可能提前淘汰;重启丢失
device_id 随机匿名安装实例 ID 非硬件 ID;撤回统计后需客户端停止使用旧凭证
管理 Cookie 管理会话随机令牌 8 小时固定有效期;退出、改密码等会使其失效

key 与 ref

服务器依据歌曲完整内部对象计算 key,并保存歌曲。客户端不能提交任意平台 ID、标题或 URL 来代替 key。

ref 目前为 base64url(JSON歌曲).HMAC-SHA256,是防篡改引用,不是加密数据。客户端应将其视为不透明字符串,不自行解码、修改、生成或提取第三方信息。原有“签名过期”错误文案不表示 ref 有独立 TTL。

收藏应保存 ref;下次播放可先 /api/restore 获取当前 key。恢复返回的新 key 有可能与原 key 相同,但重新注册缓存项;不要要求 key 一定变化。签名密钥被替换、引用损坏或音源禁用时恢复会失败。

网易云 search_signals 被排除在歌曲缓存和签名之外,避免搜索排名变化改变歌曲身份。经恢复得到的歌曲通常没有该查询的排序信号。

默认插件

  • 后台目录 default_plugin 是管理员配置值;effective_default_plugin 是当前实际生效值。
  • 公开 /api/sources.default_plugin 和 /api/plugins.default_plugin 返回有效值,不是必须等于原始配置值。
  • 没有配置默认时有效值为空,不自动挑插件;原平台 /api/media 仍可使用。
  • 已配置的插件禁用后,按后台插件创建时间/ID顺序选择其他启用项;全部禁用时为空。原配置插件重新启用后恢复原默认。
  • 公开插件接口中 plugin 省略、default 或稳定别名都会映射有效默认;没有默认返回 503,不会自动转为原平台解析。
  • 当前 Android 2.2.2 在解析支持的平台前读 /api/sources;有效默认为空才走原平台。获取配置或插件解析失败会报告错误,不静默换源。

3. 公共数据模型

3.1 Source

字段 类型 说明
id string 目录 ID;通常 [a-z0-9_]{1,48}
name string 展示名称,可被后台修改
backend string 基础平台 ID;旧网关可能缺少
plugin string 关联插件推荐 ID;未关联或已禁用时为空;不等于自动解析插件

已知基础平台:qq、netease、kugou、kuwo、migu、soda、bilibili、qianqian、joox、jamendo、fivesing、apple。后台支持配置不代表当前公开目录全部启用。

LX 映射:netease → wy、qq → tx、kugou → kg、kuwo → kw、migu → mg;汽水和哔哩哔哩不在当前网关 LX 映射中。

3.2 Song

字段 类型 是否通常存在 说明
key string 是 服务器歌曲索引
ref string 是 签名恢复引用
name string 是 标题
artist string 是 歌手/上传者,多人可能以 、 分隔
album string 是 专辑;哔哩哔哩可能为 BV 号
duration string 是 上游通常为秒数字符串,可为空;不是毫秒整数
source string 是 基础平台,而非自定义目录别名
original boolean 是 保留的历史标记;false 不证明是翻唱,true 也不构成独立音频鉴定
cover string 是 封面地址或空字符串;不保证能访问,客户端有自己的允许策略
access_hint string 否 平台权限提示,不是权限验证结果
search_signals object 否 网易云搜索的查询相关信号

Song 不返回原始平台 id、内部 extra 和上游音频 URL 字段。ref 不透明,不应作为这些字段的公共替代查询接口。

3.3 Playlist

字段 类型 说明
id string 平台公共歌单 ID,不是歌曲 key
source string 基础平台
name string 歌单标题
creator string 创建者名称,可为空
track_count string HTML 元数据保留为字符串,可能为空,不应强制要求 number

3.4 网易云 search_signals

字段 类型/固定值 意义
policy netease-signals-221 信号合同标识
original_recording object status: unknown、rank: 0、references: []、candidate_fields: {}
popularity object status: unknown、value: null、metric: null、reason、candidate_fields
version object status、kinds: string[]、evidence: object[]
upstream_index integer 原始上游位置,0 起始,包含页偏移
upstream_order_role stable_tiebreak_only_not_popularity 上游位置仅用于稳定兜底
ranking object,非空查询时存在 relevance、version_intent_misses、original_rank、popularity_rank、version_penalty

version.status 为 metadata_hint 或 unmarked_not_original。已识别 kinds:live、cover、remix、instrumental、piano、sped_up、slowed、acoustic、remaster、interlude、rnb。

证据对象:{kind, field, text, confidence: "metadata_hint"},来自明确标题版本段或 alia/alias。原唱引用对象:{artist_text, field, text, confidence: "reference_only_not_recording_proof"}。

候选字段只是未经解释的观察值;标题、权限码、上游次序都不应被展示为真实热度。未标注版本不等于原版。排序范围是当前页,不是全库热度排序。

4. 错误与状态码

常见错误:

{"error":"结果已过期,请重新搜索"}

可选附加字段有 code、source、upstream_status、state、songs。插件 probe 失败可能返回 {ok:false, detail, error};客户端可按 error、detail、HTTP 状态依次降级。不存在统一业务数字错误码表;code: access_blocked 是明确存在的例外。

HTTP 典型含义 客户端处理
200 正常结果;允许空列表、空歌词、valid:false、内部 ok:false 检查具体业务字段
206 上游实际支持的局部音频响应 核对 Content-Range 后处理续传
400 参数/JSON/签名/consent/导入验证失败 修正请求;不要原样无限重试
401 管理会话失效或设备凭证缺失/无效 重新登录;设备流程先处理同意和凭证
403 设备/IP封禁、插件/音源禁用、同源/CSRF失败 停止当前操作;不自动绕过策略
404 路径不存在;内部接口对未授权隐藏 检查接口、方法及部署版本
410 key 或 ticket 失效;key 查找还可能因音源禁用失败 restore 或重新搜索/解析,避免无界循环
416 Range 格式不支持 改用单范围;根据播放器/下载器策略重试
422 插件执行/初始化失败 查看 detail 或显式切换可用解析方式
429 并发/频率限制 指数退避加随机抖动;不要并发重试
502 上游/第三方失败、返回非音频或资源变化 保留真实错误,允许有限手动重试
503 策略、后台或运行时暂不可用;默认插件未设置 区分配置问题与暂时失败
504 原平台音频连接失败/超时分支 有限重试,不把 JSON 错误保存为音频

没有保证的 Retry-After。原平台上游 401/403/404/429 等通常被包装为外层 502,原值在 upstream_status,不可只看 HTTP 判断平台原因。

音频响应一旦发送头部,后续断流不能再转为 JSON 错误。HTTP 200 不等于文件完整;完整播放与下载完整性要由客户端核验。

5. 资源与缓存限制

以下为找到的源码默认值,按进程计算,并非公开吞吐 SLA。

项目 限制
普通网关慢请求 6 个并发槽;通常包括搜索、歌单、歌词、inspect、snapshot、原平台媒体
插件 probe/resolve/lyric/media 共用 2 个并发槽,媒体流期间占槽
插件操作频率 每真实 IP 60 秒 24 次;probe/resolve/lyric 在同意校验后计数,media 不计入此窗口
轻量列表 2 并发槽;缓存 300 秒、最多 40 项
热榜 QQ/网易云分别一个互斥加载锁;缓存 300 秒、最多 48 项
普通搜索 非空结果缓存 90 秒、最多 100 项;refresh=1 绕过,空结果不提供有效 TTL
设备注册 同一 IP 每小时最多 5 次
活动观察 每实例/未识别IP约30秒聚合一次;队列1024,满时可丢弃,不阻塞播放
后台 12 个并发槽;导入另限 1 个任务
后台登录 每IP 15分钟8次,整体15分钟80次,失败尝试也占用
后台写入 每会话60秒80次
设备 POST body 1..4096 字节;反向代理也有4KB层限制
登录 body 1..4096 字节
后台普通 body 1..1450000 字节;代理还有1500KB限制
内部统计 body 最多65536字节
LX /run body 1..32768字节
歌词读取 通常最多131072字节;snapshot另读1字节检测超限

服务器搜索/元数据超时通常 12..22 秒;原平台音频连接 35 秒;LX 运行时请求 32 秒、工作进程 28 秒、第三方取流 15 秒。实际端到端可叠加,不应把其中某个值当固定 SLA。

6. 安全与兼容

  • 网关仅接受服务器已知歌曲,插件媒体仅接受票据;没有公开任意 URL 代理接口。
  • 歌单链接只提取受支持主机的 ID,不任意抓取用户 URL;短链不展开。
  • 插件 HTTP 使用 SSRF 防护、公共地址校验及资源限制;启用脚本需要管理员确认信任。
  • 管理统计包含真实 IP 等敏感运营数据,不应公开导出示例或备份。
  • GET 插件 probe/resolve 会执行第三方请求;不要因其是 GET 就进行预取、爬取或浏览器自动探测。
  • 多实例网关的进程内 key/ticket 需要共享存储或粘性路由,签名密钥也须一致。当前代码不提供这套协调机制。
  • 接口接受新增字段;客户端应忽略未知字段,但不能把缺失字段填成已确认的热度、原唱、可播放或无损结论。