Allow the render output path to have a {timestamp} field

This commit is contained in:
Sybren A. Stüvel 2022-03-15 17:18:11 +01:00
parent 09a476e11a
commit 2187464d5e
2 changed files with 66 additions and 3 deletions

View File

@ -196,3 +196,51 @@ func TestSimpleBlenderRenderWindowsPaths(t *testing.T) {
"fps": int64(24), "fps": int64(24),
}, tVideo.Commands[0].Parameters) }, tVideo.Commands[0].Parameters)
} }
func TestSimpleBlenderRenderOutputPathFieldReplacement(t *testing.T) {
c := mockedClock(t)
s, err := Load(c)
assert.NoError(t, err)
// Compiling a job should be really fast.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Millisecond)
defer cancel()
sj := exampleSubmittedJob()
sj.Settings.AdditionalProperties["render_output_path"] = "/root/{timestamp}/jobname/######"
aj, err := s.Compile(ctx, sj)
if err != nil {
t.Fatalf("job compiler failed: %v", err)
}
if aj == nil {
t.Fatalf("job compiler returned nil but no error")
}
// The job compiler should have replaced the {timestamp} and {ext} fields.
assert.Equal(t, "/root/2006-01-02_090405/jobname/######", aj.Settings["render_output_path"])
// Tasks should have been created to render the frames: 1-3, 4-6, 7-9, 10, video-encoding
assert.Equal(t, 5, len(aj.Tasks))
t0 := aj.Tasks[0]
expectCliArgs := []interface{}{ // They are strings, but Goja doesn't know that and will produce an []interface{}.
"--render-output", "/root/2006-01-02_090405/jobname__intermediate-2006-01-02_090405/######",
"--render-format", sj.Settings.AdditionalProperties["format"].(string),
"--render-frame", "1-3",
}
assert.EqualValues(t, AuthoredCommandParameters{
"exe": "{blender}",
"blendfile": sj.Settings.AdditionalProperties["blendfile"].(string),
"args": expectCliArgs,
"argsBefore": make([]interface{}, 0),
}, t0.Commands[0].Parameters)
tVideo := aj.Tasks[4] // This should be a video encoding task
assert.EqualValues(t, AuthoredCommandParameters{
"input_files": "/root/2006-01-02_090405/jobname__intermediate-2006-01-02_090405/*.png",
"output_file": "/root/2006-01-02_090405/jobname__intermediate-2006-01-02_090405/scene123-1-10.mp4",
"fps": int64(24),
}, tVideo.Commands[0].Parameters)
}

View File

@ -14,7 +14,7 @@ const JOB_TYPE = {
{ key: "add_path_components", type: "int32", required: true, default: 0, propargs: {min: 0, max: 32}, { key: "add_path_components", type: "int32", required: true, default: 0, propargs: {min: 0, max: 32},
description: "Number of path components of the current blend file to use in the render output path"}, description: "Number of path components of the current blend file to use in the render output path"},
{ key: "render_output_path", type: "string", subtype: "file_path", editable: false, { key: "render_output_path", type: "string", subtype: "file_path", editable: false,
eval: "str(Path(settings.render_output_root) / last_n_dir_parts(settings.add_path_components) / jobname / '{timestamp}' / '######.{ext}')", eval: "str(Path(settings.render_output_root) / last_n_dir_parts(settings.add_path_components) / jobname / '{timestamp}' / '######')",
description: "Final file path of where render output will be saved"}, description: "Final file path of where render output will be saved"},
// Automatically evaluated settings: // Automatically evaluated settings:
@ -62,12 +62,14 @@ function compileJob(job) {
print("Blender Render job submitted"); print("Blender Render job submitted");
print("job: ", job); print("job: ", job);
const settings = job.settings;
const renderOutput = settings.render_output_path; const renderOutput = renderOutputPath(job);
job.settings.render_output_path = renderOutput;
const finalDir = path.dirname(renderOutput); const finalDir = path.dirname(renderOutput);
const renderDir = intermediatePath(job, finalDir); const renderDir = intermediatePath(job, finalDir);
const settings = job.settings;
const renderTasks = authorRenderTasks(settings, renderDir, renderOutput); const renderTasks = authorRenderTasks(settings, renderDir, renderOutput);
const videoTask = authorCreateVideoTask(settings, renderDir); const videoTask = authorCreateVideoTask(settings, renderDir);
@ -83,6 +85,19 @@ function compileJob(job) {
} }
} }
// Do field replacement on the render output path.
function renderOutputPath(job) {
let path = job.settings.render_output_path;
return path.replace(/{([^}]+)}/g, (match, group0) => {
switch (group0) {
case "timestamp":
return formatTimestampLocal(job.created);
default:
return match;
}
});
}
// Determine the intermediate render output path. // Determine the intermediate render output path.
function intermediatePath(job, finalDir) { function intermediatePath(job, finalDir) {
const basename = path.basename(finalDir); const basename = path.basename(finalDir);