fix(core): BuildDir 只按模板里的分隔符分层
现象:默认模板 {title} 本该只出一层目录,但标题里带 | / : 的画廊
会凭空多出一层文件夹(6 个里 5 个中招)。
根因:把「非法文件名字符集」当成了「目录分隔符集」。两者只有 \ 和 /
重叠,剩下 : * ? " < > | 这 6 个字符被完全误当成目录分隔符。
更糟的是展开顺序——旧代码先把占位符全部替换完再切分,切分对象是
替换后的完整字符串,模板里的分隔符和值里的字符混在一起根本分不开。
EH 标题惯例是「原文 | 译名」,竖线极常见,所以中招率很高。
改动:改为先按模板文本切段(新增 reSep),再逐段展开占位符;
值里的非法字符一律交给 SanitizeSegment 清洗成 _,不再产生层级。
模板里自己写的 / 仍然正常分层,{artist}/{title} 行为不变。
顺带一提:值里的非法字符以前是「变成目录」,现在才是本该有的
「清洗成 _」——两处回归测试都锁住了。
This commit is contained in:
@@ -66,6 +66,75 @@ func TestBuildDirDefaults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// 占位符「值」里的非法字符只能清洗成 _,绝不能变成目录层级。
|
||||
//
|
||||
// 回归 2026-10 的线上问题:EH 标题惯例是「原文 | 译名」,
|
||||
// 旧实现先替换占位符再按 [\\/:*?"<>|] 切分,于是标题里一个竖线
|
||||
// 就凭空多出一层文件夹(6 个里 2 个中招)。
|
||||
func TestBuildDirValueIllegalCharsDoNotNest(t *testing.T) {
|
||||
sep := string(filepath.Separator)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
tpl string
|
||||
title string
|
||||
want string // 用 / 书写,断言前会换成本机分隔符
|
||||
}{
|
||||
{
|
||||
name: "竖线(EH 标题惯例:原文 | 译名)",
|
||||
tpl: "{title}",
|
||||
title: "[Warashibe] Mesuana Hojiri Enkou | 牝穴開發援助交尾 [Chinese]",
|
||||
want: "[Warashibe] Mesuana Hojiri Enkou _ 牝穴開發援助交尾 [Chinese]",
|
||||
},
|
||||
{
|
||||
name: "斜杠",
|
||||
tpl: "{title}",
|
||||
title: "[Circle] AAA/BBB Collection",
|
||||
want: "[Circle] AAA_BBB Collection",
|
||||
},
|
||||
{
|
||||
name: "反斜杠",
|
||||
tpl: "{title}",
|
||||
title: `[Circle] AAA\BBB Collection`,
|
||||
want: "[Circle] AAA_BBB Collection",
|
||||
},
|
||||
{
|
||||
name: "冒号",
|
||||
tpl: "{title}",
|
||||
title: "Dai Ni Miyasaka Byouin 3 karte: Tsuyo Tanba",
|
||||
want: "Dai Ni Miyasaka Byouin 3 karte_ Tsuyo Tanba",
|
||||
},
|
||||
{
|
||||
name: "问号星号双引号尖括号",
|
||||
tpl: "{title}",
|
||||
title: `a?b*c"d<e>f|g`,
|
||||
want: `a_b_c_d_e_f_g`,
|
||||
},
|
||||
{
|
||||
name: "模板里的分隔符仍然生效(多级目录要保留)",
|
||||
tpl: "{artist}/{title}",
|
||||
title: "Enkou | 牝穴",
|
||||
want: "Noxe/Enkou _ 牝穴",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
g := &eh.Gallery{GID: "3492157", Title: tt.title}
|
||||
g.Meta.Artist = "Noxe"
|
||||
got := BuildDir(tt.tpl, g)
|
||||
want := strings.ReplaceAll(tt.want, "/", sep)
|
||||
if got != want {
|
||||
t.Errorf("\n got: %q\nwant: %q", got, want)
|
||||
}
|
||||
// 值里的非法字符不该产生额外层级:段数必须和模板段数一致
|
||||
if n := strings.Count(got, sep); n != strings.Count(tt.tpl, "/") {
|
||||
t.Errorf("层级数不对: got %q (%d 层)", got, n)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 占位符兜底值
|
||||
func TestBuildDirFallbacks(t *testing.T) {
|
||||
g := &eh.Gallery{GID: "12345678", Title: "Plain Title"}
|
||||
|
||||
Reference in New Issue
Block a user