diff --git a/openpype/hosts/nuke/api/lib.py b/openpype/hosts/nuke/api/lib.py
index fb2b5d0f45..07f394ec00 100644
--- a/openpype/hosts/nuke/api/lib.py
+++ b/openpype/hosts/nuke/api/lib.py
@@ -3423,3 +3423,55 @@ def create_viewer_profile_string(viewer, display=None, path_like=False):
if path_like:
return "{}/{}".format(display, viewer)
return "{} ({})".format(viewer, display)
+
+
+def get_head_filename_without_hashes(original_path, name):
+ """Function to get the renamed head filename without frame hashes
+ To avoid the system being confused on finding the filename with
+ frame hashes if the head of the filename has the hashed symbol
+
+ Examples:
+ >>> get_head_filename_without_hashes("render.####.exr", "baking")
+ render.baking.####.exr
+ >>> get_head_filename_without_hashes("render.%04d.exr", "tag")
+ render.tag.%d.exr
+ >>> get_head_filename_without_hashes("exr.####.exr", "foo")
+ exr.foo.%04d.exr
+
+ Args:
+ original_path (str): the filename with frame hashes
+ name (str): the name of the tags
+
+ Returns:
+ str: the renamed filename with the tag
+ """
+ filename = os.path.basename(original_path)
+
+ def insert_name(matchobj):
+ return "{}.{}".format(name, matchobj.group(0))
+
+ return re.sub(r"(%\d*d)|#+", insert_name, filename)
+
+
+def get_filenames_without_hash(filename, frame_start, frame_end):
+ """Get filenames without frame hash
+ i.e. "renderCompositingMain.baking.0001.exr"
+
+ Args:
+ filename (str): filename with frame hash
+ frame_start (str): start of the frame
+ frame_end (str): end of the frame
+
+ Returns:
+ list: filename per frame of the sequence
+ """
+ filenames = []
+ for frame in range(int(frame_start), (int(frame_end) + 1)):
+ if "#" in filename:
+ # use regex to convert #### to {:0>4}
+ def replace(match):
+ return "{{:0>{}}}".format(len(match.group()))
+ filename_without_hashes = re.sub("#+", replace, filename)
+ new_filename = filename_without_hashes.format(frame)
+ filenames.append(new_filename)
+ return filenames
diff --git a/openpype/hosts/nuke/api/plugin.py b/openpype/hosts/nuke/api/plugin.py
index 6d5d7eddf1..81841d17be 100644
--- a/openpype/hosts/nuke/api/plugin.py
+++ b/openpype/hosts/nuke/api/plugin.py
@@ -21,6 +21,9 @@ from openpype.pipeline import (
CreatedInstance,
get_current_task_name
)
+from openpype.lib.transcoding import (
+ VIDEO_EXTENSIONS
+)
from .lib import (
INSTANCE_DATA_KNOB,
Knobby,
@@ -35,7 +38,9 @@ from .lib import (
get_node_data,
get_view_process_node,
get_viewer_config_from_string,
- deprecated
+ deprecated,
+ get_head_filename_without_hashes,
+ get_filenames_without_hash
)
from .pipeline import (
list_instances,
@@ -634,6 +639,10 @@ class ExporterReview(object):
"frameStart": self.first_frame,
"frameEnd": self.last_frame,
})
+ if ".{}".format(self.ext) not in VIDEO_EXTENSIONS:
+ filenames = get_filenames_without_hash(
+ self.file, self.first_frame, self.last_frame)
+ repre["files"] = filenames
if self.multiple_presets:
repre["outputName"] = self.name
@@ -808,6 +817,18 @@ class ExporterReviewMov(ExporterReview):
self.log.info("File info was set...")
self.file = self.fhead + self.name + ".{}".format(self.ext)
+ if ".{}".format(self.ext) not in VIDEO_EXTENSIONS:
+ # filename would be with frame hashes if
+ # the file extension is not in video format
+ filename = get_head_filename_without_hashes(
+ self.path_in, self.name)
+ self.file = filename
+ # make sure the filename are in
+ # correct image output format
+ if ".{}".format(self.ext) not in self.file:
+ filename_no_ext, _ = os.path.splitext(filename)
+ self.file = "{}.{}".format(filename_no_ext, self.ext)
+
self.path = os.path.join(
self.staging_dir, self.file).replace("\\", "/")
@@ -933,7 +954,6 @@ class ExporterReviewMov(ExporterReview):
self.log.debug("Path: {}".format(self.path))
write_node["file"].setValue(str(self.path))
write_node["file_type"].setValue(str(self.ext))
-
# Knobs `meta_codec` and `mov64_codec` are not available on centos.
# TODO shouldn't this come from settings on outputs?
try:
diff --git a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py b/openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py
similarity index 84%
rename from openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py
rename to openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py
index 956d1a54a3..da060e3157 100644
--- a/openpype/hosts/nuke/plugins/publish/extract_review_data_mov.py
+++ b/openpype/hosts/nuke/plugins/publish/extract_review_intermediates.py
@@ -8,15 +8,16 @@ from openpype.hosts.nuke.api import plugin
from openpype.hosts.nuke.api.lib import maintained_selection
-class ExtractReviewDataMov(publish.Extractor):
- """Extracts movie and thumbnail with baked in luts
+class ExtractReviewIntermediates(publish.Extractor):
+ """Extracting intermediate videos or sequences with
+ thumbnail for transcoding.
must be run after extract_render_local.py
"""
order = pyblish.api.ExtractorOrder + 0.01
- label = "Extract Review Data Mov"
+ label = "Extract Review Intermediates"
families = ["review"]
hosts = ["nuke"]
@@ -25,6 +26,22 @@ class ExtractReviewDataMov(publish.Extractor):
viewer_lut_raw = None
outputs = {}
+ @classmethod
+ def apply_settings(cls, project_settings):
+ """Apply the settings from the deprecated
+ ExtractReviewDataMov plugin for backwards compatibility
+ """
+ nuke_publish = project_settings["nuke"]["publish"]
+ deprecated_setting = nuke_publish["ExtractReviewDataMov"]
+ current_setting = nuke_publish["ExtractReviewIntermediates"]
+ if deprecated_setting["enabled"]:
+ # Use deprecated settings if they are still enabled
+ cls.viewer_lut_raw = deprecated_setting["viewer_lut_raw"]
+ cls.outputs = deprecated_setting["outputs"]
+ elif current_setting["enabled"]:
+ cls.viewer_lut_raw = current_setting["viewer_lut_raw"]
+ cls.outputs = current_setting["outputs"]
+
def process(self, instance):
families = set(instance.data["families"])
diff --git a/openpype/settings/ayon_settings.py b/openpype/settings/ayon_settings.py
index 3be8ac8ae5..68693bb953 100644
--- a/openpype/settings/ayon_settings.py
+++ b/openpype/settings/ayon_settings.py
@@ -748,7 +748,19 @@ def _convert_nuke_project_settings(ayon_settings, output):
)
new_review_data_outputs = {}
- for item in ayon_publish["ExtractReviewDataMov"]["outputs"]:
+ outputs_settings = None
+ # Check deprecated ExtractReviewDataMov
+ # settings for backwards compatibility
+ deprecrated_review_settings = ayon_publish["ExtractReviewDataMov"]
+ current_review_settings = (
+ ayon_publish["ExtractReviewIntermediates"]
+ )
+ if deprecrated_review_settings["enabled"]:
+ outputs_settings = deprecrated_review_settings["outputs"]
+ elif current_review_settings["enabled"]:
+ outputs_settings = current_review_settings["outputs"]
+
+ for item in outputs_settings:
item_filter = item["filter"]
if "product_names" in item_filter:
item_filter["subsets"] = item_filter.pop("product_names")
@@ -767,7 +779,11 @@ def _convert_nuke_project_settings(ayon_settings, output):
name = item.pop("name")
new_review_data_outputs[name] = item
- ayon_publish["ExtractReviewDataMov"]["outputs"] = new_review_data_outputs
+
+ if deprecrated_review_settings["enabled"]:
+ deprecrated_review_settings["outputs"] = new_review_data_outputs
+ elif current_review_settings["enabled"]:
+ current_review_settings["outputs"] = new_review_data_outputs
collect_instance_data = ayon_publish["CollectInstanceData"]
if "sync_workfile_version_on_product_types" in collect_instance_data:
diff --git a/openpype/settings/defaults/project_settings/nuke.json b/openpype/settings/defaults/project_settings/nuke.json
index 7961e77113..ad9f46c8ab 100644
--- a/openpype/settings/defaults/project_settings/nuke.json
+++ b/openpype/settings/defaults/project_settings/nuke.json
@@ -501,6 +501,60 @@
}
}
},
+ "ExtractReviewIntermediates": {
+ "enabled": true,
+ "viewer_lut_raw": false,
+ "outputs": {
+ "baking": {
+ "filter": {
+ "task_types": [],
+ "families": [],
+ "subsets": []
+ },
+ "read_raw": false,
+ "viewer_process_override": "",
+ "bake_viewer_process": true,
+ "bake_viewer_input_process": true,
+ "reformat_nodes_config": {
+ "enabled": false,
+ "reposition_nodes": [
+ {
+ "node_class": "Reformat",
+ "knobs": [
+ {
+ "type": "text",
+ "name": "type",
+ "value": "to format"
+ },
+ {
+ "type": "text",
+ "name": "format",
+ "value": "HD_1080"
+ },
+ {
+ "type": "text",
+ "name": "filter",
+ "value": "Lanczos6"
+ },
+ {
+ "type": "bool",
+ "name": "black_outside",
+ "value": true
+ },
+ {
+ "type": "bool",
+ "name": "pbb",
+ "value": false
+ }
+ ]
+ }
+ ]
+ },
+ "extension": "mov",
+ "add_custom_tags": []
+ }
+ }
+ },
"ExtractSlateFrame": {
"viewer_lut_raw": false,
"key_value_mapping": {
diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json
index f006392bef..fa08e19c63 100644
--- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json
+++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_nuke_publish.json
@@ -371,6 +371,151 @@
]
},
+ {
+ "type": "label",
+ "label": "^ Settings and for ExtractReviewDataMov is deprecated and will be soon removed.
Please use ExtractReviewIntermediates instead."
+ },
+ {
+ "type": "dict",
+ "collapsible": true,
+ "checkbox_key": "enabled",
+ "key": "ExtractReviewIntermediates",
+ "label": "ExtractReviewIntermediates",
+ "is_group": true,
+ "children": [
+ {
+ "type": "boolean",
+ "key": "enabled",
+ "label": "Enabled"
+ },
+ {
+ "type": "boolean",
+ "key": "viewer_lut_raw",
+ "label": "Viewer LUT raw"
+ },
+ {
+ "key": "outputs",
+ "label": "Output Definitions",
+ "type": "dict-modifiable",
+ "highlight_content": true,
+ "object_type": {
+ "type": "dict",
+ "children": [
+ {
+ "type": "dict",
+ "collapsible": false,
+ "key": "filter",
+ "label": "Filtering",
+ "children": [
+ {
+ "key": "task_types",
+ "label": "Task types",
+ "type": "task-types-enum"
+ },
+ {
+ "key": "families",
+ "label": "Families",
+ "type": "list",
+ "object_type": "text"
+ },
+ {
+ "key": "subsets",
+ "label": "Subsets",
+ "type": "list",
+ "object_type": "text"
+ }
+ ]
+ },
+ {
+ "type": "separator"
+ },
+ {
+ "type": "boolean",
+ "key": "read_raw",
+ "label": "Read colorspace RAW",
+ "default": false
+ },
+ {
+ "type": "text",
+ "key": "viewer_process_override",
+ "label": "Viewer Process colorspace profile override"
+ },
+ {
+ "type": "boolean",
+ "key": "bake_viewer_process",
+ "label": "Bake Viewer Process"
+ },
+ {
+ "type": "boolean",
+ "key": "bake_viewer_input_process",
+ "label": "Bake Viewer Input Process (LUTs)"
+ },
+ {
+ "type": "separator"
+ },
+ {
+ "key": "reformat_nodes_config",
+ "type": "dict",
+ "label": "Reformat Nodes",
+ "collapsible": true,
+ "checkbox_key": "enabled",
+ "children": [
+ {
+ "type": "boolean",
+ "key": "enabled",
+ "label": "Enabled"
+ },
+ {
+ "type": "label",
+ "label": "Reposition knobs supported only.
You can add multiple reformat nodes
and set their knobs. Order of reformat
nodes is important. First reformat node
will be applied first and last reformat
node will be applied last."
+ },
+ {
+ "key": "reposition_nodes",
+ "type": "list",
+ "label": "Reposition nodes",
+ "object_type": {
+ "type": "dict",
+ "children": [
+ {
+ "key": "node_class",
+ "label": "Node class",
+ "type": "text"
+ },
+ {
+ "type": "schema_template",
+ "name": "template_nuke_knob_inputs",
+ "template_data": [
+ {
+ "label": "Node knobs",
+ "key": "knobs"
+ }
+ ]
+ }
+ ]
+ }
+ }
+ ]
+ },
+ {
+ "type": "separator"
+ },
+ {
+ "type": "text",
+ "key": "extension",
+ "label": "Write node file type"
+ },
+ {
+ "key": "add_custom_tags",
+ "label": "Add custom tags",
+ "type": "list",
+ "object_type": "text"
+ }
+ ]
+ }
+ }
+
+ ]
+ },
{
"type": "dict",
"collapsible": true,
diff --git a/server_addon/nuke/server/settings/publish_plugins.py b/server_addon/nuke/server/settings/publish_plugins.py
index c78685534f..19206149b6 100644
--- a/server_addon/nuke/server/settings/publish_plugins.py
+++ b/server_addon/nuke/server/settings/publish_plugins.py
@@ -149,7 +149,7 @@ class ReformatNodesConfigModel(BaseSettingsModel):
)
-class BakingStreamModel(BaseSettingsModel):
+class IntermediateOutputModel(BaseSettingsModel):
name: str = Field(title="Output name")
filter: BakingStreamFilterModel = Field(
title="Filter", default_factory=BakingStreamFilterModel)
@@ -166,9 +166,21 @@ class BakingStreamModel(BaseSettingsModel):
class ExtractReviewDataMovModel(BaseSettingsModel):
+ """[deprecated] use Extract Review Data Baking
+ Streams instead.
+ """
enabled: bool = Field(title="Enabled")
viewer_lut_raw: bool = Field(title="Viewer lut raw")
- outputs: list[BakingStreamModel] = Field(
+ outputs: list[IntermediateOutputModel] = Field(
+ default_factory=list,
+ title="Baking streams"
+ )
+
+
+class ExtractReviewIntermediatesModel(BaseSettingsModel):
+ enabled: bool = Field(title="Enabled")
+ viewer_lut_raw: bool = Field(title="Viewer lut raw")
+ outputs: list[IntermediateOutputModel] = Field(
default_factory=list,
title="Baking streams"
)
@@ -270,6 +282,10 @@ class PublishPuginsModel(BaseSettingsModel):
title="Extract Review Data Mov",
default_factory=ExtractReviewDataMovModel
)
+ ExtractReviewIntermediates: ExtractReviewIntermediatesModel = Field(
+ title="Extract Review Intermediates",
+ default_factory=ExtractReviewIntermediatesModel
+ )
ExtractSlateFrame: ExtractSlateFrameModel = Field(
title="Extract Slate Frame",
default_factory=ExtractSlateFrameModel
@@ -465,6 +481,61 @@ DEFAULT_PUBLISH_PLUGIN_SETTINGS = {
}
]
},
+ "ExtractReviewIntermediates": {
+ "enabled": True,
+ "viewer_lut_raw": False,
+ "outputs": [
+ {
+ "name": "baking",
+ "filter": {
+ "task_types": [],
+ "product_types": [],
+ "product_names": []
+ },
+ "read_raw": False,
+ "viewer_process_override": "",
+ "bake_viewer_process": True,
+ "bake_viewer_input_process": True,
+ "reformat_nodes_config": {
+ "enabled": False,
+ "reposition_nodes": [
+ {
+ "node_class": "Reformat",
+ "knobs": [
+ {
+ "type": "text",
+ "name": "type",
+ "text": "to format"
+ },
+ {
+ "type": "text",
+ "name": "format",
+ "text": "HD_1080"
+ },
+ {
+ "type": "text",
+ "name": "filter",
+ "text": "Lanczos6"
+ },
+ {
+ "type": "bool",
+ "name": "black_outside",
+ "boolean": True
+ },
+ {
+ "type": "bool",
+ "name": "pbb",
+ "boolean": False
+ }
+ ]
+ }
+ ]
+ },
+ "extension": "mov",
+ "add_custom_tags": []
+ }
+ ]
+ },
"ExtractSlateFrame": {
"viewer_lut_raw": False,
"key_value_mapping": {
diff --git a/server_addon/nuke/server/version.py b/server_addon/nuke/server/version.py
index b3f4756216..ae7362549b 100644
--- a/server_addon/nuke/server/version.py
+++ b/server_addon/nuke/server/version.py
@@ -1 +1 @@
-__version__ = "0.1.2"
+__version__ = "0.1.3"
diff --git a/website/docs/project_settings/settings_project_global.md b/website/docs/project_settings/settings_project_global.md
index e0481a8717..27aa60a464 100644
--- a/website/docs/project_settings/settings_project_global.md
+++ b/website/docs/project_settings/settings_project_global.md
@@ -189,7 +189,7 @@ A profile may generate multiple outputs from a single input. Each output must de
- Profile filtering defines which group of output definitions is used but output definitions may require more specific filters on their own.
- They may filter by subset name (regex can be used) or publish families. Publish families are more complex as are based on knowing code base.
- Filtering by custom tags -> this is used for targeting to output definitions from other extractors using settings (at this moment only Nuke bake extractor can target using custom tags).
- - Nuke extractor settings path: `project_settings/nuke/publish/ExtractReviewDataMov/outputs/baking/add_custom_tags`
+ - Nuke extractor settings path: `project_settings/nuke/publish/ExtractReviewIntermediates/outputs/baking/add_custom_tags`
- Filtering by input length. Input may be video, sequence or single image. It is possible that `.mp4` should be created only when input is video or sequence and to create review `.png` when input is single frame. In some cases the output should be created even if it's single frame or multi frame input.
diff --git a/website/docs/pype2/admin_presets_plugins.md b/website/docs/pype2/admin_presets_plugins.md
index 6a057f4bb4..b5e8a3b8a8 100644
--- a/website/docs/pype2/admin_presets_plugins.md
+++ b/website/docs/pype2/admin_presets_plugins.md
@@ -534,8 +534,7 @@ Plugin responsible for generating thumbnails with colorspace controlled by Nuke.
}
```
-### `ExtractReviewDataMov`
-
+### `ExtractReviewIntermediates`
`viewer_lut_raw` **true** will publish the baked mov file without any colorspace conversion. It will be baked with the workfile workspace. This can happen in case the Viewer input process uses baked screen space luts.
#### baking with controlled colorspace