unreal use folder and task entity

This commit is contained in:
Jakub Trllo 2024-03-04 16:41:46 +01:00
parent 92ce8956c4
commit 69819879a5
12 changed files with 159 additions and 103 deletions

View file

@ -4,12 +4,12 @@ import json
import logging
from typing import List
from contextlib import contextmanager
import semver
import time
import semver
import pyblish.api
import ayon_api
from ayon_core.client import get_asset_by_name, get_assets
from ayon_core.pipeline import (
register_loader_plugin_path,
register_creator_plugin_path,
@ -601,34 +601,36 @@ def generate_sequence(h, h_dir):
)
project_name = get_current_project_name()
asset_data = get_asset_by_name(
# TODO Fix this does not return folder path
folder_path = h_dir.split('/')[-1],
folder_entity = ayon_api.get_folder_by_path(
project_name,
h_dir.split('/')[-1],
fields=["_id", "data.fps"]
folder_path,
fields={"id", "attrib.fps"}
)
start_frames = []
end_frames = []
elements = list(get_assets(
elements = list(ayon_api.get_folders(
project_name,
parent_ids=[asset_data["_id"]],
fields=["_id", "data.clipIn", "data.clipOut"]
parent_ids=[folder_entity["id"]],
fields={"id", "attrib.clipIn", "attrib.clipOut"}
))
for e in elements:
start_frames.append(e.get('data').get('clipIn'))
end_frames.append(e.get('data').get('clipOut'))
start_frames.append(e["attrib"].get("clipIn"))
end_frames.append(e["attrib"].get("clipOut"))
elements.extend(get_assets(
elements.extend(ayon_api.get_folders(
project_name,
parent_ids=[e["_id"]],
fields=["_id", "data.clipIn", "data.clipOut"]
parent_ids=[e["id"]],
fields={"id", "attrib.clipIn", "attrib.clipOut"}
))
min_frame = min(start_frames)
max_frame = max(end_frames)
fps = asset_data.get('data').get("fps")
fps = folder_entity["attrib"].get("fps")
sequence.set_display_rate(
unreal.FrameRate(fps, 1.0))

View file

@ -70,10 +70,12 @@ class AnimationAlembicLoader(plugin.Loader):
# Create directory for asset and ayon container
root = unreal_pipeline.AYON_ASSET_DIR
asset = context.get('asset').get('name')
folder_name = context["folder"]["name"]
folder_path = context["folder"]["path"]
product_type = context["representation"]["context"]["family"]
suffix = "_CON"
if asset:
asset_name = "{}_{}".format(asset, name)
if folder_name:
asset_name = "{}_{}".format(folder_name, name)
else:
asset_name = "{}".format(name)
version = context.get('version')
@ -85,7 +87,7 @@ class AnimationAlembicLoader(plugin.Loader):
tools = unreal.AssetToolsHelpers().get_asset_tools()
asset_dir, container_name = tools.create_unique_asset_name(
f"{root}/{asset}/{name_version}", suffix="")
f"{root}/{folder_name}/{name_version}", suffix="")
container_name += suffix
@ -105,14 +107,16 @@ class AnimationAlembicLoader(plugin.Loader):
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"asset": folder_path,
"folder_path": folder_path,
"namespace": asset_dir,
"container_name": container_name,
"asset_name": asset_name,
"loader": str(self.__class__.__name__),
"representation": context["representation"]["_id"],
"parent": context["representation"]["parent"],
"family": context["representation"]["context"]["family"]
"family": product_type,
"product_type": product_type,
}
unreal_pipeline.imprint(
f"{asset_dir}/{container_name}", data)

View file

@ -8,7 +8,7 @@ from unreal import EditorAssetLibrary
from unreal import MovieSceneSkeletalAnimationTrack
from unreal import MovieSceneSkeletalAnimationSection
from ayon_core.pipeline.context_tools import get_current_project_asset
from ayon_core.pipeline.context_tools import get_current_project_folder
from ayon_core.pipeline import (
get_representation_path,
AYON_CONTAINER_ID
@ -53,7 +53,7 @@ class AnimationFBXLoader(plugin.Loader):
if not actor:
return None
asset_doc = get_current_project_asset(fields=["data.fps"])
folder_entity = get_current_project_folder(fields=["attrib.fps"])
task.set_editor_property('filename', path)
task.set_editor_property('destination_path', asset_dir)
@ -82,7 +82,7 @@ class AnimationFBXLoader(plugin.Loader):
task.options.anim_sequence_import_data.set_editor_property(
'use_default_sample_rate', False)
task.options.anim_sequence_import_data.set_editor_property(
'custom_sample_rate', asset_doc.get("data", {}).get("fps"))
'custom_sample_rate', folder_entity.get("attrib", {}).get("fps"))
task.options.anim_sequence_import_data.set_editor_property(
'import_custom_attribute', True)
task.options.anim_sequence_import_data.set_editor_property(
@ -250,7 +250,7 @@ class AnimationFBXLoader(plugin.Loader):
repre_doc = context["representation"]
folder_name = container["asset_name"]
source_path = get_representation_path(repre_doc)
asset_doc = get_current_project_asset(fields=["data.fps"])
folder_entity = get_current_project_folder(fields=["attrib.fps"])
destination_path = container["namespace"]
task = unreal.AssetImportTask()
@ -284,7 +284,7 @@ class AnimationFBXLoader(plugin.Loader):
task.options.anim_sequence_import_data.set_editor_property(
'use_default_sample_rate', False)
task.options.anim_sequence_import_data.set_editor_property(
'custom_sample_rate', asset_doc.get("data", {}).get("fps"))
'custom_sample_rate', folder_entity.get("attrib", {}).get("fps"))
task.options.anim_sequence_import_data.set_editor_property(
'import_custom_attribute', True)
task.options.anim_sequence_import_data.set_editor_property(

View file

@ -2,6 +2,8 @@
"""Load camera from FBX."""
from pathlib import Path
import ayon_api
import unreal
from unreal import (
EditorAssetLibrary,
@ -9,7 +11,6 @@ from unreal import (
EditorLevelUtils,
LevelSequenceEditorBlueprintLibrary as LevelSequenceLib,
)
from ayon_core.client import get_asset_by_name
from ayon_core.pipeline import (
AYON_CONTAINER_ID,
get_current_project_name,
@ -83,24 +84,33 @@ class CameraLoader(plugin.Loader):
"""
# Create directory for asset and Ayon container
hierarchy = context.get('asset').get('data').get('parents')
folder_entity = context["folder"]
folder_attributes = folder_entity["attrib"]
folder_path = folder_entity["path"]
hierarchy_parts = folder_path.split("/")
# Remove empty string
hierarchy_parts.pop(0)
# Pop folder name
folder_name = hierarchy_parts.pop(-1)
root = "/Game/Ayon"
hierarchy_dir = root
hierarchy_dir_list = []
for h in hierarchy:
for h in hierarchy_parts:
hierarchy_dir = f"{hierarchy_dir}/{h}"
hierarchy_dir_list.append(hierarchy_dir)
asset = context.get('asset').get('name')
suffix = "_CON"
asset_name = f"{asset}_{name}" if asset else f"{name}"
asset_name = f"{folder_name}_{name}" if folder_name else name
tools = unreal.AssetToolsHelpers().get_asset_tools()
# Create a unique name for the camera directory
unique_number = 1
if EditorAssetLibrary.does_directory_exist(f"{hierarchy_dir}/{asset}"):
if EditorAssetLibrary.does_directory_exist(
f"{hierarchy_dir}/{folder_name}"
):
asset_content = EditorAssetLibrary.list_assets(
f"{root}/{asset}", recursive=False, include_folder=True
f"{root}/{folder_name}", recursive=False, include_folder=True
)
# Get highest number to make a unique name
@ -113,7 +123,7 @@ class CameraLoader(plugin.Loader):
unique_number = f_numbers[-1] + 1 if f_numbers else 1
asset_dir, container_name = tools.create_unique_asset_name(
f"{hierarchy_dir}/{asset}/{name}_{unique_number:02d}", suffix="")
f"{hierarchy_dir}/{folder_name}/{name}_{unique_number:02d}", suffix="")
container_name += suffix
@ -122,14 +132,18 @@ class CameraLoader(plugin.Loader):
# Create map for the shot, and create hierarchy of map. If the maps
# already exist, we will use them.
h_dir = hierarchy_dir_list[0]
h_asset = hierarchy[0]
h_asset = hierarchy_dir[0]
master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map"
if not EditorAssetLibrary.does_asset_exist(master_level):
EditorLevelLibrary.new_level(f"{h_dir}/{h_asset}_map")
level = f"{asset_dir}/{asset}_map_camera.{asset}_map_camera"
level = (
f"{asset_dir}/{folder_name}_map_camera.{folder_name}_map_camera"
)
if not EditorAssetLibrary.does_asset_exist(level):
EditorLevelLibrary.new_level(f"{asset_dir}/{asset}_map_camera")
EditorLevelLibrary.new_level(
f"{asset_dir}/{folder_name}_map_camera"
)
EditorLevelLibrary.load_level(master_level)
EditorLevelUtils.add_level_to_world(
@ -144,7 +158,7 @@ class CameraLoader(plugin.Loader):
# they don't exist.
frame_ranges = []
sequences = []
for (h_dir, h) in zip(hierarchy_dir_list, hierarchy):
for (h_dir, h) in zip(hierarchy_dir_list, hierarchy_parts):
root_content = EditorAssetLibrary.list_assets(
h_dir, recursive=False, include_folder=False)
@ -170,7 +184,7 @@ class CameraLoader(plugin.Loader):
EditorAssetLibrary.make_directory(asset_dir)
cam_seq = tools.create_asset(
asset_name=f"{asset}_camera",
asset_name=f"{folder_name}_camera",
package_path=asset_dir,
asset_class=unreal.LevelSequence,
factory=unreal.LevelSequenceFactoryNew()
@ -184,16 +198,17 @@ class CameraLoader(plugin.Loader):
frame_ranges[i + 1][0], frame_ranges[i + 1][1],
[level])
project_name = get_current_project_name()
data = get_asset_by_name(project_name, asset)["data"]
clip_in = folder_attributes.get("clipIn")
clip_out = folder_attributes.get("clipOut")
cam_seq.set_display_rate(
unreal.FrameRate(data.get("fps"), 1.0))
cam_seq.set_playback_start(data.get('clipIn'))
cam_seq.set_playback_end(data.get('clipOut') + 1)
unreal.FrameRate(folder_attributes.get("fps"), 1.0))
cam_seq.set_playback_start(clip_in)
cam_seq.set_playback_end(clip_out + 1)
set_sequence_hierarchy(
sequences[-1], cam_seq,
frame_ranges[-1][1],
data.get('clipIn'), data.get('clipOut'),
clip_in, clip_out,
[level])
settings = unreal.MovieSceneUserImportFBXSettings()
@ -215,9 +230,7 @@ class CameraLoader(plugin.Loader):
for possessable in cam_seq.get_possessables():
for tracks in possessable.get_tracks():
for section in tracks.get_sections():
section.set_range(
data.get('clipIn'),
data.get('clipOut') + 1)
section.set_range(clip_in, clip_out + 1)
for channel in section.get_all_channels():
for key in channel.get_keys():
old_time = key.get_time().get_editor_property(
@ -225,7 +238,7 @@ class CameraLoader(plugin.Loader):
old_time_value = old_time.get_editor_property(
'value')
new_time = old_time_value + (
data.get('clipIn') - data.get('frameStart')
clip_in - folder_attributes.get('frameStart')
)
key.set_time(unreal.FrameNumber(value=new_time))
@ -236,7 +249,8 @@ class CameraLoader(plugin.Loader):
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"asset": folder_name,
"folder_path": folder_path,
"namespace": asset_dir,
"container_name": container_name,
"asset_name": asset_name,

View file

@ -164,13 +164,12 @@ class PointCacheAlembicLoader(plugin.Loader):
return asset_content
def update(self, container, context):
asset_doc = context["asset"]
folder_name = context["asset"]["name"]
subset_doc = context["subset"]
version_doc = context["version"]
repre_doc = context["representation"]
# Create directory for asset and Ayon container
folder_name = asset_doc["name"]
product_name = subset_doc["name"]
suffix = "_CON"

View file

@ -15,8 +15,9 @@ from unreal import (
MovieSceneSubTrack,
LevelSequenceEditorBlueprintLibrary as LevelSequenceLib,
)
import ayon_api
from ayon_core.client import get_asset_by_name, get_representations
from ayon_core.client import get_representations
from ayon_core.pipeline import (
discover_loader_plugins,
loaders_from_representation,
@ -25,7 +26,7 @@ from ayon_core.pipeline import (
AYON_CONTAINER_ID,
get_current_project_name,
)
from ayon_core.pipeline.context_tools import get_current_project_asset
from ayon_core.pipeline.context_tools import get_current_project_folder
from ayon_core.settings import get_current_project_settings
from ayon_core.hosts.unreal.api import plugin
from ayon_core.hosts.unreal.api.pipeline import (
@ -169,7 +170,7 @@ class LayoutLoader(plugin.Loader):
anim_path = f"{asset_dir}/animations/{anim_file_name}"
asset_doc = get_current_project_asset()
folder_entity = get_current_project_folder()
# Import animation
task = unreal.AssetImportTask()
task.options = unreal.FbxImportUI()
@ -204,7 +205,7 @@ class LayoutLoader(plugin.Loader):
task.options.anim_sequence_import_data.set_editor_property(
'use_default_sample_rate', False)
task.options.anim_sequence_import_data.set_editor_property(
'custom_sample_rate', asset_doc.get("data", {}).get("fps"))
'custom_sample_rate', folder_entity.get("attrib", {}).get("fps"))
task.options.anim_sequence_import_data.set_editor_property(
'import_custom_attribute', True)
task.options.anim_sequence_import_data.set_editor_property(
@ -518,20 +519,25 @@ class LayoutLoader(plugin.Loader):
create_sequences = data["unreal"]["level_sequences_for_layouts"]
# Create directory for asset and Ayon container
hierarchy = context.get('asset').get('data').get('parents')
folder_entity = context["folder"]
folder_path = folder_entity["path"]
hierarchy = folder_path.lstrip("/").split("/")
# Remove folder name
folder_name = hierarchy.pop(-1)
root = self.ASSET_ROOT
hierarchy_dir = root
hierarchy_dir_list = []
for h in hierarchy:
hierarchy_dir = f"{hierarchy_dir}/{h}"
hierarchy_dir_list.append(hierarchy_dir)
asset = context.get('asset').get('name')
suffix = "_CON"
asset_name = f"{asset}_{name}" if asset else name
asset_name = f"{folder_name}_{name}" if folder_name else name
tools = unreal.AssetToolsHelpers().get_asset_tools()
asset_dir, container_name = tools.create_unique_asset_name(
"{}/{}/{}".format(hierarchy_dir, asset, name), suffix="")
"{}/{}/{}".format(hierarchy_dir, folder_name, name),
suffix=""
)
container_name += suffix
@ -541,8 +547,8 @@ class LayoutLoader(plugin.Loader):
shot = None
sequences = []
level = f"{asset_dir}/{asset}_map.{asset}_map"
EditorLevelLibrary.new_level(f"{asset_dir}/{asset}_map")
level = f"{asset_dir}/{folder_name}_map.{folder_name}_map"
EditorLevelLibrary.new_level(f"{asset_dir}/{folder_name}_map")
if create_sequences:
# Create map for the shot, and create hierarchy of map. If the
@ -591,7 +597,7 @@ class LayoutLoader(plugin.Loader):
e.get_asset().get_playback_end()))
shot = tools.create_asset(
asset_name=asset,
asset_name=folder_name,
package_path=asset_dir,
asset_class=unreal.LevelSequence,
factory=unreal.LevelSequenceFactoryNew()
@ -606,16 +612,24 @@ class LayoutLoader(plugin.Loader):
[level])
project_name = get_current_project_name()
data = get_asset_by_name(project_name, asset)["data"]
folder_attributes = (
ayon_api.get_folder_by_path(project_name, folder_path)["attrib"]
)
shot.set_display_rate(
unreal.FrameRate(data.get("fps"), 1.0))
unreal.FrameRate(folder_attributes.get("fps"), 1.0))
shot.set_playback_start(0)
shot.set_playback_end(data.get('clipOut') - data.get('clipIn') + 1)
shot.set_playback_end(
folder_attributes.get('clipOut')
- folder_attributes.get('clipIn')
+ 1
)
if sequences:
set_sequence_hierarchy(
sequences[-1], shot,
sequences[-1],
shot,
frame_ranges[-1][1],
data.get('clipIn'), data.get('clipOut'),
folder_attributes.get('clipIn'),
folder_attributes.get('clipOut'),
[level])
EditorLevelLibrary.load_level(level)
@ -635,7 +649,8 @@ class LayoutLoader(plugin.Loader):
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"asset": folder_name,
"folder_path": folder_path,
"namespace": asset_dir,
"container_name": container_name,
"asset_name": asset_name,
@ -678,17 +693,18 @@ class LayoutLoader(plugin.Loader):
asset_dir = container.get('namespace')
asset_doc = context["asset"]
folder_entity = context["folder"]
repre_doc = context["representation"]
hierarchy = list(asset_doc["data"]["parents"])
hierarchy = folder_entity["path"].lstrip("/").split("/")
first_parent_name = hierarchy[0]
sequence = None
master_level = None
if create_sequences:
h_dir = f"{root}/{hierarchy[0]}"
h_asset = hierarchy[0]
h_dir = f"{root}/{first_parent_name}"
h_asset = first_parent_name
master_level = f"{h_dir}/{h_asset}_map.{h_asset}_map"
filter = unreal.ARFilter(
@ -744,7 +760,7 @@ class LayoutLoader(plugin.Loader):
EditorLevelLibrary.save_current_level()
save_dir = f"{root}/{hierarchy[0]}" if create_sequences else asset_dir
save_dir = f"{root}/{first_parent_name}" if create_sequences else asset_dir
asset_content = EditorAssetLibrary.list_assets(
save_dir, recursive=True, include_folder=False)

View file

@ -3,6 +3,7 @@ from pathlib import Path
import unreal
from unreal import EditorLevelLibrary
import ayon_api
from ayon_core.client import get_representations
from ayon_core.pipeline import (
@ -11,7 +12,6 @@ from ayon_core.pipeline import (
load_container,
get_representation_path,
AYON_CONTAINER_ID,
get_current_project_name,
)
from ayon_core.hosts.unreal.api import plugin
from ayon_core.hosts.unreal.api import pipeline as upipeline
@ -43,11 +43,15 @@ class ExistingLayoutLoader(plugin.Loader):
@staticmethod
def _create_container(
asset_name, asset_dir, asset, representation, parent, family
asset_name,
asset_dir,
folder_path,
representation,
version_id,
product_type
):
container_name = f"{asset_name}_CON"
container = None
if not unreal.EditorAssetLibrary.does_asset_exist(
f"{asset_dir}/{container_name}"
):
@ -61,14 +65,16 @@ class ExistingLayoutLoader(plugin.Loader):
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"asset": folder_path,
"folder_path": folder_path,
"namespace": asset_dir,
"container_name": container_name,
"asset_name": asset_name,
# "loader": str(self.__class__.__name__),
"representation": representation,
"parent": parent,
"family": family
"parent": version_id,
"family": product_type,
"product_type": product_type,
}
upipeline.imprint(
@ -248,17 +254,27 @@ class ExistingLayoutLoader(plugin.Loader):
layout_data.append((repre_doc, element))
version_ids.add(repre_doc["parent"])
repre_parents_by_id = ayon_api.get_representation_parents(
project_name, repre_docs_by_id.keys()
)
# Prequery valid repre documents for all elements at once
valid_repre_doc_by_version_id = self._get_valid_repre_docs(
project_name, version_ids)
containers = []
actors_matched = []
for (repr_data, lasset) in layout_data:
for (repre_doc, lasset) in layout_data:
# For every actor in the scene, check if it has a representation in
# those we got from the JSON. If so, create a container for it.
# Otherwise, remove it from the scene.
found = False
repre_id = repre_doc["_id"]
repre_parents = repre_parents_by_id[repre_id]
folder_path = repre_parents.folder["path"]
folder_name = repre_parents.folder["name"]
product_name = repre_parents.product["name"]
product_type = repre_parents.product["productType"]
for actor in actors:
if not actor.get_class().get_name() == 'StaticMeshActor':
@ -275,7 +291,7 @@ class ExistingLayoutLoader(plugin.Loader):
path = Path(filename)
if (not path.name or
path.name not in repr_data.get('data').get('path')):
path.name not in repre_doc["data"]["path"]):
continue
actor.set_actor_label(lasset.get('instance_name'))
@ -283,12 +299,13 @@ class ExistingLayoutLoader(plugin.Loader):
mesh_path = Path(mesh.get_path_name()).parent.as_posix()
# Create the container for the asset.
asset = repr_data.get('context').get('asset')
product_name = repr_data.get('context').get('subset')
container = self._create_container(
f"{asset}_{product_name}", mesh_path, asset,
repr_data.get('_id'), repr_data.get('parent'),
repr_data.get('context').get('family')
f"{folder_name}_{product_name}",
mesh_path,
folder_path,
repre_doc["_id"],
repre_doc["parent"],
product_type
)
containers.append(container)
@ -318,7 +335,7 @@ class ExistingLayoutLoader(plugin.Loader):
for container in all_containers:
repr = container.get('representation')
if not repr == str(repr_data.get('_id')):
if not repr == repre_doc["_id"]:
continue
asset_dir = container.get('namespace')
@ -370,9 +387,11 @@ class ExistingLayoutLoader(plugin.Loader):
def load(self, context, name, namespace, options):
print("Loading Layout and Match Assets")
asset = context.get('asset').get('name')
asset_name = f"{asset}_{name}" if asset else name
container_name = f"{asset}_{name}_CON"
folder_name = context["folder"]["name"]
folder_path = context["folder"]["path"]
product_type = context["representation"]["context"]["family"]
asset_name = f"{folder_name}_{name}" if folder_name else name
container_name = f"{folder_name}_{name}_CON"
curr_level = self._get_current_level()
@ -395,14 +414,16 @@ class ExistingLayoutLoader(plugin.Loader):
data = {
"schema": "ayon:container-2.0",
"id": AYON_CONTAINER_ID,
"asset": asset,
"asset": folder_path,
"folder_path": folder_path,
"namespace": curr_level_path,
"container_name": container_name,
"asset_name": asset_name,
"loader": str(self.__class__.__name__),
"representation": context["representation"]["_id"],
"parent": context["representation"]["parent"],
"family": context["representation"]["context"]["family"],
"family": product_type,
"product_type": product_type,
"loaded_assets": containers
}
upipeline.imprint(f"{curr_level_path}/{container_name}", data)

View file

@ -145,12 +145,11 @@ class SkeletalMeshAlembicLoader(plugin.Loader):
return asset_content
def update(self, container, context):
asset_doc = context["asset"]
folder_name = context["folder"]["name"]
subset_doc = context["subset"]
version_doc = context["version"]
repre_doc = context["representation"]
folder_name = asset_doc["name"]
product_name = subset_doc["name"]
# Create directory for folder and Ayon container

View file

@ -147,12 +147,11 @@ class SkeletalMeshFBXLoader(plugin.Loader):
return asset_content
def update(self, container, context):
asset_doc = context["asse"]
folder_name = context["folder"]["name"]
subset_doc = context["subset"]
version_doc = context["version"]
repre_doc = context["representation"]
folder_name = asset_doc["name"]
product_name = subset_doc["name"]
# Create directory for asset and Ayon container

View file

@ -146,11 +146,10 @@ class StaticMeshAlembicLoader(plugin.Loader):
return asset_content
def update(self, container, context):
asset_doc = context["asset"]
folder_name = context["folder"]["name"]
subset_doc = context["subset"]
repre_doc = context["representation"]
folder_name = asset_doc["name"]
product_name = subset_doc["name"]
# Create directory for asset and Ayon container

View file

@ -135,12 +135,11 @@ class StaticMeshFBXLoader(plugin.Loader):
return asset_content
def update(self, container, context):
asset_doc = context["asset"]
folder_name = context["folder"]["name"]
subset_doc = context["subset"]
version_doc = context["version"]
repre_doc = context["representation"]
folder_name = asset_doc["name"]
product_name = subset_doc["name"]
# Create directory for asset and Ayon container

View file

@ -22,8 +22,12 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin):
def process(self, instance):
representations = instance.data.get("representations")
folder_attributes = (
instance.data
.get("folderEntity", {})
.get("attrib", {})
)
for repr in representations:
data = instance.data.get("assetEntity", {}).get("data", {})
repr_files = repr["files"]
if isinstance(repr_files, str):
continue
@ -64,8 +68,8 @@ class ValidateSequenceFrames(pyblish.api.InstancePlugin):
frames = frames[1:]
current_range = (frames[0], frames[-1])
required_range = (data["clipIn"],
data["clipOut"])
required_range = (folder_attributes["clipIn"],
folder_attributes["clipOut"])
if current_range != required_range:
raise PublishValidationError(