Automatically include input blend file path in job settings

This commit is contained in:
Sybren A. Stüvel 2022-03-14 18:18:10 +01:00
parent 9fec9c479f
commit 4196460c29
5 changed files with 77 additions and 39 deletions

@ -58,9 +58,10 @@ Note that list is **not** in any specific order.
## Blender Add-on
- [ ] Communication with the Flamenco Manager API
- [x] Communication with the Flamenco Manager API
- [ ] Job construction
- [ ] BAT-packing & uploading to Shaman
- [x] BAT-packing
- [ ] uploading to Shaman
- [ ] User authentication
- [ ] Editable job names (for rendering multiple jobs from the same filename)
- [ ] Add `options={'HIDDEN'}` to the Flamenco RNA properties.

@ -1,18 +1,73 @@
# SPDX-License-Identifier: GPL-3.0-or-later
from typing import TYPE_CHECKING
from pathlib import Path
from typing import TYPE_CHECKING, Optional, Union
import bpy
from .job_types_propgroup import JobTypePropertyGroup
if TYPE_CHECKING:
from .manager import ApiClient as _ApiClient
from .manager.models import (
AvailableJobType as _AvailableJobType,
Job as _Job,
SubmittedJob as _SubmittedJob,
)
else:
_AvailableJobType = object
_ApiClient = object
_Job = object
_SubmittedJob = object
# If a job has a setting with this key, type 'str', and subtype 'file_path',
# it'll be set to the path of the BAT-packed blend file.
BLENDFILE_SETTING_KEY = "blendfile"
def job_for_scene(scene: bpy.types.Scene) -> Optional[_SubmittedJob]:
from flamenco.manager.models import SubmittedJob, JobMetadata
propgroup = getattr(scene, "flamenco_job_settings", None)
assert isinstance(propgroup, JobTypePropertyGroup), "did not expect %s" % (
type(propgroup)
)
settings = propgroup.as_jobsettings()
metadata = JobMetadata()
job: SubmittedJob = SubmittedJob(
name=scene.flamenco_job_name,
type=propgroup.job_type.name,
priority=50,
settings=settings,
metadata=metadata,
)
return job
def set_blend_file(
job_type: _AvailableJobType, job: _SubmittedJob, blendfile: Union[str, Path]
) -> None:
"""Update the job's 'blendfile' setting, if available.
If a job has a 'blendfile' setting, type 'str', it'll be set to the path/URL
of the BAT-packed blend file.
"""
from .manager.models import AvailableJobSetting, AvailableJobSettingType
expected_type = AvailableJobSettingType("string")
for setting in job_type.settings:
if setting.key == BLENDFILE_SETTING_KEY and setting.type == expected_type:
break
else:
# Not having this setting is fine.
return
assert isinstance(setting, AvailableJobSetting)
job.settings[BLENDFILE_SETTING_KEY] = str(blendfile)
def submit_job(job: _SubmittedJob, api_client: _ApiClient) -> _Job:
"""Send the given job to Flamenco Manager."""
from flamenco.manager import ApiClient

@ -2,8 +2,7 @@
import json
import logging
import uuid
from typing import TYPE_CHECKING, Callable, Optional, Union
from typing import TYPE_CHECKING, Optional, Union
import bpy
@ -133,28 +132,6 @@ def update_job_type_properties(scene: bpy.types.Scene) -> None:
)
def job_for_scene(scene: bpy.types.Scene) -> Optional[_SubmittedJob]:
from flamenco.manager.models import SubmittedJob, JobMetadata
propgroup = getattr(scene, "flamenco_job_settings", None)
assert isinstance(
propgroup, job_types_propgroup.JobTypePropertyGroup
), "did not expect %s" % (type(propgroup))
settings = propgroup.as_jobsettings()
metadata = JobMetadata()
job: SubmittedJob = SubmittedJob(
name=scene.flamenco_job_name,
type=propgroup.job_type.name,
priority=50,
id=str(uuid.uuid4()),
settings=settings,
metadata=metadata,
)
return job
def _clear_available_job_types(scene: bpy.types.Scene) -> None:
global _available_job_types
global _job_type_enum_items

