ae-agent-setup 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CSXS/manifest.xml +44 -0
- package/README.ja.md +249 -0
- package/README.md +249 -0
- package/bin/ae-agent-setup.mjs +337 -0
- package/client/CSInterface.js +1291 -0
- package/client/index.html +64 -0
- package/client/lib/bridge_utils.js +56 -0
- package/client/lib/logging.js +10 -0
- package/client/lib/request_handlers.js +468 -0
- package/client/lib/request_handlers_essential.js +35 -0
- package/client/lib/request_handlers_layer_structure.js +180 -0
- package/client/lib/request_handlers_scene.js +38 -0
- package/client/lib/request_handlers_shape.js +288 -0
- package/client/lib/request_handlers_timeline.js +115 -0
- package/client/lib/runtime.js +35 -0
- package/client/lib/server.js +33 -0
- package/client/main.js +1 -0
- package/host/index.jsx +11 -0
- package/host/json2.js +504 -0
- package/host/lib/common.jsx +128 -0
- package/host/lib/mutation_handlers.jsx +358 -0
- package/host/lib/mutation_keyframe_handlers.jsx +265 -0
- package/host/lib/mutation_layer_structure_handlers.jsx +235 -0
- package/host/lib/mutation_scene_handlers.jsx +1226 -0
- package/host/lib/mutation_shape_handlers.jsx +358 -0
- package/host/lib/mutation_timeline_handlers.jsx +137 -0
- package/host/lib/property_utils.jsx +105 -0
- package/host/lib/query_handlers.jsx +427 -0
- package/package.json +21 -0
- package/scripts/signing/build-zxp.sh +56 -0
- package/scripts/signing/create-dev-cert.sh +97 -0
- package/scripts/signing/install-zxp.sh +29 -0
- package/templates/skills/aftereffects-cli.SKILL.md +74 -0
- package/templates/skills/aftereffects-declarative.SKILL.md +112 -0
|
@@ -0,0 +1,1226 @@
|
|
|
1
|
+
function aeDecodeBridgePayload(raw, label) {
|
|
2
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
3
|
+
throw new Error(label + " returned an empty payload.");
|
|
4
|
+
}
|
|
5
|
+
var decoded = raw;
|
|
6
|
+
if (decoded.indexOf("__ENC__") === 0) {
|
|
7
|
+
decoded = decodeURIComponent(decoded.substring("__ENC__".length));
|
|
8
|
+
}
|
|
9
|
+
var parsed = JSON.parse(decoded);
|
|
10
|
+
if (parsed && parsed.status === "error") {
|
|
11
|
+
throw new Error(parsed.message || (label + " failed."));
|
|
12
|
+
}
|
|
13
|
+
return parsed;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function aeInvokeMutation(fn, args, label) {
|
|
17
|
+
var result = fn.apply(this, args);
|
|
18
|
+
return aeDecodeBridgePayload(result, label);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function aeIsFiniteNumber(value) {
|
|
22
|
+
return typeof value === "number" && isFinite(value);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function aeRequireFiniteNumber(value, fieldPath, errors) {
|
|
26
|
+
if (!aeIsFiniteNumber(value)) {
|
|
27
|
+
errors.push(fieldPath + " must be a finite number.");
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var AE_SCENE_ID_PREFIX = "aeSceneId:";
|
|
34
|
+
var AE_SCENE_APPLY_MODE_MERGE = "merge";
|
|
35
|
+
var AE_SCENE_APPLY_MODE_REPLACE_MANAGED = "replace-managed";
|
|
36
|
+
var AE_SCENE_APPLY_MODE_CLEAR_ALL = "clear-all";
|
|
37
|
+
|
|
38
|
+
function aeExtractSceneIdFromComment(comment) {
|
|
39
|
+
if (comment === null || comment === undefined) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
var raw = String(comment);
|
|
43
|
+
var lines = raw.split(/\r?\n/);
|
|
44
|
+
for (var i = 0; i < lines.length; i++) {
|
|
45
|
+
var line = lines[i];
|
|
46
|
+
if (line.indexOf(AE_SCENE_ID_PREFIX) === 0) {
|
|
47
|
+
var id = line.substring(AE_SCENE_ID_PREFIX.length);
|
|
48
|
+
if (id.length > 0) {
|
|
49
|
+
return id;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function aeAttachSceneIdToLayer(layer, sceneId) {
|
|
57
|
+
if (!layer || !sceneId) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
var rawComment = "";
|
|
61
|
+
try {
|
|
62
|
+
rawComment = layer.comment ? String(layer.comment) : "";
|
|
63
|
+
} catch (eCommentRead) {
|
|
64
|
+
rawComment = "";
|
|
65
|
+
}
|
|
66
|
+
var lines = rawComment.length > 0 ? rawComment.split(/\r?\n/) : [];
|
|
67
|
+
var nextLines = [];
|
|
68
|
+
for (var i = 0; i < lines.length; i++) {
|
|
69
|
+
if (lines[i].indexOf(AE_SCENE_ID_PREFIX) !== 0) {
|
|
70
|
+
nextLines.push(lines[i]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
nextLines.push(AE_SCENE_ID_PREFIX + sceneId);
|
|
74
|
+
try {
|
|
75
|
+
layer.comment = nextLines.join("\n");
|
|
76
|
+
} catch (eCommentWrite) {}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function aeBuildSceneLayerIndex(comp) {
|
|
80
|
+
var index = {};
|
|
81
|
+
for (var i = 1; i <= comp.numLayers; i++) {
|
|
82
|
+
var layer = comp.layer(i);
|
|
83
|
+
if (!layer) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
var sceneId = aeExtractSceneIdFromComment(layer.comment);
|
|
87
|
+
if (!sceneId) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (!index[sceneId]) {
|
|
91
|
+
index[sceneId] = [];
|
|
92
|
+
}
|
|
93
|
+
index[sceneId].push(layer);
|
|
94
|
+
}
|
|
95
|
+
return index;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function aeNormalizeSceneApplyMode(mode) {
|
|
99
|
+
if (mode === null || mode === undefined || mode === "") {
|
|
100
|
+
return AE_SCENE_APPLY_MODE_MERGE;
|
|
101
|
+
}
|
|
102
|
+
var raw = String(mode).toLowerCase();
|
|
103
|
+
if (
|
|
104
|
+
raw === AE_SCENE_APPLY_MODE_MERGE
|
|
105
|
+
|| raw === AE_SCENE_APPLY_MODE_REPLACE_MANAGED
|
|
106
|
+
|| raw === AE_SCENE_APPLY_MODE_CLEAR_ALL
|
|
107
|
+
) {
|
|
108
|
+
return raw;
|
|
109
|
+
}
|
|
110
|
+
throw new Error(
|
|
111
|
+
"Invalid scene apply mode '" + raw
|
|
112
|
+
+ "'. Use one of: merge, replace-managed, clear-all."
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function aeBuildDeclaredSceneIdSet(sceneLayers) {
|
|
117
|
+
var ids = {};
|
|
118
|
+
for (var i = 0; i < sceneLayers.length; i++) {
|
|
119
|
+
var layerSpec = sceneLayers[i];
|
|
120
|
+
if (!layerSpec || layerSpec.id === undefined || layerSpec.id === null) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
ids[String(layerSpec.id)] = true;
|
|
124
|
+
}
|
|
125
|
+
return ids;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function aeCollectLayersForSceneApplyMode(comp, mode, declaredSceneIds) {
|
|
129
|
+
var targets = [];
|
|
130
|
+
for (var i = 1; i <= comp.numLayers; i++) {
|
|
131
|
+
var layer = comp.layer(i);
|
|
132
|
+
if (!layer) {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
var sceneId = aeExtractSceneIdFromComment(layer.comment);
|
|
136
|
+
var shouldDelete = false;
|
|
137
|
+
if (mode === AE_SCENE_APPLY_MODE_CLEAR_ALL) {
|
|
138
|
+
shouldDelete = true;
|
|
139
|
+
} else if (mode === AE_SCENE_APPLY_MODE_REPLACE_MANAGED) {
|
|
140
|
+
shouldDelete = !!sceneId && !declaredSceneIds[sceneId];
|
|
141
|
+
}
|
|
142
|
+
if (!shouldDelete) {
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
targets.push({
|
|
146
|
+
layerRef: layer,
|
|
147
|
+
layerId: layer.index,
|
|
148
|
+
layerName: layer.name,
|
|
149
|
+
sceneId: sceneId
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return targets;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function aeSortLayerDeleteTargetsDescending(targets) {
|
|
156
|
+
targets.sort(function(a, b) {
|
|
157
|
+
return b.layerId - a.layerId;
|
|
158
|
+
});
|
|
159
|
+
return targets;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function aeDeleteLayerTargets(targets) {
|
|
163
|
+
var deleted = [];
|
|
164
|
+
var orderedTargets = aeSortLayerDeleteTargetsDescending(targets);
|
|
165
|
+
for (var i = 0; i < orderedTargets.length; i++) {
|
|
166
|
+
var target = orderedTargets[i];
|
|
167
|
+
var layerRef = target.layerRef;
|
|
168
|
+
if (!layerRef) {
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
layerRef.remove();
|
|
172
|
+
deleted.push({
|
|
173
|
+
layerId: target.layerId,
|
|
174
|
+
layerName: target.layerName,
|
|
175
|
+
sceneId: target.sceneId
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
return deleted;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function aeFindUntaggedLayerByNameAndType(comp, name, expectedType) {
|
|
182
|
+
if (!name || typeof name !== "string") {
|
|
183
|
+
return { layer: null, error: null };
|
|
184
|
+
}
|
|
185
|
+
var matches = [];
|
|
186
|
+
for (var i = 1; i <= comp.numLayers; i++) {
|
|
187
|
+
var layer = comp.layer(i);
|
|
188
|
+
if (!layer || layer.name !== name) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
var existingSceneId = aeExtractSceneIdFromComment(layer.comment);
|
|
192
|
+
if (existingSceneId) {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
var existingType = String(getLayerTypeName(layer)).toLowerCase();
|
|
196
|
+
if (existingType === "video") {
|
|
197
|
+
existingType = "solid";
|
|
198
|
+
}
|
|
199
|
+
if (existingType === expectedType) {
|
|
200
|
+
matches.push(layer);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
if (matches.length >= 1) {
|
|
204
|
+
return {
|
|
205
|
+
layer: matches[0],
|
|
206
|
+
error: null,
|
|
207
|
+
ambiguous: matches.length > 1
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return { layer: null, error: null, ambiguous: false };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function aeNormalizeLayerTypeForScene(layer) {
|
|
214
|
+
try {
|
|
215
|
+
if (layer && layer.nullLayer === true) {
|
|
216
|
+
return "null";
|
|
217
|
+
}
|
|
218
|
+
} catch (eNullType) {}
|
|
219
|
+
var typeName = String(getLayerTypeName(layer)).toLowerCase();
|
|
220
|
+
if (typeName === "video") {
|
|
221
|
+
return "solid";
|
|
222
|
+
}
|
|
223
|
+
return typeName;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function aeSetTextLayerValue(layer, textValue) {
|
|
227
|
+
if (!(layer instanceof TextLayer)) {
|
|
228
|
+
throw new Error("text field is only allowed for text layers.");
|
|
229
|
+
}
|
|
230
|
+
var textGroup = layer.property("ADBE Text Properties");
|
|
231
|
+
if (!textGroup) {
|
|
232
|
+
throw new Error("Text properties group not found.");
|
|
233
|
+
}
|
|
234
|
+
var textDocProp = textGroup.property("ADBE Text Document");
|
|
235
|
+
if (!textDocProp) {
|
|
236
|
+
throw new Error("Source Text property not found.");
|
|
237
|
+
}
|
|
238
|
+
var textDoc = textDocProp.value;
|
|
239
|
+
textDoc.text = String(textValue);
|
|
240
|
+
textDocProp.setValue(textDoc);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function aeFindExistingEffect(layer, matchName, effectName) {
|
|
244
|
+
var effectGroup = layer.property("ADBE Effect Parade");
|
|
245
|
+
if (!effectGroup) {
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
248
|
+
for (var i = 1; i <= effectGroup.numProperties; i++) {
|
|
249
|
+
var effect = effectGroup.property(i);
|
|
250
|
+
if (!effect || effect.matchName !== matchName) {
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (effectName === null || effectName === undefined || effectName === "") {
|
|
254
|
+
return effect;
|
|
255
|
+
}
|
|
256
|
+
if (effect.name === effectName) {
|
|
257
|
+
return effect;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function aeApplyExpression(layerId, propertyPath, expression) {
|
|
264
|
+
var result = setExpression(layerId, null, propertyPath, expression);
|
|
265
|
+
if (result !== "success") {
|
|
266
|
+
throw new Error(String(result));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function aeTryAddEssentialProperty(layerId, propertyPath, essentialName) {
|
|
271
|
+
try {
|
|
272
|
+
aeInvokeMutation(
|
|
273
|
+
addEssentialProperty,
|
|
274
|
+
[layerId, null, propertyPath, essentialName !== undefined ? essentialName : null],
|
|
275
|
+
"addEssentialProperty"
|
|
276
|
+
);
|
|
277
|
+
return true;
|
|
278
|
+
} catch (e) {
|
|
279
|
+
var msg = String(e);
|
|
280
|
+
if (
|
|
281
|
+
msg.indexOf("Property cannot be added to Essential Graphics") >= 0
|
|
282
|
+
|| msg.indexOf("Failed to add property to Essential Graphics") >= 0
|
|
283
|
+
|| msg.indexOf("Property cannot be added to Essential Graphics in this AE version") >= 0
|
|
284
|
+
) {
|
|
285
|
+
// Treat as idempotent no-op when it is already exported or unavailable in context.
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
throw e;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function aeNormalizeSetValueInputForProp(prop, value) {
|
|
293
|
+
if (!(value instanceof Array)) {
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
var currentValue = prop.value;
|
|
298
|
+
if (currentValue instanceof Array && currentValue.length === 3 && value.length === 2) {
|
|
299
|
+
return [value[0], value[1], 0];
|
|
300
|
+
}
|
|
301
|
+
} catch (eCurrentValue) {}
|
|
302
|
+
return value;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
function aeResolveChildPropertyByMatchName(group, matchName) {
|
|
306
|
+
if (!group || !matchName) {
|
|
307
|
+
return null;
|
|
308
|
+
}
|
|
309
|
+
for (var i = 1; i <= group.numProperties; i++) {
|
|
310
|
+
var child = group.property(i);
|
|
311
|
+
if (child && child.matchName === matchName) {
|
|
312
|
+
return child;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function aeResolveEffectParamProperty(effect, paramSpec) {
|
|
319
|
+
if (!effect || !paramSpec) {
|
|
320
|
+
return null;
|
|
321
|
+
}
|
|
322
|
+
if (paramSpec.propertyPath !== undefined) {
|
|
323
|
+
return resolveProperty(effect, String(paramSpec.propertyPath));
|
|
324
|
+
}
|
|
325
|
+
if (paramSpec.matchName !== undefined) {
|
|
326
|
+
return aeResolveChildPropertyByMatchName(effect, String(paramSpec.matchName));
|
|
327
|
+
}
|
|
328
|
+
if (paramSpec.propertyIndex !== undefined) {
|
|
329
|
+
var idx = parseInt(paramSpec.propertyIndex, 10);
|
|
330
|
+
if (!isNaN(idx) && idx > 0) {
|
|
331
|
+
return effect.property(idx);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function aeApplyEffectParams(effect, paramSpecs) {
|
|
338
|
+
if (!(paramSpecs instanceof Array)) {
|
|
339
|
+
return 0;
|
|
340
|
+
}
|
|
341
|
+
var count = 0;
|
|
342
|
+
for (var i = 0; i < paramSpecs.length; i++) {
|
|
343
|
+
var paramSpec = paramSpecs[i];
|
|
344
|
+
var prop = aeResolveEffectParamProperty(effect, paramSpec);
|
|
345
|
+
if (!prop) {
|
|
346
|
+
throw new Error("Effect parameter target was not found.");
|
|
347
|
+
}
|
|
348
|
+
if (typeof prop.setValue !== "function") {
|
|
349
|
+
throw new Error("Effect parameter does not support setValue().");
|
|
350
|
+
}
|
|
351
|
+
var value = aeNormalizeSetValueInputForProp(prop, paramSpec.value);
|
|
352
|
+
prop.setValue(value);
|
|
353
|
+
count += 1;
|
|
354
|
+
}
|
|
355
|
+
return count;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function aeFindShapeRepeater(layer, groupIndex, repeaterName) {
|
|
359
|
+
if (!layer || layer.matchName !== "ADBE Vector Layer") {
|
|
360
|
+
return null;
|
|
361
|
+
}
|
|
362
|
+
var rootVectors = layer.property("ADBE Root Vectors Group");
|
|
363
|
+
if (!rootVectors) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
var targetIndex = groupIndex !== undefined ? parseInt(groupIndex, 10) : 1;
|
|
367
|
+
if (isNaN(targetIndex) || targetIndex <= 0) {
|
|
368
|
+
targetIndex = 1;
|
|
369
|
+
}
|
|
370
|
+
var targetGroup = rootVectors.property(targetIndex);
|
|
371
|
+
if (!targetGroup || targetGroup.matchName !== "ADBE Vector Group") {
|
|
372
|
+
return null;
|
|
373
|
+
}
|
|
374
|
+
var contents = targetGroup.property("ADBE Vectors Group");
|
|
375
|
+
if (!contents) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
for (var i = 1; i <= contents.numProperties; i++) {
|
|
379
|
+
var prop = contents.property(i);
|
|
380
|
+
if (!prop || prop.matchName !== "ADBE Vector Filter - Repeater") {
|
|
381
|
+
continue;
|
|
382
|
+
}
|
|
383
|
+
if (repeaterName !== undefined && repeaterName !== null && String(repeaterName).length > 0) {
|
|
384
|
+
if (prop.name === String(repeaterName)) {
|
|
385
|
+
return prop;
|
|
386
|
+
}
|
|
387
|
+
continue;
|
|
388
|
+
}
|
|
389
|
+
return prop;
|
|
390
|
+
}
|
|
391
|
+
return null;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function aeValidateSceneSpec(scene) {
|
|
395
|
+
var errors = [];
|
|
396
|
+
if (!scene || typeof scene !== "object" || scene instanceof Array) {
|
|
397
|
+
errors.push("scene must be an object.");
|
|
398
|
+
return { ok: false, errors: errors };
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
var comp = scene.composition;
|
|
402
|
+
if (comp !== undefined) {
|
|
403
|
+
if (!comp || typeof comp !== "object" || comp instanceof Array) {
|
|
404
|
+
errors.push("composition must be an object when specified.");
|
|
405
|
+
} else {
|
|
406
|
+
if (comp.compId !== undefined && (!aeIsFiniteNumber(comp.compId) || comp.compId <= 0)) {
|
|
407
|
+
errors.push("composition.compId must be a positive number when specified.");
|
|
408
|
+
}
|
|
409
|
+
if (comp.compName !== undefined && typeof comp.compName !== "string") {
|
|
410
|
+
errors.push("composition.compName must be a string when specified.");
|
|
411
|
+
}
|
|
412
|
+
if (comp.name !== undefined && typeof comp.name !== "string") {
|
|
413
|
+
errors.push("composition.name must be a string when specified.");
|
|
414
|
+
}
|
|
415
|
+
if (comp.width !== undefined && (!aeIsFiniteNumber(comp.width) || comp.width <= 0)) {
|
|
416
|
+
errors.push("composition.width must be a positive number when specified.");
|
|
417
|
+
}
|
|
418
|
+
if (comp.height !== undefined && (!aeIsFiniteNumber(comp.height) || comp.height <= 0)) {
|
|
419
|
+
errors.push("composition.height must be a positive number when specified.");
|
|
420
|
+
}
|
|
421
|
+
if (comp.duration !== undefined && (!aeIsFiniteNumber(comp.duration) || comp.duration <= 0)) {
|
|
422
|
+
errors.push("composition.duration must be a positive number when specified.");
|
|
423
|
+
}
|
|
424
|
+
if (comp.frameRate !== undefined && (!aeIsFiniteNumber(comp.frameRate) || comp.frameRate <= 0)) {
|
|
425
|
+
errors.push("composition.frameRate must be a positive number when specified.");
|
|
426
|
+
}
|
|
427
|
+
if (comp.pixelAspect !== undefined && (!aeIsFiniteNumber(comp.pixelAspect) || comp.pixelAspect <= 0)) {
|
|
428
|
+
errors.push("composition.pixelAspect must be a positive number when specified.");
|
|
429
|
+
}
|
|
430
|
+
if (comp.createIfMissing !== undefined && typeof comp.createIfMissing !== "boolean") {
|
|
431
|
+
errors.push("composition.createIfMissing must be a boolean when specified.");
|
|
432
|
+
}
|
|
433
|
+
if (comp.setActive !== undefined && typeof comp.setActive !== "boolean") {
|
|
434
|
+
errors.push("composition.setActive must be a boolean when specified.");
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
var layers = scene.layers;
|
|
440
|
+
if (layers !== undefined) {
|
|
441
|
+
if (!(layers instanceof Array)) {
|
|
442
|
+
errors.push("layers must be an array when specified.");
|
|
443
|
+
} else {
|
|
444
|
+
var seenIds = {};
|
|
445
|
+
for (var i = 0; i < layers.length; i++) {
|
|
446
|
+
var layer = layers[i];
|
|
447
|
+
var prefix = "layers[" + i + "]";
|
|
448
|
+
if (!layer || typeof layer !== "object" || layer instanceof Array) {
|
|
449
|
+
errors.push(prefix + " must be an object.");
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (layer.id !== undefined) {
|
|
453
|
+
if (typeof layer.id !== "string" || layer.id.length === 0) {
|
|
454
|
+
errors.push(prefix + ".id must be a non-empty string when specified.");
|
|
455
|
+
} else if (seenIds[layer.id]) {
|
|
456
|
+
errors.push(prefix + ".id is duplicated: " + layer.id);
|
|
457
|
+
} else {
|
|
458
|
+
seenIds[layer.id] = true;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
if (layer.type === undefined || typeof layer.type !== "string") {
|
|
462
|
+
errors.push(prefix + ".type is required and must be a string.");
|
|
463
|
+
} else {
|
|
464
|
+
var normalizedType = String(layer.type).toLowerCase();
|
|
465
|
+
if (
|
|
466
|
+
normalizedType !== "text"
|
|
467
|
+
&& normalizedType !== "null"
|
|
468
|
+
&& normalizedType !== "solid"
|
|
469
|
+
&& normalizedType !== "shape"
|
|
470
|
+
) {
|
|
471
|
+
errors.push(prefix + ".type must be one of: text, null, solid, shape.");
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (layer.name !== undefined && typeof layer.name !== "string") {
|
|
475
|
+
errors.push(prefix + ".name must be a string when specified.");
|
|
476
|
+
}
|
|
477
|
+
if (layer.text !== undefined && typeof layer.text !== "string") {
|
|
478
|
+
errors.push(prefix + ".text must be a string when specified.");
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
var timing = layer.timing;
|
|
482
|
+
if (timing !== undefined) {
|
|
483
|
+
if (!timing || typeof timing !== "object" || timing instanceof Array) {
|
|
484
|
+
errors.push(prefix + ".timing must be an object when specified.");
|
|
485
|
+
} else {
|
|
486
|
+
if (timing.inPoint !== undefined) {
|
|
487
|
+
aeRequireFiniteNumber(timing.inPoint, prefix + ".timing.inPoint", errors);
|
|
488
|
+
}
|
|
489
|
+
if (timing.outPoint !== undefined) {
|
|
490
|
+
aeRequireFiniteNumber(timing.outPoint, prefix + ".timing.outPoint", errors);
|
|
491
|
+
}
|
|
492
|
+
if (timing.startTime !== undefined) {
|
|
493
|
+
aeRequireFiniteNumber(timing.startTime, prefix + ".timing.startTime", errors);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
var transform = layer.transform;
|
|
499
|
+
if (transform !== undefined && (!transform || typeof transform !== "object" || transform instanceof Array)) {
|
|
500
|
+
errors.push(prefix + ".transform must be an object when specified.");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (layer.parentId !== undefined && layer.parentId !== null && typeof layer.parentId !== "string") {
|
|
504
|
+
errors.push(prefix + ".parentId must be a string or null when specified.");
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
var propertyValues = layer.propertyValues;
|
|
508
|
+
if (propertyValues !== undefined) {
|
|
509
|
+
if (!(propertyValues instanceof Array)) {
|
|
510
|
+
errors.push(prefix + ".propertyValues must be an array when specified.");
|
|
511
|
+
} else {
|
|
512
|
+
for (var j = 0; j < propertyValues.length; j++) {
|
|
513
|
+
var pv = propertyValues[j];
|
|
514
|
+
var pvPrefix = prefix + ".propertyValues[" + j + "]";
|
|
515
|
+
if (!pv || typeof pv !== "object" || pv instanceof Array) {
|
|
516
|
+
errors.push(pvPrefix + " must be an object.");
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
if (typeof pv.propertyPath !== "string" || pv.propertyPath.length === 0) {
|
|
520
|
+
errors.push(pvPrefix + ".propertyPath is required and must be a string.");
|
|
521
|
+
}
|
|
522
|
+
if (pv.value === undefined) {
|
|
523
|
+
errors.push(pvPrefix + ".value is required.");
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
var effects = layer.effects;
|
|
530
|
+
if (effects !== undefined) {
|
|
531
|
+
if (!(effects instanceof Array)) {
|
|
532
|
+
errors.push(prefix + ".effects must be an array when specified.");
|
|
533
|
+
} else {
|
|
534
|
+
for (var k = 0; k < effects.length; k++) {
|
|
535
|
+
var effect = effects[k];
|
|
536
|
+
var effectPrefix = prefix + ".effects[" + k + "]";
|
|
537
|
+
if (!effect || typeof effect !== "object" || effect instanceof Array) {
|
|
538
|
+
errors.push(effectPrefix + " must be an object.");
|
|
539
|
+
continue;
|
|
540
|
+
}
|
|
541
|
+
if (typeof effect.matchName !== "string" || effect.matchName.length === 0) {
|
|
542
|
+
errors.push(effectPrefix + ".matchName is required and must be a string.");
|
|
543
|
+
}
|
|
544
|
+
if (effect.name !== undefined && typeof effect.name !== "string") {
|
|
545
|
+
errors.push(effectPrefix + ".name must be a string when specified.");
|
|
546
|
+
}
|
|
547
|
+
if (effect.params !== undefined) {
|
|
548
|
+
if (!(effect.params instanceof Array)) {
|
|
549
|
+
errors.push(effectPrefix + ".params must be an array when specified.");
|
|
550
|
+
} else {
|
|
551
|
+
for (var p = 0; p < effect.params.length; p++) {
|
|
552
|
+
var param = effect.params[p];
|
|
553
|
+
var paramPrefix = effectPrefix + ".params[" + p + "]";
|
|
554
|
+
if (!param || typeof param !== "object" || param instanceof Array) {
|
|
555
|
+
errors.push(paramPrefix + " must be an object.");
|
|
556
|
+
continue;
|
|
557
|
+
}
|
|
558
|
+
if (param.value === undefined) {
|
|
559
|
+
errors.push(paramPrefix + ".value is required.");
|
|
560
|
+
}
|
|
561
|
+
var hasParamPath = typeof param.propertyPath === "string" && param.propertyPath.length > 0;
|
|
562
|
+
var hasParamMatchName = typeof param.matchName === "string" && param.matchName.length > 0;
|
|
563
|
+
var hasParamIndex = param.propertyIndex !== undefined;
|
|
564
|
+
var selectorCount = 0;
|
|
565
|
+
if (hasParamPath) selectorCount += 1;
|
|
566
|
+
if (hasParamMatchName) selectorCount += 1;
|
|
567
|
+
if (hasParamIndex) selectorCount += 1;
|
|
568
|
+
if (selectorCount !== 1) {
|
|
569
|
+
errors.push(paramPrefix + " must specify exactly one of propertyPath, matchName, propertyIndex.");
|
|
570
|
+
}
|
|
571
|
+
if (hasParamIndex) {
|
|
572
|
+
var parsedIndex = parseInt(param.propertyIndex, 10);
|
|
573
|
+
if (isNaN(parsedIndex) || parsedIndex <= 0) {
|
|
574
|
+
errors.push(paramPrefix + ".propertyIndex must be a positive integer.");
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
var repeaters = layer.repeaters;
|
|
585
|
+
if (repeaters !== undefined) {
|
|
586
|
+
if (!(repeaters instanceof Array)) {
|
|
587
|
+
errors.push(prefix + ".repeaters must be an array when specified.");
|
|
588
|
+
} else {
|
|
589
|
+
for (var rp = 0; rp < repeaters.length; rp++) {
|
|
590
|
+
var repeater = repeaters[rp];
|
|
591
|
+
var repeaterPrefix = prefix + ".repeaters[" + rp + "]";
|
|
592
|
+
if (!repeater || typeof repeater !== "object" || repeater instanceof Array) {
|
|
593
|
+
errors.push(repeaterPrefix + " must be an object.");
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
if (
|
|
597
|
+
repeater.groupIndex !== undefined
|
|
598
|
+
&& (!aeIsFiniteNumber(repeater.groupIndex) || repeater.groupIndex <= 0)
|
|
599
|
+
) {
|
|
600
|
+
errors.push(repeaterPrefix + ".groupIndex must be a positive number when specified.");
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
var expressions = layer.expressions;
|
|
607
|
+
if (expressions !== undefined) {
|
|
608
|
+
if (!(expressions instanceof Array)) {
|
|
609
|
+
errors.push(prefix + ".expressions must be an array when specified.");
|
|
610
|
+
} else {
|
|
611
|
+
for (var e = 0; e < expressions.length; e++) {
|
|
612
|
+
var exp = expressions[e];
|
|
613
|
+
var expPrefix = prefix + ".expressions[" + e + "]";
|
|
614
|
+
if (!exp || typeof exp !== "object" || exp instanceof Array) {
|
|
615
|
+
errors.push(expPrefix + " must be an object.");
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (typeof exp.propertyPath !== "string" || exp.propertyPath.length === 0) {
|
|
619
|
+
errors.push(expPrefix + ".propertyPath is required and must be a string.");
|
|
620
|
+
}
|
|
621
|
+
if (typeof exp.expression !== "string") {
|
|
622
|
+
errors.push(expPrefix + ".expression is required and must be a string.");
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
var essentialProperties = layer.essentialProperties;
|
|
629
|
+
if (essentialProperties !== undefined) {
|
|
630
|
+
if (!(essentialProperties instanceof Array)) {
|
|
631
|
+
errors.push(prefix + ".essentialProperties must be an array when specified.");
|
|
632
|
+
} else {
|
|
633
|
+
for (var q = 0; q < essentialProperties.length; q++) {
|
|
634
|
+
var ep = essentialProperties[q];
|
|
635
|
+
var epPrefix = prefix + ".essentialProperties[" + q + "]";
|
|
636
|
+
if (!ep || typeof ep !== "object" || ep instanceof Array) {
|
|
637
|
+
errors.push(epPrefix + " must be an object.");
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
if (typeof ep.propertyPath !== "string" || ep.propertyPath.length === 0) {
|
|
641
|
+
errors.push(epPrefix + ".propertyPath is required and must be a string.");
|
|
642
|
+
}
|
|
643
|
+
if (ep.essentialName !== undefined && typeof ep.essentialName !== "string") {
|
|
644
|
+
errors.push(epPrefix + ".essentialName must be a string when specified.");
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
var animations = layer.animations;
|
|
651
|
+
if (animations !== undefined) {
|
|
652
|
+
if (!(animations instanceof Array)) {
|
|
653
|
+
errors.push(prefix + ".animations must be an array when specified.");
|
|
654
|
+
} else {
|
|
655
|
+
for (var m = 0; m < animations.length; m++) {
|
|
656
|
+
var animation = animations[m];
|
|
657
|
+
var animationPrefix = prefix + ".animations[" + m + "]";
|
|
658
|
+
if (!animation || typeof animation !== "object" || animation instanceof Array) {
|
|
659
|
+
errors.push(animationPrefix + " must be an object.");
|
|
660
|
+
continue;
|
|
661
|
+
}
|
|
662
|
+
if (typeof animation.propertyPath !== "string" || animation.propertyPath.length === 0) {
|
|
663
|
+
errors.push(animationPrefix + ".propertyPath is required and must be a string.");
|
|
664
|
+
}
|
|
665
|
+
if (!(animation.keyframes instanceof Array) || animation.keyframes.length === 0) {
|
|
666
|
+
errors.push(animationPrefix + ".keyframes must be a non-empty array.");
|
|
667
|
+
} else {
|
|
668
|
+
for (var n = 0; n < animation.keyframes.length; n++) {
|
|
669
|
+
var keyframe = animation.keyframes[n];
|
|
670
|
+
var keyPrefix = animationPrefix + ".keyframes[" + n + "]";
|
|
671
|
+
if (!keyframe || typeof keyframe !== "object" || keyframe instanceof Array) {
|
|
672
|
+
errors.push(keyPrefix + " must be an object.");
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
if (!aeRequireFiniteNumber(keyframe.time, keyPrefix + ".time", errors)) {
|
|
676
|
+
continue;
|
|
677
|
+
}
|
|
678
|
+
if (keyframe.value === undefined) {
|
|
679
|
+
errors.push(keyPrefix + ".value is required.");
|
|
680
|
+
}
|
|
681
|
+
if (
|
|
682
|
+
keyframe.inInterp !== undefined
|
|
683
|
+
&& keyframe.inInterp !== "linear"
|
|
684
|
+
&& keyframe.inInterp !== "bezier"
|
|
685
|
+
&& keyframe.inInterp !== "hold"
|
|
686
|
+
) {
|
|
687
|
+
errors.push(keyPrefix + ".inInterp must be linear, bezier, or hold.");
|
|
688
|
+
}
|
|
689
|
+
if (
|
|
690
|
+
keyframe.outInterp !== undefined
|
|
691
|
+
&& keyframe.outInterp !== "linear"
|
|
692
|
+
&& keyframe.outInterp !== "bezier"
|
|
693
|
+
&& keyframe.outInterp !== "hold"
|
|
694
|
+
) {
|
|
695
|
+
errors.push(keyPrefix + ".outInterp must be linear, bezier, or hold.");
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
return { ok: errors.length === 0, errors: errors };
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
function aeResolveSceneComp(spec, mutate) {
|
|
710
|
+
var compSpec = spec.composition || {};
|
|
711
|
+
var targetComp = null;
|
|
712
|
+
var hasCompId = compSpec.compId !== undefined;
|
|
713
|
+
var hasCompName = compSpec.compName !== undefined && String(compSpec.compName).length > 0;
|
|
714
|
+
var createIfMissing = compSpec.createIfMissing !== false;
|
|
715
|
+
var shouldSetActive = compSpec.setActive !== false;
|
|
716
|
+
|
|
717
|
+
if (hasCompId || hasCompName) {
|
|
718
|
+
targetComp = findCompByIdOrName(hasCompId ? compSpec.compId : null, hasCompName ? compSpec.compName : null);
|
|
719
|
+
if (!targetComp) {
|
|
720
|
+
throw new Error("Specified composition was not found.");
|
|
721
|
+
}
|
|
722
|
+
if (mutate && shouldSetActive) {
|
|
723
|
+
aeInvokeMutation(
|
|
724
|
+
setActiveComp,
|
|
725
|
+
[hasCompId ? compSpec.compId : null, hasCompName ? compSpec.compName : null],
|
|
726
|
+
"setActiveComp"
|
|
727
|
+
);
|
|
728
|
+
targetComp = app.project.activeItem;
|
|
729
|
+
}
|
|
730
|
+
} else if (compSpec.name !== undefined) {
|
|
731
|
+
targetComp = findCompByIdOrName(null, compSpec.name);
|
|
732
|
+
if (!targetComp && !createIfMissing) {
|
|
733
|
+
throw new Error("composition.name was not found and createIfMissing is false.");
|
|
734
|
+
}
|
|
735
|
+
if (!targetComp && mutate) {
|
|
736
|
+
var compWidth = compSpec.width !== undefined ? compSpec.width : 1920;
|
|
737
|
+
var compHeight = compSpec.height !== undefined ? compSpec.height : 1080;
|
|
738
|
+
var compDuration = compSpec.duration !== undefined ? compSpec.duration : 8.0;
|
|
739
|
+
var compFrameRate = compSpec.frameRate !== undefined ? compSpec.frameRate : 30.0;
|
|
740
|
+
var compPixelAspect = compSpec.pixelAspect !== undefined ? compSpec.pixelAspect : 1.0;
|
|
741
|
+
aeInvokeMutation(
|
|
742
|
+
createComp,
|
|
743
|
+
[compSpec.name, compWidth, compHeight, compPixelAspect, compDuration, compFrameRate],
|
|
744
|
+
"createComp"
|
|
745
|
+
);
|
|
746
|
+
targetComp = app.project.activeItem;
|
|
747
|
+
} else if (targetComp && mutate && shouldSetActive) {
|
|
748
|
+
aeInvokeMutation(setActiveComp, [targetComp.id, null], "setActiveComp");
|
|
749
|
+
targetComp = app.project.activeItem;
|
|
750
|
+
}
|
|
751
|
+
} else {
|
|
752
|
+
targetComp = app.project && app.project.activeItem ? app.project.activeItem : null;
|
|
753
|
+
if (!targetComp || !(targetComp instanceof CompItem)) {
|
|
754
|
+
throw new Error("No target composition available. Provide composition settings or open an active comp.");
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
if (!targetComp || !(targetComp instanceof CompItem)) {
|
|
759
|
+
throw new Error("Resolved composition is invalid.");
|
|
760
|
+
}
|
|
761
|
+
return targetComp;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
function aeApplyLayerTransform(layerId, transform, skipPropertyPaths) {
|
|
765
|
+
if (!transform) {
|
|
766
|
+
return 0;
|
|
767
|
+
}
|
|
768
|
+
var count = 0;
|
|
769
|
+
var pathMap = {
|
|
770
|
+
anchorPoint: "ADBE Transform Group.ADBE Anchor Point",
|
|
771
|
+
position: "ADBE Transform Group.ADBE Position",
|
|
772
|
+
scale: "ADBE Transform Group.ADBE Scale",
|
|
773
|
+
rotation: "ADBE Transform Group.ADBE Rotate Z",
|
|
774
|
+
opacity: "ADBE Transform Group.ADBE Opacity"
|
|
775
|
+
};
|
|
776
|
+
for (var key in pathMap) {
|
|
777
|
+
if (!pathMap.hasOwnProperty(key)) {
|
|
778
|
+
continue;
|
|
779
|
+
}
|
|
780
|
+
if (transform[key] === undefined) {
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
var propertyPath = pathMap[key];
|
|
784
|
+
if (skipPropertyPaths && skipPropertyPaths[propertyPath]) {
|
|
785
|
+
continue;
|
|
786
|
+
}
|
|
787
|
+
aeInvokeMutation(
|
|
788
|
+
setPropertyValue,
|
|
789
|
+
[layerId, null, propertyPath, JSON.stringify(transform[key])],
|
|
790
|
+
"setPropertyValue(" + key + ")"
|
|
791
|
+
);
|
|
792
|
+
count += 1;
|
|
793
|
+
}
|
|
794
|
+
return count;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
function aeApplyLayerTiming(comp, layerId, timing) {
|
|
798
|
+
if (!timing) {
|
|
799
|
+
return 0;
|
|
800
|
+
}
|
|
801
|
+
var count = 0;
|
|
802
|
+
var hasIn = timing.inPoint !== undefined;
|
|
803
|
+
var hasOut = timing.outPoint !== undefined;
|
|
804
|
+
if (hasIn || hasOut) {
|
|
805
|
+
aeInvokeMutation(
|
|
806
|
+
setInOutPoint,
|
|
807
|
+
[layerId, null, hasIn ? timing.inPoint : null, hasOut ? timing.outPoint : null],
|
|
808
|
+
"setInOutPoint"
|
|
809
|
+
);
|
|
810
|
+
count += 1;
|
|
811
|
+
}
|
|
812
|
+
if (timing.startTime !== undefined) {
|
|
813
|
+
var layer = comp.layer(layerId);
|
|
814
|
+
if (!layer) {
|
|
815
|
+
throw new Error("Layer not found while setting timing: layerId=" + layerId);
|
|
816
|
+
}
|
|
817
|
+
layer.startTime = Number(timing.startTime);
|
|
818
|
+
count += 1;
|
|
819
|
+
}
|
|
820
|
+
return count;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
function aeBuildLayerCreateOptions(layerSpec) {
|
|
824
|
+
var options = {};
|
|
825
|
+
if (layerSpec.name !== undefined) options.name = layerSpec.name;
|
|
826
|
+
if (layerSpec.text !== undefined) options.text = layerSpec.text;
|
|
827
|
+
if (layerSpec.width !== undefined) options.width = layerSpec.width;
|
|
828
|
+
if (layerSpec.height !== undefined) options.height = layerSpec.height;
|
|
829
|
+
if (layerSpec.color !== undefined) options.color = layerSpec.color;
|
|
830
|
+
if (layerSpec.duration !== undefined) options.duration = layerSpec.duration;
|
|
831
|
+
if (layerSpec.shapeType !== undefined) options.shapeType = layerSpec.shapeType;
|
|
832
|
+
if (layerSpec.shapeSize !== undefined) options.shapeSize = layerSpec.shapeSize;
|
|
833
|
+
if (layerSpec.shapePosition !== undefined) options.shapePosition = layerSpec.shapePosition;
|
|
834
|
+
if (layerSpec.shapeFillColor !== undefined) options.shapeFillColor = layerSpec.shapeFillColor;
|
|
835
|
+
if (layerSpec.shapeFillOpacity !== undefined) options.shapeFillOpacity = layerSpec.shapeFillOpacity;
|
|
836
|
+
if (layerSpec.shapeStrokeColor !== undefined) options.shapeStrokeColor = layerSpec.shapeStrokeColor;
|
|
837
|
+
if (layerSpec.shapeStrokeOpacity !== undefined) options.shapeStrokeOpacity = layerSpec.shapeStrokeOpacity;
|
|
838
|
+
if (layerSpec.shapeStrokeWidth !== undefined) options.shapeStrokeWidth = layerSpec.shapeStrokeWidth;
|
|
839
|
+
if (layerSpec.shapeStrokeLineCap !== undefined) options.shapeStrokeLineCap = layerSpec.shapeStrokeLineCap;
|
|
840
|
+
if (layerSpec.shapeRoundness !== undefined) options.shapeRoundness = layerSpec.shapeRoundness;
|
|
841
|
+
return options;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
function aeResolveOrCreateSceneLayer(comp, layerSpec, layerIndex, sceneLayerIndex) {
|
|
845
|
+
var normalizedType = String(layerSpec.type).toLowerCase();
|
|
846
|
+
var sceneId = layerSpec.id !== undefined ? String(layerSpec.id) : null;
|
|
847
|
+
var layer = null;
|
|
848
|
+
var created = false;
|
|
849
|
+
if (sceneId) {
|
|
850
|
+
var taggedMatches = sceneLayerIndex[sceneId] || [];
|
|
851
|
+
if (taggedMatches.length > 1) {
|
|
852
|
+
throw new Error("Multiple layers share scene id '" + sceneId + "'. Resolve duplicates first.");
|
|
853
|
+
}
|
|
854
|
+
if (taggedMatches.length === 1) {
|
|
855
|
+
layer = taggedMatches[0];
|
|
856
|
+
} else {
|
|
857
|
+
var fallback = aeFindUntaggedLayerByNameAndType(comp, layerSpec.name, normalizedType);
|
|
858
|
+
if (fallback.error) {
|
|
859
|
+
throw new Error(fallback.error);
|
|
860
|
+
}
|
|
861
|
+
if (fallback.layer) {
|
|
862
|
+
layer = fallback.layer;
|
|
863
|
+
aeAttachSceneIdToLayer(layer, sceneId);
|
|
864
|
+
sceneLayerIndex[sceneId] = [layer];
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
if (!layer) {
|
|
869
|
+
var options = aeBuildLayerCreateOptions(layerSpec);
|
|
870
|
+
var createdPayload = aeInvokeMutation(addLayer, [normalizedType, JSON.stringify(options)], "addLayer");
|
|
871
|
+
var createdLayerId = createdPayload.layerId;
|
|
872
|
+
if (!createdLayerId) {
|
|
873
|
+
throw new Error("addLayer did not return layerId for layers[" + layerIndex + "].");
|
|
874
|
+
}
|
|
875
|
+
layer = comp.layer(createdLayerId);
|
|
876
|
+
created = true;
|
|
877
|
+
if (sceneId && layer) {
|
|
878
|
+
aeAttachSceneIdToLayer(layer, sceneId);
|
|
879
|
+
sceneLayerIndex[sceneId] = [layer];
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
if (!layer) {
|
|
883
|
+
throw new Error("Failed to resolve layer for layers[" + layerIndex + "].");
|
|
884
|
+
}
|
|
885
|
+
var existingType = aeNormalizeLayerTypeForScene(layer);
|
|
886
|
+
if (existingType !== normalizedType) {
|
|
887
|
+
throw new Error(
|
|
888
|
+
"Layer type mismatch for id '" + (sceneId || "<none>") + "': expected "
|
|
889
|
+
+ normalizedType + ", got " + existingType + "."
|
|
890
|
+
);
|
|
891
|
+
}
|
|
892
|
+
return { layer: layer, created: created, sceneId: sceneId, layerType: normalizedType };
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
function aeApplySceneLayer(comp, layerSpec, layerIndex, sceneLayerIndex) {
|
|
896
|
+
var resolved = aeResolveOrCreateSceneLayer(comp, layerSpec, layerIndex, sceneLayerIndex);
|
|
897
|
+
var layer = resolved.layer;
|
|
898
|
+
var layerId = layer.index;
|
|
899
|
+
var operationCount = resolved.created ? 1 : 0;
|
|
900
|
+
|
|
901
|
+
if (layerSpec.name !== undefined && layer.name !== layerSpec.name) {
|
|
902
|
+
layer.name = layerSpec.name;
|
|
903
|
+
operationCount += 1;
|
|
904
|
+
}
|
|
905
|
+
if (layerSpec.text !== undefined) {
|
|
906
|
+
aeSetTextLayerValue(layer, layerSpec.text);
|
|
907
|
+
operationCount += 1;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
var skipPropertyPaths = {};
|
|
911
|
+
var animationsForSkip = layerSpec.animations || [];
|
|
912
|
+
for (var s = 0; s < animationsForSkip.length; s++) {
|
|
913
|
+
var animationForSkip = animationsForSkip[s];
|
|
914
|
+
if (animationForSkip && animationForSkip.propertyPath) {
|
|
915
|
+
skipPropertyPaths[String(animationForSkip.propertyPath)] = true;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
operationCount += aeApplyLayerTransform(layerId, layerSpec.transform, skipPropertyPaths);
|
|
919
|
+
operationCount += aeApplyLayerTiming(comp, layerId, layerSpec.timing);
|
|
920
|
+
|
|
921
|
+
var propertyValues = layerSpec.propertyValues || [];
|
|
922
|
+
for (var i = 0; i < propertyValues.length; i++) {
|
|
923
|
+
var pv = propertyValues[i];
|
|
924
|
+
aeInvokeMutation(
|
|
925
|
+
setPropertyValue,
|
|
926
|
+
[layerId, null, pv.propertyPath, JSON.stringify(pv.value)],
|
|
927
|
+
"setPropertyValue(propertyValues)"
|
|
928
|
+
);
|
|
929
|
+
operationCount += 1;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
var effects = layerSpec.effects || [];
|
|
933
|
+
for (var j = 0; j < effects.length; j++) {
|
|
934
|
+
var effect = effects[j];
|
|
935
|
+
var effectName = effect.name !== undefined ? effect.name : null;
|
|
936
|
+
var existingEffect = aeFindExistingEffect(layer, effect.matchName, effectName);
|
|
937
|
+
if (!existingEffect) {
|
|
938
|
+
aeInvokeMutation(
|
|
939
|
+
addEffect,
|
|
940
|
+
[layerId, null, effect.matchName, effectName],
|
|
941
|
+
"addEffect"
|
|
942
|
+
);
|
|
943
|
+
operationCount += 1;
|
|
944
|
+
existingEffect = aeFindExistingEffect(layer, effect.matchName, effectName);
|
|
945
|
+
if (!existingEffect) {
|
|
946
|
+
throw new Error("Added effect could not be resolved for parameter updates.");
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
if (effect.params !== undefined) {
|
|
950
|
+
operationCount += aeApplyEffectParams(existingEffect, effect.params);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
var repeaters = layerSpec.repeaters || [];
|
|
955
|
+
for (var rr = 0; rr < repeaters.length; rr++) {
|
|
956
|
+
var repeaterSpec = repeaters[rr];
|
|
957
|
+
var repeaterName = repeaterSpec.name;
|
|
958
|
+
if (repeaterName !== undefined && repeaterName !== null && String(repeaterName).length > 0) {
|
|
959
|
+
var existingRepeater = aeFindShapeRepeater(layer, repeaterSpec.groupIndex, repeaterName);
|
|
960
|
+
if (existingRepeater) {
|
|
961
|
+
existingRepeater.remove();
|
|
962
|
+
operationCount += 1;
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
aeInvokeMutation(
|
|
966
|
+
addShapeRepeater,
|
|
967
|
+
[layerId, null, JSON.stringify(repeaterSpec)],
|
|
968
|
+
"addShapeRepeater"
|
|
969
|
+
);
|
|
970
|
+
operationCount += 1;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
var expressions = layerSpec.expressions || [];
|
|
974
|
+
for (var p = 0; p < expressions.length; p++) {
|
|
975
|
+
var expressionSpec = expressions[p];
|
|
976
|
+
aeApplyExpression(layerId, expressionSpec.propertyPath, expressionSpec.expression);
|
|
977
|
+
operationCount += 1;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
var essentialProperties = layerSpec.essentialProperties || [];
|
|
981
|
+
for (var r = 0; r < essentialProperties.length; r++) {
|
|
982
|
+
var essentialSpec = essentialProperties[r];
|
|
983
|
+
var addedEssential = aeTryAddEssentialProperty(
|
|
984
|
+
layerId,
|
|
985
|
+
essentialSpec.propertyPath,
|
|
986
|
+
essentialSpec.essentialName
|
|
987
|
+
);
|
|
988
|
+
if (addedEssential) {
|
|
989
|
+
operationCount += 1;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
var animations = layerSpec.animations || [];
|
|
994
|
+
for (var m = 0; m < animations.length; m++) {
|
|
995
|
+
var animation = animations[m];
|
|
996
|
+
var keyframes = animation.keyframes || [];
|
|
997
|
+
for (var n = 0; n < keyframes.length; n++) {
|
|
998
|
+
var keyframe = keyframes[n];
|
|
999
|
+
var keyframeOptions = {};
|
|
1000
|
+
if (keyframe.inInterp !== undefined) keyframeOptions.inInterp = keyframe.inInterp;
|
|
1001
|
+
if (keyframe.outInterp !== undefined) keyframeOptions.outInterp = keyframe.outInterp;
|
|
1002
|
+
if (keyframe.easeIn !== undefined) keyframeOptions.easeIn = keyframe.easeIn;
|
|
1003
|
+
if (keyframe.easeOut !== undefined) keyframeOptions.easeOut = keyframe.easeOut;
|
|
1004
|
+
aeInvokeMutation(
|
|
1005
|
+
setKeyframe,
|
|
1006
|
+
[
|
|
1007
|
+
layerId,
|
|
1008
|
+
null,
|
|
1009
|
+
animation.propertyPath,
|
|
1010
|
+
keyframe.time,
|
|
1011
|
+
JSON.stringify(keyframe.value),
|
|
1012
|
+
JSON.stringify(keyframeOptions),
|
|
1013
|
+
],
|
|
1014
|
+
"setKeyframe"
|
|
1015
|
+
);
|
|
1016
|
+
operationCount += 1;
|
|
1017
|
+
}
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
return {
|
|
1021
|
+
id: resolved.sceneId,
|
|
1022
|
+
created: resolved.created,
|
|
1023
|
+
parentId: layerSpec.parentId !== undefined ? layerSpec.parentId : undefined,
|
|
1024
|
+
layerId: layerId,
|
|
1025
|
+
layerUid: layer ? aeTryGetLayerUid(layer) : null,
|
|
1026
|
+
layerName: layer ? layer.name : null,
|
|
1027
|
+
layerType: resolved.layerType,
|
|
1028
|
+
operations: operationCount
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
function applyScene(sceneJSON, optionsJSON) {
|
|
1033
|
+
try {
|
|
1034
|
+
ensureJSON();
|
|
1035
|
+
|
|
1036
|
+
var scene = JSON.parse(sceneJSON);
|
|
1037
|
+
var options = {};
|
|
1038
|
+
if (optionsJSON && optionsJSON !== "null") {
|
|
1039
|
+
options = JSON.parse(optionsJSON);
|
|
1040
|
+
}
|
|
1041
|
+
var validateOnly = options.validateOnly === true;
|
|
1042
|
+
var applyMode = aeNormalizeSceneApplyMode(options.mode);
|
|
1043
|
+
|
|
1044
|
+
var validation = aeValidateSceneSpec(scene);
|
|
1045
|
+
if (!validation.ok) {
|
|
1046
|
+
return encodePayload({
|
|
1047
|
+
status: "error",
|
|
1048
|
+
message: "Scene validation failed.",
|
|
1049
|
+
errors: validation.errors
|
|
1050
|
+
});
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
var layers = scene.layers || [];
|
|
1054
|
+
var operationsPlanned = 0;
|
|
1055
|
+
for (var i = 0; i < layers.length; i++) {
|
|
1056
|
+
var layer = layers[i];
|
|
1057
|
+
operationsPlanned += 1;
|
|
1058
|
+
if (layer.transform) {
|
|
1059
|
+
if (layer.transform.anchorPoint !== undefined) operationsPlanned += 1;
|
|
1060
|
+
if (layer.transform.position !== undefined) operationsPlanned += 1;
|
|
1061
|
+
if (layer.transform.scale !== undefined) operationsPlanned += 1;
|
|
1062
|
+
if (layer.transform.rotation !== undefined) operationsPlanned += 1;
|
|
1063
|
+
if (layer.transform.opacity !== undefined) operationsPlanned += 1;
|
|
1064
|
+
}
|
|
1065
|
+
if (layer.timing && (layer.timing.inPoint !== undefined || layer.timing.outPoint !== undefined)) {
|
|
1066
|
+
operationsPlanned += 1;
|
|
1067
|
+
}
|
|
1068
|
+
if (layer.timing && layer.timing.startTime !== undefined) {
|
|
1069
|
+
operationsPlanned += 1;
|
|
1070
|
+
}
|
|
1071
|
+
operationsPlanned += (layer.propertyValues || []).length;
|
|
1072
|
+
var layerEffects = layer.effects || [];
|
|
1073
|
+
operationsPlanned += layerEffects.length;
|
|
1074
|
+
for (var ef = 0; ef < layerEffects.length; ef++) {
|
|
1075
|
+
operationsPlanned += (layerEffects[ef].params || []).length;
|
|
1076
|
+
}
|
|
1077
|
+
operationsPlanned += (layer.repeaters || []).length;
|
|
1078
|
+
operationsPlanned += (layer.expressions || []).length;
|
|
1079
|
+
operationsPlanned += (layer.essentialProperties || []).length;
|
|
1080
|
+
if (layer.parentId !== undefined) {
|
|
1081
|
+
operationsPlanned += 1;
|
|
1082
|
+
}
|
|
1083
|
+
var animations = layer.animations || [];
|
|
1084
|
+
for (var j = 0; j < animations.length; j++) {
|
|
1085
|
+
operationsPlanned += (animations[j].keyframes || []).length;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
var comp = null;
|
|
1090
|
+
var compSummary = null;
|
|
1091
|
+
if (validateOnly) {
|
|
1092
|
+
try {
|
|
1093
|
+
comp = aeResolveSceneComp(scene, false);
|
|
1094
|
+
} catch (eValidateComp) {
|
|
1095
|
+
var compSpec = scene.composition || {};
|
|
1096
|
+
var canUseVirtualComp = compSpec.name !== undefined && compSpec.createIfMissing !== false;
|
|
1097
|
+
if (!canUseVirtualComp) {
|
|
1098
|
+
throw eValidateComp;
|
|
1099
|
+
}
|
|
1100
|
+
compSummary = {
|
|
1101
|
+
id: null,
|
|
1102
|
+
name: compSpec.name,
|
|
1103
|
+
width: compSpec.width !== undefined ? compSpec.width : 1920,
|
|
1104
|
+
height: compSpec.height !== undefined ? compSpec.height : 1080,
|
|
1105
|
+
duration: compSpec.duration !== undefined ? compSpec.duration : 8.0,
|
|
1106
|
+
frameRate: compSpec.frameRate !== undefined ? compSpec.frameRate : 30.0
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
} else {
|
|
1110
|
+
comp = aeResolveSceneComp(scene, true);
|
|
1111
|
+
}
|
|
1112
|
+
if (!compSummary) {
|
|
1113
|
+
compSummary = {
|
|
1114
|
+
id: comp.id,
|
|
1115
|
+
name: comp.name,
|
|
1116
|
+
width: comp.width,
|
|
1117
|
+
height: comp.height,
|
|
1118
|
+
duration: comp.duration,
|
|
1119
|
+
frameRate: comp.frameRate
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
var declaredSceneIds = aeBuildDeclaredSceneIdSet(layers);
|
|
1124
|
+
var deleteTargets = comp ? aeCollectLayersForSceneApplyMode(comp, applyMode, declaredSceneIds) : [];
|
|
1125
|
+
operationsPlanned += deleteTargets.length;
|
|
1126
|
+
|
|
1127
|
+
if (validateOnly) {
|
|
1128
|
+
return encodePayload({
|
|
1129
|
+
status: "success",
|
|
1130
|
+
mode: "validate",
|
|
1131
|
+
applyMode: applyMode,
|
|
1132
|
+
composition: compSummary,
|
|
1133
|
+
layerCount: layers.length,
|
|
1134
|
+
operationsPlanned: operationsPlanned,
|
|
1135
|
+
deletedCount: deleteTargets.length
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
var appliedLayers = [];
|
|
1140
|
+
var createdCount = 0;
|
|
1141
|
+
var reusedCount = 0;
|
|
1142
|
+
var parentAppliedCount = 0;
|
|
1143
|
+
var deletedLayers = [];
|
|
1144
|
+
app.beginUndoGroup("Apply Scene");
|
|
1145
|
+
try {
|
|
1146
|
+
deletedLayers = aeDeleteLayerTargets(deleteTargets);
|
|
1147
|
+
var sceneLayerIndex = aeBuildSceneLayerIndex(comp);
|
|
1148
|
+
for (var m = 0; m < layers.length; m++) {
|
|
1149
|
+
var applied = aeApplySceneLayer(comp, layers[m], m, sceneLayerIndex);
|
|
1150
|
+
appliedLayers.push(applied);
|
|
1151
|
+
if (applied.created) {
|
|
1152
|
+
createdCount += 1;
|
|
1153
|
+
} else {
|
|
1154
|
+
reusedCount += 1;
|
|
1155
|
+
}
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
for (var t = 0; t < appliedLayers.length; t++) {
|
|
1159
|
+
var normalizedApplied = appliedLayers[t];
|
|
1160
|
+
if (!normalizedApplied.id) {
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
var normalizedLayerSet = sceneLayerIndex[normalizedApplied.id] || [];
|
|
1164
|
+
if (normalizedLayerSet.length >= 1 && normalizedLayerSet[0]) {
|
|
1165
|
+
normalizedApplied.layerId = normalizedLayerSet[0].index;
|
|
1166
|
+
normalizedApplied.layerUid = aeTryGetLayerUid(normalizedLayerSet[0]);
|
|
1167
|
+
normalizedApplied.layerName = normalizedLayerSet[0].name;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
var sceneIdToLayerId = {};
|
|
1172
|
+
for (var u = 0; u < appliedLayers.length; u++) {
|
|
1173
|
+
var appliedLayer = appliedLayers[u];
|
|
1174
|
+
if (appliedLayer.id) {
|
|
1175
|
+
sceneIdToLayerId[appliedLayer.id] = appliedLayer.layerId;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
for (var v = 0; v < layers.length; v++) {
|
|
1179
|
+
var layerSpec = layers[v];
|
|
1180
|
+
if (layerSpec.parentId === undefined) {
|
|
1181
|
+
continue;
|
|
1182
|
+
}
|
|
1183
|
+
var childApplied = appliedLayers[v];
|
|
1184
|
+
var parentLayerId = null;
|
|
1185
|
+
if (layerSpec.parentId !== null) {
|
|
1186
|
+
parentLayerId = sceneIdToLayerId[String(layerSpec.parentId)];
|
|
1187
|
+
if (!parentLayerId) {
|
|
1188
|
+
throw new Error("parentId '" + layerSpec.parentId + "' was not found in scene layers.");
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
if (parentLayerId !== null && parentLayerId === childApplied.layerId) {
|
|
1192
|
+
// Already in desired state for scene identity mapping.
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
aeInvokeMutation(
|
|
1196
|
+
parentLayer,
|
|
1197
|
+
[childApplied.layerId, parentLayerId],
|
|
1198
|
+
"parentLayer"
|
|
1199
|
+
);
|
|
1200
|
+
childApplied.operations += 1;
|
|
1201
|
+
parentAppliedCount += 1;
|
|
1202
|
+
}
|
|
1203
|
+
} finally {
|
|
1204
|
+
app.endUndoGroup();
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
return encodePayload({
|
|
1208
|
+
status: "success",
|
|
1209
|
+
mode: "apply",
|
|
1210
|
+
composition: compSummary,
|
|
1211
|
+
applyMode: applyMode,
|
|
1212
|
+
layerCount: appliedLayers.length,
|
|
1213
|
+
operationsPlanned: operationsPlanned,
|
|
1214
|
+
createdCount: createdCount,
|
|
1215
|
+
reusedCount: reusedCount,
|
|
1216
|
+
parentAppliedCount: parentAppliedCount,
|
|
1217
|
+
deletedCount: deletedLayers.length,
|
|
1218
|
+
deletedLayers: deletedLayers,
|
|
1219
|
+
createdLayers: appliedLayers,
|
|
1220
|
+
appliedLayers: appliedLayers
|
|
1221
|
+
});
|
|
1222
|
+
} catch (e) {
|
|
1223
|
+
log("applyScene() threw: " + e.toString());
|
|
1224
|
+
return encodePayload({ status: "error", message: e.toString() });
|
|
1225
|
+
}
|
|
1226
|
+
}
|