Skip to content

云曲助手 SDK 通讯规范 ​

云曲助手(fsMusicUpload 桌面端)通过「登录 → 上传配置 → 上传文件 → 上传回调 → 资源入库」链路与目标站点通讯。 目标站点服务端需按本规范实现一套 云曲助手 SDK 接口,返回的 apiMap 决定客户端后续调用哪些 URL。 客户端统一约定:所有业务接口均为 POST,认证使用请求头 x-api-key。


1. 总体流程 ​

[云曲助手客户端]                      [站点服务端 SDK]
       │ 1. POST login(携带 apikey)      │
       │ ───────────────────────────────▶ │ 校验 key → 返回站点配置(apiMap / bitrate / savekey 等)
       │ 2. POST storeCheck(可选)        │ 重复发布检测(标题/文件名)
       │ 3. POST uploadConfig              │ 返回上传策略(存储类型 + 预签名地址)
       │ 4. PUT/分片 上传文件              │ 直接 PUT 到预签名 URL(不经业务接口)
       │ 5. POST uploadNotify              │ 上传完成回调(合并分片 / 转码 / 入库返回 URL)
       │ 6. POST storeData                 │ 资源入库(歌曲元数据 + playlist/downlist 地址)
  • 渲染进程不直接发 HTTP;全部经 src/utils/ClientRequest.js → IPC → electron/requestHttp.js(net.request),但 SDK 通讯的目标 URL 由服务端 apiMap 动态给出,客户端直接用完整 URL 请求(requestHttp.get/post 对 http(s):// 开头的地址直连)。
  • 客户端主进程调用入口:electron/fileServer.js(发布流水线)、electron/upload/index.js(上传调度)、src/api/fastMusic.js(登录/检测)。

2. 认证与公共约定 ​

项约定
认证头x-api-key: <apikey>(除 login 外所有接口必须携带)
内容类型application/json(login / storeCheck / storeData / uploadConfig / uploadNotify)
成功判定客户端兼容两种成功码:code == 1 或 code == 200
返回结构{ code, msg/message, data }

参考实现:Node 端 Backend.js 定义 noNeedLogin = ["*"],在 signVerify() 里用 x-api-key 查 music_author.apikey 校验,status !== 1 拒绝。 PHP 端 BackendController.php 在 _initialize() 里排除 login / uploadNotify 后校验 x-api-key == $up_apikey。


3. 平台类型(客户端侧) ​

客户端添加平台时选择类型(src/pages/web-platform.vue):

type 值login 路径说明
djaod(默认){url}/api/v1/backend/login云曲工坊官方系统(fastify 后端,多类型存储)
sdk(自定义){url}/music/backend/login第三方自建站点(PHP 等,php 自建存储)

客户端 src/api/fastMusic.js 中 adminLoginApi(url, { apikey, type }) 按 type 映射 login 地址。 其余接口路径均由服务端 apiMap 返回,客户端不再硬编码(PHP 端示例均形如 {url}/music/backend/xxx)。


4. 接口详解 ​

4.1 登录 POST login ​

请求体:{ apikey: string }(type 由客户端决定访问哪个 login 路径)

成功返回 data 字段(客户端会整体 Object.assign 到站点对象并落库 IndexedDB):

字段类型说明
titlestring站点名称
author_idstring/number默认音乐人 ID(发布时兜底)
isSystembool是否为平台自有音乐人账号(1)
channelarray分类树 [{ label, value, source_type?, children? }]
sourceTypeOptionsarray来源类型选项 [{ label, value }],如 set(串烧)/single(单曲)
bitratearray音质配置 [first, last]:{ bitrate, suffix, title, type },type 为 play(播放)/down(下载)
isAmixbool是否开启水印混音
amixOffsetnumber水印偏移(秒)
AmixURLstring水印音频下载地址
savekeystring上传路径模板(含占位符),见 §7
upload_typestring存储类型(PHP 端在 login 直接返回,如 local)
uploadconfigobject云存储配置(isSystem 且 djaod 时返回,含 xxx_config 的 savekey 等)
apiMapobject各接口 URL 映射(见下表)
viplistarrayVIP 等级下拉 [{ label, value }](isSystem 才返回)

apiMap 结构(客户端后续全部按此 URL 请求):

key用途
storeCheck发布前重复检测
storeData资源入库
uploadConfig获取上传配置
uploadNotify上传完成回调
authors音乐人下拉分页
albums专辑下拉分页

Node 端 Backend.js:apiMap 基于 site_url 拼 /api/v1/backend/*;PHP 端 BackendController.php 基于 $site_url 拼 /music/backend/*。

4.2 发布前检测 POST storeCheck ​

请求体(二选一,均可带):

  • { title: string } → 检测该标题是否已发布
  • { fileNames: string[] } → 批量文件名重复检测

返回:

  • Node 端:
    • title 检测:{ code: 200, msg: "标题检测通过" };已存在返回 { code: 400, msg: "已发布过《X》,或者没有彻底删除" }
    • fileNames 检测:{ code: 200, data: string[] } → data 必须是已存在的文件名数组
  • PHP 端:check() 目前恒返回 { code: 200, msg: "...检测通过", data: [] }

客户端 fileServer.js 用返回的已存在文件名数组过滤待发布列表(已存在的跳过并提示不重复发布)。

4.3 获取上传配置 POST uploadConfig ​

请求体:{ mime, filename, size, hls, path }(hls 为 m3u8 关联 ts 数组,path 本地路径)

返回 data 通用字段:

字段说明
upload_type存储类型:local / oss / cos / qiniu / bitiful / minio / r2 / s3
isChunk是否分片
key存储 Key(对象路径)
putUrl单文件预签名上传地址(PUT)
uploadId分片上传 ID(合并用)
chunkUrls分片预签名 URL 数组(按 PartNumber 顺序)
chunkSize分片大小(字节)
chunkCount分片数
notifyUrl分片合并回调地址(local 分片用)

存储类型说明:

  • local(php 自建存储):由上传服务器(如 go-uploads http://60.174.238.119:9000)接收。putUrl/chunkUrls 为带签名参数的地址:{up_apiurl}/upload?signature=...&options=...;uploadId = md5(json(key, contenttype));分片大小固定 2 * 1024 * 1024。客户端 electron/upload/localUpload.js 用 net.request 直接 PUT,分片传完 POST notifyUrl(body {key, uploadId})让服务端合并。
  • oss:返回 STS 临时凭证 + region/bucket;客户端用 ali-oss SDK multipartUpload(electron/upload/ossUpload.js)。
  • qiniu:返回 uploadUrl + uploadToken;客户端 V2 分片 PUT,每片返回 etag 记入 contexts(electron/upload/qiniuUpload.js)。
  • cos / bitiful / minio / r2 / s3:返回 putUrl/chunkUrls 预签名地址(S3 兼容,electron/upload/S3Upload.js)。

Node 端 UploadService.js:init(storage) 按 request.body.mime/filename/size/hls 计算;local() 返回 { uploadUrl: "/v1/attachment/upload", mimetype: "..." }。 PHP 端 uploadConfig():$size > 2MB 则分片,否则单文件预签名。

4.4 上传完成回调 POST uploadNotify ​

请求体(_options = uploadConfig 返回 + 客户端补充):

json
{
  "mime": "audio/mp3", "filename": "xxx.mp3", "size": 123456,
  "md5": "…", "key": "uploads/…/xxx.mp3", "savekey": "…",
  "transcode": false,
  "upload_type": "local", "isChunk": false,
  "uploadId": "…", "contexts": [ { "PartNumber": 1, "ETag": "…" } ]
}

返回 data:{ url, fullurl, cover, md5 }(url 客户端直接作为该产物的访问地址;分片合并时由服务端回填最终 key/url)。

服务端职责:

  • 分片 → 合并(本地存储由 go-uploads /upload/complete 合并;云存储走各自 mkfile)。
  • transcode 与 bitrate 存在且 mime 为音视频 → 触发服务端转码,返回转码后 play/down 各码率地址。
  • 图片类 → 按 md5 去重入库附件表。

说明:uploadNotify 与 storeData 是两个不同环节——uploadNotify 负责「文件已上传、拿 URL」,storeData 负责「把歌曲元数据+URL 写入曲库」。

4.5 资源入库 POST storeData ​

请求体(Node 端 Backend.js 的完整字段):

字段类型说明
namestring文件名(服务端自动去扩展名作 title)
source_typestring来源类型(set/single/…)
type_idsarray分类 ID(Node 端为 ObjectId 数组;PHP 端取数组最后一个当 genre_id)
author_idstring音乐人 ID
imagestring封面地址(客户端上传前为 {uploadType}::remote,回调后为实际 URL)
waveformstring波形图地址
price / scorenumber售价 / 积分
playlistarray播放音频列表(客户端转码产物)
downlistarray下载音频列表
disklistarray网盘列表 [{ type, link, password }]
extensionstring文件格式
sizenumber字节
durationnumber秒
bitratenumber码率
sampleratenumber采样率
keystring音调
bpmnumber节拍
channelsnumber声道
md5string转码唯一标识 → 服务端存 file_md5
vip / album_ids / designated_upload_date / createtime-仅 isSystem(平台音乐人)时发送

playlist / downlist 元素结构(客户端 transcodeRowToUploads 生成):

json
{ "type": "local", "name": "128k", "title": "普通", "url": "uploads/play/128k/…/xxx.mp3" }

(type 为存储类型;url 为产物 key)

Node 端入库逻辑:

  • 标题重复 → { code: 400, msg: "您已经发布过该作品" }
  • system_author_id == author_id → 直接 status=1,可带 vip/定时发布
  • 否则按 is_music_audit 配置走审核(1→status=2 待审,2→敏感词检测)
  • 入库后触发 post_music_settled hook

PHP 端入库逻辑(BackendController.php storeData()):

  • 同名存在 → 覆盖更新(songs + songs_extend + 专辑关联),否则新建
  • source_type == 'single' → car_id = 0
  • vip 等级 → down_rule.group 收集所有 id >= vip 的用户组
  • playlist[0] → listen_url,downlist[0] → down_url,disklist[0] → disk_url/disk_pass
  • bitrate 单位 bps → /1000 取整为 kbps

5. 下拉分页接口 ​

5.1 音乐人 POST/GET authors ​

请求参数(query):pageNum、pageSize、keyword、_id(置顶项)

返回 data:{ list: [{ label, value }], total, pageNum }

  • Node 端:list 元素含 label(=title) / value(=ObjectId),_id 命中时插到第一页首位。
  • PHP 端:list 元素 { label: name, value: id },_id 命中时同样置顶。

5.2 专辑 POST/GET albums ​

同上,模型换为 music_album / album。


6. 客户端调用链(代码索引) ​

环节客户端代码
平台选择 / loginsrc/pages/web-platform.vue、src/api/fastMusic.js:adminLoginApi
站点配置合并src/utils/siteWeb.js:prepareSiteWeb(login 结果 + site_configs 缓存)
发布流水线electron/fileServer.js:corePublish → storeCheck → 转码 → Upload.batchUpload → publishWork(storeData)
转码/产物规划electron/fileServer.js:transcodeRowToUploads(savekey + bitrate + playlist/downlist)
上传调度electron/upload/index.js:Upload.start(按 upload_type 选实现)
各存储实现electron/upload/{localUpload,S3Upload,ossUpload,qiniuUpload,cosUpload}.js
HTTP 层electron/requestHttp.js(net.request,对完整 URL 直连)
登录 API 映射src/api/fastMusic.js(djaod→/api/v1/backend/login,sdk→/music/backend/login)

7. savekey 路径模板 ​

savekey 由服务端在 login 返回,客户端 electron/Utils.js:getSavekey 渲染,支持占位符:

占位符含义
{year} {mon} {day} {hour} {min} {sec}当前时间
{mime} / {mimeType}主类型(如 audio)
{filename}原始文件名(截断 100 字符)
{fileprefix}去掉后缀的文件名
{suffix} / {.suffix}后缀(无点/带点)
{filemd5}文件 MD5
{random} / {random32}16/32 位随机串
{category}分类(默认 all)
{index}index(m3u8 用)

默认模板(Node 端):uploads/{year}{mon}{day}/{filemd5}{.suffix} PHP 端示例:/uploads/{year}-{mon}-{day}/{filename}{.suffix}

转码产物(playlist/downlist)的远程路径由客户端按 uploadsDirectory/type/bitrate/dateDirectory/文件名 拼装(见 fileServer.js:transcodeRowToUploads)。


8. 两套服务端实现对照 ​

维度djaod(Node/fastify)Backend.jsphp 自建 BackendController.php
login 路径/api/v1/backend/login/music/backend/login
存储能力多类型(local/qiniu/oss/cos/bitiful/minio/r2),upload_config 存 savekey固定 local(go-uploads 服务器承接)
认证x-api-key 查 music_author(key 有效性 + status)_initialize 比较 $up_apikey,排除 login/uploadNotify
上传签名云存储 SDK 内部签名hash_hmac('sha256', json, key) + md5(json) 生成 uploadId
重复策略storeData 直接拒绝重复标题storeData 同名覆盖更新
音频处理服务端可转码(transcode/bitrate)客户端本地转码,上传产物
分类system_type 树(channel)Genre 树
VIPvip_level 集合 → viplistget_user_groups() → viplist
审核is_music_audit 配置固定 status=1 直接上架

9. 接入清单(第三方站点需实现) ​

  1. login(返回 apiMap、savekey、bitrate、sourceTypeOptions、channel、author_id、isSystem)
  2. uploadConfig(返回 upload_type + 预签名上传地址)
  3. uploadNotify(返回最终 url,必要时合并分片/转码)
  4. storeData(歌曲元数据入库,按客户端字段)
  5. (可选)storeCheck、authors、albums

若第三方站点无法返回完整 apiMap,可在客户端 fallback:src/api/fastMusic.js 中 checkloginApi / storeDataApi 等已按 {url}/music/backend/* 拼接(sdk 类型默认路径)。

Released under the MIT License.