Skip to content

Commit

Permalink
Merge pull request #30 from ynput/bugfix/AY-6259_14_flame-vertical-al…
Browse files Browse the repository at this point in the history
…ignment-not-identifying-hierotracks

Fixing multiple `:` split issue and others small issues
  • Loading branch information
tatiana-ynput authored Nov 15, 2024
2 parents 58e2d02 + 7754b2a commit 2f1b4d6
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 57 deletions.
10 changes: 5 additions & 5 deletions client/ayon_flame/api/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ def get_segment_attributes(segment):
"tape_name": segment.tape_name,
"source_name": segment.source_name,
"fpath": segment.file_path,
"PySegment": segment
"PySegment": segment,
}

# head and tail with forward compatibility
Expand Down Expand Up @@ -1154,17 +1154,17 @@ def _get_resolution_info_from_origin(self, xml_data):
for out_feed in out_track.iter("feed"):
# width
out_feed_width_obj = out_feed.find("storageFormat/width")
self.width = self._get_typed_value(out_feed_width_obj)
self.width = int(self._get_typed_value(out_feed_width_obj))

# height
out_feed_height_obj = out_feed.find("storageFormat/height")
self.height = self._get_typed_value(out_feed_height_obj)
self.height = int(self._get_typed_value(out_feed_height_obj))

# pixel aspect ratio
out_feed_pixel_aspect_obj = out_feed.find(
"storageFormat/pixelRatio")
self.pixel_aspect = self._get_typed_value(
out_feed_pixel_aspect_obj)
self.pixel_aspect = float(
self._get_typed_value(out_feed_pixel_aspect_obj))
break
except Exception as msg:
self.log.warning(msg)
Expand Down
109 changes: 79 additions & 30 deletions client/ayon_flame/api/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import shutil
from copy import deepcopy
from xml.etree import ElementTree as ET
from pprint import pformat

import qargparse
from qtpy import QtCore, QtWidgets
Expand Down Expand Up @@ -277,8 +278,11 @@ def populate_widgets(self, data, content_layout=None):
elif v["type"] == "QSpinBox":
data[k]["value"] = self.create_row(
content_layout, "QSpinBox", v["label"],
setValue=v["value"], setMinimum=0,
setMaximum=100000, setToolTip=tool_tip)
setMaximum=100000,
setMinimum=0,
setValue=v["value"],
setToolTip=tool_tip,
)
return data


Expand Down Expand Up @@ -337,6 +341,7 @@ class PublishableClip:
flame.PySegment: flame api object
"""
vertical_clip_match = {}
vertical_clip_used = {}
marker_data = {}
types = {
"shot": "shot",
Expand Down Expand Up @@ -377,6 +382,8 @@ def __init__(self, segment, **kwargs):
self.sequence_name = str(sequence_name).replace(" ", "_")

self.clip_data = flib.get_segment_attributes(segment)
self.log.debug(f"clip_data: {pformat(self.clip_data)}")

# segment (clip) main attributes
self.cs_name = self.clip_data["segment_name"]
self.cs_index = int(self.clip_data["segment"])
Expand All @@ -385,8 +392,13 @@ def __init__(self, segment, **kwargs):
# get track name and index
self.track_index = int(self.clip_data["track"])
track_name = self.clip_data["track_name"]
self.track_name = str(track_name).replace(" ", "_").replace(
"*", "noname{}".format(self.track_index))
self.track_name = (
# make sure no space and other special characters are in track name
# default track name is `*`
str(track_name)
.replace(" ", "_")
.replace("*", f"noname{self.track_index}")
)

if kwargs.get("basicProductData"):
self.marker_data.update(kwargs["basicProductData"])
Expand All @@ -397,9 +409,7 @@ def __init__(self, segment, **kwargs):
# adding ui inputs if any
self.ui_inputs = kwargs.get("ui_inputs", {})

self.log.info("Inside of plugin: {}".format(
self.marker_data
))
self.log.info(f"Inside of plugin: {self.marker_data}")
# populate default data before we get other attributes
self._populate_segment_default_data()

Expand Down Expand Up @@ -479,8 +489,7 @@ def _populate_attributes(self):

# define ui inputs if non gui mode was used
self.shot_num = self.cs_index
self.log.debug(
"____ self.shot_num: {}".format(self.shot_num))
self.log.debug(f"____ self.shot_num: {self.shot_num}")

# ui_inputs data or default values if gui was not used
self.rename = self.ui_inputs.get(
Expand Down Expand Up @@ -612,29 +621,69 @@ def _convert_to_marker_data(self):

if not hero_track and self.vertical_sync:
# driving layer is set as negative match
for (_in, _out), hero_data in self.vertical_clip_match.items():
"""
Since only one instance of hero clip is expected in
`self.vertical_clip_match`, this will loop only once
until none hero clip will be matched with hero clip.
for (hero_in, hero_out), hero_data in self.vertical_clip_match.items(): # noqa
""" Iterate over all clips in vertical sync match
`tag_hierarchy_data` will be set only once for every
clip which is not hero clip.
If clip frame range is outside of hero clip frame range
then skip this clip and do not add to hierarchical shared
metadata to them.
"""
_hero_data = deepcopy(hero_data)
_hero_data.update({"heroTrack": False})
if _in <= self.clip_in and _out >= self.clip_out:
data_product_name = hero_data["productName"]
# add track index in case duplicity of names in hero data
if self.product_name in data_product_name:
_hero_data["productName"] = self.product_name + str(
self.track_index)
# in case track name and product name is the same then add
if self.base_product_name == self.track_name:
_hero_data["productName"] = self.product_name
# assign data to return hierarchy data to tag
tag_hierarchy_data = _hero_data
break

