chore(contracts): 冻结 v0.1.0 跨端契约(REST/WebSocket/数据模型/拓扑/格式/数据库)
This commit is contained in:
@@ -0,0 +1,817 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: OpenDance Studio Web 管理服务端 API
|
||||
version: 0.1.0
|
||||
description: |
|
||||
OpenDance Studio 的唯一数据源与契约权威。
|
||||
契约版本见 contracts/VERSION。字段语义见 contracts/data-models.md。
|
||||
|
||||
- 所有 JSON 字段 camelCase
|
||||
- 列表接口统一 { items, total, page, pageSize }
|
||||
- 来源五元组(sourceType/sourceName/sourceUrl/license/author)在三类资产上均为必填
|
||||
servers:
|
||||
- url: http://localhost:3000
|
||||
description: 本地开发
|
||||
- url: http://<host>:3000
|
||||
description: Docker 部署
|
||||
|
||||
tags:
|
||||
- name: health
|
||||
- name: songs
|
||||
- name: motions
|
||||
- name: models
|
||||
- name: reviews
|
||||
- name: catalog
|
||||
- name: assets
|
||||
|
||||
paths:
|
||||
/health:
|
||||
get:
|
||||
tags: [health]
|
||||
summary: 健康检查(含数据库连通性)
|
||||
responses:
|
||||
'200':
|
||||
description: 服务与数据库均正常
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Health'
|
||||
'503':
|
||||
description: 数据库不可用
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Health'
|
||||
|
||||
/api/songs:
|
||||
get:
|
||||
tags: [songs]
|
||||
summary: 曲目列表
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/Page'
|
||||
- $ref: '#/components/parameters/PageSize'
|
||||
- name: q
|
||||
in: query
|
||||
schema: { type: string }
|
||||
description: 按 title/artist/album 模糊匹配
|
||||
- name: status
|
||||
in: query
|
||||
schema: { $ref: '#/components/schemas/PublishStatus' }
|
||||
- name: artist
|
||||
in: query
|
||||
schema: { type: string }
|
||||
responses:
|
||||
'200':
|
||||
description: 分页曲目
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SongPage'
|
||||
post:
|
||||
tags: [songs]
|
||||
summary: 新建曲目
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/SongCreate'
|
||||
responses:
|
||||
'201':
|
||||
description: 已创建
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Song' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
|
||||
/api/songs/{id}:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
get:
|
||||
tags: [songs]
|
||||
summary: 曲目详情
|
||||
responses:
|
||||
'200':
|
||||
description: 曲目
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Song' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
patch:
|
||||
tags: [songs]
|
||||
summary: 更新曲目
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/SongUpdate' }
|
||||
responses:
|
||||
'200':
|
||||
description: 更新后的曲目
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Song' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
delete:
|
||||
tags: [songs]
|
||||
summary: 删除曲目(软删除)
|
||||
responses:
|
||||
'204': { description: 已删除 }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
|
||||
/api/songs/{id}/audio:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
post:
|
||||
tags: [songs]
|
||||
summary: 上传曲目音频
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required: [file]
|
||||
properties:
|
||||
file: { type: string, format: binary }
|
||||
responses:
|
||||
'201':
|
||||
description: 上传后的曲目
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Song' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
|
||||
/api/songs/{id}/cover:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
post:
|
||||
tags: [songs]
|
||||
summary: 上传曲目封面
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required: [file]
|
||||
properties:
|
||||
file: { type: string, format: binary }
|
||||
responses:
|
||||
'201':
|
||||
description: 上传后的曲目
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Song' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
|
||||
/api/motions:
|
||||
get:
|
||||
tags: [motions]
|
||||
summary: 动作列表
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/Page'
|
||||
- $ref: '#/components/parameters/PageSize'
|
||||
- name: q
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: songId
|
||||
in: query
|
||||
schema: { type: integer, format: int64 }
|
||||
- name: format
|
||||
in: query
|
||||
schema: { type: string, enum: [bvh, fbx, gltf, glb, keypoints-json] }
|
||||
- name: status
|
||||
in: query
|
||||
schema: { $ref: '#/components/schemas/PublishStatus' }
|
||||
responses:
|
||||
'200':
|
||||
description: 分页动作
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/MotionPage' }
|
||||
post:
|
||||
tags: [motions]
|
||||
summary: 上传动作文件 + 来源信息
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required: [file, name, sourceType, sourceName, sourceUrl, license, author]
|
||||
properties:
|
||||
file: { type: string, format: binary }
|
||||
name: { type: string }
|
||||
songId: { type: integer, format: int64 }
|
||||
fps: { type: number }
|
||||
sourceType: { $ref: '#/components/schemas/SourceType' }
|
||||
sourceName: { type: string }
|
||||
sourceUrl: { type: string }
|
||||
license: { type: string }
|
||||
author: { type: string }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
autoPreprocess: { type: boolean, default: false }
|
||||
responses:
|
||||
'201':
|
||||
description: 已创建
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Motion' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'422':
|
||||
description: 文件格式不支持或无法解析
|
||||
|
||||
/api/motions/{id}:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
get:
|
||||
tags: [motions]
|
||||
summary: 动作详情
|
||||
responses:
|
||||
'200':
|
||||
description: 动作
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Motion' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
patch:
|
||||
tags: [motions]
|
||||
summary: 更新动作元数据
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/MotionUpdate' }
|
||||
responses:
|
||||
'200':
|
||||
description: 更新后的动作
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Motion' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
delete:
|
||||
tags: [motions]
|
||||
summary: 删除动作(软删除)
|
||||
responses:
|
||||
'204': { description: 已删除 }
|
||||
|
||||
/api/motions/{id}/preprocess:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
post:
|
||||
tags: [motions]
|
||||
summary: 触发 BVH/FBX → MediaPipe33 关键点序列预处理(同步执行)
|
||||
description: |
|
||||
同步执行并返回最终状态:成功时 preprocessState=done;
|
||||
失败时返回 422,且 Motion.preprocessError 记录可读原因。
|
||||
responses:
|
||||
'200':
|
||||
description: 预处理完成
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Motion' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'422':
|
||||
description: 预处理失败,reason 见 preprocessError
|
||||
|
||||
/api/motions/{id}/keypoints:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
get:
|
||||
tags: [motions]
|
||||
summary: 下载关键点序列(NDJSON,每行一帧)
|
||||
responses:
|
||||
'200':
|
||||
description: |
|
||||
application/x-ndjson,每行一个帧对象:
|
||||
{"frame":0,"timeMs":0,"points":[[x,y,z,conf], …33],"angles":[9 个余弦]}
|
||||
content:
|
||||
application/x-ndjson:
|
||||
schema: { type: string }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
'409':
|
||||
description: 尚未完成预处理
|
||||
|
||||
/api/models:
|
||||
get:
|
||||
tags: [models]
|
||||
summary: 模型列表
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/Page'
|
||||
- $ref: '#/components/parameters/PageSize'
|
||||
- name: q
|
||||
in: query
|
||||
schema: { type: string }
|
||||
- name: format
|
||||
in: query
|
||||
schema: { type: string, enum: [vrm, glb, gltf, fbx] }
|
||||
- name: status
|
||||
in: query
|
||||
schema: { $ref: '#/components/schemas/PublishStatus' }
|
||||
responses:
|
||||
'200':
|
||||
description: 分页模型
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ModelPage' }
|
||||
post:
|
||||
tags: [models]
|
||||
summary: 上传模型 + 来源信息(VRM 优先)
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
multipart/form-data:
|
||||
schema:
|
||||
type: object
|
||||
required: [file, name, sourceType, sourceName, sourceUrl, license, author]
|
||||
properties:
|
||||
file: { type: string, format: binary }
|
||||
name: { type: string }
|
||||
isPrimary: { type: boolean }
|
||||
sourceType: { $ref: '#/components/schemas/SourceType' }
|
||||
sourceName: { type: string }
|
||||
sourceUrl: { type: string }
|
||||
license: { type: string }
|
||||
author: { type: string }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
responses:
|
||||
'201':
|
||||
description: 已创建
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Model' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
'422':
|
||||
description: 不支持的模型格式
|
||||
|
||||
/api/models/{id}:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
get:
|
||||
tags: [models]
|
||||
summary: 模型详情
|
||||
responses:
|
||||
'200':
|
||||
description: 模型
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Model' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
patch:
|
||||
tags: [models]
|
||||
summary: 更新模型元数据
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ModelUpdate' }
|
||||
responses:
|
||||
'200':
|
||||
description: 更新后的模型
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Model' }
|
||||
'400': { $ref: '#/components/responses/BadRequest' }
|
||||
delete:
|
||||
tags: [models]
|
||||
summary: 删除模型(软删除)
|
||||
responses:
|
||||
'204': { description: 已删除 }
|
||||
|
||||
/api/models/{id}/primary:
|
||||
parameters: [{ $ref: '#/components/parameters/Id' }]
|
||||
post:
|
||||
tags: [models]
|
||||
summary: 设为全局默认模型(互斥,同事务清零其余)
|
||||
responses:
|
||||
'200':
|
||||
description: 设置后的模型
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/Model' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
|
||||
/api/reviews:
|
||||
get:
|
||||
tags: [reviews]
|
||||
summary: 审核流水 / 待审列表
|
||||
parameters:
|
||||
- name: targetType
|
||||
in: query
|
||||
schema: { type: string, enum: [song, motion, model] }
|
||||
- name: targetId
|
||||
in: query
|
||||
schema: { type: integer, format: int64 }
|
||||
- name: status
|
||||
in: query
|
||||
schema: { $ref: '#/components/schemas/PublishStatus' }
|
||||
description: 传入时改为返回该状态的待审资产列表(合并三类)
|
||||
- $ref: '#/components/parameters/Page'
|
||||
- $ref: '#/components/parameters/PageSize'
|
||||
responses:
|
||||
'200':
|
||||
description: 审核流水或待审资产
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/ReviewPage'
|
||||
- $ref: '#/components/schemas/PendingPage'
|
||||
|
||||
/api/reviews/{targetType}/{id}/submit:
|
||||
parameters:
|
||||
- name: targetType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, enum: [song, motion, model] }
|
||||
- $ref: '#/components/parameters/Id'
|
||||
post:
|
||||
tags: [reviews]
|
||||
summary: 提交审核
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
reviewer: { type: string }
|
||||
comment: { type: string }
|
||||
responses:
|
||||
'200': { description: 状态已流转 }
|
||||
'409': { description: 当前状态不允许该操作 }
|
||||
|
||||
/api/reviews/{targetType}/{id}/approve:
|
||||
parameters:
|
||||
- name: targetType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, enum: [song, motion, model] }
|
||||
- $ref: '#/components/parameters/Id'
|
||||
post:
|
||||
tags: [reviews]
|
||||
summary: 审核通过 → published
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
reviewer: { type: string }
|
||||
comment: { type: string }
|
||||
responses:
|
||||
'200': { description: 状态已流转 }
|
||||
'409': { description: 当前状态不允许该操作 }
|
||||
|
||||
/api/reviews/{targetType}/{id}/withdraw:
|
||||
parameters:
|
||||
- name: targetType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, enum: [song, motion, model] }
|
||||
- $ref: '#/components/parameters/Id'
|
||||
post:
|
||||
tags: [reviews]
|
||||
summary: 撤回审核 → draft
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
reviewer: { type: string }
|
||||
comment: { type: string }
|
||||
responses:
|
||||
'200': { description: 状态已流转 }
|
||||
'409': { description: 当前状态不允许该操作 }
|
||||
|
||||
/api/reviews/{targetType}/{id}/history:
|
||||
parameters:
|
||||
- name: targetType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, enum: [song, motion, model] }
|
||||
- $ref: '#/components/parameters/Id'
|
||||
get:
|
||||
tags: [reviews]
|
||||
summary: 单个资产的审核历史
|
||||
responses:
|
||||
'200':
|
||||
description: 审核流水(按时间倒序)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: array
|
||||
items: { $ref: '#/components/schemas/ReviewRecord' }
|
||||
'404': { $ref: '#/components/responses/NotFound' }
|
||||
|
||||
/api/reviews/{targetType}/{id}/reject:
|
||||
parameters:
|
||||
- name: targetType
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: string, enum: [song, motion, model] }
|
||||
- $ref: '#/components/parameters/Id'
|
||||
post:
|
||||
tags: [reviews]
|
||||
summary: 审核驳回 → rejected
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [comment]
|
||||
properties:
|
||||
reviewer: { type: string }
|
||||
comment: { type: string }
|
||||
responses:
|
||||
'200': { description: 状态已流转 }
|
||||
'400': { description: 驳回必须填写理由 }
|
||||
'409': { description: 当前状态不允许该操作 }
|
||||
|
||||
/api/catalog/export:
|
||||
get:
|
||||
tags: [catalog]
|
||||
summary: 客户端一次性拉取已发布目录
|
||||
responses:
|
||||
'200':
|
||||
description: CatalogBundle
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/CatalogBundle' }
|
||||
|
||||
/api/catalog/version:
|
||||
get:
|
||||
tags: [catalog]
|
||||
summary: 契约版本与目录指纹(客户端增量同步用)
|
||||
responses:
|
||||
'200':
|
||||
description: 版本信息
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
contractVersion: { type: object, additionalProperties: { type: string } }
|
||||
revision: { type: string, description: 目录内容 sha256,变化即需重新拉取 }
|
||||
|
||||
components:
|
||||
parameters:
|
||||
Id:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema: { type: integer, format: int64 }
|
||||
Page:
|
||||
name: page
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, default: 1 }
|
||||
PageSize:
|
||||
name: pageSize
|
||||
in: query
|
||||
schema: { type: integer, minimum: 1, maximum: 200, default: 20 }
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: 参数校验失败(含来源五元组缺失)
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ApiError' }
|
||||
NotFound:
|
||||
description: 资源不存在
|
||||
content:
|
||||
application/json:
|
||||
schema: { $ref: '#/components/schemas/ApiError' }
|
||||
|
||||
schemas:
|
||||
SourceType:
|
||||
type: string
|
||||
enum: [original, licensed, cc, public_domain, user_upload, other]
|
||||
PublishStatus:
|
||||
type: string
|
||||
enum: [draft, pending, published, rejected]
|
||||
MotionFormat:
|
||||
type: string
|
||||
enum: [bvh, fbx, gltf, glb, keypoints-json]
|
||||
ModelFormat:
|
||||
type: string
|
||||
enum: [vrm, glb, gltf, fbx]
|
||||
|
||||
ApiError:
|
||||
type: object
|
||||
properties:
|
||||
statusCode: { type: integer }
|
||||
message: { oneOf: [{ type: string }, { type: array, items: { type: string } }] }
|
||||
error: { type: string }
|
||||
|
||||
SourceFields:
|
||||
type: object
|
||||
required: [sourceType, sourceName, sourceUrl, license, author]
|
||||
properties:
|
||||
sourceType: { $ref: '#/components/schemas/SourceType' }
|
||||
sourceName: { type: string, maxLength: 200 }
|
||||
sourceUrl: { type: string, maxLength: 500, description: 必须为 http(s) URL }
|
||||
license: { type: string, maxLength: 100 }
|
||||
author: { type: string, maxLength: 200 }
|
||||
|
||||
Health:
|
||||
type: object
|
||||
properties:
|
||||
status: { type: string, enum: [ok, degraded] }
|
||||
uptimeSec: { type: number }
|
||||
version: { type: string }
|
||||
contractVersion: { type: object, additionalProperties: { type: string } }
|
||||
database:
|
||||
type: object
|
||||
properties:
|
||||
connected: { type: boolean }
|
||||
server: { type: string, description: '如 MariaDB 10.11.19' }
|
||||
database: { type: string }
|
||||
migrationsPending: { type: integer }
|
||||
|
||||
Song:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/SourceFields'
|
||||
- type: object
|
||||
properties:
|
||||
id: { type: integer, format: int64 }
|
||||
title: { type: string }
|
||||
artist: { type: string }
|
||||
album: { type: string, nullable: true }
|
||||
language: { type: string, nullable: true }
|
||||
durationMs: { type: integer, nullable: true }
|
||||
bpm: { type: number, nullable: true }
|
||||
difficulty: { type: integer, nullable: true, minimum: 1, maximum: 5 }
|
||||
tags: { type: array, items: { type: string } }
|
||||
coverUrl: { type: string, nullable: true }
|
||||
audioUrl: { type: string, nullable: true }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
createdAt: { type: string, format: date-time }
|
||||
updatedAt: { type: string, format: date-time }
|
||||
|
||||
SongCreate:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/SourceFields'
|
||||
- type: object
|
||||
required: [title, artist]
|
||||
properties:
|
||||
title: { type: string, maxLength: 200 }
|
||||
artist: { type: string, maxLength: 200 }
|
||||
album: { type: string, maxLength: 200 }
|
||||
language: { type: string }
|
||||
durationMs: { type: integer }
|
||||
bpm: { type: number }
|
||||
difficulty: { type: integer, minimum: 1, maximum: 5 }
|
||||
tags: { type: array, items: { type: string } }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
|
||||
SongUpdate:
|
||||
type: object
|
||||
description: 所有字段可选;提供 source* 时必须五元组同时提供
|
||||
properties:
|
||||
title: { type: string }
|
||||
artist: { type: string }
|
||||
album: { type: string }
|
||||
language: { type: string }
|
||||
durationMs: { type: integer }
|
||||
bpm: { type: number }
|
||||
difficulty: { type: integer, minimum: 1, maximum: 5 }
|
||||
tags: { type: array, items: { type: string } }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
sourceType: { $ref: '#/components/schemas/SourceType' }
|
||||
sourceName: { type: string }
|
||||
sourceUrl: { type: string }
|
||||
license: { type: string }
|
||||
author: { type: string }
|
||||
|
||||
SongPage:
|
||||
type: object
|
||||
properties:
|
||||
items: { type: array, items: { $ref: '#/components/schemas/Song' } }
|
||||
total: { type: integer }
|
||||
page: { type: integer }
|
||||
pageSize: { type: integer }
|
||||
|
||||
Motion:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/SourceFields'
|
||||
- type: object
|
||||
properties:
|
||||
id: { type: integer, format: int64 }
|
||||
songId: { type: integer, format: int64, nullable: true }
|
||||
name: { type: string }
|
||||
format: { $ref: '#/components/schemas/MotionFormat' }
|
||||
fileUrl: { type: string, nullable: true }
|
||||
fileSize: { type: integer, nullable: true }
|
||||
fps: { type: number, nullable: true }
|
||||
frameCount: { type: integer, nullable: true }
|
||||
durationMs: { type: integer, nullable: true }
|
||||
keypointFormat: { type: string, nullable: true }
|
||||
keypointUrl: { type: string, nullable: true }
|
||||
keypointFrames: { type: integer, nullable: true }
|
||||
preprocessState: { type: string, enum: [none, running, done, failed] }
|
||||
preprocessError: { type: string, nullable: true }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
createdAt: { type: string, format: date-time }
|
||||
updatedAt: { type: string, format: date-time }
|
||||
|
||||
MotionUpdate:
|
||||
type: object
|
||||
properties:
|
||||
name: { type: string }
|
||||
songId: { type: integer, format: int64, nullable: true }
|
||||
fps: { type: number }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
sourceType: { $ref: '#/components/schemas/SourceType' }
|
||||
sourceName: { type: string }
|
||||
sourceUrl: { type: string }
|
||||
license: { type: string }
|
||||
author: { type: string }
|
||||
|
||||
MotionPage:
|
||||
type: object
|
||||
properties:
|
||||
items: { type: array, items: { $ref: '#/components/schemas/Motion' } }
|
||||
total: { type: integer }
|
||||
page: { type: integer }
|
||||
pageSize: { type: integer }
|
||||
|
||||
Model:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/SourceFields'
|
||||
- type: object
|
||||
properties:
|
||||
id: { type: integer, format: int64 }
|
||||
name: { type: string }
|
||||
format: { $ref: '#/components/schemas/ModelFormat' }
|
||||
vrmVersion: { type: string, nullable: true }
|
||||
isPrimary: { type: boolean }
|
||||
fileUrl: { type: string, nullable: true }
|
||||
fileSize: { type: integer, nullable: true }
|
||||
thumbnailUrl: { type: string, nullable: true }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
createdAt: { type: string, format: date-time }
|
||||
updatedAt: { type: string, format: date-time }
|
||||
|
||||
ModelUpdate:
|
||||
type: object
|
||||
properties:
|
||||
name: { type: string }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
sourceType: { $ref: '#/components/schemas/SourceType' }
|
||||
sourceName: { type: string }
|
||||
sourceUrl: { type: string }
|
||||
license: { type: string }
|
||||
author: { type: string }
|
||||
|
||||
ModelPage:
|
||||
type: object
|
||||
properties:
|
||||
items: { type: array, items: { $ref: '#/components/schemas/Model' } }
|
||||
total: { type: integer }
|
||||
page: { type: integer }
|
||||
pageSize: { type: integer }
|
||||
|
||||
ReviewRecord:
|
||||
type: object
|
||||
properties:
|
||||
id: { type: integer, format: int64 }
|
||||
targetType: { type: string, enum: [song, motion, model] }
|
||||
targetId: { type: integer, format: int64 }
|
||||
action: { type: string, enum: [submit, approve, reject, withdraw] }
|
||||
fromStatus: { $ref: '#/components/schemas/PublishStatus' }
|
||||
toStatus: { $ref: '#/components/schemas/PublishStatus' }
|
||||
reviewer: { type: string, nullable: true }
|
||||
comment: { type: string, nullable: true }
|
||||
createdAt: { type: string, format: date-time }
|
||||
|
||||
ReviewPage:
|
||||
type: object
|
||||
properties:
|
||||
items: { type: array, items: { $ref: '#/components/schemas/ReviewRecord' } }
|
||||
total: { type: integer }
|
||||
page: { type: integer }
|
||||
pageSize: { type: integer }
|
||||
|
||||
PendingPage:
|
||||
type: object
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
targetType: { type: string, enum: [song, motion, model] }
|
||||
targetId: { type: integer, format: int64 }
|
||||
name: { type: string }
|
||||
status: { $ref: '#/components/schemas/PublishStatus' }
|
||||
source: { $ref: '#/components/schemas/SourceFields' }
|
||||
updatedAt: { type: string, format: date-time }
|
||||
total: { type: integer }
|
||||
page: { type: integer }
|
||||
pageSize: { type: integer }
|
||||
|
||||
CatalogBundle:
|
||||
type: object
|
||||
properties:
|
||||
contractVersion: { type: object, additionalProperties: { type: string } }
|
||||
generatedAt: { type: string, format: date-time }
|
||||
songs: { type: array, items: { $ref: '#/components/schemas/Song' } }
|
||||
motions: { type: array, items: { $ref: '#/components/schemas/Motion' } }
|
||||
models: { type: array, items: { $ref: '#/components/schemas/Model' } }
|
||||
defaultModelId: { type: integer, format: int64, nullable: true }
|
||||
Reference in New Issue
Block a user