mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
#663 - Added load/update/remove implementation
This commit is contained in:
parent
02e906d0e9
commit
c3018baa07
3 changed files with 134 additions and 4 deletions
|
|
@ -7,6 +7,9 @@ import json
|
|||
from collections import namedtuple
|
||||
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
class AfterEffectsServerStub():
|
||||
"""
|
||||
Stub for calling function on client (Photoshop js) side.
|
||||
|
|
@ -44,10 +47,15 @@ class AfterEffectsServerStub():
|
|||
return layers_meta.get(str(layer.id))
|
||||
|
||||
def get_metadata(self):
|
||||
layers_data = {}
|
||||
res = self.websocketserver.call(self.client.call
|
||||
('AfterEffects.get_metadata')
|
||||
)
|
||||
return self._to_records(res)
|
||||
try:
|
||||
layers_data = json.loads(res)
|
||||
except json.decoder.JSONDecodeError:
|
||||
raise ValueError("Unparsable metadata {}".format(res))
|
||||
return layers_data or {}
|
||||
|
||||
def imprint(self, layer, data, all_layers=None, layers_meta=None):
|
||||
"""
|
||||
|
|
@ -65,6 +73,7 @@ class AfterEffectsServerStub():
|
|||
"""
|
||||
if not layers_meta:
|
||||
layers_meta = self.get_metadata()
|
||||
|
||||
# json.dumps writes integer values in a dictionary to string, so
|
||||
# anticipating it here.
|
||||
if str(layer.id) in layers_meta and layers_meta[str(layer.id)]:
|
||||
|
|
@ -74,13 +83,11 @@ class AfterEffectsServerStub():
|
|||
layers_meta.pop(str(layer.id))
|
||||
else:
|
||||
layers_meta[str(layer.id)] = data
|
||||
|
||||
# Ensure only valid ids are stored.
|
||||
if not all_layers:
|
||||
all_layers = self.get_items(False)
|
||||
item_ids = [item.id for item in all_layers]
|
||||
item_ids = [int(item.id) for item in all_layers]
|
||||
cleaned_data = {}
|
||||
|
||||
for id in layers_meta:
|
||||
if int(id) in item_ids:
|
||||
cleaned_data[id] = layers_meta[id]
|
||||
|
|
@ -118,6 +125,28 @@ class AfterEffectsServerStub():
|
|||
)
|
||||
return self._to_records(res)
|
||||
|
||||
def import_file(self, path, item_name):
|
||||
res = self.websocketserver.call(self.client.call(
|
||||
'AfterEffects.import_file',
|
||||
path=path,
|
||||
item_name=item_name)
|
||||
)
|
||||
return self._to_records(res).pop()
|
||||
|
||||
def replace_item(self, item, path, item_name):
|
||||
""" item is currently comp, might be layer, investigate TODO """
|
||||
self.websocketserver.call(self.client.call
|
||||
('AfterEffects.replace_item',
|
||||
item_id=item.id,
|
||||
path=path, item_name=item_name))
|
||||
|
||||
def delete_item(self, item):
|
||||
""" item is currently comp, might be layer, investigate TODO """
|
||||
self.websocketserver.call(self.client.call
|
||||
('AfterEffects.delete_item',
|
||||
item_id=item.id
|
||||
))
|
||||
|
||||
def is_saved(self):
|
||||
# TODO
|
||||
return True
|
||||
|
|
@ -153,12 +182,16 @@ class AfterEffectsServerStub():
|
|||
Returns: <list of named tuples>
|
||||
res(string): - json representation
|
||||
"""
|
||||
if not res:
|
||||
return []
|
||||
|
||||
try:
|
||||
layers_data = json.loads(res)
|
||||
except json.decoder.JSONDecodeError:
|
||||
raise ValueError("Received broken JSON {}".format(res))
|
||||
if not layers_data:
|
||||
return []
|
||||
|
||||
ret = []
|
||||
# convert to namedtuple to use dot donation
|
||||
if isinstance(layers_data, dict): # TODO refactore
|
||||
|
|
|
|||
72
pype/plugins/aftereffects/load/load_image.py
Normal file
72
pype/plugins/aftereffects/load/load_image.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
from avalon import api, aftereffects
|
||||
from pype.plugins import lib
|
||||
import re
|
||||
|
||||
stub = aftereffects.stub()
|
||||
|
||||
|
||||
class ImageLoader(api.Loader):
|
||||
"""Load images
|
||||
|
||||
Stores the imported asset in a container named after the asset.
|
||||
"""
|
||||
|
||||
families = ["image"]
|
||||
representations = ["*"]
|
||||
|
||||
def load(self, context, name=None, namespace=None, data=None):
|
||||
print("Load:::")
|
||||
layer_name = lib.get_unique_layer_name(stub.get_items(False),
|
||||
context["asset"]["name"],
|
||||
name)
|
||||
#with photoshop.maintained_selection():
|
||||
comp = stub.import_file(self.fname, layer_name)
|
||||
|
||||
self[:] = [comp]
|
||||
namespace = namespace or layer_name
|
||||
|
||||
return aftereffects.containerise(
|
||||
name,
|
||||
namespace,
|
||||
comp,
|
||||
context,
|
||||
self.__class__.__name__
|
||||
)
|
||||
|
||||
def update(self, container, representation):
|
||||
""" Switch asset or change version """
|
||||
layer = container.pop("layer")
|
||||
|
||||
context = representation.get("context", {})
|
||||
|
||||
namespace_from_container = re.sub(r'_\d{3}$', '',
|
||||
container["namespace"])
|
||||
layer_name = "{}_{}".format(context["asset"], context["subset"])
|
||||
# switching assets
|
||||
if namespace_from_container != layer_name:
|
||||
layer_name = lib.get_unique_layer_name(stub.get_items(False),
|
||||
context["asset"],
|
||||
context["subset"])
|
||||
else: # switching version - keep same name
|
||||
layer_name = container["namespace"]
|
||||
path = api.get_representation_path(representation)
|
||||
# with aftereffects.maintained_selection(): # TODO
|
||||
stub.replace_item(layer, path, layer_name)
|
||||
stub.imprint(
|
||||
layer, {"representation": str(representation["_id"])}
|
||||
)
|
||||
|
||||
def remove(self, container):
|
||||
"""
|
||||
Removes element from scene: deletes layer + removes from Headline
|
||||
Args:
|
||||
container (dict): container to be removed - used to get layer_id
|
||||
"""
|
||||
layer = container.pop("layer")
|
||||
stub.imprint(layer, {})
|
||||
stub.delete_layer(layer.id)
|
||||
|
||||
def switch(self, container, representation):
|
||||
self.update(container, representation)
|
||||
|
||||
|
||||
25
pype/plugins/lib.py
Normal file
25
pype/plugins/lib.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
import re
|
||||
|
||||
def get_unique_layer_name(layers, 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:
|
||||
layers (list): of namedtuples, expects 'name' field present
|
||||
asset_name (string): in format asset_subset (Hero)
|
||||
subset_name (string): (LOD)
|
||||
|
||||
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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue