web UI 按用途分成六个分区,整体改版并跟随系统深浅色

需求是「界面比较杂乱,做一下分类,UI 也现代化一些」。原来所有设置挤在一张
「设置」卡片里,从保存目录一路排到管理口令,加上通知推送的两个渠道,一屏
拉不到底,找东西全靠翻。

1) 分成六个分区,顶部一条导航切换
   - 监控:添加主播 + 主播列表 + 运行日志(默认打开的就是这里)
   - 录制:保存目录、录播/弹幕和成片子文件夹、录播格式、默认码率上限、ffmpeg 路径
   - 合并:自动合并的三个开关、成片输出目录和合成码率、手动合并
   - 通知:推送哪些事件、QQ 机器人渠道、MeoW 渠道
   - 文件:磁盘容量 + 文件列表
   - 设置:外网访问、管理口令
   - 分区只靠 class 切显示,所有元素始终在 DOM 里,所以原来按 id 取值的
     那一大堆逻辑一行都不用改;「监控」是默认页,因为看录制状态是最高频的操作

2) 地址栏带上 #分区名
   - 用 replaceState 写,不往历史里塞记录,但刷新、收藏、把链接发给别人
     都能落到同一个分区;也顺便记住了上次看的是哪一页(localStorage 兜底)

3) 大改样式(都在同一个模板里,没有引入任何外部依赖)
   - 颜色、圆角、阴影收进 CSS 变量,卡片改成柔和阴影 + 大圆角,输入框加了
     hover 和 focus 光晕,按钮分主次两级
   - 勾选框改成开关样式(隐藏原生 input + 兄弟节点画轨道,所以 el.checked
     和 :focus 判断照旧能用);主播列表的「弹幕/录播」改成小圆片
   - 把原来那个行内的小 #msg 文案换成右下角提示条:成功 2.6 秒、失败 6 秒
     自动消失,最多同时留 4 条,报错信息不会再一闪而过
   - 顶栏常驻状态摘要(录制中 N / 直播中 N / 空闲),「保存设置」也挪到顶栏,
     一直可见——文本框可能在别的分区里,按钮跟着分区走会找不到
   - 跟随系统深浅色(prefers-color-scheme),配套改了 color-scheme 元信息;
     日志面板在两种模式下都是深色终端风格
   - 手机上标题居中、右侧按钮收成两个字(「保存」),分区导航横向滚动;
     顶栏用 1fr auto 1fr 的网格,两侧等宽才是真的居中
   - 文件列表里的文件名原来被 max-width:200px 截成「2026-09-24 20-00-00 Xsp…」,
     文件名本来就是用来认文件的,改成不截断、允许换行

4) 顺手修的两个真问题
   - 口令里有中文时,页面彻底用不了:HTTP 请求头只接受 ISO-8859-1,浏览器
     遇到非 ASCII 的 X-Auth-Token 会直接抛 TypeError
     (Failed to read the 'headers' property…),请求根本发不出去,页面只显示
     「无法连接到服务器」,用户既进不去也没法在页面上把口令改回来。
     现在页面统一把口令 encodeURIComponent 之后再放进头里,服务端
     authTokenCandidates() 把原样和解码后的都作为候选逐个定长比较
     (不提前返回,避免响应时间泄露是哪一种对上了),所以中文口令能用,
     curl / 脚本按文档原样发中文口令也照样能过
   - 删「正在写入」的文件返回 500 而不是 409,见上一个提交

5) 文档
   - README 的「使用方法」补分区表、保存规则(开关立即生效 / 文本框点保存)、
     顶栏状态和深浅色说明;各处「设置区」改成对应的分区名
   - doc/webapi.md 补口令编码那段,说明脚本侧按原样填即可

