Files
ShowenV2/clients/docs/API.md
showen d30c111c71 feat: M1.1 完成 + M1.2 启动 — 全量更新
M1.1 收尾:
- 24项 P0/P1/P2 bug 修复 (Rust 107 tests + Flutter 15 tests)
- Flutter App v0.3: cupertino_icons 修复, 单元测试, 调试面板, APK 52.6MB
- 示例插件完善: manifest.json + 请求/响应示范 + 7个测试
- API 文档重写 (以 routes.rs 为唯一权威)
- MILESTONES.md 更新至 100%

M1.2 启动:
- P0: 插件管理 API 闭环 (handle_manager_message Custom 分支 + broadcast_plugin_states)
- ServiceManager 集成测试 8/8 (tests/m1_2_service_manager.rs)
- M1.2 测试计划 (docs/M1.2_TEST_PLAN.md, 18个E2E场景)
- 动态插件系统: auto_rollback + version_manager GC + 路径穿越防护

总计: Rust 115/115 测试, Flutter 15/15 测试, 零 warning

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 18:12:42 +08:00

1366 lines
25 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ShowenV2 HTTP API
## 基础信息
- Base URL: `http://<device-ip>:8080`
- API 前缀: `/api`
- 编码: `UTF-8`
- 认证: 当前版本局域网无认证,后续版本预留
- 权威实现: `src/plugins/http/routes.rs`
## 响应约定
### 成功响应
写操作接口统一返回:
```json
{
"status": "ok",
"message": "开始播放"
}
```
### 错误响应
除文件下载接口外,错误统一返回:
```json
{
"status": "error",
"message": "错误描述"
}
```
查询接口直接返回业务 JSON不包裹 `status` 字段。
### 典型错误码
- `400 Bad Request`: 参数、JSON、文件名或配置内容非法
- `403 Forbidden`: 文件管理路径越界或目标目录不合法
- `404 Not Found`: 文件、目录、插件或配置不存在
- `409 Conflict`: 文件移动目标已存在
- `413 Payload Too Large`: 单文件超过 100 MB
- `500 Internal Server Error`: 内部发送消息失败、文件操作失败
- `502 Bad Gateway`: WiFi 插件返回无效 JSON
- `504 Gateway Timeout`: 等待 WiFi 插件响应超时
## Web UI
### GET /
- Method: `GET`
- Path: `/`
- Request Body: 无
- Response Example:
```html
<!doctype html>
<html lang="zh-CN">
<head><title>Showen 控制台</title></head>
<body>...</body>
</html>
```
- Error Response: 标准 HTTP 错误页面,无 JSON 包装
### GET /index.html
- Method: `GET`
- Path: `/index.html`
- Request Body: 无
- Response Example:
```html
<!doctype html>
<html lang="zh-CN">
<head><title>Showen 控制台</title></head>
<body>...</body>
</html>
```
- Error Response: 标准 HTTP 错误页面,无 JSON 包装
## WebSocket
### GET /ws
- Method: `GET` (Upgrade to WebSocket)
- Path: `/ws`
- Request Body: 无
- Response Example: 连接建立后服务端会先推送当前快照,再持续推送事件
- Error Response: WebSocket 握手失败时返回标准 HTTP 错误
### 服务端事件
#### `status_update`
```json
{
"type": "status_update",
"data": {
"running": true,
"paused": false,
"in_transition": false,
"current_index": 0,
"playlist_length": 3,
"current_video": "intro"
}
}
```
#### `state_update`
```json
{
"type": "state_update",
"data": {
"old_state": "rest",
"new_state": "interact"
}
}
```
#### `config_update`
```json
{
"type": "config_update",
"data": {
"display": {
"fullscreen": true,
"window_title": "Hologram Player - Cat",
"rotation": 0,
"flip_horizontal": true,
"flip_vertical": true,
"offset_x": 0,
"offset_y": 0,
"prevent_screen_lock": true,
"render_width": 1280,
"render_height": 800,
"output_width": null,
"output_height": null,
"scale_mode": "stretch",
"allow_upscale": true,
"perspective_correction": {
"enabled": false,
"points": [[0, 0], [1280, 0], [1280, 800], [0, 800]]
},
"chroma_key": {
"enabled": false,
"hsv_min": [0, 0, 200],
"hsv_max": [180, 30, 255],
"invert": false,
"feather": 3
},
"brightness_adjust": {
"enabled": true,
"subject_boost": 1.5,
"background_suppress": 0.3,
"threshold": 30
}
},
"playlist": [
{
"id": "anim_0",
"path": "videos/intro.mp4",
"duration": null,
"loop_count": 1,
"random_loop_range": null
}
],
"transition": {
"enabled": true,
"type": "fade",
"duration": 0.5
},
"playback": {
"loop_playlist": true,
"auto_start": true
},
"scenes": {
"rest": [],
"active": [],
"sleep": [],
"interact": [],
"state_machine": null
},
"remote_control": {
"enabled": true,
"host": "0.0.0.0",
"port": 8080
},
"ble": {
"enabled": true,
"device_name": "Showen"
},
"source_path": "/home/showen/Showen/ShowenV2/configs/cat_state_machine.json",
"source_dir": "/home/showen/Showen/ShowenV2/configs"
}
}
```
#### `wifi_update`
```json
{
"type": "wifi_update",
"data": {
"ok": true,
"networks": [
{
"ssid": "OfficeWiFi",
"signal": 78,
"security": "WPA2"
}
]
}
}
```
说明:该事件直接转发 WiFi 插件返回的 JSON字段随具体命令而变。
#### `ble_update`
```json
{
"type": "ble_update",
"data": {
"ready": true
}
}
```
### 客户端可发送命令
WebSocket 文本消息需为 JSON成功响应格式不是 HTTP API 的 `{ "status": "ok" }`,而是 WebSocket 专用格式:
```json
{
"ok": true,
"cmd": "play"
}
```
错误示例:
```json
{
"ok": false,
"cmd": "goto",
"error": "missing index"
}
```
已支持命令示例:
```json
{"cmd":"play"}
{"cmd":"pause"}
{"cmd":"next"}
{"cmd":"previous"}
{"cmd":"goto","index":3}
{"cmd":"scene","name":"rest"}
{"cmd":"trigger","name":"voice","value":"name"}
{"cmd":"connect","ssid":"OfficeWiFi","password":"secret"}
{"cmd":"ap_start","ssid":"showen","password":"12345678"}
```
## 播放控制
### GET /api/status
- Method: `GET`
- Path: `/api/status`
- Request Body: 无
- Response Example:
```json
{
"running": true,
"paused": false,
"in_transition": false,
"current_index": 0,
"playlist_length": 3,
"current_video": "intro"
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### POST /api/play
- Method: `POST`
- Path: `/api/play`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "开始播放"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
### POST /api/pause
- Method: `POST`
- Path: `/api/pause`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "已暂停"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
### POST /api/next
- Method: `POST`
- Path: `/api/next`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "切换到下一个视频"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
### POST /api/previous
- Method: `POST`
- Path: `/api/previous`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "切换到上一个视频"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
### POST /api/goto/:index
- Method: `POST`
- Path: `/api/goto/:index`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "跳转到视频 2"
}
```
- Error Response: `{ "status": "error", "message": "无效的视频索引" }``{ "status": "error", "message": "发送命令失败: ..." }`
### GET /api/playlist
- Method: `GET`
- Path: `/api/playlist`
- Request Body: 无
- Response Example:
```json
{
"playlist": [
{
"id": "anim_0",
"path": "videos/intro.mp4",
"duration": null,
"loop_count": 1,
"random_loop_range": null
},
{
"id": "anim_1",
"path": "videos/idle.mp4",
"duration": 12.5,
"loop_count": 2,
"random_loop_range": null
}
],
"current_index": 0
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### POST /api/scene/:name
- Method: `POST`
- Path: `/api/scene/:name`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "切换到场景: rest"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
### POST /api/trigger/:name
- Method: `POST`
- Path: `/api/trigger/:name`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "触发器 'voice' 已发送"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
### POST /api/trigger/:name/:value
- Method: `POST`
- Path: `/api/trigger/:name/:value`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "触发器 'voice' 已发送,值: name"
}
```
- Error Response: `{ "status": "error", "message": "发送命令失败: ..." }`
## 配置管理
### GET /api/config
- Method: `GET`
- Path: `/api/config`
- Request Body: 无
- Response Example:
```json
{
"display": {
"fullscreen": true,
"window_title": "Hologram Player - Cat",
"rotation": 0,
"flip_horizontal": true,
"flip_vertical": true,
"offset_x": 0,
"offset_y": 0,
"prevent_screen_lock": true,
"render_width": 1280,
"render_height": 800,
"output_width": null,
"output_height": null,
"scale_mode": "stretch",
"allow_upscale": true,
"perspective_correction": {
"enabled": false,
"points": [[0, 0], [1280, 0], [1280, 800], [0, 800]]
},
"chroma_key": {
"enabled": false,
"hsv_min": [0, 0, 200],
"hsv_max": [180, 30, 255],
"invert": false,
"feather": 3
},
"brightness_adjust": {
"enabled": true,
"subject_boost": 1.5,
"background_suppress": 0.3,
"threshold": 30
}
},
"playlist": [
{
"id": "anim_0",
"path": "videos/intro.mp4",
"duration": null,
"loop_count": 1,
"random_loop_range": null
}
],
"transition": {
"enabled": true,
"type": "fade",
"duration": 0.5
},
"playback": {
"loop_playlist": true,
"auto_start": true
},
"scenes": {
"rest": [],
"active": [],
"sleep": [],
"interact": [],
"state_machine": null
},
"remote_control": {
"enabled": true,
"host": "0.0.0.0",
"port": 8080
},
"ble": {
"enabled": true,
"device_name": "Showen"
},
"source_path": "/home/showen/Showen/ShowenV2/configs/cat_state_machine.json",
"source_dir": "/home/showen/Showen/ShowenV2/configs"
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### GET /api/config/display
- Method: `GET`
- Path: `/api/config/display`
- Request Body: 无
- Response Example:
```json
{
"fullscreen": true,
"window_title": "Hologram Player - Cat",
"rotation": 0,
"flip_horizontal": true,
"flip_vertical": true,
"offset_x": 0,
"offset_y": 0,
"prevent_screen_lock": true,
"render_width": 1280,
"render_height": 800,
"output_width": null,
"output_height": null,
"scale_mode": "stretch",
"allow_upscale": true,
"perspective_correction": {
"enabled": false,
"points": [[0, 0], [1280, 0], [1280, 800], [0, 800]]
},
"chroma_key": {
"enabled": false,
"hsv_min": [0, 0, 200],
"hsv_max": [180, 30, 255],
"invert": false,
"feather": 3
},
"brightness_adjust": {
"enabled": true,
"subject_boost": 1.5,
"background_suppress": 0.3,
"threshold": 30
}
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### POST /api/config
- Method: `POST`
- Path: `/api/config`
- Request Body Example:
```json
{
"display": {
"fullscreen": true,
"window_title": "Showen",
"rotation": 0,
"flip_horizontal": false,
"flip_vertical": false,
"offset_x": 0,
"offset_y": 0,
"prevent_screen_lock": true,
"render_width": 1280,
"render_height": 800,
"output_width": null,
"output_height": null,
"scale_mode": "fit",
"allow_upscale": true,
"perspective_correction": {
"enabled": false,
"points": []
},
"chroma_key": {
"enabled": false,
"hsv_min": [0, 0, 200],
"hsv_max": [180, 30, 255],
"invert": false,
"feather": 0
},
"brightness_adjust": {
"enabled": false,
"subject_boost": 1.5,
"background_suppress": 0.3,
"threshold": 30
}
},
"playlist": [
{
"id": "intro",
"path": "videos/intro.mp4",
"duration": null,
"loop_count": 1,
"random_loop_range": null
}
],
"transition": {
"enabled": true,
"type": "fade",
"duration": 0.5
},
"playback": {
"loop_playlist": true,
"auto_start": true
},
"scenes": {
"rest": [],
"active": [],
"sleep": [],
"interact": [],
"state_machine": null
},
"remote_control": {
"enabled": true,
"host": "0.0.0.0",
"port": 8080
},
"ble": {
"enabled": true,
"device_name": "Showen"
}
}
```
- Response Example:
```json
{
"status": "ok",
"message": "配置已保存,热重载将自动生效"
}
```
- Error Response: `{ "status": "error", "message": "请求体不是有效的 UTF-8" }``{ "status": "error", "message": "配置验证失败: ..." }``{ "status": "error", "message": "写入配置文件失败: ..." }`
### GET /api/config/available
- Method: `GET`
- Path: `/api/config/available`
- Request Body: 无
- Response Example:
```json
{
"configs": [
"cat_state_machine.json",
"dog_state_machine.json"
],
"active": "cat_state_machine.json"
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### POST /api/config/switch
- Method: `POST`
- Path: `/api/config/switch`
- Request Body Example:
```json
{
"filename": "dog_state_machine.json"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "已切换到配置: dog_state_machine.json"
}
```
- Error Response: `{ "status": "error", "message": "文件名不合法" }``{ "status": "error", "message": "只支持 .json 配置文件" }``{ "status": "error", "message": "配置文件不存在" }``{ "status": "error", "message": "配置验证失败: ..." }`
## 视频管理
### GET /api/videos
- Method: `GET`
- Path: `/api/videos`
- Request Body: 无
- Response Example:
```json
[
{
"name": "intro.mp4",
"size": 1048576
},
{
"name": "subdir/idle.mp4",
"size": 2097152
}
]
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### POST /api/videos/upload
- Method: `POST`
- Path: `/api/videos/upload`
- Request Body Example: `multipart/form-data`,一个或多个 `file` 字段
- Response Example:
```json
{
"status": "ok",
"message": "已上传 2 个文件: intro.mp4, idle.mp4"
}
```
- Error Response: `{ "status": "error", "message": "未找到上传文件" }``{ "status": "error", "message": "文件大小超过限制: 单文件最大 100 MB" }``{ "status": "error", "message": "保存文件失败: ..." }`
### DELETE /api/videos/:filename
- Method: `DELETE`
- Path: `/api/videos/:filename`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "已删除: intro.mp4"
}
```
- Error Response: `{ "status": "error", "message": "无效的文件名" }``{ "status": "error", "message": "文件不存在" }``{ "status": "error", "message": "删除失败: ..." }`
## WiFi
### GET /api/wifi/status
- Method: `GET`
- Path: `/api/wifi/status`
- Request Body: 无
- Response Example:
```json
{
"connected": true,
"ssid": "OfficeWiFi",
"ip": "192.168.1.23"
}
```
- Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }``{ "status": "error", "message": "WiFi 返回了无效 JSON: ..." }``{ "status": "error", "message": "WiFi 操作失败" }`
### GET /api/wifi/scan
- Method: `GET`
- Path: `/api/wifi/scan`
- Request Body: 无
- Response Example:
```json
[
{
"ssid": "OfficeWiFi",
"signal": 78,
"security": "WPA2"
},
{
"ssid": "Guest",
"signal": 42,
"security": "open"
}
]
```
- Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }``{ "status": "error", "message": "WiFi 返回了无效 JSON: ..." }`
### POST /api/wifi/scan
- Method: `POST`
- Path: `/api/wifi/scan`
- Request Body: 无
- Response Example:
```json
[
{
"ssid": "OfficeWiFi",
"signal": 78,
"security": "WPA2"
}
]
```
- Error Response: 与 `GET /api/wifi/scan` 相同
### POST /api/wifi/connect
- Method: `POST`
- Path: `/api/wifi/connect`
- Request Body Example:
```json
{
"ssid": "OfficeWiFi",
"password": "secret123"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "WiFi 连接成功: OfficeWiFi"
}
```
- Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }``{ "status": "error", "message": "WiFi 操作失败" }`
### POST /api/wifi/ap/start
- Method: `POST`
- Path: `/api/wifi/ap/start`
- Request Body Example:
```json
{
"ssid": "showen",
"password": "12345678"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "AP 热点已启动: SSID=showen"
}
```
- Error Response: `{ "status": "error", "message": "JSON 格式错误: ..." }``{ "status": "error", "message": "等待 WiFi 响应超时" }`
说明:请求体可省略;默认 `ssid=showen``password=12345678`
### POST /api/wifi/hotspot/start
- Method: `POST`
- Path: `/api/wifi/hotspot/start`
- Request Body Example:
```json
{
"ssid": "showen",
"password": "12345678"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "AP 热点已启动: SSID=showen"
}
```
- Error Response: 与 `POST /api/wifi/ap/start` 相同
说明:这是 `POST /api/wifi/ap/start` 的兼容别名。
### POST /api/wifi/ap/stop
- Method: `POST`
- Path: `/api/wifi/ap/stop`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "AP 热点已关闭"
}
```
- Error Response: `{ "status": "error", "message": "等待 WiFi 响应超时" }``{ "status": "error", "message": "WiFi 操作失败" }`
### POST /api/wifi/hotspot/stop
- Method: `POST`
- Path: `/api/wifi/hotspot/stop`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "AP 热点已关闭"
}
```
- Error Response: 与 `POST /api/wifi/ap/stop` 相同
说明:这是 `POST /api/wifi/ap/stop` 的兼容别名。
## BLE
### POST /api/ble/start
- Method: `POST`
- Path: `/api/ble/start`
- Request Body Example:
```json
{
"device_name": "Showen"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "BLE 配网服务已内嵌运行中,设备名: Showen"
}
```
- Error Response: `{ "status": "error", "message": "JSON 格式错误: ..." }`
说明:请求体可省略;未传时使用当前配置中的 `ble.device_name`
### POST /api/ble/stop
- Method: `POST`
- Path: `/api/ble/stop`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "BLE 配网服务随主进程运行,无需手动停止"
}
```
- Error Response: 无业务级错误 JSON
### GET /api/ble/status
- Method: `GET`
- Path: `/api/ble/status`
- Request Body: 无
- Response Example:
```json
{
"running": true,
"embedded": true,
"device_name": "Showen"
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
## App 下载
### GET /api/app/info
- Method: `GET`
- Path: `/api/app/info`
- Request Body: 无
- Response Example:
```json
{
"version": "0.1.0",
"apk_available": true,
"apk_size": 18432000,
"download_url": "/download/showen-app.apk"
}
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### GET /download/:filename
- Method: `GET`
- Path: `/download/:filename`
- Request Body: 无
- Response Example: 二进制附件下载,响应头包含:
```text
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="showen-app.apk"
```
- Error Response Example:
```text
HTTP 400/404/500
text/html; charset=utf-8
无效的文件名
```
说明:该接口错误响应不是 JSON。
## 插件管理
### GET /api/plugins
- Method: `GET`
- Path: `/api/plugins`
- Request Body: 无
- Response Example:
```json
[
{
"id": "wifi",
"info": {
"name": "WiFi Plugin",
"version": "0.1.0",
"description": "Manage WiFi via nmcli",
"platform": "LinuxArm64"
},
"is_dynamic": false,
"error_policy": "auto_rollback",
"error_count": 0,
"max_errors": 5,
"enabled": true,
"test_results": [
{
"capability": "wifi_scan",
"passed": true,
"message": "no test defined"
}
],
"capabilities": ["wifi_scan", "wifi_connect"],
"needs_rollback": false
}
]
```
- Error Response: `404/405` 由路由层处理;无业务级错误 JSON
### GET /api/plugins/:id
- Method: `GET`
- Path: `/api/plugins/:id`
- Request Body: 无
- Response Example:
```json
{
"id": "wifi",
"info": {
"name": "WiFi Plugin",
"version": "0.1.0",
"description": "Manage WiFi via nmcli",
"platform": "LinuxArm64"
},
"is_dynamic": false,
"error_policy": "auto_rollback",
"error_count": 0,
"max_errors": 5,
"enabled": true,
"test_results": [],
"capabilities": ["wifi_scan", "wifi_connect"],
"needs_rollback": false
}
```
- Error Response: `{ "status": "error", "message": "plugin 'wifi' not found" }`
### POST /api/plugins/:id/enable
- Method: `POST`
- Path: `/api/plugins/:id/enable`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "plugin_enable 命令已发送"
}
```
- Error Response: `{ "status": "error", "message": "发送失败: ..." }`
### POST /api/plugins/:id/disable
- Method: `POST`
- Path: `/api/plugins/:id/disable`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "plugin_disable 命令已发送"
}
```
- Error Response: `{ "status": "error", "message": "发送失败: ..." }`
### POST /api/plugins/:id/rollback
- Method: `POST`
- Path: `/api/plugins/:id/rollback`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "plugin_rollback 命令已发送"
}
```
- Error Response: `{ "status": "error", "message": "发送失败: ..." }`
### POST /api/plugins/:id/switch
- Method: `POST`
- Path: `/api/plugins/:id/switch`
- Request Body Example:
```json
{
"version": "1.2.3"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "版本切换请求已发送: wifi -> v1.2.3"
}
```
- Error Response: `{ "status": "error", "message": "发送失败: ..." }`
### POST /api/plugins/install
- Method: `POST`
- Path: `/api/plugins/install`
- Request Body Example:
```json
{
"id": "weather",
"version": "0.3.0"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "安装请求已发送: weather"
}
```
- Error Response: `{ "status": "error", "message": "发送失败: ..." }`
说明:`version` 可省略,省略时请求体仍需提供 `id`
### POST /api/plugins/check-updates
- Method: `POST`
- Path: `/api/plugins/check-updates`
- Request Body: 无
- Response Example:
```json
{
"status": "ok",
"message": "plugin_check_updates 命令已发送"
}
```
- Error Response: `{ "status": "error", "message": "发送失败: ..." }`
## 文件管理
目录参数 `:dir` 仅支持:`videos``configs``plugins`
### GET /api/files/:dir
- Method: `GET`
- Path: `/api/files/:dir?path=<subdir>`
- Request Body: 无
- Response Example:
```json
[
{
"name": "subdir",
"is_dir": true,
"size": 0
},
{
"name": "intro.mp4",
"is_dir": false,
"size": 1048576
}
]
```
- Error Response: `{ "status": "error", "message": "不支持的目录: logs仅支持 videos/configs/plugins" }``{ "status": "error", "message": "路径不合法" }``{ "status": "error", "message": "目录不存在" }`
### POST /api/files/:dir/upload
- Method: `POST`
- Path: `/api/files/:dir/upload?path=<subdir>`
- Request Body Example: `multipart/form-data`,一个或多个 `file` 字段
- Response Example:
```json
{
"status": "ok",
"message": "已上传 1 个文件: intro.mp4"
}
```
- Error Response: `{ "status": "error", "message": "不支持的目录" }``{ "status": "error", "message": "目标目录不合法" }``{ "status": "error", "message": "未找到上传文件" }``{ "status": "error", "message": "文件大小超过限制: 单文件最大 100 MB" }`
### GET /api/files/:dir/download
- Method: `GET`
- Path: `/api/files/:dir/download?path=<file>`
- Request Body: 无
- Response Example: 二进制附件下载,响应头包含:
```text
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="intro.mp4"
```
- Error Response Example:
```text
HTTP 400/403/404
text/html; charset=utf-8
缺少 path 参数
```
说明:该接口错误响应不是 JSON。
### POST /api/files/:dir/delete
- Method: `POST`
- Path: `/api/files/:dir/delete`
- Request Body Example:
```json
{
"path": "subdir/intro.mp4"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "已删除: subdir/intro.mp4"
}
```
- Error Response: `{ "status": "error", "message": "不支持的目录" }``{ "status": "error", "message": "缺少 path" }``{ "status": "error", "message": "路径不合法" }``{ "status": "error", "message": "文件不存在" }`
### POST /api/files/move
- Method: `POST`
- Path: `/api/files/move`
- Request Body Example:
```json
{
"from_dir": "videos",
"from_path": "intro.mp4",
"to_dir": "videos",
"to_path": "archive/intro.mp4"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "已移动: intro.mp4 → archive/intro.mp4"
}
```
- Error Response: `{ "status": "error", "message": "源目录不支持" }``{ "status": "error", "message": "目标目录不支持" }``{ "status": "error", "message": "源路径不合法" }``{ "status": "error", "message": "目标路径已存在" }`
### POST /api/files/:dir/mkdir
- Method: `POST`
- Path: `/api/files/:dir/mkdir`
- Request Body Example:
```json
{
"path": "archive"
}
```
- Response Example:
```json
{
"status": "ok",
"message": "已创建目录: archive"
}
```
- Error Response: `{ "status": "error", "message": "不支持的目录" }``{ "status": "error", "message": "缺少 path" }``{ "status": "error", "message": "路径不合法" }``{ "status": "error", "message": "创建失败: ..." }`
## 已移除的旧文档端点
以下端点当前实现中不存在,不应再使用:
- `/api/stop`
- `/api/wifi/disconnect`