@nexrender/core 1.32.3 → 1.33.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/package.json +2 -2
- package/readme.md +1 -0
- package/src/assets/commandLineRenderer-2022.jsx +1130 -0
- package/src/assets/{commandLineRenderer.jsx → commandLineRenderer-default.jsx} +12 -12
- package/src/helpers/autofind.js +1 -0
- package/src/helpers/patch.js +9 -1
- package/src/index.js +1 -0
- package/src/tasks/render.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexrender/core",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.33.0",
|
|
4
4
|
"main": "src/index.js",
|
|
5
5
|
"author": "Inlife",
|
|
6
6
|
"scripts": {
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
|
-
"gitHead": "
|
|
32
|
+
"gitHead": "6f3bdccfa13723b3b43552193871973ab395d428"
|
|
33
33
|
}
|
package/readme.md
CHANGED
|
@@ -59,6 +59,7 @@ Second one is responsible for mainly job-related operations of the full cycle: d
|
|
|
59
59
|
* `skipCleanup` - boolean, providing true will prevent nexrender from removing the temp folder with project (false by default)
|
|
60
60
|
* `skipRender` - boolean, providing true will prevent nexrender from running actual rendering, might be useful if you only want to call scripts
|
|
61
61
|
* `multiFrames` - boolean, providing true will attmpt to use aerender's built-in feature of multi frame rendering (false by default)
|
|
62
|
+
* `multiFramesCPU` - integer between 1-100, the percentage of CPU used by multi frame rendering, if enabled (90 by default)
|
|
62
63
|
* `reuse` - boolean, false by default, (from Adobe site): Reuse the currently running instance of After Effects (if found) to perform the render. When an already running instance is used, aerender saves preferences to disk when rendering has completed, but does not quit After Effects. If this argument is not used, aerender starts a new instance of After Effects, even if one is already running. It quits that instance when rendering has completed, and does not save preferences.
|
|
63
64
|
* `maxMemoryPercent` - integer, undefined by default, check [original documentation](https://helpx.adobe.com/after-effects/using/automated-rendering-network-rendering.html) for more info
|
|
64
65
|
* `imageCachePercent` - integer, undefined by default, check [original documentation](https://helpx.adobe.com/after-effects/using/automated-rendering-network-rendering.html) for more info
|
|
@@ -0,0 +1,1130 @@
|
|
|
1
|
+
module.exports = /*syntax:js*/ `// Command line renderer for After Effects. (nexrender-patch-v1.0.3)
|
|
2
|
+
|
|
3
|
+
// This function constructs an AECommandLineRenderer object.
|
|
4
|
+
// One and only one of these will be created to perform rendering tasks
|
|
5
|
+
// at the end of this file.
|
|
6
|
+
//
|
|
7
|
+
// The constructor has 3 sections:
|
|
8
|
+
// [1] define all the variable-type attributes used by this class;
|
|
9
|
+
// [2] define all the functions used by this class;
|
|
10
|
+
// [3] assign all the functions to be method-type attributes.
|
|
11
|
+
//
|
|
12
|
+
function AECommandLineRenderer() {
|
|
13
|
+
// [1] define all the variable-type attributes used by this class
|
|
14
|
+
//
|
|
15
|
+
// Input before parsing
|
|
16
|
+
//
|
|
17
|
+
this.inArgs = null;
|
|
18
|
+
//
|
|
19
|
+
// Input after parsing
|
|
20
|
+
//
|
|
21
|
+
this.in_project_path = null;
|
|
22
|
+
this.in_teamproject_name = null;
|
|
23
|
+
this.in_comp_name = null;
|
|
24
|
+
this.in_rq_index = null;
|
|
25
|
+
this.in_RStemplate = null;
|
|
26
|
+
this.in_RSsettings = null;
|
|
27
|
+
this.in_OMtemplate = null;
|
|
28
|
+
this.in_OMsettings = null;
|
|
29
|
+
this.in_output_path = null;
|
|
30
|
+
this.in_logfile_path = null;
|
|
31
|
+
this.in_start_frame = null;
|
|
32
|
+
this.in_end_frame = null;
|
|
33
|
+
this.in_increment = null;
|
|
34
|
+
this.in_image_cache_percent = null;
|
|
35
|
+
this.in_max_mem_percent = null;
|
|
36
|
+
this.in_verbose_flag = null;
|
|
37
|
+
this.in_close_flag = null;
|
|
38
|
+
this.in_sound_flag = null;
|
|
39
|
+
this.in_port_address = null;
|
|
40
|
+
this.in_stop_on_missing_frame = true;
|
|
41
|
+
this.in_mfr_enable = null;
|
|
42
|
+
this.in_mfr_max_cpu_percent = null;
|
|
43
|
+
this.in_script_path = null;
|
|
44
|
+
//
|
|
45
|
+
// Exit codes:
|
|
46
|
+
//
|
|
47
|
+
this.EXIT_OK = 0;
|
|
48
|
+
this.EXIT_FAILURE_CODE_FROM_APP = 1;
|
|
49
|
+
this.EXIT_SHOW_USAGE = 2;
|
|
50
|
+
this.EXIT_SYNTAX_ERROR = 3;
|
|
51
|
+
this.EXIT_SYNTAX_ERROR_USER_LOG = 4;
|
|
52
|
+
this.EXIT_OTHER_SCRIPTING_ERROR = 5;
|
|
53
|
+
this.EXIT_OTHER_SCRIPTING_ERROR_USER_LOG = 6;
|
|
54
|
+
this.EXIT_AERENDER_RUNTIME = 7;
|
|
55
|
+
this.EXIT_AERENDER_RUNTIME_USER_LOG = 8;
|
|
56
|
+
this.EXIT_AE_RUNTIME = 9;
|
|
57
|
+
this.EXIT_AE_RUNTIME_USER_LOG = 10;
|
|
58
|
+
this.EXIT_CANNOT_OPEN_SOCKET = 11;
|
|
59
|
+
this.EXIT_CODE_NO_LONGER_IN_USE = 12;
|
|
60
|
+
//
|
|
61
|
+
// Exit code message prefixes:
|
|
62
|
+
//
|
|
63
|
+
this.EXIT_MSG_PREFIX = new Array(
|
|
64
|
+
"", // EXIT_OK
|
|
65
|
+
"ERROR: ", // EXIT_FAILURE_CODE_FROM_APP
|
|
66
|
+
"USAGE: ", // EXIT_SHOW_USAGE
|
|
67
|
+
"SYNTAX ERROR: ", // EXIT_SYNTAX_ERROR
|
|
68
|
+
"SYNTAX ERROR: ", // EXIT_SYNTAX_ERROR_USER_LOG
|
|
69
|
+
"ERROR: ", // EXIT_OTHER_SCRIPTING_ERROR
|
|
70
|
+
"ERROR: ", // EXIT_OTHER_SCRIPTING_ERROR_USER_LOG
|
|
71
|
+
"ERROR: ", // EXIT_AERENDER_ERROR
|
|
72
|
+
"ERROR: ", // EXIT_AERENDER_ERROR_USER_LOG
|
|
73
|
+
"ERROR: ", // EXIT_AE_RUNTIME
|
|
74
|
+
"ERROR: ", // EXIT_AE_RUNTIME_USER_LOG
|
|
75
|
+
"ERROR: ", // EXIT_CANNOT_OPEN_SOCKET
|
|
76
|
+
"", // EXIT_CODE_NO_LONGER_IN_USE
|
|
77
|
+
);
|
|
78
|
+
//
|
|
79
|
+
// Messages:
|
|
80
|
+
//
|
|
81
|
+
this.MSG_NONE = "";
|
|
82
|
+
this.MSG_NOT_HANDLED_HERE = "reported by another script or AE runtime.";
|
|
83
|
+
this.MSG_SHOW_USAGE = "";
|
|
84
|
+
this.MSG_TRIED_TO_PARSE_UNDEFINED = "aerender tried to parse an undefined argument.";
|
|
85
|
+
this.MSG_UNDEFINED_VALUE_FOR_FLAG = "no value given for flag: ";
|
|
86
|
+
this.MSG_BAD_FLAG = "Illegal argument flag: ";
|
|
87
|
+
this.MSG_NO_PROJECT = "No project provided and no project open.";
|
|
88
|
+
this.MSG_BAD_VERBOSE_FLAG = "Bad value for -verbose.";
|
|
89
|
+
this.MSG_BAD_CLOSE_FLAG = "Bad value for -close.";
|
|
90
|
+
this.MSG_BAD_SOUND_FLAG = "Bad value for -sound.";
|
|
91
|
+
this.MSG_BAD_MFR_FLAG = "Bad value for -mfr.";
|
|
92
|
+
this.MSG_BAD_INCREMENT = "Bad value for -increment. Must be between 1 and 100, inclusive.";
|
|
93
|
+
this.MSG_COMP_NOT_FOUND = "No comp was found with the given name.";
|
|
94
|
+
this.MSG_RQINDEX_NOT_FOUND = "No render queue item was found with the given index.";
|
|
95
|
+
this.MSG_AE_RUNTIME = "Runtime error in After Effects.";
|
|
96
|
+
this.MSG_ADDING_TO_RQ = "PROGRESS: Adding specified comp to Render Queue";
|
|
97
|
+
this.MSG_NEEDS_OUTPUT = "Specified render queue item needs output file but none provided.";
|
|
98
|
+
this.MSG_RS_TEMPLATE_NOT_FOUND = "No render settings template was found with the given name.";
|
|
99
|
+
this.MSG_OM_TEMPLATE_NOT_FOUND = "No output module template was found with the given name.";
|
|
100
|
+
this.MSG_RS_SETTINGS_NO_RQI = "Can't use -renderSettings because no render queue item was specified.";
|
|
101
|
+
this.MSG_OM_SETTINGS_NO_RQI = "Can't use -outputSettings because no render queue item was specified.";
|
|
102
|
+
this.MSG_CAN_NOT_OPEN_SOCKET = "Can not open socket.";
|
|
103
|
+
this.MSG_NO_COMP_YES_TEMPLATE = "WARNING: -RStemplate argument ignored since no -comp or -rqindex provided.";
|
|
104
|
+
this.MSG_NO_COMP_YES_OMTEMPLATE = "WARNING: -OMtemplate argument ignored since no -comp or -rqindex provided.";
|
|
105
|
+
this.MSG_NO_COMP_YES_OUTPUT = "WARNING: -output argument ignored since no -comp or -rqindex provided.";
|
|
106
|
+
this.MSG_NO_COMP_YES_START_OR_END = "WARNING: -s and/or -e arguments ignored since no -comp or -rqindex provided.";
|
|
107
|
+
this.MSG_NO_COMP_YES_INCREMENT = "WARNING: -i argument ignored since no -comp or -rqindex provided.";
|
|
108
|
+
this.MSG_SKIPPING_WILL_CONTINUE = "INFO: Skipping render queue item with correct comp name but marked to continue from a partly complete render.";
|
|
109
|
+
this.MSG_RENDER_ABORTED = "INFO: Render aborted.";
|
|
110
|
+
this.MSG_SCRIPT_CAN_NOT_EXEC = "aerender ERROR: Error executing script: ";
|
|
111
|
+
this.MSG_SCRIPT_CAN_NOT_OPEN = "aerender ERROR: Can not open script file. Make sure path is correct: ";
|
|
112
|
+
|
|
113
|
+
// These three don't get the prefix printed since they are not exit messages
|
|
114
|
+
this.MSG_LOG_DIR_NO_EXISTS = "aerender ERROR: Directory specified for log file does not exist: ";
|
|
115
|
+
this.MSG_LOG_DIR_NOT_A_DIR = "aerender ERROR: Directory specified for log file is a file, not a directory: ";
|
|
116
|
+
this.MSG_LOG_CAN_NOT_OPEN = "aerender ERROR: Can not open log file. Try checking write protection of directory: ";
|
|
117
|
+
//
|
|
118
|
+
// Variables for rendering
|
|
119
|
+
//
|
|
120
|
+
this.log_file = null;
|
|
121
|
+
this.has_user_log_file = false;
|
|
122
|
+
this.is_verbose_mode = true;
|
|
123
|
+
this.saved_sound_setting = null;
|
|
124
|
+
this.my_sound_setting = null;
|
|
125
|
+
|
|
126
|
+
// [2] define all the functions used by this class
|
|
127
|
+
//
|
|
128
|
+
// Report an error. This writes errors to the log file, if present.
|
|
129
|
+
// This is called from the context of the application, so we
|
|
130
|
+
// need to precede variable names with gAECommandLineRenderer
|
|
131
|
+
//
|
|
132
|
+
function checkParentDied() {
|
|
133
|
+
var result = false;
|
|
134
|
+
if (gAECommandLineRenderer.log_file instanceof Socket) {
|
|
135
|
+
if (!gAECommandLineRenderer.log_file.connected) {
|
|
136
|
+
app.project.renderQueue.stopRendering();
|
|
137
|
+
result = true;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
function my_onError(error_string, severity_string) {
|
|
144
|
+
// This method is called with a variety of types of messages.
|
|
145
|
+
// The severity_string tells us what kind.
|
|
146
|
+
// Choices are:
|
|
147
|
+
// NAKED, INFO, WARNING, PROBLEM, FATAL, PROGRESS, and DEBUG
|
|
148
|
+
|
|
149
|
+
// Two of these, PROBLEM and FATAL, are errors that should cause us to change
|
|
150
|
+
// the exit code:
|
|
151
|
+
checkParentDied();
|
|
152
|
+
|
|
153
|
+
if (severity_string == "PROBLEM" || severity_string == "FATAL") {
|
|
154
|
+
// These two errors cause us to change the exit code.
|
|
155
|
+
// We don't write an error or throw here, because we got here as part of a thrown
|
|
156
|
+
// error already, and the message will be printed as part of the catch.
|
|
157
|
+
gAECommandLineRenderer.SetExitCode(gAECommandLineRenderer.EXIT_AE_RUNTIME);
|
|
158
|
+
} else {
|
|
159
|
+
// PROBLEM and FATAL will throw exceptions, and so will be logged to the file
|
|
160
|
+
// when we catch the exception.
|
|
161
|
+
// All other errors (NAKED, INFO, WARNING, PROGRESS, and DEBUG) will not
|
|
162
|
+
// throw exceptions. So we log them to the file right here:
|
|
163
|
+
if (gAECommandLineRenderer.is_verbose_mode) {
|
|
164
|
+
if (gAECommandLineRenderer.log_file != null) {
|
|
165
|
+
if (severity_string == "NAKED") {
|
|
166
|
+
// everybody is confused by this category. Just use INFO instead.
|
|
167
|
+
gAECommandLineRenderer.log_file.writeln("INFO:" + error_string);
|
|
168
|
+
} else {
|
|
169
|
+
gAECommandLineRenderer.log_file.writeln(severity_string + ":" + error_string);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
// call the error handler that was in place before we started rendering.
|
|
175
|
+
if (gAECommandLineRenderer.oldErrorHandler) {
|
|
176
|
+
gAECommandLineRenderer.oldErrorHandler(error_string, severity_string);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Report an error and throw an exception.
|
|
181
|
+
// Causes the script to exit.
|
|
182
|
+
function my_SetExitCodeAndThrowException(code, message) {
|
|
183
|
+
this.SetExitCode(code);
|
|
184
|
+
throw (this.EXIT_MSG_PREFIX[code] + message);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Report an error. This establishes exitCodes for reporting errors from AfterFX.
|
|
188
|
+
function my_SetExitCode(code) {
|
|
189
|
+
// Some codes are set differently depending on whether we have a custom user
|
|
190
|
+
// log file. Check for these and use the alternate if appropriate.
|
|
191
|
+
var real_code = code;
|
|
192
|
+
if (gAECommandLineRenderer.has_user_log_file) {
|
|
193
|
+
switch (real_code) {
|
|
194
|
+
case gAECommandLineRenderer.EXIT_SYNTAX_ERROR:
|
|
195
|
+
real_code = gAECommandLineRenderer.EXIT_SYNTAX_ERROR_USER_LOG;
|
|
196
|
+
break;
|
|
197
|
+
case gAECommandLineRenderer.EXIT_OTHER_SCRIPTING_ERROR:
|
|
198
|
+
real_code = gAECommandLineRenderer.EXIT_OTHER_SCRIPTING_ERROR_USER_LOG;
|
|
199
|
+
break;
|
|
200
|
+
case gAECommandLineRenderer.EXIT_AERENDER_RUNTIME:
|
|
201
|
+
real_code = gAECommandLineRenderer.EXIT_AERENDER_RUNTIME_USER_LOG;
|
|
202
|
+
break;
|
|
203
|
+
case gAECommandLineRenderer.EXIT_AE_RUNTIME:
|
|
204
|
+
real_code = gAECommandLineRenderer.EXIT_AE_RUNTIME_USER_LOG;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Always keep the first error. So only set if the exitCode is still EXIT_OK.
|
|
210
|
+
if (app.exitCode == gAECommandLineRenderer.EXIT_OK) {
|
|
211
|
+
app.exitCode = real_code;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Arguments may be enclosed in quotes. This
|
|
216
|
+
// will remove them and return the result.
|
|
217
|
+
function my_StripAnyEnclosingQuotes(inString) {
|
|
218
|
+
var result = inString;
|
|
219
|
+
if (inString &&
|
|
220
|
+
inString.charAt(0) == '"' &&
|
|
221
|
+
inString.charAt(inString.length - 1) == '"') {
|
|
222
|
+
result = inString.substring(1, inString.length - 1);
|
|
223
|
+
}
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Make sure the value is there, and returns it, stripping away any enclosing quotes.
|
|
228
|
+
//
|
|
229
|
+
function my_GetValueForFlag(arg_num, the_flag) {
|
|
230
|
+
if (!this.inArgs[arg_num]) {
|
|
231
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, (this.MSG_UNDEFINED_VALUE_FOR_FLAG + the_flag));
|
|
232
|
+
}
|
|
233
|
+
return this.StripAnyEnclosingQuotes(this.inArgs[arg_num]);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// this function takes a string like "key:value; key2:value2" and
|
|
237
|
+
// constructs an object {key:"value", key2: "value2"} which is
|
|
238
|
+
// the format expected by RQ scripting APIs
|
|
239
|
+
//
|
|
240
|
+
// you might reasonably wonder why this isn't JSON.parse?
|
|
241
|
+
//
|
|
242
|
+
// * ExtendScript's ES version doesn't include JSON
|
|
243
|
+
// * didn't want to pollute global space/aerender at startup with a
|
|
244
|
+
// possibly different copy of JSON
|
|
245
|
+
// * settings dictionary for RenderSettings and OutputModule use
|
|
246
|
+
// string values exclusively. escaping a real world RQ/OM settings
|
|
247
|
+
// JSON obj on the command line is alarmingly complicated and dangerous
|
|
248
|
+
// (2*N backslashes for every " where) N = total number of quotes to escape
|
|
249
|
+
// in the _entire_ command line
|
|
250
|
+
|
|
251
|
+
function my_settingsStringToObject(sTokens) {
|
|
252
|
+
var obj = {};
|
|
253
|
+
var keyValuePairs = sTokens.split(";");
|
|
254
|
+
|
|
255
|
+
// ExtendScript too old to have str.trim(), replace when it does
|
|
256
|
+
function trim(s) {
|
|
257
|
+
return s.replace(/^\s+|\s+$/g, '');
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
for (var i in keyValuePairs) {
|
|
261
|
+
var kv_array = keyValuePairs[i].split(":");
|
|
262
|
+
var k = trim(kv_array[0]);
|
|
263
|
+
var v = trim(kv_array[1]);
|
|
264
|
+
obj[k] = v;
|
|
265
|
+
}
|
|
266
|
+
return obj;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// Parse the parameter.
|
|
270
|
+
// Return the number of arguments used in parsing the parameter.
|
|
271
|
+
function my_ParseParamStartingAt(arg_num) {
|
|
272
|
+
if (!this.inArgs[arg_num]) {
|
|
273
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_TRIED_TO_PARSE_UNDEFINED);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
var num_args_parsed = 0;
|
|
277
|
+
|
|
278
|
+
// Check for a valid flag:
|
|
279
|
+
var my_flag = this.inArgs[arg_num];
|
|
280
|
+
if (my_flag == "-port") {
|
|
281
|
+
// -port is used by aerender to specify a port address for a socket.
|
|
282
|
+
//
|
|
283
|
+
// Note: this value is sought/parsed earlier, in the SetupDefaultLog method.
|
|
284
|
+
// We can just ignore here.
|
|
285
|
+
var dummy = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
286
|
+
num_args_parsed = 2;
|
|
287
|
+
}
|
|
288
|
+
if (my_flag == "-project") {
|
|
289
|
+
this.in_project_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
290
|
+
num_args_parsed = 2;
|
|
291
|
+
}
|
|
292
|
+
if (my_flag == "-teamproject") {
|
|
293
|
+
this.in_teamproject_name = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
294
|
+
num_args_parsed = 2;
|
|
295
|
+
}
|
|
296
|
+
if (my_flag == "-comp") {
|
|
297
|
+
this.in_comp_name = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
298
|
+
num_args_parsed = 2;
|
|
299
|
+
}
|
|
300
|
+
if (my_flag == "-rqindex") {
|
|
301
|
+
this.in_rq_index = parseInt(this.GetValueForFlag(arg_num + 1, my_flag));
|
|
302
|
+
num_args_parsed = 2;
|
|
303
|
+
}
|
|
304
|
+
if (my_flag == "-RStemplate") {
|
|
305
|
+
this.in_RStemplate = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
306
|
+
num_args_parsed = 2;
|
|
307
|
+
}
|
|
308
|
+
if (my_flag == "-OMtemplate") {
|
|
309
|
+
this.in_OMtemplate = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
310
|
+
num_args_parsed = 2;
|
|
311
|
+
}
|
|
312
|
+
if (my_flag == "-renderSettings") {
|
|
313
|
+
this.in_RSsettings = my_settingsStringToObject(this.GetValueForFlag(arg_num + 1, my_flag));
|
|
314
|
+
num_args_parsed = 2;
|
|
315
|
+
}
|
|
316
|
+
if (my_flag == "-outputSettings") {
|
|
317
|
+
this.in_OMsettings = my_settingsStringToObject(this.GetValueForFlag(arg_num + 1, my_flag));
|
|
318
|
+
num_args_parsed = 2;
|
|
319
|
+
}
|
|
320
|
+
if (my_flag == "-output") {
|
|
321
|
+
this.in_output_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
322
|
+
num_args_parsed = 2;
|
|
323
|
+
}
|
|
324
|
+
if (my_flag == "-log") {
|
|
325
|
+
this.in_logfile_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
326
|
+
num_args_parsed = 2;
|
|
327
|
+
}
|
|
328
|
+
if (my_flag == "-s") {
|
|
329
|
+
this.in_start_frame = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
330
|
+
num_args_parsed = 2;
|
|
331
|
+
}
|
|
332
|
+
if (my_flag == "-e") {
|
|
333
|
+
this.in_end_frame = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
334
|
+
num_args_parsed = 2;
|
|
335
|
+
}
|
|
336
|
+
if (my_flag == "-i") {
|
|
337
|
+
this.in_increment = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
338
|
+
num_args_parsed = 2;
|
|
339
|
+
}
|
|
340
|
+
if (my_flag == "-mem_usage") {
|
|
341
|
+
this.in_image_cache_percent = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
342
|
+
this.in_max_mem_percent = this.GetValueForFlag(arg_num + 2, my_flag);
|
|
343
|
+
num_args_parsed = 3;
|
|
344
|
+
}
|
|
345
|
+
if (my_flag == "-mfr") {
|
|
346
|
+
this.in_mfr_enable = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
347
|
+
this.in_mfr_max_cpu_percent = this.GetValueForFlag(arg_num + 2, my_flag);
|
|
348
|
+
num_args_parsed = 3;
|
|
349
|
+
}
|
|
350
|
+
if (my_flag == "-v") {
|
|
351
|
+
this.in_verbose_flag = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
352
|
+
num_args_parsed = 2;
|
|
353
|
+
}
|
|
354
|
+
if (my_flag == "-r") {
|
|
355
|
+
this.in_script_path = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
356
|
+
num_args_parsed = 2;
|
|
357
|
+
}
|
|
358
|
+
if (my_flag == "-close") {
|
|
359
|
+
this.in_close_flag = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
360
|
+
num_args_parsed = 2;
|
|
361
|
+
}
|
|
362
|
+
if (my_flag == "-sound") {
|
|
363
|
+
this.in_sound_flag = this.GetValueForFlag(arg_num + 1, my_flag);
|
|
364
|
+
num_args_parsed = 2;
|
|
365
|
+
}
|
|
366
|
+
if (my_flag == "-doSavePrefsOnQuit") {
|
|
367
|
+
// The effect of this flag will be taken into account when we
|
|
368
|
+
// exit the app. See comment in the "finally" block.
|
|
369
|
+
// All we do here is increment the num_args_parsed count.
|
|
370
|
+
num_args_parsed = 1;
|
|
371
|
+
}
|
|
372
|
+
if (my_flag == "-continueOnMissingFootage") {
|
|
373
|
+
this.in_stop_on_missing_frame = false;
|
|
374
|
+
num_args_parsed = 1;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (num_args_parsed == 0) {
|
|
378
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, (this.MSG_BAD_FLAG + my_flag));
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
return num_args_parsed;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// This parses the inArgs array. Assumes
|
|
385
|
+
// the array has already been filled.
|
|
386
|
+
function my_ParseInArgs() {
|
|
387
|
+
// First, undefine all the inputs we're potentially looking for
|
|
388
|
+
this.in_project_path = null;
|
|
389
|
+
this.in_teamproject_name = null;
|
|
390
|
+
this.in_comp_name = null;
|
|
391
|
+
this.in_rq_index = null;
|
|
392
|
+
this.in_RStemplate = null;
|
|
393
|
+
this.in_RSsettings = null;
|
|
394
|
+
this.in_OMtemplate = null;
|
|
395
|
+
this.in_output_path = null;
|
|
396
|
+
this.in_logfile_path = null;
|
|
397
|
+
this.in_start_frame = null;
|
|
398
|
+
this.in_end_frame = null;
|
|
399
|
+
this.in_increment = null;
|
|
400
|
+
this.in_image_cache_percent = null;
|
|
401
|
+
this.in_max_mem_percent = null;
|
|
402
|
+
this.in_verbose_flag = null;
|
|
403
|
+
this.in_close_flag = null;
|
|
404
|
+
this.in_sound_flag = null;
|
|
405
|
+
this.in_mfr_enable = null;
|
|
406
|
+
this.in_mfr_max_cpu_percent = null;
|
|
407
|
+
this.in_script_path = null;
|
|
408
|
+
|
|
409
|
+
// Special case: check if any argument is "-help"
|
|
410
|
+
for (var i = 0; i < this.inArgs.length; i++) {
|
|
411
|
+
if (this.inArgs[i] == "-help") {
|
|
412
|
+
this.SetExitCodeAndThrowException(this.EXIT_SHOW_USAGE, this.MSG_SHOW_USAGE);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
var arg_num = 0;
|
|
417
|
+
while (arg_num < this.inArgs.length) {
|
|
418
|
+
// ParseParamStartingAt returns the number of arguments used up parsing the param.
|
|
419
|
+
arg_num += this.ParseParamStartingAt(arg_num);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// This arg is treated differently than others because it's extra important
|
|
424
|
+
// that we exit properly in the face of anything that might go wrong even
|
|
425
|
+
// during initialization. So we don't parse the standard way, we check this
|
|
426
|
+
// before exit...
|
|
427
|
+
function my_IsSavePrefsArgGiven(arglist) {
|
|
428
|
+
return this.IsInArray("-doSavePrefsOnQuit", arglist);
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Returns true if the item equals an item in the array, false if otherwise.
|
|
432
|
+
function my_IsInArray(needle, haystack) {
|
|
433
|
+
result = false;
|
|
434
|
+
for (var i = 0; i < haystack.length; i++) {
|
|
435
|
+
if (needle == haystack[i]) {
|
|
436
|
+
result = true;
|
|
437
|
+
break;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return result;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
function my_SetupDefaultLog(arg_list) {
|
|
444
|
+
this.has_user_log_file = false;
|
|
445
|
+
|
|
446
|
+
// Clean up after a potentially bad exit last time:
|
|
447
|
+
if (this.log_file && this.log_file != null) {
|
|
448
|
+
this.log_file.close();
|
|
449
|
+
this.log_file = null;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// Open the socket.
|
|
453
|
+
// It is used:
|
|
454
|
+
// [a] to log errors if there is no user-specified log file (specified with a "-log" arg)
|
|
455
|
+
// [b] to log errors encountered while opening any user-specified log file.
|
|
456
|
+
|
|
457
|
+
// See if a -port argument was passed:
|
|
458
|
+
this.log_file = null;
|
|
459
|
+
for (var i = 0; i < arg_list.length; i++) {
|
|
460
|
+
if (arg_list[i] == "-port") {
|
|
461
|
+
if (arg_list.length > i + 1) {
|
|
462
|
+
// The argument value is the port address
|
|
463
|
+
this.in_port_address = arg_list[i + 1];
|
|
464
|
+
// Yes, the log_file variable is being used to hold a socket.
|
|
465
|
+
this.log_file = new Socket();
|
|
466
|
+
|
|
467
|
+
// cprosser [26961]
|
|
468
|
+
// could possibly use ISO-8856-1 for non japanese systems,
|
|
469
|
+
// but I am going for small changes now.
|
|
470
|
+
// and again cprosser 8/8/2005 [33884]
|
|
471
|
+
// CP_OEMCP means use the OEM code page, the default
|
|
472
|
+
// for the console.
|
|
473
|
+
// alas, it doens't understand that so we are hardcoding
|
|
474
|
+
// codepage 850. Not the default on windows for US systems
|
|
475
|
+
// but should be the default on european systems and will
|
|
476
|
+
// get the high ascii correct.
|
|
477
|
+
// Search for chcp at microsoft for info on changing
|
|
478
|
+
// the console.
|
|
479
|
+
// on the mac, leave as binary
|
|
480
|
+
|
|
481
|
+
/*
|
|
482
|
+
davec [DVAAE-4195268]
|
|
483
|
+
update: we now make everything utf8
|
|
484
|
+
and in aerender.cpp we cope with converting
|
|
485
|
+
that to whatever the console is expecting.
|
|
486
|
+
|
|
487
|
+
on mac, it's just utf8 (yay)
|
|
488
|
+
on windows, it's "oem codepage" which == 1
|
|
489
|
+
|
|
490
|
+
learn about JS Blob encodings here:
|
|
491
|
+
https://estk.aenhancers.com/3%20-%20File%20System%20Access/file-and-folder-supported-encoding-names.html#file-and-folder-supported-encoding-names
|
|
492
|
+
*/
|
|
493
|
+
|
|
494
|
+
if (!this.log_file.open(this.in_port_address, "UTF-8")) {
|
|
495
|
+
this.log_file = null;
|
|
496
|
+
this.SetExitCodeAndThrowException(this.EXIT_CANNOT_OPEN_SOCKET,
|
|
497
|
+
this.MSG_CAN_NOT_OPEN_SOCKET);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
this.is_verbose_mode = true;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
function my_CleanupDefaultLog() {
|
|
506
|
+
// Close the log file
|
|
507
|
+
if (this.log_file != null) {
|
|
508
|
+
this.log_file.close();
|
|
509
|
+
this.log_file = null;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// This is the external entry point.
|
|
514
|
+
// Bat files or executables may call this method.
|
|
515
|
+
//
|
|
516
|
+
// This function assumes that it has been passed all the arguments.
|
|
517
|
+
// It parses the arguments and then renders.
|
|
518
|
+
function my_Render() {
|
|
519
|
+
app.beginSuppressDialogs();
|
|
520
|
+
|
|
521
|
+
if (checkParentDied()) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
try {
|
|
526
|
+
this.SetupDefaultLog(my_Render.arguments);
|
|
527
|
+
|
|
528
|
+
// start by assuming successful execution, exit code 0.
|
|
529
|
+
app.exitCode = 0;
|
|
530
|
+
|
|
531
|
+
// Check number of arguments
|
|
532
|
+
if (!my_Render.arguments || my_Render.arguments.length == 0) {
|
|
533
|
+
this.SetExitCodeAndThrowException(this.EXIT_SHOW_USAGE, this.MSG_SHOW_USAGE);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
var numArgs = my_Render.arguments.length;
|
|
537
|
+
// Allocate the array of arguments:
|
|
538
|
+
this.inArgs = new Array(numArgs);
|
|
539
|
+
|
|
540
|
+
// Load the input arguments into the inArgs array.
|
|
541
|
+
for (var i = 0; i < numArgs; i++) {
|
|
542
|
+
this.inArgs[i] = my_Render.arguments[i];
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Parse the arguments, and render
|
|
546
|
+
this.ParseInArgs();
|
|
547
|
+
|
|
548
|
+
if (checkParentDied()) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
this.ReallyRender();
|
|
553
|
+
} catch (error) {
|
|
554
|
+
// Add any errors to the log file.
|
|
555
|
+
if (this.log_file != null) {
|
|
556
|
+
this.log_file.writeln("aerender " + error.toString());
|
|
557
|
+
}
|
|
558
|
+
this.SetExitCode(this.EXIT_AE_RUNTIME);
|
|
559
|
+
} finally {
|
|
560
|
+
// This arg is treated differently than others because it's extra important
|
|
561
|
+
// that we exit properly in the face of anything that might go wrong even
|
|
562
|
+
// during initialization. So we don't parse the standard way, we check this
|
|
563
|
+
// before exit...
|
|
564
|
+
app.setSavePreferencesOnQuit(this.IsSavePrefsArgGiven(my_Render.arguments));
|
|
565
|
+
|
|
566
|
+
this.CleanupDefaultLog();
|
|
567
|
+
app.endSuppressDialogs(false);
|
|
568
|
+
app.reportErrorOnMissingFrame = false;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
function my_ReallyRender() {
|
|
573
|
+
this.saved_sound_setting = null;
|
|
574
|
+
app.reportErrorOnMissingFrame = this.in_stop_on_missing_frame;
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
// While rendering we'll report errors to the log file.
|
|
578
|
+
if (app.onError == this.onError) {
|
|
579
|
+
// If the previous error handler is just this one, don't store it.
|
|
580
|
+
// That can happen in extreme cases where this script does not get a
|
|
581
|
+
// chance to clean up and put back the oldErrorHandler when it's done.
|
|
582
|
+
this.oldErrorHandler = null;
|
|
583
|
+
} else {
|
|
584
|
+
this.oldErrorHandler = app.onError;
|
|
585
|
+
}
|
|
586
|
+
app.onError = this.onError;
|
|
587
|
+
// Open the user log file, if specified, and use it instead of the socket.
|
|
588
|
+
if (this.in_logfile_path) {
|
|
589
|
+
// Keep the socket open; errors we encounter while opening the
|
|
590
|
+
// user log file will be logged to the socket.
|
|
591
|
+
var user_log_file = new File(this.in_logfile_path);
|
|
592
|
+
var parent_dir = user_log_file.parent;
|
|
593
|
+
if (!parent_dir.exists) {
|
|
594
|
+
if (this.log_file) {
|
|
595
|
+
this.log_file.writeln(this.MSG_LOG_DIR_NO_EXISTS + this.in_logfile_path);
|
|
596
|
+
}
|
|
597
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
598
|
+
}
|
|
599
|
+
var test_folder = Folder(parent_dir);
|
|
600
|
+
if (!(test_folder instanceof Folder)) {
|
|
601
|
+
if (this.log_file) {
|
|
602
|
+
this.log_file.writeln(this.MSG_LOG_DIR_NOT_A_DIR + this.in_logfile_path);
|
|
603
|
+
}
|
|
604
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
605
|
+
}
|
|
606
|
+
if (!user_log_file.open("w", 'TEXT', 'ttxt')) {
|
|
607
|
+
if (this.log_file) {
|
|
608
|
+
this.log_file.writeln(this.MSG_LOG_CAN_NOT_OPEN + this.in_logfile_path);
|
|
609
|
+
}
|
|
610
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// no errors were encountered opening the file.
|
|
614
|
+
// Close the socket and use this one instead.
|
|
615
|
+
if (this.log_file != null) {
|
|
616
|
+
this.log_file.close();
|
|
617
|
+
}
|
|
618
|
+
this.log_file = user_log_file; // which is still open
|
|
619
|
+
this.has_user_log_file = true;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (this.in_verbose_flag) {
|
|
623
|
+
if (this.in_verbose_flag == "ERRORS") {
|
|
624
|
+
this.is_verbose_mode = false;
|
|
625
|
+
} else if (this.in_verbose_flag == "ERRORS_AND_PROGRESS") {
|
|
626
|
+
this.is_verbose_mode = true;
|
|
627
|
+
} else {
|
|
628
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_VERBOSE_FLAG);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
if (this.in_close_flag) {
|
|
632
|
+
if (this.in_close_flag != "DO_NOT_CLOSE" &&
|
|
633
|
+
this.in_close_flag != "DO_NOT_SAVE_CHANGES" &&
|
|
634
|
+
this.in_close_flag != "SAVE_CHANGES") {
|
|
635
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_CLOSE_FLAG);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
if (this.in_sound_flag) {
|
|
639
|
+
if (this.in_sound_flag != "ON" &&
|
|
640
|
+
this.in_sound_flag != "OFF" &&
|
|
641
|
+
this.in_sound_flag != "on" &&
|
|
642
|
+
this.in_sound_flag != "off") {
|
|
643
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_SOUND_FLAG);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// Set the memory usage, if specified as an argument.
|
|
648
|
+
if (this.in_image_cache_percent && this.in_max_mem_percent) {
|
|
649
|
+
app.setMemoryUsageLimits(this.in_image_cache_percent, this.in_max_mem_percent);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// set the Multi-Frame Rendering and CPU Max Percent
|
|
653
|
+
// this.in_mfr_enable can be null, ON or OFF so as long as we arne't null...
|
|
654
|
+
if (this.in_mfr_enable != null && this.in_mfr_max_cpu_percent) {
|
|
655
|
+
if (this.in_mfr_enable != "ON" &&
|
|
656
|
+
this.in_mfr_enable != "OFF" &&
|
|
657
|
+
this.in_mfr_enable != "on" &&
|
|
658
|
+
this.in_mfr_enable != "off") {
|
|
659
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_MFR_FLAG);
|
|
660
|
+
} else {
|
|
661
|
+
if (this.in_mfr_enable == "ON" ||
|
|
662
|
+
this.in_mfr_enable == "on") {
|
|
663
|
+
this.in_mfr_enable = true;
|
|
664
|
+
} else {
|
|
665
|
+
this.in_mfr_enable = false;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// finally call the API
|
|
669
|
+
app.setMultiFrameRenderingConfig(this.in_mfr_enable, this.in_mfr_max_cpu_percent);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
// If the user provided a project, close the current project and open the project specified.
|
|
674
|
+
// Else, leave the current project open.
|
|
675
|
+
if (this.in_project_path) {
|
|
676
|
+
// Close the current project
|
|
677
|
+
if (app.project != null) {
|
|
678
|
+
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// Open the specified project:
|
|
682
|
+
var proj_file = new File(this.in_project_path);
|
|
683
|
+
app.openFast(proj_file);
|
|
684
|
+
}
|
|
685
|
+
if (!app.project) {
|
|
686
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_NO_PROJECT);
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
// If the user provided a teamproject, close the current project and open the teamproject specified.
|
|
690
|
+
// Else, leave the current project open.
|
|
691
|
+
if (this.in_teamproject_name) {
|
|
692
|
+
// Close the current project
|
|
693
|
+
if (app.project != null) {
|
|
694
|
+
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// Open the specified team project:
|
|
698
|
+
app.openTeamProject(this.in_teamproject_name);
|
|
699
|
+
}
|
|
700
|
+
if (!app.project) {
|
|
701
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_NO_PROJECT);
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
if (this.in_script_path) {
|
|
705
|
+
this.log_file.writeln("Running Script: " + this.in_script_path);
|
|
706
|
+
var scriptFile = new File(this.in_script_path);
|
|
707
|
+
|
|
708
|
+
scriptFile.encoding = "UTF-8";
|
|
709
|
+
if (!scriptFile.open("r")) {
|
|
710
|
+
if (this.log_file) {
|
|
711
|
+
this.log_file.writeln(this.MSG_SCRIPT_CAN_NOT_OPEN + this.in_script_path);
|
|
712
|
+
}
|
|
713
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
try {
|
|
717
|
+
// Use evalFile instead of eval to make the script path context
|
|
718
|
+
// the same as the scriptFile
|
|
719
|
+
//
|
|
720
|
+
// For example using eval(), the $.fileName would be the commandLineRenderer's
|
|
721
|
+
// path and we want the executing scriptFile's path for our fallback
|
|
722
|
+
// Using evalFile evaluates the file in another context
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
// Update v1.0.2: returning back to eval
|
|
726
|
+
// since there are issues with encoding caused by $.evalFile
|
|
727
|
+
eval(scriptFile.read());
|
|
728
|
+
} catch (e) {
|
|
729
|
+
if (this.log_file) {
|
|
730
|
+
this.log_file.writeln(this.MSG_SCRIPT_CAN_NOT_EXEC + this.in_script_path);
|
|
731
|
+
this.log_file.writeln(e);
|
|
732
|
+
}
|
|
733
|
+
this.SetExitCodeAndThrowException(this.EXIT_AE_RUNTIME, this.MSG_AE_RUNTIME);
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
scriptFile.close();
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
// Get the RenderQueueItem for the specified comp, if specified.
|
|
740
|
+
var rqi = null;
|
|
741
|
+
if (this.in_comp_name) {
|
|
742
|
+
rqi = this.GetFirstQueuedRQItemWithName(this.in_comp_name);
|
|
743
|
+
} else if (this.in_rq_index != null) {
|
|
744
|
+
this.log_file.writeln("rqindex " + this.in_rq_index + "num " + app.project.renderQueue.numItems);
|
|
745
|
+
if (this.in_rq_index >= 1 && this.in_rq_index <= app.project.renderQueue.numItems) {
|
|
746
|
+
rqi = app.project.renderQueue.item(this.in_rq_index);
|
|
747
|
+
} else {
|
|
748
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_RQINDEX_NOT_FOUND);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
if (this.in_comp_name && !rqi) {
|
|
752
|
+
// Try to find the comp in the project and add to the render queue:
|
|
753
|
+
rqi = this.AddCompToRenderQueue(this.in_comp_name);
|
|
754
|
+
if (rqi) {
|
|
755
|
+
if (this.log_file != null) {
|
|
756
|
+
this.log_file.writeln(this.MSG_ADDING_TO_RQ);
|
|
757
|
+
}
|
|
758
|
+
} else {
|
|
759
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_COMP_NOT_FOUND);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Apply the templates, if provided
|
|
764
|
+
if (this.in_RStemplate) {
|
|
765
|
+
if (!rqi) {
|
|
766
|
+
if (this.log_file != null) {
|
|
767
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_TEMPLATE);
|
|
768
|
+
}
|
|
769
|
+
} else {
|
|
770
|
+
if (!this.IsInArray(this.in_RStemplate, rqi.templates)) {
|
|
771
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_RS_TEMPLATE_NOT_FOUND);
|
|
772
|
+
}
|
|
773
|
+
rqi.applyTemplate(this.in_RStemplate);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
function _setPropertiesFromObj(aeDOMObject, settingsDictionary) {
|
|
778
|
+
for (key in settingsDictionary) {
|
|
779
|
+
aeDOMObject.setSetting(key, settingsDictionary[key]);
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// mutate new/existing RS with settings dictionary
|
|
784
|
+
if (this.in_RSsettings) {
|
|
785
|
+
if (!rqi) {
|
|
786
|
+
if (this.log_file != null) {
|
|
787
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_RS_SETTINGS_NO_RQI);
|
|
788
|
+
}
|
|
789
|
+
} else {
|
|
790
|
+
_setPropertiesFromObj(rqi, this.in_RSsettings);
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
if (this.in_OMtemplate) {
|
|
795
|
+
if (!rqi) {
|
|
796
|
+
if (this.log_file != null) {
|
|
797
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_OMTEMPLATE);
|
|
798
|
+
}
|
|
799
|
+
} else {
|
|
800
|
+
if (!this.IsInArray(this.in_OMtemplate, rqi.outputModule(1).templates)) {
|
|
801
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_OM_TEMPLATE_NOT_FOUND);
|
|
802
|
+
}
|
|
803
|
+
rqi.outputModule(1).applyTemplate(this.in_OMtemplate);
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
}
|
|
807
|
+
if (this.in_OMsettings) {
|
|
808
|
+
if (!rqi) {
|
|
809
|
+
if (this.log_file != null) {
|
|
810
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_OM_SETTINGS_NO_RQI);
|
|
811
|
+
}
|
|
812
|
+
} else {
|
|
813
|
+
_setPropertiesFromObj(rqi.outputModule(1), this.in_OMsettings);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
// If a comp was specified, make it the only one to render.
|
|
819
|
+
// If none was provided, leave everything alone so render queue renders as is.
|
|
820
|
+
if (rqi) {
|
|
821
|
+
this.EstablishAsOnlyQueuedItem(rqi);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (rqi) {
|
|
825
|
+
// If the user provided a path, set the output path on rqi's OutputModule
|
|
826
|
+
if (rqi.status == RQItemStatus.NEEDS_OUTPUT && !this.in_output_path) {
|
|
827
|
+
this.SetExitCodeAndThrowException(this.EXIT_AERENDER_RUNTIME, this.MSG_NEEDS_OUTPUT);
|
|
828
|
+
}
|
|
829
|
+
if (this.in_output_path) {
|
|
830
|
+
var om = rqi.outputModule(1);
|
|
831
|
+
om.file = new File(this.in_output_path);
|
|
832
|
+
}
|
|
833
|
+
} else {
|
|
834
|
+
if (this.in_output_path) {
|
|
835
|
+
if (this.log_file != null) {
|
|
836
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_OUTPUT);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
// Set the start and end frames.
|
|
842
|
+
if (this.in_start_frame || this.in_end_frame) {
|
|
843
|
+
if (!rqi) {
|
|
844
|
+
if (this.log_file != null) {
|
|
845
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_START_OR_END);
|
|
846
|
+
}
|
|
847
|
+
} else {
|
|
848
|
+
// Render times are stored as timeSpanStart and timeSpanDuration.
|
|
849
|
+
// Setting only the timeSpanStart will not change the timeSpanDuration and
|
|
850
|
+
// so will move the end time, but we want the end time unchanged if
|
|
851
|
+
// it was not specified.
|
|
852
|
+
// So we must calculate both start_time and end_time,
|
|
853
|
+
// then set both timeSpanStart and timeSpanDuration.
|
|
854
|
+
// Note: frameDuration is stored in the comp.
|
|
855
|
+
var start_time = rqi.timeSpanStart;
|
|
856
|
+
var end_time = rqi.timeSpanStart + rqi.timeSpanDuration;
|
|
857
|
+
if (this.in_start_frame) {
|
|
858
|
+
start_time = -rqi.comp.displayStartTime + ((parseInt(this.in_start_frame, 10) - app.project.displayStartFrame) * rqi.comp.frameDuration);
|
|
859
|
+
}
|
|
860
|
+
if (this.in_end_frame) {
|
|
861
|
+
// The way AE works, final frame is not included.
|
|
862
|
+
// But aerender wants final frame included.
|
|
863
|
+
// So, just add 1 to end frame right here before setting
|
|
864
|
+
// duration for AE:
|
|
865
|
+
// Note: must call parseInt() here, or the 1 will be added as if it
|
|
866
|
+
// were a string. For example, 35 would become 351, not 36. Hoo boy!
|
|
867
|
+
var end_frame_plus_one = parseInt(this.in_end_frame, 10) + 1.0 - app.project.displayStartFrame;
|
|
868
|
+
end_time = -rqi.comp.displayStartTime + (end_frame_plus_one * rqi.comp.frameDuration);
|
|
869
|
+
}
|
|
870
|
+
rqi.timeSpanStart = start_time;
|
|
871
|
+
rqi.timeSpanDuration = end_time - start_time;
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Set the skipFrames (based on increment).
|
|
876
|
+
if (this.in_increment) {
|
|
877
|
+
if (this.in_increment < 1 || this.in_increment > 100) {
|
|
878
|
+
this.SetExitCodeAndThrowException(this.EXIT_SYNTAX_ERROR, this.MSG_BAD_INCREMENT);
|
|
879
|
+
}
|
|
880
|
+
if (!rqi) {
|
|
881
|
+
if (this.log_file != null) {
|
|
882
|
+
this.log_file.writeln(this.MSG_NO_COMP_YES_INCREMENT);
|
|
883
|
+
}
|
|
884
|
+
} else {
|
|
885
|
+
// Set the skipFrames based on the increment.
|
|
886
|
+
//
|
|
887
|
+
// Increment as defined here is one greater then the
|
|
888
|
+
// the render queue item's skipFrames.
|
|
889
|
+
// skipFrames 0 is the same as increment of 1.
|
|
890
|
+
//
|
|
891
|
+
rqi.skipFrames = (this.in_increment - 1);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
// If we are in verbose mode, set the log type to ERRORS_AND_PER_FRAME_INFO
|
|
896
|
+
// for all RQ items we are about to render.
|
|
897
|
+
if (this.is_verbose_mode) {
|
|
898
|
+
this.SetLogPerFrameInfoInRQ();
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
this.SaveAndSetRenderSoundSetting();
|
|
902
|
+
|
|
903
|
+
// Render!
|
|
904
|
+
// true skips the recursive check for footage files
|
|
905
|
+
// and will only check the one's used
|
|
906
|
+
|
|
907
|
+
if (checkParentDied()) {
|
|
908
|
+
return;
|
|
909
|
+
}
|
|
910
|
+
app.project.renderQueue.render(true);
|
|
911
|
+
} catch (error) {
|
|
912
|
+
// Add any errors to the log file.
|
|
913
|
+
if (this.log_file != null) {
|
|
914
|
+
this.log_file.writeln("aerender " + error.toString());
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
// It's possible that errors were encountered while trying to render.
|
|
918
|
+
// Stop the render if in progress for a clean exit from the application.
|
|
919
|
+
if (app.project && app.project.renderQueue && app.project.renderQueue.rendering) {
|
|
920
|
+
// This will prevent the message "render stopped by user" from showing up...
|
|
921
|
+
app.onError = null;
|
|
922
|
+
app.project.renderQueue.stopRendering();
|
|
923
|
+
// This will print a better message:
|
|
924
|
+
if (this.log_file != null) {
|
|
925
|
+
this.log_file.writeln(this.MSG_RENDER_ABORTED);
|
|
926
|
+
}
|
|
927
|
+
app.onError = this.onError;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
this.SetExitCode(this.EXIT_AE_RUNTIME);
|
|
931
|
+
} finally {
|
|
932
|
+
// Close the project.
|
|
933
|
+
this.CloseProjectIfDesired();
|
|
934
|
+
|
|
935
|
+
// Put back the old error handler
|
|
936
|
+
app.onError = this.oldErrorHandler;
|
|
937
|
+
|
|
938
|
+
// Restore the setting for hearing the render-done sound.
|
|
939
|
+
this.RestoreRenderSoundSetting()
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Returns the first item on the render queue that:
|
|
944
|
+
// [a] contains a comp named comp_name
|
|
945
|
+
// [b] has a render status of QUEUED or UNQUEUED or NEEDS_OUTPUT
|
|
946
|
+
// Note that if the status is NEEDS_OUTPUT, one better be provided or
|
|
947
|
+
// an error will result.
|
|
948
|
+
//
|
|
949
|
+
// If not found, returns null.
|
|
950
|
+
//
|
|
951
|
+
function my_GetFirstQueuedRQItemWithName(comp_name) {
|
|
952
|
+
var result = null;
|
|
953
|
+
|
|
954
|
+
var rq = app.project.renderQueue;
|
|
955
|
+
if (rq && rq.numItems > 0) {
|
|
956
|
+
var cur_item;
|
|
957
|
+
// the items are indexed from 1 to numItems.
|
|
958
|
+
for (var i = 1; i <= rq.numItems; i++) {
|
|
959
|
+
cur_item = rq.item(i);
|
|
960
|
+
if (cur_item.comp.name == comp_name &&
|
|
961
|
+
cur_item.status == RQItemStatus.WILL_CONTINUE) {
|
|
962
|
+
if (this.log_file != null) {
|
|
963
|
+
this.log_file.writeln(this.MSG_SKIPPING_WILL_CONTINUE);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (cur_item.comp.name == comp_name &&
|
|
967
|
+
(cur_item.status == RQItemStatus.QUEUED ||
|
|
968
|
+
// pmi 9/24/03 -- do not render unqueued items. Let a new
|
|
969
|
+
// one be added instead.
|
|
970
|
+
// cur_item.status == RQItemStatus.UNQUEUED ||
|
|
971
|
+
cur_item.status == RQItemStatus.NEEDS_OUTPUT)) {
|
|
972
|
+
// We found it!
|
|
973
|
+
result = cur_item;
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
return result;
|
|
980
|
+
}
|
|
981
|
+
|
|
982
|
+
// Find a comp with the given name, and adds it to the render queue.
|
|
983
|
+
// Returns the newly added render queue item
|
|
984
|
+
//
|
|
985
|
+
// If not found, returns null.
|
|
986
|
+
//
|
|
987
|
+
function my_AddCompToRenderQueue(comp_name) {
|
|
988
|
+
var result = null;
|
|
989
|
+
|
|
990
|
+
// Get the comp with the name we are after
|
|
991
|
+
var cur_item;
|
|
992
|
+
var desired_comp = null;
|
|
993
|
+
// the items in the project are indexed from 1 to numItems
|
|
994
|
+
for (var i = 1; i <= app.project.numItems; i++) {
|
|
995
|
+
cur_item = app.project.item(i);
|
|
996
|
+
if (cur_item instanceof CompItem && cur_item.name == comp_name) {
|
|
997
|
+
desired_comp = cur_item;
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Add the desired_comp to the render queue. The add() method
|
|
1003
|
+
// returns the new render queue item.
|
|
1004
|
+
if (desired_comp) {
|
|
1005
|
+
result = app.project.renderQueue.items.add(desired_comp);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
return result;
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// Sets the render flag on all RenderQueueItems other than rqi to false,
|
|
1012
|
+
//
|
|
1013
|
+
function my_EstablishAsOnlyQueuedItem(rqi) {
|
|
1014
|
+
var rq = app.project.renderQueue;
|
|
1015
|
+
if (rq && rq.numItems > 0) {
|
|
1016
|
+
var cur_item;
|
|
1017
|
+
// the items are indexed from 1 to numItems.
|
|
1018
|
+
for (var i = 1; i <= rq.numItems; i++) {
|
|
1019
|
+
cur_item = rq.item(i);
|
|
1020
|
+
if (cur_item == rqi) {
|
|
1021
|
+
cur_item.render = true;
|
|
1022
|
+
} else {
|
|
1023
|
+
// You can only change the render flag when these are the current status value:
|
|
1024
|
+
if (cur_item.status == RQItemStatus.QUEUED ||
|
|
1025
|
+
cur_item.status == RQItemStatus.UNQUEUED ||
|
|
1026
|
+
cur_item.status == RQItemStatus.NEEDS_OUTPUT ||
|
|
1027
|
+
cur_item.status == RQItemStatus.WILL_CONTINUE) {
|
|
1028
|
+
cur_item.render = false;
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// Sets the log type to be ERRORS_AND_PER_FRAME_INFO for all items that are going to render.
|
|
1036
|
+
//
|
|
1037
|
+
function my_SetLogPerFrameInfoInRQ() {
|
|
1038
|
+
var rq = app.project.renderQueue;
|
|
1039
|
+
if (rq && rq.numItems > 0) {
|
|
1040
|
+
var cur_item;
|
|
1041
|
+
// the items are indexed from 1 to numItems.
|
|
1042
|
+
for (var i = 1; i <= rq.numItems; i++) {
|
|
1043
|
+
cur_item = rq.item(i);
|
|
1044
|
+
if (cur_item.render == true) {
|
|
1045
|
+
if (cur_item.status != RQItemStatus.USER_STOPPED &&
|
|
1046
|
+
cur_item.status != RQItemStatus.ERR_STOPPED &&
|
|
1047
|
+
cur_item.status != RQItemStatus.RENDERING &&
|
|
1048
|
+
cur_item.status != RQItemStatus.DONE) {
|
|
1049
|
+
cur_item.logType = LogType.ERRORS_AND_PER_FRAME_INFO;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
|
|
1056
|
+
// Closes the project if the close flag specifies to do so
|
|
1057
|
+
//
|
|
1058
|
+
function my_CloseProjectIfDesired() {
|
|
1059
|
+
if (app.project) {
|
|
1060
|
+
// Close the project we just used, if desired
|
|
1061
|
+
if (!this.in_close_flag || this.in_close_flag == "DO_NOT_SAVE_CHANGES") {
|
|
1062
|
+
// If no flag provided, this is the default.
|
|
1063
|
+
app.project.close(CloseOptions.DO_NOT_SAVE_CHANGES);
|
|
1064
|
+
} else {
|
|
1065
|
+
if (this.in_close_flag == "SAVE_CHANGES") {
|
|
1066
|
+
app.project.close(CloseOptions.SAVE_CHANGES);
|
|
1067
|
+
}
|
|
1068
|
+
// otherwise, flag is DO_NOT_CLOSE, so we do nothing.
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
function my_SaveAndSetRenderSoundSetting() {
|
|
1074
|
+
// Save the current setting for hearing the render-done sound, we'll restore it later.
|
|
1075
|
+
if (app.preferences.havePref("Misc Section",
|
|
1076
|
+
"Play sound when render finishes", PREFType.PREF_Type_MACHINE_INDEPENDENT)) {
|
|
1077
|
+
// Get the current value if the pref exists.
|
|
1078
|
+
this.saved_sound_setting = app.preferences.getPrefAsLong("Misc Section",
|
|
1079
|
+
"Play sound when render finishes", PREFType.PREF_Type_MACHINE_INDEPENDENT);
|
|
1080
|
+
} else {
|
|
1081
|
+
// default is to play the sound, value of 1.
|
|
1082
|
+
// Use this if the pref does not yet exist.
|
|
1083
|
+
this.saved_sound_setting = 1;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
// Set the setting for hearing the render-done sound, based on the input, default is off.
|
|
1087
|
+
this.my_sound_setting = 0; // 0 is off
|
|
1088
|
+
if (this.in_sound_flag && (this.in_sound_flag == "ON" || this.in_sound_flag == "on")) {
|
|
1089
|
+
this.my_sound_setting = 1; // 1 is on
|
|
1090
|
+
}
|
|
1091
|
+
|
|
1092
|
+
app.preferences.savePrefAsLong("Misc Section",
|
|
1093
|
+
"Play sound when render finishes",
|
|
1094
|
+
this.my_sound_setting, PREFType.PREF_Type_MACHINE_INDEPENDENT);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
function my_RestoreRenderSoundSetting() {
|
|
1098
|
+
if (this.saved_sound_setting) {
|
|
1099
|
+
app.preferences.savePrefAsLong("Misc Section",
|
|
1100
|
+
"Play sound when render finishes",
|
|
1101
|
+
this.saved_sound_setting, PREFType.PREF_Type_MACHINE_INDEPENDENT);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
// [3] assign all the functions to be method-type attributes.
|
|
1106
|
+
//
|
|
1107
|
+
this.onError = my_onError;
|
|
1108
|
+
this.SetExitCodeAndThrowException = my_SetExitCodeAndThrowException;
|
|
1109
|
+
this.SetExitCode = my_SetExitCode;
|
|
1110
|
+
this.StripAnyEnclosingQuotes = my_StripAnyEnclosingQuotes;
|
|
1111
|
+
this.GetValueForFlag = my_GetValueForFlag;
|
|
1112
|
+
this.ParseParamStartingAt = my_ParseParamStartingAt;
|
|
1113
|
+
this.ParseInArgs = my_ParseInArgs;
|
|
1114
|
+
this.IsInArray = my_IsInArray;
|
|
1115
|
+
this.SetupDefaultLog = my_SetupDefaultLog;
|
|
1116
|
+
this.CleanupDefaultLog = my_CleanupDefaultLog;
|
|
1117
|
+
this.Render = my_Render;
|
|
1118
|
+
this.ReallyRender = my_ReallyRender;
|
|
1119
|
+
this.GetFirstQueuedRQItemWithName = my_GetFirstQueuedRQItemWithName;
|
|
1120
|
+
this.AddCompToRenderQueue = my_AddCompToRenderQueue;
|
|
1121
|
+
this.EstablishAsOnlyQueuedItem = my_EstablishAsOnlyQueuedItem;
|
|
1122
|
+
this.SetLogPerFrameInfoInRQ = my_SetLogPerFrameInfoInRQ;
|
|
1123
|
+
this.CloseProjectIfDesired = my_CloseProjectIfDesired;
|
|
1124
|
+
this.SaveAndSetRenderSoundSetting = my_SaveAndSetRenderSoundSetting;
|
|
1125
|
+
this.RestoreRenderSoundSetting = my_RestoreRenderSoundSetting;
|
|
1126
|
+
this.IsSavePrefsArgGiven = my_IsSavePrefsArgGiven;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
var gAECommandLineRenderer = new AECommandLineRenderer();
|
|
1130
|
+
`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module.exports = /*syntax:js*/ `// Command line renderer for After Effects. (nexrender-patch-v1.0.
|
|
1
|
+
module.exports = /*syntax:js*/ `// Command line renderer for After Effects. (nexrender-patch-v1.0.3)
|
|
2
2
|
|
|
3
3
|
// This function constructs an AECommandLineRenderer object.
|
|
4
4
|
// One and only one of these will be created to perform rendering tasks
|
|
@@ -120,7 +120,7 @@ function AECommandLineRenderer() {
|
|
|
120
120
|
// Report an error. This writes errors to the log file, if present.
|
|
121
121
|
// This is called from the context of the application, so we
|
|
122
122
|
// need to precede variable names with gAECommandLineRenderer
|
|
123
|
-
//
|
|
123
|
+
//
|
|
124
124
|
function checkParentDied() {
|
|
125
125
|
var result = false;
|
|
126
126
|
if (gAECommandLineRenderer.log_file instanceof Socket) {
|
|
@@ -143,13 +143,13 @@ function AECommandLineRenderer() {
|
|
|
143
143
|
checkParentDied();
|
|
144
144
|
if (severity_string == "PROBLEM" || severity_string == "FATAL") {
|
|
145
145
|
// These two errors cause us to change the exit code.
|
|
146
|
-
// We don't write an error or throw here, because we got here as part of a thrown
|
|
146
|
+
// We don't write an error or throw here, because we got here as part of a thrown
|
|
147
147
|
// error already, and the message will be printed as part of the catch.
|
|
148
148
|
gAECommandLineRenderer.SetExitCode(gAECommandLineRenderer.EXIT_AE_RUNTIME);
|
|
149
149
|
} else {
|
|
150
150
|
// PROBLEM and FATAL will throw exceptions, and so will be logged to the file
|
|
151
151
|
// when we catch the exception.
|
|
152
|
-
// All other errors (NAKED, INFO, WARNING, PROGRESS, and DEBUG) will not
|
|
152
|
+
// All other errors (NAKED, INFO, WARNING, PROGRESS, and DEBUG) will not
|
|
153
153
|
// throw exceptions. So we log them to the file right here:
|
|
154
154
|
if (gAECommandLineRenderer.is_verbose_mode) {
|
|
155
155
|
if (gAECommandLineRenderer.log_file != null) {
|
|
@@ -177,7 +177,7 @@ function AECommandLineRenderer() {
|
|
|
177
177
|
|
|
178
178
|
// Report an error. This establishes exitCodes for reporting errors from AfterFX.
|
|
179
179
|
function my_SetExitCode(code) {
|
|
180
|
-
// Some codes are set differently depending on whether we have a custom user
|
|
180
|
+
// Some codes are set differently depending on whether we have a custom user
|
|
181
181
|
// log file. Check for these and use the alternate if appropriate.
|
|
182
182
|
var real_code = code;
|
|
183
183
|
if (gAECommandLineRenderer.has_user_log_file) {
|
|
@@ -203,7 +203,7 @@ function AECommandLineRenderer() {
|
|
|
203
203
|
}
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
// Arguments may be enclosed in quotes. This
|
|
206
|
+
// Arguments may be enclosed in quotes. This
|
|
207
207
|
// will remove them and return the result.
|
|
208
208
|
function my_StripAnyEnclosingQuotes(inString) {
|
|
209
209
|
var result = inString;
|
|
@@ -514,7 +514,7 @@ function AECommandLineRenderer() {
|
|
|
514
514
|
try {
|
|
515
515
|
// While rendering we'll report errors to the log file.
|
|
516
516
|
if (app.onError == this.onError) {
|
|
517
|
-
// If the previous error handler is just this one, don't store it.
|
|
517
|
+
// If the previous error handler is just this one, don't store it.
|
|
518
518
|
// That can happen in extreme cases where this script does not get a
|
|
519
519
|
// chance to clean up and put back the oldErrorHandler when it's done.
|
|
520
520
|
this.oldErrorHandler = null;
|
|
@@ -719,10 +719,10 @@ function AECommandLineRenderer() {
|
|
|
719
719
|
}
|
|
720
720
|
} else {
|
|
721
721
|
// Render times are stored as timeSpanStart and timeSpanDuration.
|
|
722
|
-
// Setting only the timeSpanStart will not change the timeSpanDuration and
|
|
723
|
-
// so will move the end time, but we want the end time unchanged if
|
|
722
|
+
// Setting only the timeSpanStart will not change the timeSpanDuration and
|
|
723
|
+
// so will move the end time, but we want the end time unchanged if
|
|
724
724
|
// it was not specified.
|
|
725
|
-
// So we must calculate both start_time and end_time,
|
|
725
|
+
// So we must calculate both start_time and end_time,
|
|
726
726
|
// then set both timeSpanStart and timeSpanDuration.
|
|
727
727
|
// Note: frameDuration is stored in the comp.
|
|
728
728
|
var start_time = rqi.timeSpanStart;
|
|
@@ -760,12 +760,12 @@ function AECommandLineRenderer() {
|
|
|
760
760
|
// Increment as defined here is one greater then the
|
|
761
761
|
// the render queue item's skipFrames.
|
|
762
762
|
// skipFrames 0 is the same as increment of 1.
|
|
763
|
-
//
|
|
763
|
+
//
|
|
764
764
|
rqi.skipFrames = (this.in_increment - 1);
|
|
765
765
|
}
|
|
766
766
|
}
|
|
767
767
|
|
|
768
|
-
// If we are in verbose mode, set the log type to ERRORS_AND_PER_FRAME_INFO
|
|
768
|
+
// If we are in verbose mode, set the log type to ERRORS_AND_PER_FRAME_INFO
|
|
769
769
|
// for all RQ items we are about to render.
|
|
770
770
|
if (this.is_verbose_mode) {
|
|
771
771
|
this.SetLogPerFrameInfoInRQ();
|
package/src/helpers/autofind.js
CHANGED
|
@@ -12,6 +12,7 @@ const defaultPaths = {
|
|
|
12
12
|
'/Applications/Adobe After Effects CC 2019',
|
|
13
13
|
'/Applications/Adobe After Effects 2020',
|
|
14
14
|
'/Applications/Adobe After Effects 2021',
|
|
15
|
+
'/Applications/Adobe After Effects 2022',
|
|
15
16
|
'/Applications/Adobe After Effects CC 2021',
|
|
16
17
|
'/Applications/Adobe After Effects CC 2022',
|
|
17
18
|
],
|
package/src/helpers/patch.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const mkdirp = require('mkdirp')
|
|
4
|
-
const
|
|
4
|
+
const patchedDefault = require('../assets/commandLineRenderer-default.jsx')
|
|
5
|
+
const patched2022 = require('../assets/commandLineRenderer-2022.jsx')
|
|
5
6
|
|
|
6
7
|
const writeTo = (data, dst) => fs.writeFileSync(dst, data)
|
|
7
8
|
const copyTo = (src, dst) => fs.writeFileSync(dst, fs.readFileSync(src))
|
|
@@ -14,6 +15,13 @@ module.exports = (settings) => {
|
|
|
14
15
|
const targetScript = 'commandLineRenderer.jsx';
|
|
15
16
|
|
|
16
17
|
const afterEffects = path.dirname(settings.binary)
|
|
18
|
+
const afterEffectsYearMatch = afterEffects.match(/(20[0-9]{2})/);
|
|
19
|
+
|
|
20
|
+
let patched = patchedDefault;
|
|
21
|
+
if (afterEffectsYearMatch && afterEffectsYearMatch[0] >= "2022") {
|
|
22
|
+
patched = patched2022;
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
const originalFile = path.join(afterEffects, 'Scripts', 'Startup', targetScript)
|
|
18
26
|
const backupFile = path.join(afterEffects, 'Backup.Scripts', 'Startup', targetScript)
|
|
19
27
|
|
package/src/index.js
CHANGED
package/src/tasks/render.js
CHANGED
|
@@ -53,7 +53,7 @@ module.exports = (job, settings) => {
|
|
|
53
53
|
|
|
54
54
|
option(params, '-r', jobScriptFile);
|
|
55
55
|
|
|
56
|
-
if (!settings.skipRender && settings.multiFrames) params.push('-
|
|
56
|
+
if (!settings.skipRender && settings.multiFrames) params.push('-mfr', 'ON', settings.multiFramesCPU);
|
|
57
57
|
if (settings.reuse) params.push('-reuse');
|
|
58
58
|
if (job.template.continueOnMissing) params.push('-continueOnMissingFootage')
|
|
59
59
|
|