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
@@ -191,9 +191,11 @@ describe.skipIf(!hasPg)("整理:跨卷 Move 恢复 / 路径绑定固定 / 手动
|
||||
input: { recordId: r1.body.data.recordId },
|
||||
});
|
||||
await executeRecord(h.d, r1.body.data.recordId);
|
||||
const ep1 = join(lib.root, "旧译名 (2020)", "Season 1", "旧译名 - S01E01.mkv");
|
||||
const ep1 = join(lib.root, "旧译名 (2020)", "Season 1", "旧译名 - S01E01 - 第 1 集.mkv");
|
||||
expect(existsSync(ep1)).toBe(true);
|
||||
expect(existsSync(join(lib.root, "旧译名 (2020)", "Season 1", "旧译名 - S01E01.chi.zh-cn.srt"))).toBe(true);
|
||||
expect(existsSync(join(lib.root, "旧译名 (2020)", "Season 1", "旧译名 - S01E01 - 第 1 集.chi.zh-cn.srt"))).toBe(
|
||||
true,
|
||||
);
|
||||
const rec1 = await h.api("GET", `/organization-records/${r1.body.data.recordId}`, undefined, READ_KEY);
|
||||
expect(rec1.body.data).toMatchObject({ origin: "manual", status: "succeeded", counts: { total: 2, succeeded: 2 } });
|
||||
expect(rec1.body.data.actor.type).toBe("api_key");
|
||||
@@ -207,7 +209,7 @@ describe.skipIf(!hasPg)("整理:跨卷 Move 恢复 / 路径绑定固定 / 手动
|
||||
EXEC_KEY,
|
||||
);
|
||||
await executeRecord(h.d, r2.body.data.recordId);
|
||||
expect(existsSync(join(lib.root, "旧译名 (2020)", "Season 1", "新译名 - S01E02.mkv"))).toBe(true);
|
||||
expect(existsSync(join(lib.root, "旧译名 (2020)", "Season 1", "新译名 - S01E02 - 第 2 集.mkv"))).toBe(true);
|
||||
expect(existsSync(join(lib.root, "新译名 (2020)"))).toBe(false);
|
||||
|
||||
const r3 = await h.api(
|
||||
@@ -217,7 +219,7 @@ describe.skipIf(!hasPg)("整理:跨卷 Move 恢复 / 路径绑定固定 / 手动
|
||||
EXEC_KEY,
|
||||
);
|
||||
await executeRecord(h.d, r3.body.data.recordId);
|
||||
expect(existsSync(join(lib.root, "旧译名 (2020)", "Season 2", "新译名 - S02E01.mkv"))).toBe(true);
|
||||
expect(existsSync(join(lib.root, "旧译名 (2020)", "Season 2", "新译名 - S02E01 - 第 1 集.mkv"))).toBe(true);
|
||||
|
||||
const bindings = await h.db
|
||||
.selectFrom("path_binding")
|
||||
|
||||
Reference in new issue
Block a user