[Automated] Merged develop into main

This commit is contained in:
pypebot 2021-06-24 14:58:50 +02:00 committed by GitHub
commit e9e4133820
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 672 additions and 147 deletions

View file

@ -1,3 +1,4 @@
from copy import deepcopy
import openpype.hosts.hiero.api as phiero
# from openpype.hosts.hiero.api import plugin, lib
# reload(lib)
@ -206,20 +207,24 @@ class CreateShotClip(phiero.Creator):
presets = None
def process(self):
# Creator copy of object attributes that are modified during `process`
presets = deepcopy(self.presets)
gui_inputs = deepcopy(self.gui_inputs)
# get key pares from presets and match it on ui inputs
for k, v in self.gui_inputs.items():
for k, v in gui_inputs.items():
if v["type"] in ("dict", "section"):
# nested dictionary (only one level allowed
# for sections and dict)
for _k, _v in v["value"].items():
if self.presets.get(_k):
self.gui_inputs[k][
"value"][_k]["value"] = self.presets[_k]
if self.presets.get(k):
self.gui_inputs[k]["value"] = self.presets[k]
if presets.get(_k):
gui_inputs[k][
"value"][_k]["value"] = presets[_k]
if presets.get(k):
gui_inputs[k]["value"] = presets[k]
# open widget for plugins inputs
widget = self.widget(self.gui_name, self.gui_info, self.gui_inputs)
widget = self.widget(self.gui_name, self.gui_info, gui_inputs)
widget.exec_()
if len(self.selected) < 1:

View file

@ -46,12 +46,6 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
source_clip = track_item.source()
self.log.debug("clip_name: {}".format(clip_name))
# get clips subtracks and anotations
annotations = self.clip_annotations(source_clip)
subtracks = self.clip_subtrack(track_item)
self.log.debug("Annotations: {}".format(annotations))
self.log.debug(">> Subtracks: {}".format(subtracks))
# get openpype tag data
tag_data = phiero.get_track_item_pype_data(track_item)
self.log.debug("__ tag_data: {}".format(pformat(tag_data)))
@ -62,6 +56,12 @@ class PrecollectInstances(pyblish.api.ContextPlugin):
if tag_data.get("id") != "pyblish.avalon.instance":
continue
# get clips subtracks and anotations
annotations = self.clip_annotations(source_clip)
subtracks = self.clip_subtrack(track_item)
self.log.debug("Annotations: {}".format(annotations))
self.log.debug(">> Subtracks: {}".format(subtracks))
# solve handles length
tag_data["handleStart"] = min(
tag_data["handleStart"], int(track_item.handleInLength()))

View file

@ -128,5 +128,4 @@ class CreateWritePrerender(plugin.PypeCreator):
w_node["first"].setValue(nuke.root()["first_frame"].value())
w_node["last"].setValue(nuke.root()["last_frame"].value())
return write_node

View file

