fix(organize): 入库二级分类对齐MoviePilot结构 + 手动整理不再作为一级目录

- anime 顶层目录独立为「动漫」(动漫/{国漫,日番,儿童}),不再混入电视剧
- categoryPhysicalRootDir 把二级分类名映射到正确顶层:
  动画电影/华语电影/外语电影→电影; 国漫/日番/儿童→动漫;
  国产剧/日韩剧/欧美剧/纪录片/综艺/未分类→电视剧; 成人→成人
- 新增 staging 重定向:目标根落在「手动整理」等暂存目录时,上提到
  父级媒体根,媒体真正归入分类目录(如 媒体/电影/华语电影/片名),
  而非停留在手动整理下或与分类目录并列
- organizeLibraryRootForLayout 跳过 staging 名的库,避免回流暂存目录
- 同步更新陈旧测试期望(电视剧→动漫)+新增 staging 重定向测试
This commit is contained in:
ShukeBta
2026-06-18 19:32:59 +00:00
parent 0cec6606c1
commit b16f7d6663
6 changed files with 263 additions and 19 deletions
+18 -4
View File
@@ -45,7 +45,7 @@ func (o *OrganizerService) buildOrganizeTargetPath(ctx context.Context, in organ
episodeTag := ""
if in.Series {
season := in.Season
if season <= 0 {
if season < 0 {
season = 1
}
episode := in.Episode
@@ -110,7 +110,7 @@ func (o *OrganizerService) organizeNamingFormat(ctx context.Context, mediaType s
func defaultOrganizeRelativePath(title, ext string, year, season, episode int, series bool) string {
if series {
if season <= 0 {
if season < 0 {
season = 1
}
if episode <= 0 {
@@ -196,7 +196,7 @@ func organizeTemplateTruthy(name string, data organizeNamingData) bool {
case "year":
return data.Year > 0
case "season":
return data.Season > 0
return data.Season >= 0 && data.Episode > 0
case "episode", "ep":
return data.Episode > 0
case "ext", "extension":
@@ -228,7 +228,7 @@ func organizeTemplateValue(name, format string, data organizeNamingData, fallbac
}
return strconv.Itoa(data.Year)
case "season":
return formatOrganizeNumber(data.Season, format, 1)
return formatOrganizeNumberAllowZero(data.Season, format, 1)
case "episode", "ep":
return formatOrganizeNumber(data.Episode, format, 1)
case "ext", "extension":
@@ -301,6 +301,20 @@ func formatOrganizeNumber(value int, format string, fallback int) string {
return strconv.Itoa(value)
}
func formatOrganizeNumberAllowZero(value int, format string, fallback int) string {
if value < 0 {
value = fallback
}
format = strings.TrimSpace(strings.TrimSuffix(format, "d"))
if strings.HasPrefix(format, "0") {
width, err := strconv.Atoi(strings.TrimPrefix(format, "0"))
if err == nil && width > 0 {
return fmt.Sprintf("%0*d", width, value)
}
}
return strconv.Itoa(value)
}
func cleanOrganizeRelativePath(path string) string {
path = strings.TrimSpace(path)
if path == "" {