已验证:新增 webui_test.go 5 个用例(ASCII 口令、含 % 的口令、中文口令的
编码与原样两种写法、Bearer 与 ?token= 三个来源、以及错口令/空口令/口令未配
一律拒绝、候选顺序与非 Bearer 的 Authorization 不算数),全量 39 个用例通过。
真机用 Edge 无头浏览器跑了两轮共 40 项断言,覆盖:自动登录、六个分区逐一点开
(只显示该分区、页签高亮、hash 跟着变)、六个分区 + 深色 + 三个移动端截图、
开关点了立刻落盘并能点回来、顶栏保存写到配置文件、在别的分区保存不会把隐藏
表单的值清空、刷新后仍在原分区、MeoW 红字提示的显示与隐藏、合并中按钮禁用
并改文案、口令弹窗的失败与重试,桌面/深色/移动端三处控制台零报错。
中文口令另做了端到端验证:配置里放中文口令能直接进、换口令后接口继续可用、
重开页面用新口令能进、旧口令被拒;把客户端编码去掉后同一个测试立刻失败,
确认这个修复是必需的而不是想当然。Windows/Linux 双平台构建、go vet、
gofmt 全干净。51880 的上游原版全程未动。
This commit is contained in:
tamakyi
2026-09-25 14:19:44 +08:00
parent be8ec5f953
commit a2f27974b2
4 changed files with 596 additions and 206 deletions
+20 -5
View File
@@ -114,7 +114,7 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
录播原片和弹幕文件(`.ass`、`.nick.ass`、`.jsonl`)保存在保存目录下的`recordSubdir`子文件夹里(默认`record`),两者同名配对才能自动合并;合并后的成片保存在`mergeSubdir`子文件夹里(默认`merged`),留空则用默认值,两个名字不能相同。如果设置了`mergeOutputDir`,成片优先移动到那里。
`recordFormat`决定录播原片的封装格式,默认为`mp4`(和原版`config.Output`的默认值一致),也可以改成`flv`、`ts`、`mkv`,在 web UI 设置区用下拉框修改。录制始终是`-c copy`直接封装直播源、不重新编码,所以四种格式的**画质和码率完全一样,区别只在容器**。
`recordFormat`决定录播原片的封装格式,默认为`mp4`(和原版`config.Output`的默认值一致),也可以改成`flv`、`ts`、`mkv`,在 web UI 的`录制`分区用下拉框修改。录制始终是`-c copy`直接封装直播源、不重新编码,所以四种格式的**画质和码率完全一样,区别只在容器**。
正常停止(web UI 的停止按钮、`stoprecord`、`Ctrl+C`、`quit`)会先向 ffmpeg 发`q`让它正常收尾,**四种格式都能正常播放**——本机 ffmpeg 6.0 实测录 5 秒后发`q`:mp4 161 KB、flv 163 KB、ts 191 KB、mkv 160 KB,全部可读且时长 5.14 秒。但如果进程被强杀(任务管理器结束进程、断电、系统崩溃),差别就很大了——同样录制 8 秒后强杀:
@@ -131,9 +131,9 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
`webExternal`为 false 时 web UI 只监听`127.0.0.1`,只有本机能打开;设为 true 后监听所有网卡,同一局域网的设备可以用本机 IP 加端口访问。这项设置改动后 web 服务会自动重启。
`authToken`是管理接口的访问口令,首次启动时自动生成(12 字节随机数的十六进制)并打印在运行日志里,忘记时可以打开`config.json`查看,也能在 web UI 设置区查看、复制和更换。**所有`/api/`接口都必须带口令**,页面本身可以匿名打开,打开后会要求输入口令并保存在浏览器本地。口令可以用三种方式提供:`X-Auth-Token`请求头、`Authorization: Bearer <口令>`、或者`?token=<口令>`查询参数。同一来源连续输错时每次会增加最多 2 秒延迟,避免被暴力尝试。手工把`config.json`里的`authToken`清空保存后,程序会自动重新生成一个,不会把自己锁在外面。
`authToken`是管理接口的访问口令,首次启动时自动生成(12 字节随机数的十六进制)并打印在运行日志里,忘记时可以打开`config.json`查看,也能在 web UI 的`设置`分区查看、复制和更换。**所有`/api/`接口都必须带口令**,页面本身可以匿名打开,打开后会要求输入口令并保存在浏览器本地。口令可以用三种方式提供:`X-Auth-Token`请求头、`Authorization: Bearer <口令>`、或者`?token=<口令>`查询参数。口令可以用任意字符,包括中文。注意 HTTP 请求头只接受 ISO-8859-1,浏览器遇到中文口令会直接拒绝发请求,所以页面发给服务端的`X-Auth-Token`是百分号编码过的口令,服务端原样和解码后的都认;用 curl 或脚本调接口时按原样填即可,不用自己编码。同一来源连续输错时每次会增加最多 2 秒延迟,避免被暴力尝试。手工把`config.json`里的`authToken`清空保存后,程序会自动重新生成一个,不会把自己锁在外面。
`defaultBitrate`是下载码率的默认值:在 web UI 里新增主播、且不单独指定码率时使用它,也可以在 web UI 设置区随时修改,只对新添加的主播生效,已有主播保持各自的值。
`defaultBitrate`是下载码率的默认值:在 web UI 里新增主播、且不单独指定码率时使用它,也可以在 web UI 的`录制`分区随时修改,只对新添加的主播生效,已有主播保持各自的值。
`ffmpegPath`用来指定 ffmpeg 的位置,可以填可执行文件本身(如`D:\ffmpeg\bin\ffmpeg.exe`)或它所在的文件夹,留空时按「PATH → 程序所在文件夹 → 程序所在文件夹的 bin、ffmpeg、ffmpeg/bin 子目录」的顺序自动查找。填相对路径时按程序所在目录解析,不会因为合并时会切换工作目录而失效(这是`ffmpeg.exe`这种只写文件名的写法能正常工作的原因)。录播和弹幕合并都依赖 ffmpeg,找不到时启动日志里会有明确提示。
@@ -145,6 +145,21 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
web UI 默认通过`http://localhost:51880`访问(端口对应`webPort`),可以在网页里增删主播、切换每个主播的弹幕和录播开关、修改码率上限、修改保存目录和自动合并设置。
页面按用途分成六个分区,顶部一条导航切换,地址栏会跟着带上`#分区名`,所以刷新、收藏、直接把链接发给别人都能落到同一个分区:
| 分区 | 内容 |
| --- | --- |
| 监控 | 添加主播、主播列表(默认打开的分区),以及运行日志 |
| 录制 | 保存目录和子文件夹、录播格式、默认码率上限、ffmpeg 路径 |
| 合并 | 自动合并开关、成片输出目录和合成码率、手动合并 |
| 通知 | 推送哪些事件,以及 QQ 机器人 / MeoW 两个渠道的配置和测试连通 |
| 文件 | 磁盘剩余容量、录播和成片的文件列表 |
| 设置 | 是否允许外网访问、管理口令的查看与更换 |
开关和下拉框改完立即保存;文本框(目录、地址、口令这些)填完点右上角的`保存设置`才生效,这一条在每个有文本框的分区里也写了提示。
顶栏右上角一直显示当前状态(`录制中 N` / `直播中 N` / `空闲`)。窄屏上按钮收起成短文案、标题居中,手机上也能正常用;页面跟随系统的深浅色设置,深色模式下日志和表单自动变深色,不用额外配置。
主播列表每行右侧的`停止`和`重新开始`按钮控制该主播当前的录制:`停止`会结束这一场的弹幕和录播(同时把该主播的弹幕、录播开关关掉,避免被监控循环自动重启),`重新开始`会重新开启开关并立刻开始新的一组录制文件。这两个按钮同时作用于弹幕和录播,只控制其中一项可以用对应的勾选框。
命令行模式运行时可以输入命令控制本程序,输入`help`查看全部命令的解释,输入`quit`退出程序。
@@ -196,7 +211,7 @@ acfunlive -danmuburn xxx.jsonl -video xxx.flv -ffmpeg D:\tools\ffmpeg.exe
### 手动合并
web UI 的`手动合并`区用来自己挑视频和弹幕出片,适合手动停止录制过的一场、或者手里只有零散文件的情况。
web UI 的`合并`分区里的`手动合并`用来自己挑视频和弹幕出片,适合手动停止录制过的一场、或者手里只有零散文件的情况。
- **视频**:既可以在文本框里一行一个地填,也可以从录播目录的下拉列表里多选(选完自动填进文本框)。填的名字不带路径就按录播目录找,带路径的相对和绝对都能用,所以录播目录以外的文件也合得来。粘贴路径时带上的引号会被自动去掉。
- **弹幕**:支持`.jsonl`和`.ass`。填`.ass`时会先还原成 jsonl 再合并(规则和`-danmuburn`一样,优先用同名的 jsonl),还原结果写回录播目录,页面的下拉列表里也会出现。
@@ -266,7 +281,7 @@ webhook 返回 200 只代表**地址和口令没问题**,能不能真的收到
### 文件管理
web UI 的`文件管理`区可以列出录播文件夹和成片文件夹里的文件(名称、大小、修改时间),并显示保存目录所在磁盘的剩余和总容量。
web UI 的`文件`分区可以列出录播文件夹和成片文件夹里的文件(名称、大小、修改时间),并显示保存目录所在磁盘的剩余和总容量。
- `下载`:以附件形式下载,中文文件名用 RFC 5987 编码,不会乱码
- `播放`:只对浏览器能直接播的格式(mp4、m4v、webm、ogv)显示,在新标签页里内联播放;`.flv` 浏览器放不了,只提供下载