Files
MediaOrganizer/docs/adr/0006-user-custom-rules.md
T
Shuery c1ed1795c2
CI / lint + test + build (push) Canceled after 0s
docs: 重写 README、新增项目报告与开发工具配置
- README 现代化重写:徽章区、特性一览、统一 GitHub 提示块格式、修正版本号与 AI 默认值
- 新增 docs/PROJECT_REPORT.md 学术项目报告(含许可证合规分析与死链修复记录)
- 收录 23 份 ADR 架构决策记录与 CONTEXT.md 领域术语表
- 新增开发配置:.editorconfig / .shellcheckrc / .markdownlint-cli2.jsonc
- .gitignore 补充 mo_map/、检查报告、编辑器临时文件
- 新增 config.example.json 配置模板(不含真实密钥)
2026-08-14 22:41:40 +08:00

4.1 KiB
Raw Blame History

用户自定义规则:命名模板与匹配规则

用户自定义能力增强:命名模板(NAMING_* 配置键)把命名格式化从硬编码外置为模板;匹配规则(mo_config/match_rules.json)提供确定性匹配——搜索别名与 ID 映射。两者共同把"用户的定制意图"从"改代码/依赖 AI 运气"变为"编辑配置文件"。

命名模板(NAMING_*)

六个配置键对应六处硬编码命名:NAMING_MOVIE(电影目录/文件名)、NAMING_SHOW(剧集目录名)、NAMING_SEASON(季目录名)、NAMING_EPISODE(剧集文件名)、NAMING_SPECIAL(未匹配特典文件名)、NAMING_MUSIC(音乐目录结构)。占位符语法三级:{name} 值插入、{name:NN} 数字补零、{?name:text} 条件段(name 非空才渲染 text,正文可含其他占位符,不支持嵌套条件段)。

关键实现决策:

  1. 逐 token 扫描渲染:render_naming_template 按 { 分界逐个解析占位符拼接输出,不用 ${var//pat/repl} 全局替换——bash 替换串中的 & 会被当作"匹配整体"展开(MYTH & ROID 这类乐队名会被损坏),逐 token 拼接天然免疫。
  2. 条件段用花括号深度配对:{?year: ({year})} 的正文含嵌套占位符,正文的结束 } 与条件段的结束 } 需区分——match_conditional_close 按 {} 深度计数找配对右花括号,正文取出后递归渲染(深度上限 10)。
  3. 默认值集中:naming_template_default 是六个默认模板的唯一定义点(config.sh 加载与 render_naming 兜底共用),保证"未配置"与"配置默认值"行为一致;默认模板与 v9.4 硬编码输出逐字节一致,升级零行为变化。
  4. 加载期校验:validate_naming_templates 提取全部占位符名(含条件段正文内)与允许集合比对,未知名打印警告(渲染为空)——拼写错误不静默。
  5. 值内花括号剔除:值中的 {/} 在赋值时剔除(防破坏模板解析);渲染结果整体 sanitize(电影/剧集目标要求目录名=文件名,模板不能引入路径分隔/非法字符)。

考虑过的方案:模板用 printf 风格 %s 占位(可读性差、无法表达条件段);条件段用单独配置键(如 MOVIE_YEAR_TAG,组合爆炸);正文禁止嵌套占位符(默认模板 {?year: ({year})} 即需要嵌套,否决);sed 正则替换(& 与转义问题同全局替换,且多字节文件名风险)。

匹配规则(match_rules.json)

用户手工维护的 JSON:search_aliases(搜索别名)与 id_maps(ID 映射,movie/tv 分表)。键 = 文件名清洗后的标题,rule_key 归一化(小写 + 空白折叠)后与 parse 产出的标题对齐。文件缺失时在用户确认下用 MATCH_RULES_TEMPLATE 常量创建空规则(自动化模式跳过创建、空规则继续);非法 JSON → 空规则不阻断。

优先级:ID 映射(跳过搜索)> 常规搜索链(zh → en → 别名 → 目录名 → MAL)→ AI。别名只在常规搜索无结果时介入;ID 映射先于一切搜索执行。规则全部确定性命中即不走 AI(省轮次、结果可预期)。

考虑过的方案:规则支持正则/glob 匹配(bash 正则性能与转义风险高,且命名清洗后的精确标题已覆盖主要场景);别名直接替换标题无条件生效(会绕过 TMDB 原语言搜索的命中,别名定位为"兜底"而非"替换");AI 学习写回 match_rules(用户显式维护是权威信号,与纠错学习同构——自动识别结果不学习)。

配套

  • 匹配规则插入 identify_movie/identify_tv_show 的搜索链(ID 映射在搜索前,别名在 zh→en 之后、目录名兜底之前)。
  • 命名模板接入 build_movie_dest/build_tv_dest/special_s00_dest/fallback_naming/音乐目标(识别路径与回退命名共用同一渲染,保证两套命名规则一致)。
  • 新模块 src/lib/rules.sh(加载序在 maps.sh 之后);测试 tests/cases/rules.sh(渲染器 11 例)与 tests/cases/match_rules.sh(加载/查询 7 例)。