@ -7,7 +7,7 @@ from typing import Optional, TYPE_CHECKING
import bpy
from . import job_submission
from . import job_types, job_submission
if TYPE_CHECKING:
from .bat_interface import (
@ -111,6 +111,7 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
bl_description = "Pack the current blend file and send it to Flamenco"
bl_options = {"REGISTER"} # No UNDO.
blendfile_on_farm: Optional[Path] = None
job_name: bpy.props.StringProperty(name="Job Name") # type: ignore
job: Optional[_SubmittedJob] = None
@ -123,9 +124,7 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
filepath = self._save_blendfile(context)
# Construct the Job locally before trying to pack. If any validations fail, better fail early.
from . import job_types
self.job = job_types.job_for_scene(context.scene)
self.job = job_submission.job_for_scene(context.scene)
if self.job is None:
self.report({"ERROR"}, "Unable to create job")
return {"CANCELLED"}
@ -202,13 +201,17 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
return {"CANCELLED"}
# Determine where the render output will be stored.
render_output = Path("/render/_flamenco/tests/renders") / self.job_name
self.log.info("Will output render files to %s", render_output)
pack_target_dir = Path("/render/_flamenco/tests/renders") / self.job_name
# TODO: this should take the blendfile location relative to the project path into account.
pack_target_file = pack_target_dir / blendfile.name
self.log.info("Will store blend file at %s", pack_target_file)
self.blendfile_on_farm = pack_target_file
self.packthread = bat_interface.copy(
base_blendfile=blendfile,
project=project_path,
target=render_output,
target=pack_target_dir,
exclusion_filter="", # TODO: get from GUI.
relative_only=True, # TODO: get from GUI.
)
@ -223,7 +226,6 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
from . import bat_interface
if isinstance(msg, bat_interface.MsgDone):
self.report({"INFO"}, "BAT pack is done")
self._submit_job(context)
return self._quit(context)
@ -245,10 +247,13 @@ class FLAMENCO_OT_submit_job(FlamencoOpMixin, bpy.types.Operator):
"""Use the Flamenco API to submit the new Job."""
assert self.job is not None
job_type = job_types.active_job_type(context.scene)
job_submission.set_blend_file(job_type, self.job, self.blendfile_on_farm)
api_client = self.get_api_client(context)
job = job_submission.submit_job(self.job, api_client)
self.report({"INFO"}, "Job submitted")
self.report({"INFO"}, "Job %s submitted" % job.name)
def _quit(self, context: bpy.types.Context) -> set[str]:
"""Stop any timer and return a 'FINISHED' status.

@ -4,7 +4,7 @@ const JOB_TYPE = {
label: "Simple Blender Render",
settings: [
{ key: "blender_cmd", type: "string", default: "{blender}", visible: false },
{ key: "filepath", type: "string", subtype: "file_path", required: true, description: "Blend file to render", visible: false },
{ key: "blendfile", type: "string", required: true, description: "Path of the Blend file to render", visible: false },
{ key: "chunk_size", type: "int32", default: 1, description: "Number of frames to render in one Blender render task" },
{ key: "frames", type: "string", required: true },
{ key: "render_output", type: "string", subtype: "hashed_file_path", required: true },
@ -76,7 +76,7 @@ function authorRenderTasks(settings, renderDir, renderOutput) {
const command = author.Command("blender-render", {
exe: settings.blender_cmd,
argsBefore: [],
blendfile: settings.filepath,
blendfile: settings.blendfile,
args: [
"--render-output", path.join(renderDir, path.basename(renderOutput)),
"--render-format", settings.format,
@ -99,7 +99,7 @@ function authorCreateVideoTask(settings, renderDir) {
return;
}
const stem = path.stem(settings.filepath).replace('.flamenco', '');
const stem = path.stem(settings.blendfile).replace('.flamenco', '');
const outfile = path.join(renderDir, `${stem}-${settings.frames}.mp4`);
const task = author.Task('create-video', 'ffmpeg');