if self.clip_in < hero_in or self.clip_out > hero_out:
continue

_distrib_data = deepcopy(hero_data)
_distrib_data["heroTrack"] = False
# form used clip unique key
data_product_name = hero_data["productName"]
new_clip_name = hero_data["newClipName"]

# get used names list for duplicity check
used_names_list = self.vertical_clip_used.setdefault(
f"{new_clip_name}{data_product_name}", []
)
self.log.debug(
f">> used_names_list: {used_names_list}"
)
clip_product_name = self.product_name
self.log.debug(
f">> clip_product_name: {clip_product_name}")

# in case track name and product name is the same then add
if self.base_product_name == self.track_name:
clip_product_name = self.product_name

# add track index in case duplicity of names in hero data
# INFO: this is for case where hero clip product name
# is the same as current clip product name
if clip_product_name == data_product_name:
clip_product_name = (
f"{clip_product_name}{self.track_index}")

# in case track clip product name had been already used
# then add product name with clip index
if clip_product_name in used_names_list:
_clip_product_name = (
f"{clip_product_name}{self.cs_index}"
)
# just in case lets validate if new name is not used
# in case the track_index is the same as clip_index
if _clip_product_name in used_names_list:
_clip_product_name = (
f"{clip_product_name}"
f"{self.track_index}{self.cs_index}"
)
clip_product_name = _clip_product_name

self.log.debug(
f">> clip_product_name: {clip_product_name}")
_distrib_data["productName"] = clip_product_name
# assign data to return hierarchy data to tag
tag_hierarchy_data = _distrib_data

# add used product name to used list to avoid duplicity
used_names_list.append(clip_product_name)
break

# add data to return data dict
self.marker_data.update(tag_hierarchy_data)
Expand Down
2 changes: 1 addition & 1 deletion client/ayon_flame/hooks/pre_flame_setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ def execute(self):
self.flame_python_exe = _env["AYON_FLAME_PYTHON_EXEC"]

# add it to data for other hooks
self.data["fusion_python_executable"] = self.flame_python_exe
self.data["flame_python_executable"] = self.flame_python_exe

self.flame_pythonpath = _env["AYON_FLAME_PYTHONPATH"]

Expand Down
2 changes: 1 addition & 1 deletion client/ayon_flame/hooks/pre_opentimelineio_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ def execute(self):
def inner_execute(self):
self.log.debug("Check for OpenTimelineIO installation.")

flame_py_exe = self.data.get("fusion_python_executable")
flame_py_exe = self.data.get("flame_python_executable")
if not flame_py_exe:
self.log.warning("Flame python executable not found.")
return
Expand Down
2 changes: 1 addition & 1 deletion client/ayon_flame/otio/flame_export.py
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ def _create_otio_timeline(sequence):
metadata.update({
"ayon.timeline.width": int(sequence.width),
"ayon.timeline.height": int(sequence.height),
"ayon.timeline.pixelAspect": 1
"ayon.timeline.pixelAspect": float(1)
})

