录制过程直接写进配置里的保存目录,不再落到程序目录下绕一圈

为什么:

原来存在两个语义几乎相同的目录函数:recordingDir() 只看 -record 命令行参数,
没传就是程序所在目录;recordSaveDir() 才尊重 config.json 里的 directory。
ffmpeg 的实时输出、弹幕 ass/jsonl 的落盘、启动时建目录都走前者,录制结束后
moveFile() 才把文件搬到后者。

后果是:配了 directory 的人会发现录制中的文件一直躺在程序目录里(通常是系统盘),
录完才搬一次,跨盘就等于把整份文件再复制一遍;录制中途中断或者进程崩掉,文件还会
永久留在那儿。根目录 record\、merged\ 里那几个旧产物就是这么留下的。

处理方式是删掉 recordingDir(),四处调用点(启动建目录、两个平台的 transFilename、
web 保存设置后)统一走 recordSaveDir()。没有给旧函数留壳:留两个语义相近的目录函数,
迟早还会再漂一次。

saveRootDir() 依次兜底到 -record 目录、程序所在目录、当前工作目录,绝不返回空串——
空串会让后面 filepath.Join 拼出个相对路径,ffmpeg 就按自己的当前目录去写,文件落到
哪里完全不可控。

顺带订正两处与代码不符的注释:configData.Directory 原本写的是「弹幕文件录制结束后
会被移动到该文件夹」,README 也跟着这么写;现在如实写成保存根目录,并补上优先级。

验证:

- gofmt -l 干净、go vet ./... 干净、Windows 与 GOOS=linux 均编译通过。
- 新增 filename_test.go:锁住 transFilename 生成的路径必然落在 recordSaveDir() 下
  (含 directory 为空时回落 -record 目录),以及 moveFile 在路径一致时不动文件。
- go test ./... 全绿。
- 反向验证:把 recordSaveDir() 退回旧的 recordingDir() 写法后,对应用例确实变红。
- 最小实例端到端:exe 放进单独目录、-record 指向自身、directory 指向别处,
  record\ 与 merged\ 建在 directory 下,程序目录里一个都没有。
This commit is contained in:
tamakyi
2026-09-28 02:03:39 +08:00
parent 3c17503a21
commit 7ab80ec429
6 changed files with 111 additions and 22 deletions
+21 -15
View File
@@ -129,7 +129,7 @@ var configMu sync.Mutex
// 设置数据
type configData struct {
UIDs uidList `json:"uids"` // 要录制的主播 uid 列表和各自的开关
Directory string `json:"directory"` // 弹幕文件录制结束后会被移动到该文件夹
Directory string `json:"directory"` // 录播和弹幕文件保存的根目录,留空用 -record 指定的文件夹
WebPort int `json:"webPort"` // web UI 的本地端口,为 0 时不启动 web UI
AutoMerge bool `json:"autoMerge"` // 直播结束后自动把弹幕层合并进录播
@@ -190,25 +190,29 @@ func saveRootDir() string {
if config.Directory != "" {
return absOrSelf(config.Directory)
}
if recordDir == nil {
return ""
if recordDir != nil && *recordDir != "" {
return absOrSelf(*recordDir)
}
return absOrSelf(*recordDir)
// 命令行参数还没解析时(比如 initialize 之前被调用)退回程序所在目录,
// 再不济退回当前工作目录:这里返回空串的话,后面拼出来的就是个相对路径,
// ffmpeg 会按自己的当前目录去写,录制文件就不知道落到哪去了
if exeDir != "" {
return absOrSelf(exeDir)
}
if wd, err := os.Getwd(); err == nil {
return wd
}
return "."
}
// 录播和弹幕文件保存的文件夹
// 录播和弹幕文件保存的文件夹。
// 录制过程中 ffmpeg 就直接写在这里,不会再中途挪窝:以前单独有一个「录制中的目录」,
// 它只认 -record 参数不看 directory 设置,配了保存目录的人会发现文件先落在程序目录下,
// 录完才搬一次(跨盘就是整份文件再复制一遍),提前中断还会留在那儿。
func recordSaveDir() string {
return filepath.Join(saveRootDir(), config.RecordSubdir)
}
// 录制过程中文件直接写入的文件夹
func recordingDir() string {
if recordDir == nil {
return config.RecordSubdir
}
return filepath.Join(absOrSelf(*recordDir), config.RecordSubdir)
}
// 合并成片保存的文件夹
func mergeSaveDir() string {
if config.MergeOutputDir != "" {
@@ -480,7 +484,7 @@ func checkConfig() {
config.FFmpegPath = ""
}
// 确保保存文件夹存在
for _, d := range []string{recordingDir(), recordSaveDir(), mergeSaveDir()} {
for _, d := range []string{recordSaveDir(), mergeSaveDir()} {
if err := os.MkdirAll(d, 0755); err != nil {
lPrintErrf("创建文件夹 %s 失败:%v", d, err)
os.Exit(1)
@@ -1119,7 +1123,9 @@ func (s *streamer) moveDanmuFiles(assFile string) {
s.moveFile(jsonlFile)
}
// 移动文件
// 把送出文件到保存目录下,路径一致时什么也不做。
// 录制的产出本来就写在 recordSaveDir() 里(见 recordSaveDir 的注释),
// 这里是条保险:路径由别处给进来、或者运行中被改过保存目录时,仍以当前配置为准收拢一次。
func (s *streamer) moveFile(oldFile string) {
if oldFile == "" {
return