diff --git a/openpype/hosts/aftereffects/api/extension.zxp b/openpype/hosts/aftereffects/api/extension.zxp index 358e9740d3..933dc7dc6c 100644 Binary files a/openpype/hosts/aftereffects/api/extension.zxp and b/openpype/hosts/aftereffects/api/extension.zxp differ diff --git a/openpype/hosts/aftereffects/api/extension/CSXS/manifest.xml b/openpype/hosts/aftereffects/api/extension/CSXS/manifest.xml index 0057758320..7329a9e723 100644 --- a/openpype/hosts/aftereffects/api/extension/CSXS/manifest.xml +++ b/openpype/hosts/aftereffects/api/extension/CSXS/manifest.xml @@ -1,5 +1,5 @@ - @@ -10,22 +10,22 @@ - + - + - - + + - + - - + + - + @@ -63,7 +63,7 @@ 550 400 --> - + ./icons/iconNormal.png @@ -71,9 +71,9 @@ ./icons/iconDisabled.png ./icons/iconDarkNormal.png ./icons/iconDarkRollover.png - + - \ No newline at end of file + diff --git a/openpype/hosts/aftereffects/api/extension/jsx/hostscript.jsx b/openpype/hosts/aftereffects/api/extension/jsx/hostscript.jsx index bc443930df..c00844e637 100644 --- a/openpype/hosts/aftereffects/api/extension/jsx/hostscript.jsx +++ b/openpype/hosts/aftereffects/api/extension/jsx/hostscript.jsx @@ -215,6 +215,8 @@ function _getItem(item, comps, folders, footages){ * Refactor */ var item_type = ''; + var path = ''; + var containing_comps = []; if (item instanceof FolderItem){ item_type = 'folder'; if (!folders){ @@ -222,10 +224,18 @@ function _getItem(item, comps, folders, footages){ } } if (item instanceof FootageItem){ - item_type = 'footage'; if (!footages){ return "{}"; } + item_type = 'footage'; + if (item.file){ + path = item.file.fsName; + } + if (item.usedIn){ + for (j = 0; j < item.usedIn.length; ++j){ + containing_comps.push(item.usedIn[j].id); + } + } } if (item instanceof CompItem){ item_type = 'comp'; @@ -236,7 +246,9 @@ function _getItem(item, comps, folders, footages){ var item = {"name": item.name, "id": item.id, - "type": item_type}; + "type": item_type, + "path": path, + "containing_comps": containing_comps}; return JSON.stringify(item); } diff --git a/openpype/hosts/aftereffects/api/ws_stub.py b/openpype/hosts/aftereffects/api/ws_stub.py index f5b96fa63a..18f530e272 100644 --- a/openpype/hosts/aftereffects/api/ws_stub.py +++ b/openpype/hosts/aftereffects/api/ws_stub.py @@ -37,6 +37,9 @@ class AEItem(object): height = attr.ib(default=None) is_placeholder = attr.ib(default=False) uuid = attr.ib(default=False) + path = attr.ib(default=False) # path to FootageItem to validate + # list of composition Footage is in + containing_comps = attr.ib(factory=list) class AfterEffectsServerStub(): @@ -704,7 +707,10 @@ class AfterEffectsServerStub(): d.get("instance_id"), d.get("width"), d.get("height"), - d.get("is_placeholder")) + d.get("is_placeholder"), + d.get("uuid"), + d.get("path"), + d.get("containing_comps"),) ret.append(item) return ret diff --git a/openpype/hosts/aftereffects/plugins/publish/help/validate_footage_items.xml b/openpype/hosts/aftereffects/plugins/publish/help/validate_footage_items.xml new file mode 100644 index 0000000000..01c8966015 --- /dev/null +++ b/openpype/hosts/aftereffects/plugins/publish/help/validate_footage_items.xml @@ -0,0 +1,14 @@ + + + +Footage item missing + +## Footage item missing + + FootageItem `{name}` contains missing `{path}`. Render will not produce any frames and AE will stop react to any integration +### How to repair? + +Remove `{name}` or provide missing file. + + + diff --git a/openpype/hosts/aftereffects/plugins/publish/validate_footage_items.py b/openpype/hosts/aftereffects/plugins/publish/validate_footage_items.py new file mode 100644 index 0000000000..40a08a2c3f --- /dev/null +++ b/openpype/hosts/aftereffects/plugins/publish/validate_footage_items.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +"""Validate presence of footage items in composition +Requires: +""" +import os + +import pyblish.api + +from openpype.pipeline import ( + PublishXmlValidationError +) +from openpype.hosts.aftereffects.api import get_stub + + +class ValidateFootageItems(pyblish.api.InstancePlugin): + """ + Validates if FootageItems contained in composition exist. + + AE fails silently and doesn't render anything if footage item file is + missing. This will result in nonresponsiveness of AE UI as it expects + reaction from user, but it will not provide dialog. + This validator tries to check existence of the files. + It will not protect from missing frame in multiframes though + (as AE api doesn't provide this information and it cannot be told how many + frames should be there easily). Missing frame is replaced by placeholder. + """ + + order = pyblish.api.ValidatorOrder + label = "Validate Footage Items" + families = ["render.farm", "render.local", "render"] + hosts = ["aftereffects"] + optional = True + + def process(self, instance): + """Plugin entry point.""" + + comp_id = instance.data["comp_id"] + for footage_item in get_stub().get_items(comps=False, folders=False, + footages=True): + self.log.info(footage_item) + if comp_id not in footage_item.containing_comps: + continue + + path = footage_item.path + if path and not os.path.exists(path): + msg = f"File {path} not found." + formatting = {"name": footage_item.name, "path": path} + raise PublishXmlValidationError(self, msg, + formatting_data=formatting) diff --git a/website/docs/admin_hosts_aftereffects.md b/website/docs/admin_hosts_aftereffects.md index 974428fe06..72fdb32faf 100644 --- a/website/docs/admin_hosts_aftereffects.md +++ b/website/docs/admin_hosts_aftereffects.md @@ -18,6 +18,10 @@ Location: Settings > Project > AfterEffects ## Publish plugins +### Collect Review + +Enable/disable creation of auto instance of review. + ### Validate Scene Settings #### Skip Resolution Check for Tasks @@ -28,6 +32,10 @@ Set regex pattern(s) to look for in a Task name to skip resolution check against Set regex pattern(s) to look for in a Task name to skip `frameStart`, `frameEnd` check against values from DB. +### ValidateContainers + +By default this validator will look loaded items with lower version than latest. This validator is context wide so it must be disabled in Context button. + ### AfterEffects Submit to Deadline * `Use Published scene` - Set to True (green) when Deadline should take published scene as a source instead of uploaded local one.