录制档位改成「最高/第二高/最低/自定义」四种相对偏好,没开播也能先设

上一版的下拉里列的是「这次读到的实际档位」,没读到档位表(没开播)时下拉里就只剩
一项,想预先设「我要最高档」或「最低档」都做不到。改成按「实际档位里的第几档」来选:

- 新增 `qualityPref`:top(最高档)/ second(第二高,默认)/ lowest(最低档)/
  custom(取不超过给定码率的最高档,都比它高时退回最低档)。四种偏好任何时候都
  在列表里,开播后自动对应到实际档位;读到档位表后把对应结果标在选项后面
  (`第二高(蓝光 4M)`、`自定义(≤2500K = 高清)`)。
- `bitrate` 只在 custom 时有意义。`resolveQualityBitrate(tiers, pref, custom)` 统一
  解析:相对偏好没有档位表时返回 0(取流退回最高档),custom 返回填的上限。
  解析只在取流时做,所以主播换了档位表,偏好会跟着一起变。
- 老配置兼容:没有 qualityPref 时,`bitrate > 0` 当成 custom(就是原来的「码率上限」,
  行为不变),`bitrate == 0` 当成默认的第二高;在 checkConfig 里补齐(不写盘,下次
  保存自然带上)。`setBitrate` 相应换成 `setQuality(uid, pref, custom)`。
- 页面:选 custom 时旁边出现码率框,初始值就是**当前实际在用的那一档**(不会一切过去
  就掉到最低档),回车或失焦即提交,填错给提示并回填服务端的值;从 custom 切到别的
  档位不带 bitrate,服务端保留原值,改回来还是原来那个数。
- 设置区同步:新主播的默认档位也用同一套四项(`defaultQualityPref`),只有选自定义
  才露出码率上限框(切过去会补一个能用的 3000,免得新主播默默用最低档)。

顺带修一个脚本抓到的真 bug:档位名传成了档位对象(`esc()` 里会 `.replace`),只要
档位表非空就会抛异常,而 refresh() 整段包在 try/catch 里 —— 表现是整个主播列表
变成空白且没有任何报错。现在取的是 `qs[i].name`。

