为什么: 原来存在两个语义几乎相同的目录函数: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 下,程序目录里一个都没有。
39 lines
1.0 KiB
Go
39 lines
1.0 KiB
Go
//go:build windows
|
|
|
|
package main
|
|
|
|
import (
|
|
"path/filepath"
|
|
"regexp"
|
|
"unicode/utf8"
|
|
)
|
|
|
|
// windows 下全路径的字符数上限,留几个字符给后面追加的扩展名
|
|
const maxPathRunes = 250
|
|
|
|
// 转换文件名和限制文件名长度,添加保存文件夹的路径
|
|
func transFilename(filename string) string {
|
|
// 转换文件名不允许的特殊字符
|
|
re := regexp.MustCompile(`[<>:"/\\|?*\r\n]`)
|
|
filename = re.ReplaceAllString(filename, "-")
|
|
dir := recordSaveDir()
|
|
outFilename := filepath.Join(dir, filename)
|
|
if utf8.RuneCountInString(outFilename) <= maxPathRunes {
|
|
return outFilename
|
|
}
|
|
|
|
// 路径过长时截断文件名而不是直接放弃录制
|
|
keep := maxPathRunes - utf8.RuneCountInString(dir) - 2
|
|
if keep < 10 {
|
|
lPrintErrf("保存文件夹的路径太长,无法生成文件名:%s", dir)
|
|
return ""
|
|
}
|
|
runes := []rune(filename)
|
|
if len(runes) > keep {
|
|
runes = runes[:keep]
|
|
}
|
|
outFilename = filepath.Join(dir, string(runes))
|
|
lPrintWarnf("文件名过长,已截断为 %s", filepath.Base(outFilename))
|
|
return outFilename
|
|
}
|