Search code examples
pythoncmdjsxafter-effects

After Effects: How to launch an external process and detach it


I've got an After Effects Scripting question, but I'm not sure it will be resolved with AE knowledge, maybe more with standalone development.

I want to launch an external process from After Effects, actually I want to launch a render of the openned AEP file with the aerender.exe provided with After Effects while keeping it usable.

var projectFile = app.project.file;
var aeRender = "C:\\Program Files\\Adobe\\Adobe After Effects CC 2018\\Support Files\\aerender.exe";
var myCommand = "-project" + " " + projectFile.fsName;
system.callSystem("cmd /c \""+aeRender+"\"" + " " + myCommand);

So I wrote this simple JSX code and it works, it renders the scene render queue properly. But After Effects is freezing, it waits for the end of the process. I want it to stay usable.

So I tried to write a .cmd file and launch it with AE system.callSystem and I got the same problem, I tried to go through an .exe file (compiled from a simple python with pyInstaller), same problem :

import sys
import subprocess

arg = sys.argv
pythonadress = arg[0]
aeRender = arg[1]
projectFileFSname = arg[2]

myCommand = "-project" + " " +projectFileFSname
callSystem = "cmd /c \""+aeRender +"\"" + " " + myCommand
subprocess.run(callSystem)

I even tried with "cmd /c start ", and it seems to be worse as After Effects continue freezing after the process is completed.

Is there a way to make AE believe the process is complete while it's actually not ?

Any help would be very apreciated !


Solution

  • system.callSystem() will freeze the script's execution so instead, you can dynamically create a .bat file and run it with .execute().

    Here's a sample .js:

    var path = {
      "join": function ()
      {
        if (arguments.length === 0) return null;
    
        var args = [];
    
        for (var i = 0, iLen = arguments.length; i < iLen; i++)
        {
          args.push(arguments[i]);
        }
    
        return args.join(String($.os.toLowerCase().indexOf('win') > -1 ? '\\' : '/'));
      }
    };
    
    if (app.project.file !== null && app.project.renderQueue.numItems > 0)
    {
      var
      // aeRenderPath = path.join(new File($._ADBE_LIBS_CORE.getHostAppPathViaBridgeTalk()).parent.fsName, 'aerender.exe'), // works only in CC 2018 and earlier
      aeRenderPath = path.join(new File(BridgeTalk.getAppPath(BridgeTalk.appName)).parent.fsName, 'aerender.exe'),
      batFile = new File(path.join(new File($.fileName).parent.fsName, 'render.bat')),
      batFileContent = [
        '"' + aeRenderPath + '"',
        "-project",
        '"' + app.project.file.fsName + '"'
      ];
    
      batFile.open('w', undefined, undefined);
      batFile.encoding = 'UTF-8';
      batFile.lineFeed = 'Unix';
      batFile.write(batFileContent.join(' '));
      batFile.close();
    
      // system.callSystem('explorer ' + batFile.fsName);
      batFile.execute();
    
      $.sleep(1000); // Delay the script so that the .bat file can be executed before it's being deleted
      batFile.remove();
    }
    

    You can, of course, develop it further and make it OSX compatible, add more features to it .etc, but this is the main idea.

    Here's a list with all the aerender options (if you don't already know them): https://helpx.adobe.com/after-effects/using/automated-rendering-network-rendering.html

    Btw, $._ADBE_LIBS_CORE.getHostAppPathViaBridgeTalk() will get you the "AfterFX.exe" file path so you can get the "aerender.exe" path easier this way.

    EDIT: $._ADBE_LIBS_CORE was removed in CC2019 so you can use BridgeTalk directly instead for CC 2019 and above.