huz1xuan

docs: 补充高光录制部署与测试手册

  1 +# WebScreen 高光录制部署、使用与测试手册
  2 +
  3 +## 1. 范围
  4 +
  5 +本文用于同事在新 Linux 服务器部署 WebScreen,并只对 `xdyui2` 验证高光 MP4 录制。
  6 +
  7 +当前规则:
  8 +
  9 +- 一个高光时间段生成一个 MP4。
  10 +- 一个课堂有 N 条高光,生成 N 个 MP4。
  11 +- 全量模式录制 xdyui2 前一天全部高光。
  12 +- 任务模式只处理 `status=0 && onlyHighlight=1`。
  13 +- WebScreen 只生成本地文件,服务器原任务负责搬运到 OSS。
  14 +- 暂不启用 CrazyTalk。
  15 +
  16 +不要直接覆盖现有正式录制服务器。
  17 +
  18 +## 2. 交付物和外部依赖
  19 +
  20 +项目包:
  21 +
  22 +```text
  23 +webScreen-full-latest.zip
  24 +```
  25 +
  26 +包内含源码、Git 历史、`.env`、`node_modules`、文档和测试。`node_modules` 来自 macOS,Linux 必须重新安装。
  27 +
  28 +项目不包含 `web_capture_c`。需从现有录制服务器复制完整运行目录:
  29 +
  30 +```text
  31 +/root/web_capture_release
  32 +/root/web_capture_release/linux-x64/web_capture_c
  33 +```
  34 +
  35 +同时复制其动态库、字体、浏览器运行环境和显示服务配置。
  36 +
  37 +## 3. 部署前检查
  38 +
  39 +```bash
  40 +date
  41 +timedatectl
  42 +node -v
  43 +npm -v
  44 +ss -lntp | grep ':3001'
  45 +df -h /root
  46 +test -x /root/web_capture_release/linux-x64/web_capture_c && echo CAPTURE_OK
  47 +```
  48 +
  49 +要求:
  50 +
  51 +- 时区为 `Asia/Shanghai`,NTP 已同步。
  52 +- Node.js 与现有正式服务器一致。
  53 +- 端口 `3001` 未被占用。
  54 +- 录制程序可执行,磁盘空间充足。
  55 +
  56 +## 4. 解压和安装
  57 +
  58 +```bash
  59 +cd /root
  60 +unzip webScreen-full-latest.zip
  61 +cd /root/webScreen
  62 +mv node_modules node_modules.macos.bak
  63 +npm install
  64 +npm test
  65 +```
  66 +
  67 +预期测试输出:
  68 +
  69 +```text
  70 +highlightRecordingService tests passed
  71 +highlight routes tests passed
  72 +```
  73 +
  74 +## 5. 环境变量
  75 +
  76 +`.env` 需要包含:
  77 +
  78 +```text
  79 +ALIBABA_CLOUD_ACCESS_KEY_ID=...
  80 +ALIBABA_CLOUD_ACCESS_KEY_SECRET=...
  81 +```
  82 +
  83 +只检查是否存在:
  84 +
  85 +```bash
  86 +grep -q '^ALIBABA_CLOUD_ACCESS_KEY_ID=' .env && echo ACCESS_KEY_ID_OK
  87 +grep -q '^ALIBABA_CLOUD_ACCESS_KEY_SECRET=' .env && echo ACCESS_KEY_SECRET_OK
  88 +```
  89 +
  90 +这两个变量只用于查询 OSS 状态;WebScreen 不主动上传文件。
  91 +
  92 +## 6. 配置
  93 +
  94 +编辑 `/root/webScreen/config/config.json`。保留服务器原有:
  95 +
  96 +- `GETCLASSURL`
  97 +- `GETCLASSURLPARAMETER`
  98 +- `PROJECTWINCATALOG`
  99 +- `PROJECTCATALOG`
  100 +- `BACKMEDIACONFIG`
  101 +- `classLastNumber`
  102 +
  103 +目录应与服务器一致:
  104 +
  105 +```json
  106 +"PROJECTWINCATALOG": "/root/web_capture_release/linux-x64",
  107 +"PROJECTCATALOG": "/root/web_capture_release"
  108 +```
  109 +
  110 +`BACKMEDIACONFIG.url` 必须指向已支持 `recBeginTime/recEndTime` 的 PCLive 测试版本。保留验证服务器已确认可用的 `devback` 或测试路径,不在代码中硬编码。
  111 +
  112 +高光配置:
  113 +
  114 +```json
  115 +"HIGHLIGHTCONFIG": {
  116 + "enabled": false,
  117 + "sourceMode": "site",
  118 + "siteIds": ["xdyui2"],
  119 + "apiBaseUrl": "https://saas.xuedianyun.com",
  120 + "pageSize": 100,
  121 + "taskPageSize": 100,
  122 + "maxPages": 1000,
  123 + "maxConcurrent": 2,
  124 + "maxDurationMs": 21600000,
  125 + "apiTimeoutMs": 10000,
  126 + "apiRetryCount": 2,
  127 + "apiRetryBaseDelayMs": 500,
  128 + "loadGraceMs": 60000,
  129 + "endGraceMs": 10000,
  130 + "taskRetentionMs": 86400000,
  131 + "outputNamespace": "",
  132 + "outputBaseUrl": "https://xdymp4.xuedianyun.com"
  133 +}
  134 +```
  135 +
  136 +首次启动保持 `enabled=false`。验证 JSON:
  137 +
  138 +```bash
  139 +node -e "JSON.parse(require('fs').readFileSync('config/config.json')); console.log('config ok')"
  140 +```
  141 +
  142 +## 7. 启动服务
  143 +
  144 +测试期间先不要配置 cron。
  145 +
  146 +```bash
  147 +npm run pm2
  148 +pm2 show webScreen
  149 +curl http://127.0.0.1:3001/highlight/status
  150 +```
  151 +
  152 +若 PM2 已有同名进程:
  153 +
  154 +```bash
  155 +pm2 restart webScreen
  156 +```
  157 +
  158 +状态接口预期:
  159 +
  160 +```json
  161 +{
  162 + "code": 0,
  163 + "message": "success",
  164 + "data": {
  165 + "queued": 0,
  166 + "recording": 0,
  167 + "knownTasks": 0
  168 + }
  169 +}
  170 +```
  171 +
  172 +查看日志:
  173 +
  174 +```bash
  175 +pm2 logs webScreen --lines 100
  176 +```
  177 +
  178 +## 8. 开启 xdyui2
  179 +
  180 +基础服务正常后修改:
  181 +
  182 +```json
  183 +"enabled": true,
  184 +"sourceMode": "site",
  185 +"siteIds": ["xdyui2"]
  186 +```
  187 +
  188 +```bash
  189 +pm2 restart webScreen
  190 +```
  191 +
  192 +## 9. 准备测试课堂
  193 +
  194 +选择一个 xdyui2 已结束课堂:
  195 +
  196 +- 至少两条高光。
  197 +- 回放正常。
  198 +- 最好含教师、学生音视频、屏幕共享和声音。
  199 +
  200 +记录:
  201 +
  202 +```text
  203 +siteId:xdyui2
  204 +classId:__________
  205 +高光数量:__________
  206 +课堂日期:__________
  207 +```
  208 +
  209 +## 10. 只读预览
  210 +
  211 +预览不会启动录制程序:
  212 +
  213 +```bash
  214 +curl -X POST http://127.0.0.1:3001/highlight/preview/by-class \
  215 + -H 'Content-Type: application/json' \
  216 + -d '{"classId":"替换为课堂号"}'
  217 +```
  218 +
  219 +逐条检查:
  220 +
  221 +- `siteId` 是 `xdyui2`。
  222 +- `highlightId` 不重复。
  223 +- `classId` 正确。
  224 +- `beginTime/endTime` 是 13 位毫秒时间戳。
  225 +- `duration = endTime - beginTime`。
  226 +- `playbackUrl` 含正确的 `recBeginTime/recEndTime`。
  227 +- 文件名为 `{classId}_highlight_{highlightId}.mp4`。
  228 +- 路径位于 `/root/web_capture_release/media/xdyui2/{yyyyMMdd}/`。
  229 +
  230 +返回“无高光数据”时,先让后端确认高光表确实存在记录。
  231 +
  232 +## 11. 单课堂录制
  233 +
  234 +```bash
  235 +curl -X POST http://127.0.0.1:3001/highlight/recording/by-class \
  236 + -H 'Content-Type: application/json' \
  237 + -d '{"classId":"替换为课堂号"}'
  238 +```
  239 +
  240 +新任务初始状态应为 `queued`;已有文件可能返回 `uploading` 或 `generated`。
  241 +
  242 +观察队列和进程:
  243 +
  244 +```bash
  245 +watch -n 2 'curl -s http://127.0.0.1:3001/highlight/status'
  246 +tail -f /root/webScreen/log/$(date +%Y%m%d).txt
  247 +ps -ef | grep '[w]eb_capture_c'
  248 +```
  249 +
  250 +响应返回后不能立即停止 PM2;录制在后台队列继续执行。
  251 +
  252 +## 12. 本地文件验证
  253 +
  254 +```bash
  255 +find /root/web_capture_release/media/xdyui2 -type f -name '课堂号_highlight_*.mp4' -ls
  256 +```
  257 +
  258 +要求:
  259 +
  260 +- N 条高光生成 N 个文件。
  261 +- 文件名中的 `highlightId` 不同。
  262 +- 文件大小大于 0。
  263 +- 不覆盖旧 `{classId}.mp4`。
  264 +- 日期目录包含 `download.json`。
  265 +- `.highlight_tmp` 无本次任务残留。
  266 +
  267 +如有 ffprobe:
  268 +
  269 +```bash
  270 +ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 /完整/文件路径.mp4
  271 +```
  272 +
  273 +人工播放检查:
  274 +
  275 +- 开始位置接近 `beginTime`。
  276 +- 结束位置接近 `endTime`。
  277 +- 教师、学生、屏幕共享画面正常。
  278 +- 声音正常。
  279 +- 文件不是整堂课堂。
  280 +
  281 +## 13. 重复录制验证
  282 +
  283 +再次调用同一课堂的 `/highlight/recording/by-class`。
  284 +
  285 +要求:
  286 +
  287 +- 不再启动新的 `web_capture_c`。
  288 +- 文件数量不增加。
  289 +- 原文件不被覆盖。
  290 +- OSS 已有文件时也不重复录制。
  291 +
  292 +## 14. OSS 搬运和多地址查询
  293 +
  294 +等待服务器原搬运任务执行。预期 OSS Key:
  295 +
  296 +```text
  297 +oss/xdyui2/{yyyyMMdd}/{classId}_highlight_{highlightId}.mp4
  298 +```
  299 +
  300 +查询:
  301 +
  302 +```bash
  303 +curl -X POST http://127.0.0.1:3001/highlight/fileExists \
  304 + -H 'Content-Type: application/json' \
  305 + -d '{"siteId":"xdyui2","classId":"替换为课堂号"}'
  306 +```
  307 +
  308 +OSS 尚不可见时:
  309 +
  310 +```text
  311 +status = uploading
  312 +generated = false
  313 +```
  314 +
  315 +OSS 可见后:
  316 +
  317 +```text
  318 +status = generated
  319 +generated = true
  320 +url = https://xdymp4.xuedianyun.com/oss/...
  321 +```
  322 +
  323 +N 条高光时,`classUrlList` 必须有 N 条记录。
  324 +
  325 +## 15. 前一天全量验证
  326 +
  327 +保持:
  328 +
  329 +```json
  330 +"sourceMode": "site",
  331 +"siteIds": ["xdyui2"]
  332 +```
  333 +
  334 +手工调用 cron 入口:
  335 +
  336 +```bash
  337 +wget -qO- http://127.0.0.1:3001/recording
  338 +```
  339 +
  340 +检查:
  341 +
  342 +- `code` 为 `"0"`。
  343 +- `data.mode` 为 `site`。
  344 +- `beginTime/endTime` 是 Asia/Shanghai 前一天。
  345 +- 只查询 xdyui2。
  346 +- 前一天每条有效高光都进入队列。
  347 +
  348 +## 16. 任务模式验证
  349 +
  350 +全量模式通过后改为:
  351 +
  352 +```json
  353 +"sourceMode": "task"
  354 +```
  355 +
  356 +```bash
  357 +pm2 restart webScreen
  358 +```
  359 +
  360 +请后端创建四组任务:
  361 +
  362 +1. `status=0, onlyHighlight=1, siteId=xdyui2`:应录制。
  363 +2. `status!=0, onlyHighlight=1`:不录制。
  364 +3. `status=0, onlyHighlight=0`:不进入高光录制。
  365 +4. 其他站点 `status=0, onlyHighlight=1`:不录制。
  366 +
  367 +```bash
  368 +wget -qO- http://127.0.0.1:3001/recording
  369 +```
  370 +
  371 +检查:
  372 +
  373 +- `data.mode` 为 `task`。
  374 +- `pendingTasks` 只统计第一类任务。
  375 +- 使用 `taskList.meetingNumber` 查询课堂高光。
  376 +
  377 +后端尚未确认任务状态回写接口。当前依靠内存队列、本地文件和 OSS 文件避免重复录制。
  378 +
  379 +## 17. 启用每日 cron
  380 +
  381 +只有单课堂、重复录制、OSS 搬运和全量模式全部通过后才启用:
  382 +
  383 +```cron
  384 +57 7 * * * wget -qO- http://127.0.0.1:3001/recording >/dev/null 2>&1
  385 +```
  386 +
  387 +```bash
  388 +crontab -l
  389 +```
  390 +
  391 +任务每天 `07:57` 执行。任务模式中新任务最多等待约 24 小时,业务已确认可接受。
  392 +
  393 +## 18. 日常使用
  394 +
  395 +```bash
  396 +pm2 show webScreen
  397 +curl http://127.0.0.1:3001/highlight/status
  398 +pm2 logs webScreen --lines 200
  399 +tail -n 200 /root/webScreen/log/$(date +%Y%m%d).txt
  400 +```
  401 +
  402 +手工补录:
  403 +
  404 +```bash
  405 +curl -X POST http://127.0.0.1:3001/highlight/recording/by-class \
  406 + -H 'Content-Type: application/json' \
  407 + -d '{"classId":"课堂号"}'
  408 +```
  409 +
  410 +查询地址:
  411 +
  412 +```bash
  413 +curl -X POST http://127.0.0.1:3001/highlight/fileExists \
  414 + -H 'Content-Type: application/json' \
  415 + -d '{"siteId":"xdyui2","classId":"课堂号"}'
  416 +```
  417 +
  418 +## 19. 故障排查
  419 +
  420 +### 高光录制功能未启用
  421 +
  422 +检查 `HIGHLIGHTCONFIG.enabled=true`,修改后执行 `pm2 restart webScreen`。
  423 +
  424 +### SaaS 接口 code=4
  425 +
  426 +检查服务器时间、NTP、`apiBaseUrl` 和最新代码。签名时间戳必须是 13 位毫秒。
  427 +
  428 +### 无高光数据
  429 +
  430 +检查高光表记录、`meetingNumber`、`siteId=xdyui2`,以及全量模式时间窗是否为前一天。
  431 +
  432 +### web_capture_c 启动失败
  433 +
  434 +```bash
  435 +ls -l /root/web_capture_release/linux-x64/web_capture_c
  436 +ldd /root/web_capture_release/linux-x64/web_capture_c
  437 +echo "$DISPLAY"
  438 +```
  439 +
  440 +比较正式服务器的显示服务、字体、浏览器依赖和 PM2 环境变量。
  441 +
  442 +### 一直是 uploading
  443 +
  444 +检查搬运任务是否运行,是否支持 `{classId}_highlight_{highlightId}.mp4`、`download.json` 和 `oss/xdyui2/{yyyyMMdd}/`。
  445 +
  446 +### OSS文件状态查询失败
  447 +
  448 +检查 `.env`、AccessKey 权限、OSS 网络和 bucket `xdymp4`。OSS 查询异常不会被当作“文件不存在”。
  449 +
  450 +### 视频时间错误
  451 +
  452 +确认 `playbackUrl` 的 `recBeginTime/recEndTime` 与接口原值完全一致。不能传 duration,不能换算相对秒数。
  453 +
  454 +## 20. 回滚
  455 +
  456 +优先使用配置回滚:
  457 +
  458 +```json
  459 +"HIGHLIGHTCONFIG": {
  460 + "enabled": false
  461 +}
  462 +```
  463 +
  464 +```bash
  465 +pm2 restart webScreen
  466 +```
  467 +
  468 +关闭后,`GET /recording` 恢复原整课逻辑。`POST /recording`、`POST /recordingTask`、`POST /fileExists` 和实时录制接口不变。
  469 +
  470 +## 21. 测试记录模板
  471 +
  472 +```text
  473 +测试服务器:
  474 +测试日期:
  475 +测试人员:
  476 +Git 提交(执行 git rev-parse --short HEAD):
  477 +站点:xdyui2
  478 +课堂号:
  479 +高光记录数:
  480 +本地 MP4 数量:
  481 +OSS MP4 数量:
  482 +预览接口:通过 / 失败
  483 +单课堂录制:通过 / 失败
  484 +时间范围:通过 / 失败
  485 +音频:通过 / 失败
  486 +教师视频:通过 / 失败
  487 +学生视频:通过 / 失败
  488 +屏幕共享:通过 / 失败
  489 +重复录制:通过 / 失败
  490 +OSS 搬运:通过 / 失败
  491 +多地址查询:通过 / 失败
  492 +前一天全量:通过 / 失败
  493 +任务模式:通过 / 失败 / 未测试
  494 +问题记录:
  495 +结论:可继续验证 / 需要修复
  496 +```