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

25 KiB
Raw Blame History

ShowenV2 HTTP API

基础信息

  • Base URL: http://<device-ip>:8080
  • API 前缀: /api
  • 编码: UTF-8
  • 认证: 当前版本局域网无认证,后续版本预留
  • 权威实现: src/plugins/http/routes.rs

响应约定

成功响应

写操作接口统一返回:

{
  "status": "ok",
  "message": "开始播放"
}

错误响应

除文件下载接口外,错误统一返回:

{
  "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:
<!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:
<!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

{
  "type": "status_update",
  "data": {
    "running": true,
    "paused": false,
    "in_transition": false,
    "current_index": 0,
    "playlist_length": 3,
    "current_video": "intro"
  }
}

state_update

{
  "type": "state_update",
  "data": {
    "old_state": "rest",
    "new_state": "interact"
  }
}

config_update

{
  "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

{
  "type": "wifi_update",
  "data": {
    "ok": true,
    "networks": [
      {
        "ssid": "OfficeWiFi",
        "signal": 78,
        "security": "WPA2"
      }
    ]
  }
}

说明:该事件直接转发 WiFi 插件返回的 JSON字段随具体命令而变。

ble_update

{
  "type": "ble_update",
  "data": {
    "ready": true
  }
}

客户端可发送命令

WebSocket 文本消息需为 JSON成功响应格式不是 HTTP API 的 { "status": "ok" },而是 WebSocket 专用格式:

{
  "ok": true,
  "cmd": "play"
}

错误示例:

{
  "ok": false,
  "cmd": "goto",
  "error": "missing index"
}

已支持命令示例:

{"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:
{
  "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:
{
  "status": "ok",
  "message": "开始播放"
}
  • Error Response: { "status": "error", "message": "发送命令失败: ..." }

POST /api/pause

  • Method: POST
  • Path: /api/pause
  • Request Body: 无
  • Response Example:
{
  "status": "ok",
  "message": "已暂停"
}
  • Error Response: { "status": "error", "message": "发送命令失败: ..." }

POST /api/next

  • Method: POST
  • Path: /api/next
  • Request Body: 无
  • Response Example:
{
  "status": "ok",
  "message": "切换到下一个视频"
}
  • Error Response: { "status": "error", "message": "发送命令失败: ..." }

POST /api/previous

  • Method: POST
  • Path: /api/previous
  • Request Body: 无
  • Response Example:
{
  "status": "ok",
  "message": "切换到上一个视频"
}
  • Error Response: { "status": "error", "message": "发送命令失败: ..." }

POST /api/goto/:index

  • Method: POST
  • Path: /api/goto/:index
  • Request Body: 无
  • Response Example:
{
  "status": "ok",
  "message": "跳转到视频 2"
}
  • Error Response: { "status": "error", "message": "无效的视频索引" }{ "status": "error", "message": "发送命令失败: ..." }

GET /api/playlist

  • Method: GET
  • Path: /api/playlist
  • Request Body: 无
  • Response Example:
{
  "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:
{
  "status": "ok",
  "message": "切换到场景: rest"
}
  • Error Response: { "status": "error", "message": "发送命令失败: ..." }

POST /api/trigger/:name

  • Method: POST
  • Path: /api/trigger/:name
  • Request Body: 无
  • Response Example:
{
  "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:
{
  "status": "ok",
  "message": "触发器 'voice' 已发送,值: name"
}
  • Error Response: { "status": "error", "message": "发送命令失败: ..." }

配置管理

GET /api/config

  • Method: GET
  • Path: /api/config
  • Request Body: 无
  • Response Example:
{
  "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:
{
  "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:
{
  "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:
{
  "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:
{
  "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:
{
  "filename": "dog_state_machine.json"
}
  • Response Example:
{
  "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:
[
  {
    "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:
{
  "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:
{
  "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:
{
  "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:
[
  {
    "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:
[
  {
    "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:
{
  "ssid": "OfficeWiFi",
  "password": "secret123"
}
  • Response Example:
{
  "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:
{
  "ssid": "showen",
  "password": "12345678"
}
  • Response Example:
{
  "status": "ok",
  "message": "AP 热点已启动: SSID=showen"
}
  • Error Response: { "status": "error", "message": "JSON 格式错误: ..." }{ "status": "error", "message": "等待 WiFi 响应超时" }

说明:请求体可省略;默认 ssid=showenpassword=12345678

POST /api/wifi/hotspot/start

  • Method: POST
  • Path: /api/wifi/hotspot/start
  • Request Body Example:
{
  "ssid": "showen",
  "password": "12345678"
}
  • Response Example:
{
  "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:
{
  "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:
{
  "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:
{
  "device_name": "Showen"
}
  • Response Example:
{
  "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:
{
  "status": "ok",
  "message": "BLE 配网服务随主进程运行,无需手动停止"
}
  • Error Response: 无业务级错误 JSON

GET /api/ble/status

  • Method: GET
  • Path: /api/ble/status
  • Request Body: 无
  • Response Example:
{
  "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:
{
  "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: 二进制附件下载,响应头包含:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="showen-app.apk"
  • Error Response Example:
HTTP 400/404/500
text/html; charset=utf-8
无效的文件名

说明:该接口错误响应不是 JSON。

插件管理

GET /api/plugins

  • Method: GET
  • Path: /api/plugins
  • Request Body: 无
  • Response Example:
[
  {
    "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:
{
  "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:
{
  "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:
{
  "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:
{
  "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:
{
  "version": "1.2.3"
}
  • Response Example:
{
  "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:
{
  "id": "weather",
  "version": "0.3.0"
}
  • Response Example:
{
  "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:
{
  "status": "ok",
  "message": "plugin_check_updates 命令已发送"
}
  • Error Response: { "status": "error", "message": "发送失败: ..." }

文件管理

目录参数 :dir 仅支持:videosconfigsplugins

GET /api/files/:dir

  • Method: GET
  • Path: /api/files/:dir?path=<subdir>
  • Request Body: 无
  • Response Example:
[
  {
    "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:
{
  "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: 二进制附件下载,响应头包含:
Content-Type: application/octet-stream
Content-Disposition: attachment; filename="intro.mp4"
  • Error Response Example:
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:
{
  "path": "subdir/intro.mp4"
}
  • Response Example:
{
  "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:
{
  "from_dir": "videos",
  "from_path": "intro.mp4",
  "to_dir": "videos",
  "to_path": "archive/intro.mp4"
}
  • Response Example:
{
  "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:
{
  "path": "archive"
}
  • Response Example:
{
  "status": "ok",
  "message": "已创建目录: archive"
}
  • Error Response: { "status": "error", "message": "不支持的目录" }{ "status": "error", "message": "缺少 path" }{ "status": "error", "message": "路径不合法" }{ "status": "error", "message": "创建失败: ..." }

已移除的旧文档端点

以下端点当前实现中不存在,不应再使用:

  • /api/stop
  • /api/wifi/disconnect