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

为什么:

原来存在两个语义几乎相同的目录函数: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
+86
View File
@@ -0,0 +1,86 @@
package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
// 录制过程中 ffmpeg 是按 transFilename 给的路径写文件的。
// 以前这条路径走的是 -record 参数而不是 directory 设置,配了保存目录的人会看到
// 文件先落在程序目录里、录完才搬一次;这里把「必须等于最终保存目录」钉死。
func TestTransFilenameSavesIntoConfiguredDir(t *testing.T) {
savedConfig, savedRecordDir := config, recordDir
defer func() { config, recordDir = savedConfig, savedRecordDir }()
root, dashDir := t.TempDir(), t.TempDir()
recordDir = &dashDir
config.RecordSubdir = "record"
// 配了 directory:不管 -record 参数是什么,都得以它为准
config.Directory = root
got := filepath.Clean(transFilename("2026-09-27 22-40-42 甲 标题.mp4"))
want := filepath.Join(root, "record", "2026-09-27 22-40-42 甲 标题.mp4")
if got != filepath.Clean(want) {
t.Errorf("配了 directory 后录制路径不对:\n got %s\n want %s", got, want)
}
if !strings.HasPrefix(got, filepath.Clean(root)) {
t.Errorf("录制路径落在了保存目录之外:%s", got)
}
// 没配 directory:回落到 -record 指定的文件夹
config.Directory = ""
got = filepath.Clean(transFilename("x.mp4"))
if filepath.Dir(got) != filepath.Clean(filepath.Join(dashDir, "record")) {
t.Errorf("directory 为空时应回落到 -record 目录:%s", got)
}
// 连 -record 都还没解析时也不能拼出相对路径,否则 ffmpeg 会写到进程的工作目录去
blank := ""
recordDir = &blank
if root := saveRootDir(); !filepath.IsAbs(root) {
t.Errorf("传入的参数都没解析时 saveRootDir 仍应是绝对路径,实际 %q", root)
}
if got := filepath.Clean(transFilename("x.mp4")); !filepath.IsAbs(got) {
t.Errorf("录制路径不能是相对路径:%q", got)
}
}
// 保存目录和录制目录现在是一个,moveFile 再挪一遍等于白复制一份(跨盘时尤其慢)
func TestMoveFileKeepsFileInSaveDir(t *testing.T) {
savedConfig, savedRecordDir := config, recordDir
defer func() { config, recordDir = savedConfig, savedRecordDir }()
root := t.TempDir()
recordDir = &root
config.Directory = root
config.RecordSubdir = "record"
if err := os.MkdirAll(recordSaveDir(), 0755); err != nil {
t.Fatal(err)
}
p := filepath.Join(recordSaveDir(), "2026-09-27 22-40-42 甲 标题.mp4")
if err := os.WriteFile(p, []byte("fake"), 0644); err != nil {
t.Fatal(err)
}
s := &streamer{UID: 1}
s.moveFile(p)
if _, err := os.Stat(p); err != nil {
t.Errorf("文件已经在保存目录里了,moveFile 不该动它:%v", err)
}
// 别处给进来的路径(比如手填的绝对路径)仍要收拢到保存目录
outside := filepath.Join(t.TempDir(), "outside.mp4")
if err := os.WriteFile(outside, []byte("fake"), 0644); err != nil {
t.Fatal(err)
}
s.moveFile(outside)
if _, err := os.Stat(outside); !os.IsNotExist(err) {
t.Errorf("保存目录之外的文件应当被移动,原位置却还在")
}
if _, err := os.Stat(filepath.Join(recordSaveDir(), "outside.mp4")); err != nil {
t.Errorf("文件没有出现在保存目录里:%v", err)
}
}