@nexrender/core 1.31.0 → 1.35.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.
@@ -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
+ `;