@ -100,6 +100,13 @@ class CreateWriteRender(plugin.PypeCreator):
"/{subset}.{frame}.{ext}")})
# add crop node to cut off all outside of format bounding box
# get width and height
try:
width, height = (selected_node.width(), selected_node.height())
except AttributeError:
actual_format = nuke.root().knob('format').value()
width, height = (actual_format.width(), actual_format.height())
_prenodes = [
{
"name": "Crop01",
@ -108,8 +115,8 @@ class CreateWriteRender(plugin.PypeCreator):
("box", [
0.0,
0.0,
selected_node.width(),
selected_node.height()
width,
height
])
],
"dependent": None

View file

@ -0,0 +1,26 @@
import re
def get_unique_layer_name(layers, asset_name, subset_name):
"""
Gets all layer names and if 'asset_name_subset_name' is present, it
increases suffix by 1 (eg. creates unique layer name - for Loader)
Args:
layers (list) of dict with layers info (name, id etc.)
asset_name (string):
subset_name (string):
Returns:
(string): name_00X (without version)
"""
name = "{}_{}".format(asset_name, subset_name)
names = {}
for layer in layers:
layer_name = re.sub(r'_\d{3}$', '', layer.name)
if layer_name in names.keys():
names[layer_name] = names[layer_name] + 1
else:
names[layer_name] = 1
occurrences = names.get(name, 0)
return "{}_{:0>3d}".format(name, occurrences + 1)

View file

@ -1,7 +1,9 @@
from avalon import api, photoshop
import os
import re
from avalon import api, photoshop
from openpype.hosts.photoshop.plugins.lib import get_unique_layer_name
stub = photoshop.stub()
@ -15,8 +17,9 @@ class ImageLoader(api.Loader):
representations = ["*"]
def load(self, context, name=None, namespace=None, data=None):
layer_name = self._get_unique_layer_name(context["asset"]["name"],
name)
layer_name = get_unique_layer_name(stub.get_layers(),
context["asset"]["name"],
name)
with photoshop.maintained_selection():
layer = stub.import_smart_object(self.fname, layer_name)
@ -69,25 +72,3 @@ class ImageLoader(api.Loader):
def switch(self, container, representation):
self.update(container, representation)
def _get_unique_layer_name(self, asset_name, subset_name):
"""
Gets all layer names and if 'name' is present in them, increases
suffix by 1 (eg. creates unique layer name - for Loader)
Args:
name (string): in format asset_subset
Returns:
(string): name_00X (without version)
"""
name = "{}_{}".format(asset_name, subset_name)
names = {}
for layer in stub.get_layers():
layer_name = re.sub(r'_\d{3}$', '', layer.name)
if layer_name in names.keys():
names[layer_name] = names[layer_name] + 1
else:
names[layer_name] = 1
occurrences = names.get(name, 0)
return "{}_{:0>3d}".format(name, occurrences + 1)

View file

@ -0,0 +1,98 @@
import os
from avalon import api
from avalon import photoshop
from avalon.pipeline import get_representation_path_from_context
from avalon.vendor import qargparse
from openpype.lib import Anatomy
from openpype.hosts.photoshop.plugins.lib import get_unique_layer_name
stub = photoshop.stub()
class ImageFromSequenceLoader(api.Loader):
""" Load specifing image from sequence
Used only as quick load of reference file from a sequence.
Plain ImageLoader picks first frame from sequence.
Loads only existing files - currently not possible to limit loaders
to single select - multiselect. If user selects multiple repres, list
for all of them is provided, but selection is only single file.
This loader will be triggered multiple times, but selected name will
match only to proper path.
Loader doesnt do containerization as there is currently no data model
of 'frame of rendered files' (only rendered sequence), update would be
difficult.
"""
families = ["render"]
representations = ["*"]
options = []
def load(self, context, name=None, namespace=None, data=None):
if data.get("frame"):
self.fname = os.path.join(os.path.dirname(self.fname),
data["frame"])
if not os.path.exists(self.fname):
return
stub = photoshop.stub()
layer_name = get_unique_layer_name(stub.get_layers(),
context["asset"]["name"],
name)
with photoshop.maintained_selection():
layer = stub.import_smart_object(self.fname, layer_name)
self[:] = [layer]
namespace = namespace or layer_name
return namespace
@classmethod
def get_options(cls, repre_contexts):
"""
Returns list of files for selected 'repre_contexts'.
It returns only files with same extension as in context as it is
expected that context points to sequence of frames.
Returns:
(list) of qargparse.Choice
"""
files = []
for context in repre_contexts:
fname = get_representation_path_from_context(context)
_, file_extension = os.path.splitext(fname)
for file_name in os.listdir(os.path.dirname(fname)):
if not file_name.endswith(file_extension):
continue
files.append(file_name)
# return selection only if there is something
if not files or len(files) <= 1:
return []
return [
qargparse.Choice(
"frame",
label="Select specific file",
items=files,
default=0,
help="Which frame should be loaded?"
)
]
def update(self, container, representation):
"""No update possible, not containerized."""
pass
def remove(self, container):
"""No update possible, not containerized."""
pass

View file

@ -34,7 +34,6 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
# presets
batch_extensions = ["edl", "xml", "psd"]
default_families = ["ftrack"]
def process(self, context):
# get json paths from os and load them
@ -213,10 +212,6 @@ class CollectContextDataSAPublish(pyblish.api.ContextPlugin):
subset = in_data["subset"]
# If instance data already contain families then use it
instance_families = in_data.get("families") or []
# Make sure default families are in instance
for default_family in self.default_families or []:
if default_family not in instance_families:
instance_families.append(default_family)
instance = context.create_instance(subset)
instance.data.update(

View file

@ -16,12 +16,12 @@ class CollectInstances(pyblish.api.InstancePlugin):
subsets = {
"referenceMain": {
"family": "review",
"families": ["clip", "ftrack"],
"families": ["clip"],
"extensions": [".mp4"]
},
"audioMain": {
"family": "audio",
"families": ["clip", "ftrack"],
"families": ["clip"],
"extensions": [".wav"],
},
"shotMain": {

View file

@ -1,29 +0,0 @@
"""
Requires:
Nothing
Provides:
Instance
"""
import pyblish.api
import logging
log = logging.getLogger("collector")
class CollectMatchmovePublish(pyblish.api.InstancePlugin):
"""
Collector with only one reason for its existence - remove 'ftrack'
family implicitly added by Standalone Publisher
"""
label = "Collect Matchmove - SA Publish"
order = pyblish.api.CollectorOrder
families = ["matchmove"]
hosts = ["standalonepublisher"]
def process(self, instance):
if "ftrack" in instance.data["families"]:
instance.data["families"].remove("ftrack")

View file

@ -1,5 +1,6 @@
import os
import json
import tempfile
import pyblish.api
import avalon.api
@ -153,9 +154,45 @@ class CollectWorkfileData(pyblish.api.ContextPlugin):
"sceneMarkIn": int(mark_in_frame),
"sceneMarkInState": mark_in_state == "set",
"sceneMarkOut": int(mark_out_frame),
"sceneMarkOutState": mark_out_state == "set"
"sceneMarkOutState": mark_out_state == "set",
"sceneBgColor": self._get_bg_color()
}
self.log.debug(
"Scene data: {}".format(json.dumps(scene_data, indent=4))
)
context.data.update(scene_data)
def _get_bg_color(self):
"""Background color set on scene.
Is important for review exporting where scene bg color is used as
background.
"""
output_file = tempfile.NamedTemporaryFile(
mode="w", prefix="a_tvp_", suffix=".txt", delete=False
)
output_file.close()
output_filepath = output_file.name.replace("\\", "/")
george_script_lines = [
# Variable containing full path to output file
"output_path = \"{}\"".format(output_filepath),
"tv_background",
"bg_color = result",
# Write data to output file
(
"tv_writetextfile"
" \"strict\" \"append\" '\"'output_path'\"' bg_color"
)
]
george_script = "\n".join(george_script_lines)
lib.execute_george_through_file(george_script)
with open(output_filepath, "r") as stream:
data = stream.read()
os.remove(output_filepath)
data = data.strip()
if not data:
return None
return data.split(" ")

View file

@ -1,5 +1,6 @@
import os
import shutil
import copy
import tempfile
import pyblish.api
@ -13,6 +14,9 @@ class ExtractSequence(pyblish.api.Extractor):
hosts = ["tvpaint"]
families = ["review", "renderPass", "renderLayer"]
# Modifiable with settings
review_bg = [255, 255, 255, 255]
def process(self, instance):
self.log.info(
"* Processing instance \"{}\"".format(instance.data["label"])
@ -53,6 +57,8 @@ class ExtractSequence(pyblish.api.Extractor):
handle_start = instance.context.data["handleStart"]
handle_end = instance.context.data["handleEnd"]
scene_bg_color = instance.context.data["sceneBgColor"]
# --- Fallbacks ----------------------------------------------------
# This is required if validations of ranges are ignored.
# - all of this code won't change processing if range to render
@ -120,7 +126,8 @@ class ExtractSequence(pyblish.api.Extractor):
if instance.data["family"] == "review":
output_filenames, thumbnail_fullpath = self.render_review(
filename_template, output_dir, mark_in, mark_out
filename_template, output_dir, mark_in, mark_out,
scene_bg_color
)
else:
# Render output
@ -241,7 +248,9 @@ class ExtractSequence(pyblish.api.Extractor):
for path in repre_filepaths
]
def render_review(self, filename_template, output_dir, mark_in, mark_out):
def render_review(
self, filename_template, output_dir, mark_in, mark_out, scene_bg_color
):
""" Export images from TVPaint using `tv_savesequence` command.
Args:
@ -252,6 +261,8 @@ class ExtractSequence(pyblish.api.Extractor):
output_dir (str): Directory where files will be stored.
mark_in (int): Starting frame index from which export will begin.
mark_out (int): On which frame index export will end.
scene_bg_color (list): Bg color set in scene. Result of george
script command `tv_background`.
Retruns:
tuple: With 2 items first is list of filenames second is path to
@ -263,7 +274,11 @@ class ExtractSequence(pyblish.api.Extractor):
filename_template.format(frame=mark_in)
)
bg_color = self._get_review_bg_color()
george_script_lines = [
# Change bg color to color from settings
"tv_background \"color\" {} {} {}".format(*bg_color),
"tv_SaveMode \"PNG\"",
"export_path = \"{}\"".format(
first_frame_filepath.replace("\\", "/")
@ -272,6 +287,18 @@ class ExtractSequence(pyblish.api.Extractor):
mark_in, mark_out
)
]
if scene_bg_color:
# Change bg color back to previous scene bg color
_scene_bg_color = copy.deepcopy(scene_bg_color)
bg_type = _scene_bg_color.pop(0)
orig_color_command = [
"tv_background",
"\"{}\"".format(bg_type)
]
orig_color_command.extend(_scene_bg_color)
george_script_lines.append(" ".join(orig_color_command))
lib.execute_george_through_file("\n".join(george_script_lines))
first_frame_filepath = None
@ -291,12 +318,13 @@ class ExtractSequence(pyblish.api.Extractor):
if first_frame_filepath is None:
first_frame_filepath = filepath
thumbnail_filepath = os.path.join(output_dir, "thumbnail.jpg")
thumbnail_filepath = None
if first_frame_filepath and os.path.exists(first_frame_filepath):
thumbnail_filepath = os.path.join(output_dir, "thumbnail.jpg")
source_img = Image.open(first_frame_filepath)
thumbnail_obj = Image.new("RGB", source_img.size, (255, 255, 255))
thumbnail_obj.paste(source_img)
thumbnail_obj.save(thumbnail_filepath)
if source_img.mode.lower() != "rgb":
source_img = source_img.convert("RGB")
source_img.save(thumbnail_filepath)
return output_filenames, thumbnail_filepath
@ -392,12 +420,35 @@ class ExtractSequence(pyblish.api.Extractor):
if thumbnail_src_filepath and os.path.exists(thumbnail_src_filepath):
source_img = Image.open(thumbnail_src_filepath)
thumbnail_filepath = os.path.join(output_dir, "thumbnail.jpg")
thumbnail_obj = Image.new("RGB", source_img.size, (255, 255, 255))
thumbnail_obj.paste(source_img)
thumbnail_obj.save(thumbnail_filepath)
# Composite background only on rgba images
# - just making sure
if source_img.mode.lower() == "rgba":
bg_color = self._get_review_bg_color()
self.log.debug("Adding thumbnail background color {}.".format(
" ".join([str(val) for val in bg_color])
))
bg_image = Image.new("RGBA", source_img.size, bg_color)
thumbnail_obj = Image.alpha_composite(bg_image, source_img)
thumbnail_obj.convert("RGB").save(thumbnail_filepath)
else:
self.log.info((
"Source for thumbnail has mode \"{}\" (Expected: RGBA)."
" Can't use thubmanail background color."
).format(source_img.mode))
source_img.save(thumbnail_filepath)
return output_filenames, thumbnail_filepath
def _get_review_bg_color(self):
red = green = blue = 255
if self.review_bg:
if len(self.review_bg) == 4:
red, green, blue, _ = self.review_bg
elif len(self.review_bg) == 3:
red, green, blue = self.review_bg
return (red, green, blue)
def _render_layer(
self,
layer,

View file

@ -1,29 +1,107 @@
"""
Requires:
none
Provides:
instance -> families ([])
"""
import pyblish.api
import avalon.api
from openpype.lib.plugin_tools import filter_profiles
class CollectFtrackFamilies(pyblish.api.InstancePlugin):
"""Collect family for ftrack publishing
Add ftrack family to those instance that should be published to ftrack
class CollectFtrackFamily(pyblish.api.InstancePlugin):
"""
Adds explicitly 'ftrack' to families to upload instance to FTrack.
order = pyblish.api.CollectorOrder + 0.3
label = 'Add ftrack family'
families = ["model",
"setdress",
"model",
"animation",
"look",
"rig",
"camera"
]
hosts = ["maya"]
Uses selection by combination of hosts/families/tasks names via
profiles resolution.
Triggered everywhere, checks instance against configured.
Checks advanced filtering which works on 'families' not on main
'family', as some variants dynamically resolves addition of ftrack
based on 'families' (editorial drives it by presence of 'review')
"""
label = "Collect Ftrack Family"
order = pyblish.api.CollectorOrder + 0.4998
profiles = None
def process(self, instance):
if not self.profiles:
self.log.warning("No profiles present for adding Ftrack family")
return
# make ftrack publishable
if instance.data.get('families'):
instance.data['families'].append('ftrack')
task_name = instance.data.get("task",
avalon.api.Session["AVALON_TASK"])
host_name = avalon.api.Session["AVALON_APP"]
family = instance.data["family"]
filtering_criteria = {
"hosts": host_name,
"families": family,
"tasks": task_name
}
profile = filter_profiles(self.profiles, filtering_criteria,
logger=self.log)
if profile:
families = instance.data.get("families")
add_ftrack_family = profile["add_ftrack_family"]
additional_filters = profile.get("additional_filters")
if additional_filters:
add_ftrack_family = self._get_add_ftrack_f_from_addit_filters(
additional_filters,
families,
add_ftrack_family
)
if add_ftrack_family:
self.log.debug("Adding ftrack family for '{}'".
format(instance.data.get("family")))
if families and "ftrack" not in families:
instance.data["families"].append("ftrack")
else:
instance.data["families"] = ["ftrack"]
else:
instance.data['families'] = ['ftrack']
self.log.debug("Instance '{}' doesn't match any profile".format(
instance.data.get("family")))
def _get_add_ftrack_f_from_addit_filters(self,
additional_filters,
families,
add_ftrack_family):
"""
Compares additional filters - working on instance's families.
Triggered for more detailed filtering when main family matches,
but content of 'families' actually matter.
(For example 'review' in 'families' should result in adding to
Ftrack)
Args:
additional_filters (dict) - from Setting
families (list) - subfamilies
add_ftrack_family (bool) - add ftrack to families if True
"""
override_filter = None
override_filter_value = -1
for additional_filter in additional_filters:
filter_families = set(additional_filter["families"])
valid = filter_families <= set(families) # issubset
if not valid:
continue
value = len(filter_families)
if value > override_filter_value:
override_filter = additional_filter
override_filter_value = value
if override_filter:
add_ftrack_family = override_filter["add_ftrack_family"]
return add_ftrack_family

View file

@ -200,6 +200,68 @@
}
},
"publish": {
"CollectFtrackFamily": {
"enabled": true,
"profiles": [
{
"hosts": [
"standalonepublisher"
],
"families": [],
"tasks": [],
"add_ftrack_family": true,
"advanced_filtering": []
},
{
"hosts": [
"standalonepublisher"
],
"families": [
"matchmove",
"shot"
],
"tasks": [],
"add_ftrack_family": false,
"advanced_filtering": []
},
{
"hosts": [
"standalonepublisher"
],
"families": [
"review",
"plate"
],
"tasks": [],
"add_ftrack_family": false,
"advanced_filtering": [
{
"families": [
"clip",
"review"
],
"add_ftrack_family": true
}
]
},
{
"hosts": [
"maya"
],
"families": [
"model",
"setdress",
"animation",
"look",
"rig",
"camera"
],
"tasks": [],
"add_ftrack_family": true,
"advanced_filtering": []
}
]
},
"IntegrateFtrackNote": {
"enabled": true,
"note_with_intent_template": "{intent}: {comment}",

View file

@ -105,16 +105,23 @@
"label": "Render",
"family": "render",
"icon": "image",
"defaults": ["Animation", "Lighting", "Lookdev", "Compositing"],
"defaults": [
"Animation",
"Lighting",
"Lookdev",
"Compositing"
],
"help": "Rendered images or video files"
},
"create_mov_batch": {
"name": "mov_batch",
"label": "Batch Mov",
"family": "render_mov_batch",
"icon": "image",
"defaults": ["Main"],
"help": "Process multiple Mov files and publish them for layout and comp."
"name": "mov_batch",
"label": "Batch Mov",
"family": "render_mov_batch",
"icon": "image",
"defaults": [
"Main"
],
"help": "Process multiple Mov files and publish them for layout and comp."
},
"__dynamic_keys_labels__": {
"create_workfile": "Workfile",

View file

@ -1,5 +1,13 @@
{
"publish": {
"ExtractSequence": {
"review_bg": [
255,
255,
255,
255
]
},
"ValidateProjectSettings": {
"enabled": true,
"optional": true,

View file

@ -101,6 +101,7 @@ from .color_entity import ColorEntity
from .enum_entity import (
BaseEnumEntity,
EnumEntity,
HostsEnumEntity,
AppsEnumEntity,
ToolsEnumEntity,
TaskTypeEnumEntity,
@ -153,6 +154,7 @@ __all__ = (
"BaseEnumEntity",
"EnumEntity",
"HostsEnumEntity",
"AppsEnumEntity",
"ToolsEnumEntity",
"TaskTypeEnumEntity",

View file

@ -101,6 +101,78 @@ class EnumEntity(BaseEnumEntity):
super(EnumEntity, self).schema_validations()
class HostsEnumEntity(BaseEnumEntity):
"""Enumeration of host names.
Enum items are hardcoded in definition of the entity.
Hosts enum can have defined empty value as valid option which is
represented by empty string. Schema key to set this option is
`use_empty_value` (true/false). And to set label of empty value set
`empty_label` (string).
Enum can have single and multiselection.
NOTE:
Host name is not the same as application name. Host name defines
implementation instead of application name.
"""
schema_types = ["hosts-enum"]
def _item_initalization(self):
self.multiselection = self.schema_data.get("multiselection", True)
self.use_empty_value = self.schema_data.get(
"use_empty_value", not self.multiselection
)
custom_labels = self.schema_data.get("custom_labels") or {}
host_names = [
"aftereffects",
"blender",
"celaction",
"fusion",
"harmony",
"hiero",
"houdini",
"maya",
"nuke",
"photoshop",
"resolve",
"tvpaint",
"unreal"
]
if self.use_empty_value:
host_names.insert(0, "")
# Add default label for empty value if not available
if "" not in custom_labels:
custom_labels[""] = "< without host >"
# These are hardcoded there is not list of available host in OpenPype
enum_items = []
valid_keys = set()
for key in host_names:
label = custom_labels.get(key, key)
valid_keys.add(key)
enum_items.append({key: label})
self.enum_items = enum_items
self.valid_keys = valid_keys
if self.multiselection:
self.valid_value_types = (list, )
self.value_on_not_set = []
else:
for key in valid_keys:
if self.value_on_not_set is NOT_SET:
self.value_on_not_set = key
break
self.valid_value_types = (STRING_TYPE, )
# GUI attribute
self.placeholder = self.schema_data.get("placeholder")
class AppsEnumEntity(BaseEnumEntity):
schema_types = ["apps-enum"]

View file

@ -272,6 +272,25 @@
}
```
### hosts-enum
- enumeration of available hosts
- multiselection can be allowed with setting key `"multiselection"` to `True` (Default: `False`)
- it is possible to add empty value (represented with empty string) with setting `"use_empty_value"` to `True` (Default: `False`)
- it is possible to set `"custom_labels"` for host names where key `""` is empty value (Default: `{}`)
```
{
"key": "host",
"label": "Host name",
"type": "hosts-enum",
"multiselection": false,
"use_empty_value": true,
"custom_labels": {
"": "N/A",
"nuke": "Nuke"
}
}
```
## Inputs for setting value using Pure inputs
- these inputs also have required `"key"`
- attribute `"label"` is required in few conditions

View file

@ -604,6 +604,82 @@
"key": "publish",
"label": "Publish plugins",
"children": [
{
"type": "dict",
"collapsible": true,
"checkbox_key": "enabled",
"key": "CollectFtrackFamily",
"label": "Collect Ftrack Family",
"is_group": true,
"children": [
{
"type": "boolean",
"key": "enabled",
"label": "Enabled"
},
{
"type": "list",
"collapsible": true,
"key": "profiles",
"label": "Profiles",
"use_label_wrap": true,
"object_type": {
"type": "dict",
"children": [
{
"key": "hosts",
"label": "Host names",
"type": "list",
"object_type": "text"
},
{
"key": "families",
"label": "Families",
"type": "list",
"object_type": "text"
},
{
"key": "tasks",
"label": "Task names",
"type": "list",
"object_type": "text"
},
{
"type": "separator"
},
{
"key": "add_ftrack_family",
"label": "Add Ftrack Family",
"type": "boolean"
},
{
"type": "list",
"collapsible": true,
"key": "advanced_filtering",
"label": "Advanced adding if additional families present",
"use_label_wrap": true,
"object_type": {
"type": "dict",
"children": [
{
"key": "families",
"label": "Additional Families",
"type": "list",
"object_type": "text"
},
{
"key": "add_ftrack_family",
"label": "Add Ftrack Family",
"type": "boolean"
}
]
}
}
]
}
}
]
},
{
"type": "dict",
"collapsible": true,

View file

@ -59,10 +59,10 @@
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Host names",
"type": "list",
"object_type": "text"
"multiselection": true
},
{
"type": "separator"

View file

@ -11,6 +11,25 @@
"key": "publish",
"label": "Publish plugins",
"children": [
{
"type": "dict",
"collapsible": true,
"key": "ExtractSequence",
"label": "ExtractSequence",
"is_group": true,
"children": [
{
"type": "label",
"label": "<b>Review BG color</b> is used for whole scene review and for thumbnails."
},
{
"type": "color",
"key": "review_bg",
"label": "Review BG color",
"use_alpha": false
}
]
},
{
"type": "schema_template",
"name": "template_publish_plugin",

View file

@ -90,10 +90,10 @@
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"type": "list",
"object_type": "text"
"multiselection": true
},
{
"type": "splitter"
@ -358,10 +358,10 @@
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"type": "list",
"object_type": "text"
"multiselection": true
},
{
"type": "splitter"
@ -492,10 +492,10 @@
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"type": "list",
"object_type": "text"
"multiselection": true
},
{
"key": "tasks",

View file

@ -35,10 +35,10 @@
"object_type": "text"
},
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"type": "list",
"object_type": "text"
"multiselection": true
},
{
"key": "tasks",
@ -75,10 +75,10 @@
"type": "dict",
"children": [
{
"type": "hosts-enum",
"key": "hosts",
"label": "Hosts",
"type": "list",
"object_type": "text"
"multiselection": true
},
{
"key": "tasks",

View file

@ -14,25 +14,11 @@
"roles": ["developer"]
},
{
"type": "enum",
"type": "hosts-enum",
"key": "host_name",
"label": "Host implementation",
"enum_items": [
{ "": "< without host >" },
{ "aftereffects": "aftereffects" },
{ "blender": "blender" },
{ "celaction": "celaction" },
{ "fusion": "fusion" },
{ "harmony": "harmony" },
{ "hiero": "hiero" },
{ "houdini": "houdini" },
{ "maya": "maya" },
{ "nuke": "nuke" },
{ "photoshop": "photoshop" },
{ "resolve": "resolve" },
{ "tvpaint": "tvpaint" },
{ "unreal": "unreal" }
],
"multiselection": false,
"use_empty_value": true,
"roles": ["developer"]
}
]

2
poetry.lock generated
View file

@ -11,7 +11,7 @@ develop = false
type = "git"
url = "https://github.com/pypeclub/acre.git"
reference = "master"
resolved_reference = "efc1b8faa8f84568538b936688ae6f7604dd194c"
resolved_reference = "68784b7eb5b7bb5f409b61ab31d4403878a3e1b7"
[[package]]
name = "aiohttp"

View file

@ -14,7 +14,7 @@ All of them are Project based, eg. each project could have different configurati
Location: Settings > Project > AfterEffects
![Harmony Project Settings](assets/admin_hosts_aftereffects_settings.png)
![AfterEffects Project Settings](assets/admin_hosts_aftereffects_settings.png)
## Publish plugins

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -196,7 +196,7 @@ Is used to remove value from `Avalon/Mongo Id` Custom Attribute when entity is c
### Sync status from Task to Parent
List of parent boject types where this is triggered ("Shot", "Asset build", etc. Skipped if it is empty)
List of parent object types where this is triggered ("Shot", "Asset build", etc. Skipped if it is empty)
### Sync status from Version to Task
@ -214,3 +214,29 @@ This is usefull for example if first version publish doesn't contain any actual
### Update status on next task
Change status on next task by task types order when task status state changed to "Done". All tasks with the same Task mapping of next task status changes From → To. Some status can be ignored.
## Publish plugins
### Collect Ftrack Family
Reviews uploads to Ftrack could be configured by combination of hosts, families and task names.
(Currently implemented only in Standalone Publisher, Maya.)
#### Profiles
Profiles are used to select when to add Ftrack family to the instance. One or multiple profiles could be configured, Families, Task names (regex available), Host names combination is needed.
Eg. If I want review created and uploaded to Ftrack for render published from Maya , setting is:
Host names: 'Maya'
Families: 'render'
Add Ftrack Family: enabled
![Collect Ftrack Family](assets/ftrack/ftrack-collect-main.png)
#### Advanced adding if additional families present
In special cases adding 'ftrack' based on main family ('Families' set higher) is not enough.
(For example upload to Ftrack for 'plate' main family should only happen if 'review' is contained in instance 'families', not added in other cases. )
![Collect Ftrack Family](assets/ftrack/ftrack-collect-advanced.png)