#663 - Added load/update/remove implementation

This commit is contained in:
Petr Kalis 2020-10-28 19:24:32 +01:00
parent 02e906d0e9
commit c3018baa07
3 changed files with 134 additions and 4 deletions

View file

@ -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

View 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
View 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)