rt_start_time = create_otio_rational_time(
Expand Down
2 changes: 1 addition & 1 deletion client/ayon_flame/plugins/create/create_shot_clip.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ def process(self):
"log": self.log,
"ui_inputs": results_back,
"basicProductData": self.data,
"productType": self.data["productType"]
"productType": self.data["productType"],
}

for i, segment in enumerate(sorted_selected_segments):
Expand Down
51 changes: 34 additions & 17 deletions client/ayon_flame/plugins/publish/collect_timeline_instances.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
from pprint import pformat

# constatns
NUM_PATERN = re.compile(r"([0-9\.]+)")
TXT_PATERN = re.compile(r"([a-zA-Z]+)")
NUM_PATTERN = re.compile(r"([0-9\.]+)")
TXT_PATTERN = re.compile(r"([a-zA-Z]+)")


class CollectTimelineInstances(pyblish.api.ContextPlugin):
Expand Down Expand Up @@ -209,13 +209,18 @@ def _get_comment_attributes(self, segment):
"pixelRatio": 1.00}
}
# search for `:`
# INFO: clip based overrides needs to have specific format
# `key: value` separated `,` or `;`. This is for cases where we
# need to override resolution, aspect ratio, etc. per clip.
for split in self._split_comments(comment):
self.log.debug(f"__ split: {split}")

# make sure we ignore if not `:` in key
if ":" not in split:
# of if there is more than one `:` in key
if split.count(":") != 1:
continue

self._get_xml_preset_attrs(
attributes, split)
self._get_xml_preset_attrs(attributes, split)

# add xml overrides resolution to instance data
xml_overrides = attributes["xml_overrides"]
Expand All @@ -229,6 +234,18 @@ def _get_comment_attributes(self, segment):
return attributes

def _get_xml_preset_attrs(self, attributes, split):
"""Helper function to get xml preset attributes from comments
Example of comment:
`resolution:1920x1080;pixelRatio:1.5`
Args:
attributes (dict): attributes dict to update
split (str): string to split
Returns:
None
"""

# split to key and value
key, value = split.split(":")
Expand All @@ -242,36 +259,36 @@ def _get_xml_preset_attrs(self, attributes, split):
continue

# get pattern defined by type
pattern = TXT_PATERN
pattern = TXT_PATTERN
if a_type in ("number", "float"):
pattern = NUM_PATERN
pattern = NUM_PATTERN

res_goup = pattern.findall(value)
res_group = pattern.findall(value)

# raise if nothing is found as it is not correctly defined
if not res_goup:
if not res_group:
raise ValueError((
"Value for `{}` attribute is not "
"set correctly: `{}`").format(a_name, split))

if "string" in a_type:
_value = res_goup[0]
_value = res_group[0]
if "float" in a_type:
_value = float(res_goup[0])
_value = float(res_group[0])
if "number" in a_type:
_value = int(res_goup[0])
_value = int(res_group[0])

attributes["xml_overrides"][a_name] = _value

# condition for resolution in key
if "resolution" in key.lower():
res_goup = NUM_PATERN.findall(value)
# check if axpect was also defined
res_group = NUM_PATTERN.findall(value)
# check if aspect was also defined
# 1920x1080x1.5
aspect = res_goup[2] if len(res_goup) > 2 else 1
aspect = res_group[2] if len(res_group) > 2 else float(1)

width = int(res_goup[0])
height = int(res_goup[1])
width = int(res_group[0])
height = int(res_group[1])
pixel_ratio = float(aspect)
attributes["xml_overrides"].update({
"width": width,
Expand Down
1 change: 0 additions & 1 deletion client/ayon_flame/plugins/publish/collect_timeline_otio.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def process(self, context):
with ayfapi.maintained_segment_selection(sequence) as selected_seg:
otio_timeline = flame_export.create_otio_timeline(sequence)


# update context with main project attributes
timeline_data = {
"flameProject": project,
Expand Down

0 comments on commit 2f1b4d6

Please sign in to comment.