测试:qualities_test.go 重写 TestResolveQualityBitrate(10 种偏好/码率组合)并新增
TestMigrateQualityPref、TestUpgradeQualityPrefs、TestSetQuality;verify_streamer_br.py
改成带迷你后端的假服务(POST 会真正落到假状态上),30 项断言全过;verify_qualities.py
25 项(含设置区与 config.json 往返)全过;verify_settings.py / verify_pick.py /
verify_danmu_match.py 无回归;go test ./...、gofmt、go vet 干净。
This commit is contained in:
tamakyi
2026-09-25 20:42:22 +08:00
parent 7b853c1a22
commit 237fffa8fe
6 changed files with 549 additions and 215 deletions
+17 -6
View File
@@ -70,8 +70,9 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
"uid": 23682490, // 主播的 uid
"danmu": true, // 是否录制弹幕
"record": true, // 是否录制直播视频
"bitrate": 0, // 选定的档位码率(Kbps),对应下面 qualities 里的一个档位;0 = 自动(按实际档位取第二高)
"qualities": [] // 开播时读到的码率档位列表,缓存下来让没开播时也能选
"qualityPref": "second", // 档位偏好:top(最高档)/ second(第二高)/ lowest(最低档)/ custom(自定义)
"bitrate": 0, // 只在 qualityPref 为 custom 时有意义:不超过这个码率(Kbps)的最高档
"qualities": [] // 开播时读到的码率档位列表,缓存下来让没开播时也能显示对应关系
}
],
"directory": "", // 录制文件保存的文件夹,留空是程序运行时的 -record 文件夹
@@ -83,7 +84,8 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
"mergeOutputDir": "", // 合并完成后成片移动到该文件夹,留空则不移动
"mergeBitrate": 0, // 合并成片的目标码率(Kbps),0 表示按「源片码率 + 500」自动计算
"danmuFontSize": 0, // 合并时弹幕文字的字号(像素),0 表示跟随弹幕文件;头像随字号等比缩放
"defaultBitrate": 0, // 新添加主播默认选的档位,0 = 自动(按实际档位取第二高)
"defaultQualityPref": "second", // 新添加主播的默认档位偏好,取值同上面的 qualityPref
"defaultBitrate": 0, // 只在上面为 custom 时有意义:默认的自定义码率上限(Kbps)
"webExternal": false, // 是否允许外网访问 web UI,false 时只监听本机 127.0.0.1
"authToken": "…", // web UI 管理接口的访问口令,首次启动自动生成
@@ -112,9 +114,18 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
`uids`也兼容旧的纯数字数组格式,如`"uids": [23682490, 12345]`,此时弹幕和录播都默认开启、码率按实际档位取第二档。
`bitrate`是**直播的实际档位**(如`蓝光 8M`、`高清`),在 web UI 的主播列表里一律用下拉选择,正在录制时换档会自动重录。下拉的第一项是`自动 · 第二高`(值 0),意思是**按这次读到的档位排序自上往下取第二高** —— 因为不一定每场都有`蓝光 8M`这类最高档,按位置排序比写死某个码率稳;只要一档就用那一档,实在读不到档位表才退回最高档。后面依次列出这次读到的实际档位,想固定用最高、最低或中间某一档直接选它;手动选过之后下拉里仍留着`自动`项,随时能改回去。
`qualityPref`是**按档位里的第几档**来选的,不是写死某个码率 —— 因为每场直播的档位表不一定一样(不一定都有`蓝光 8M`):
档位要开播后读直播源列表才知道,读到以后写进`config.json`的`qualities`里缓存,所以没开播也能看和改;从来没读过档位的行,下拉里只有`自动`一项,旁边有`档位`按钮可以去直播间接一次(主播没开播时会失败并提示)。读档位的时机是:录制开始取流时、页面上点`档位`按钮、以及发现主播在直播但还没有档位缓存时自动读一次(同一个主播 10 秒内只读一次)。录制始终是原画质直接保存(`-c copy`),不会重新编码,所以只能在这几个档位里挑。
| 取值 | 页面上的选项 | 含义 |
| --- | --- | --- |
| `top` | 最高档 | 这次能读到的最高档 |
| `second` | 第二高(默认) | 按实际档位排序自上往下第二高,只有一档时用它 |
| `lowest` | 最低档 | 这次能读到的最低档 |
| `custom` | 自定义 | 取不超过`bitrate`(Kbps)的最高档,都比它高时退回最低档 |
四种偏好**永远都在下拉里**,所以还没开播、连档位表都没读到的时候也能先设好;读到档位表以后,每个选项后面会标出它现在对应哪个档位(例如`第二高(蓝光 4M)`、`自定义(≤2500K = 高清)`),选完立即生效,正在录制时换档会自动重录。选`自定义`时会出现一个码率框,初始值就是当前实际在用的那一档,填完回车即生效。
档位表要开播后读直播源列表才知道(写在`config.json`的`qualities`里缓存)。没读到过的行,选项后面不会带档位名,旁边的`档位`按钮可以去直播间接一次(主播没开播时会失败并提示,服务端本身要重试三次、约 5 秒,所以点下去会先给一句`正在读取码率档位…`)。读档位的时机是:录制开始取流时、页面上点`档位`按钮、以及发现主播在直播但还没有档位缓存时自动读一次(同一个主播 10 秒内只读一次)。录制始终是原画质直接保存(`-c copy`),不会重新编码,所以只能在这几个档位里挑。
录播原片和弹幕文件(`.ass`、`.nick.ass`、`.jsonl`)保存在保存目录下的`recordSubdir`子文件夹里(默认`record`),两者同名配对才能自动合并;合并后的成片保存在`mergeSubdir`子文件夹里(默认`merged`),留空则用默认值,两个名字不能相同。如果设置了`mergeOutputDir`,成片优先移动到那里。
@@ -139,7 +150,7 @@ GOOS=windows GOARCH=amd64 go build -o acfunlive.exe
`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 的`录制`分区随时修改,只对新添加的主播生效,已有主播保持各自的值。填 0 时按主播**实际能用的档位**来决定 —— 取自上而下的**第二档**(比如有`蓝光 8M / 蓝光 4M / 高清`就录`蓝光 4M`),只有一档时就用那一档;这个档位是开播后读到直播源列表才知道的,读到以后会记进`config.json`,没开播时页面也能显示和修改。
`defaultQualityPref`/`defaultBitrate`是新主播的默认档位:在 web UI 里新增主播、且没有单独指定档位时用它,`录制`分区可以随时改,只对新添加的主播生效,已有主播保持各自选的。默认是`第二高`,也就是按主播**实际能用的档位**自上往下取第二档(比如有`蓝光 8M / 蓝光 4M / 高清`就录`蓝光 4M`),只有一档时就用那一档;档位表要开播后才读得到,读到以后会记进`config.json`,没开播时页面也能显示和修改。
`ffmpegPath`用来指定 ffmpeg 的位置,可以填可执行文件本身(如`D:\ffmpeg\bin\ffmpeg.exe`)或它所在的文件夹,留空时按「PATH → 程序所在文件夹 → 程序所在文件夹的 bin、ffmpeg、ffmpeg/bin 子目录」的顺序自动查找。填相对路径时按程序所在目录解析,不会因为合并时会切换工作目录而失效(这是`ffmpeg.exe`这种只写文件名的写法能正常工作的原因)。录播和弹幕合并都依赖 ffmpeg,找不到时启动日志里会有明确提示。