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.