feat(domain): naming template engine (Jinja safe subset, MP variables, path layout)
- naming/engine: lexer/parser/AST/render for {{ }} / if-elif-else / whitelisted filters
(default pad pad2 upper lower trim replace truncate date join); rejects for/set/attribute/
subscript/call/~/% with line:col errors and 'did you mean' hints
- naming/variables: variable table aligned with MoviePilot names plus ours (cut, airDate,
issue, slotName, libraryRoot ...); buildNamingVars from parsed release + entity + units
- naming/layout: split by literal '/', segment roles (category/root/season/sub/file),
value escaping, reserved names, 255-byte segments, validateNamingTemplate
- naming/defaults: MP default movie/tv + our variety template, v1 syntax upgrade,
entity > root > global override resolution, builtin preview samples
- path/binding: resolveTargetDirectory keeps bound dirs, only unbound segments render;
renderMediaFileName = last segment of the full template; DEFAULT_TEMPLATES = MP v2
- differential: 34 cases vs MP (21 identical, 13 documented deviations)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
e8745115f4
commit
f7c75ad781
22 files changed
+2674
-281
No files matched your search
@@ -32,10 +32,10 @@ describe("planOrganize 整季包", () => {
|
||||
it("主视频 + 随行字幕,样例/nfo/图片排除,跨卷标记", () => {
|
||||
const plan = planOrganize(tvInput());
|
||||
expect(plan.files.map((f) => [f.role, f.dst])).toEqual([
|
||||
["main", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E01.mkv"],
|
||||
["main", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E02.mkv"],
|
||||
["sidecar", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E01.chi.zh-cn.srt"],
|
||||
["sidecar", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E01.eng.default.srt"],
|
||||
["main", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E01 - 第 1 集.mkv"],
|
||||
["main", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E02 - 第 2 集.mkv"],
|
||||
["sidecar", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E01 - 第 1 集.chi.zh-cn.srt"],
|
||||
["sidecar", "/media/tv/最后生还者 (2023)/Season 1/最后生还者 - S01E01 - 第 1 集.eng.default.srt"],
|
||||
]);
|
||||
expect(plan.files[0]).toMatchObject({
|
||||
kind: "video",
|
||||
@@ -291,10 +291,10 @@ describe("W4-E4:字幕 .default 与 latest 旧版本判定口径(对照 MP)", ()
|
||||
},
|
||||
});
|
||||
expect(plan.files.map((f) => f.dst)).toEqual([
|
||||
"/lib/剧/Season 2/剧 - S02E03-E04.mkv",
|
||||
"/lib/剧/Season 1/剧 - S01E06.mkv",
|
||||
"/lib/剧/Season 2/剧 - S02E07.mkv",
|
||||
"/lib/剧/Season 2/剧 - S02E03-E04.chi.zh-cn.srt",
|
||||
"/lib/剧/Season 2/剧 - S02E03-E04 - 第 3-4 集.mkv",
|
||||
"/lib/剧/Season 1/剧 - S01E06 - 第 6 集.mkv",
|
||||
"/lib/剧/Season 2/剧 - S02E07 - 第 7 集.mkv",
|
||||
"/lib/剧/Season 2/剧 - S02E03-E04 - 第 3-4 集.chi.zh-cn.srt",
|
||||
]);
|
||||
expect(plan.files[0]).toMatchObject({ season: 2, episodes: { start: 3, end: 4 } });
|
||||
const movie = planOrganize({
|
||||
|
||||
Reference in new issue
Block a user