From ebb847b09eeaa959a79cd6d62ebd7f8ba6b38713 Mon Sep 17 00:00:00 2001 From: Brett Williams Date: Sat, 3 Aug 2024 20:00:36 -0500 Subject: [PATCH 1/3] Fix getting path to After Effects --- src/engines/aerender/aerender_engine.py | 22 +++++++++++++++++++--- src/engines/core/base_engine.py | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/engines/aerender/aerender_engine.py b/src/engines/aerender/aerender_engine.py index 7e55664..64eb8de 100644 --- a/src/engines/aerender/aerender_engine.py +++ b/src/engines/aerender/aerender_engine.py @@ -1,4 +1,10 @@ -from src.engines.core.base_engine import BaseRenderEngine +import glob +import logging +import subprocess + +from src.engines.core.base_engine import BaseRenderEngine, SUBPROCESS_TIMEOUT + +logger = logging.getLogger() class AERender(BaseRenderEngine): @@ -10,12 +16,22 @@ class AERender(BaseRenderEngine): try: render_path = self.renderer_path() if render_path: - ver_out = subprocess.check_output([render_path, '-version'], timeout=SUBPROCESS_TIMEOUT) - version = ver_out.decode('utf-8').split(" ")[-1].strip() + ver_out = subprocess.run([render_path, '-version'], capture_output=True, text=True) + version = ver_out.stdout.split(" ")[-1].strip() except Exception as e: logger.error(f'Failed to get {self.name()} version: {e}') return version + @classmethod + def default_renderer_path(cls): + paths = glob.glob('/Applications/*After Effects*/aerender') + if len(paths) > 1: + logger.warning('Multiple After Effects installations detected') + elif not paths: + logger.error('After Effects installation not found') + else: + return paths[0] + @classmethod def get_output_formats(cls): # todo: create implementation diff --git a/src/engines/core/base_engine.py b/src/engines/core/base_engine.py index 469e87f..26371e2 100644 --- a/src/engines/core/base_engine.py +++ b/src/engines/core/base_engine.py @@ -14,7 +14,7 @@ class BaseRenderEngine(object): def __init__(self, custom_path=None): self.custom_renderer_path = custom_path if not self.renderer_path() or not os.path.exists(self.renderer_path()): - raise FileNotFoundError(f"Cannot find path to renderer for {self.name()} instance") + raise FileNotFoundError(f"Cannot find path ({self.renderer_path()}) for renderer '{self.name()}'") if not os.access(self.renderer_path(), os.X_OK): logger.warning(f"Path is not executable. Setting permissions to 755 for {self.renderer_path()}") From 7986960b2133b0f0fbf8b7ad89b95f345801c4ef Mon Sep 17 00:00:00 2001 From: Brett Williams Date: Sat, 3 Aug 2024 20:21:26 -0500 Subject: [PATCH 2/3] Changes to engine file extensions structure --- src/engines/aerender/aerender_engine.py | 9 +++++++-- src/engines/aerender/aerender_worker.py | 1 - src/engines/blender/blender_engine.py | 5 +---- src/engines/core/base_engine.py | 9 ++++++--- src/engines/ffmpeg/ffmpeg_engine.py | 16 +++++++++------- 5 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/engines/aerender/aerender_engine.py b/src/engines/aerender/aerender_engine.py index 64eb8de..45736ce 100644 --- a/src/engines/aerender/aerender_engine.py +++ b/src/engines/aerender/aerender_engine.py @@ -9,7 +9,7 @@ logger = logging.getLogger() class AERender(BaseRenderEngine): - supported_extensions = ['.aep'] + file_extensions = ['aep'] def version(self): version = None @@ -35,4 +35,9 @@ class AERender(BaseRenderEngine): @classmethod def get_output_formats(cls): # todo: create implementation - return [] \ No newline at end of file + return [] + + +if __name__ == "__main__": + x = AERender().supported_extensions() + print(x) diff --git a/src/engines/aerender/aerender_worker.py b/src/engines/aerender/aerender_worker.py index 65d386c..76802c8 100644 --- a/src/engines/aerender/aerender_worker.py +++ b/src/engines/aerender/aerender_worker.py @@ -22,7 +22,6 @@ def aerender_path(): class AERenderWorker(BaseRenderWorker): - supported_extensions = ['.aep'] engine = AERender def __init__(self, input_path, output_path, args=None, parent=None, name=None): diff --git a/src/engines/blender/blender_engine.py b/src/engines/blender/blender_engine.py index b086c33..5729932 100644 --- a/src/engines/blender/blender_engine.py +++ b/src/engines/blender/blender_engine.py @@ -11,6 +11,7 @@ class Blender(BaseRenderEngine): install_paths = ['/Applications/Blender.app/Contents/MacOS/Blender'] binary_names = {'linux': 'blender', 'windows': 'blender.exe', 'macos': 'Blender'} + file_extensions = ['blend'] @staticmethod def downloader(): @@ -26,10 +27,6 @@ class Blender(BaseRenderEngine): from src.engines.blender.blender_ui import BlenderUI return BlenderUI.get_options(self) - @staticmethod - def supported_extensions(): - return ['blend'] - def version(self): version = None try: diff --git a/src/engines/core/base_engine.py b/src/engines/core/base_engine.py index 26371e2..c1bc0ed 100644 --- a/src/engines/core/base_engine.py +++ b/src/engines/core/base_engine.py @@ -9,7 +9,7 @@ SUBPROCESS_TIMEOUT = 5 class BaseRenderEngine(object): install_paths = [] - supported_extensions = [] + file_extensions = [] def __init__(self, custom_path=None): self.custom_renderer_path = custom_path @@ -58,8 +58,7 @@ class BaseRenderEngine(object): path = self.renderer_path() if not path: raise FileNotFoundError("renderer path not found") - help_doc = subprocess.check_output([path, '-h'], stderr=subprocess.STDOUT, - timeout=SUBPROCESS_TIMEOUT).decode('utf-8') + help_doc = subprocess.run([path, '-h'], capture_output=True, text=True).stdout.strip() return help_doc def get_project_info(self, project_path, timeout=10): @@ -69,6 +68,10 @@ class BaseRenderEngine(object): def get_output_formats(cls): raise NotImplementedError(f"get_output_formats not implemented for {cls.__name__}") + @classmethod + def supported_extensions(cls): + return cls.file_extensions + def get_arguments(self): pass diff --git a/src/engines/ffmpeg/ffmpeg_engine.py b/src/engines/ffmpeg/ffmpeg_engine.py index 5e780a6..c9da9f1 100644 --- a/src/engines/ffmpeg/ffmpeg_engine.py +++ b/src/engines/ffmpeg/ffmpeg_engine.py @@ -23,13 +23,15 @@ class FFMPEG(BaseRenderEngine): @classmethod def supported_extensions(cls): - help_text = (subprocess.check_output([cls().renderer_path(), '-h', 'full'], stderr=subprocess.STDOUT) - .decode('utf-8')) - found = re.findall(r'extensions that .* is allowed to access \(default "(.*)"', help_text) - found_extensions = set() - for match in found: - found_extensions.update(match.split(',')) - return list(found_extensions) + if not cls.file_extensions: + help_text = (subprocess.check_output([cls().renderer_path(), '-h', 'full'], stderr=subprocess.STDOUT) + .decode('utf-8')) + found = re.findall(r'extensions that .* is allowed to access \(default "(.*)"', help_text) + found_extensions = set() + for match in found: + found_extensions.update(match.split(',')) + cls.file_extensions = list(found_extensions) + return cls.file_extensions def version(self): version = None From e6e2ff8e07a246f81b474af8fc94c730bfa512d0 Mon Sep 17 00:00:00 2001 From: Brett Williams Date: Sat, 3 Aug 2024 20:45:43 -0500 Subject: [PATCH 3/3] Fix generate_worker_subprocess in aerender_worker.py --- src/engines/aerender/aerender_worker.py | 69 ++++++------------------- src/engines/blender/blender_worker.py | 3 +- 2 files changed, 17 insertions(+), 55 deletions(-) diff --git a/src/engines/aerender/aerender_worker.py b/src/engines/aerender/aerender_worker.py index 76802c8..e6c4a7b 100644 --- a/src/engines/aerender/aerender_worker.py +++ b/src/engines/aerender/aerender_worker.py @@ -9,28 +9,16 @@ import time from src.engines.core.base_worker import BaseRenderWorker, timecode_to_frames from src.engines.aerender.aerender_engine import AERender - -def aerender_path(): - paths = glob.glob('/Applications/*After Effects*/aerender') - if len(paths) > 1: - logging.warning('Multiple After Effects installations detected') - elif not paths: - logging.error('After Effects installation not found') - else: - return paths[0] +logger = logging.getLogger() class AERenderWorker(BaseRenderWorker): engine = AERender - def __init__(self, input_path, output_path, args=None, parent=None, name=None): - super(AERenderWorker, self).__init__(input_path=input_path, output_path=output_path, args=args, - parent=parent, name=name) - - self.comp = args.get('comp', None) - self.render_settings = args.get('render_settings', None) - self.omsettings = args.get('omsettings', None) + def __init__(self, input_path, output_path, engine_path, args=None, parent=None, name=None): + super(AERenderWorker, self).__init__(input_path=input_path, output_path=output_path, engine_path=engine_path, + args=args, parent=parent, name=name) self.progress = 0 self.progress_history = [] @@ -38,42 +26,13 @@ class AERenderWorker(BaseRenderWorker): def generate_worker_subprocess(self): - if os.path.exists('nexrender-cli-macos'): - logging.info('nexrender found') - # { - # "template": { - # "src": String, - # "composition": String, - # - # "frameStart": Number, - # "frameEnd": Number, - # "frameIncrement": Number, - # - # "continueOnMissing": Boolean, - # "settingsTemplate": String, - # "outputModule": String, - # "outputExt": String, - # }, - # "assets": [], - # "actions": { - # "prerender": [], - # "postrender": [], - # }, - # "onChange": Function, - # "onRenderProgress": Function - # } - job = {'template': - { - 'src': 'file://' + self.input_path, 'composition': self.comp.replace('"', ''), - 'settingsTemplate': self.render_settings.replace('"', ''), - 'outputModule': self.omsettings.replace('"', ''), 'outputExt': 'mov'} - } - x = ['./nexrender-cli-macos', "'{}'".format(json.dumps(job))] - else: - logging.info('nexrender not found') - x = [aerender_path(), '-project', self.input_path, '-comp', self.comp, '-RStemplate', self.render_settings, - '-OMtemplate', self.omsettings, '-output', self.output_path] - return x + comp = self.args.get('comp', 'Comp 1') + render_settings = self.args.get('render_settings', None) + omsettings = self.args.get('omsettings', None) + + command = [self.renderer_path, '-project', self.input_path, '-comp', comp, '-RStemplate', + render_settings, '-OMtemplate', omsettings, '-output', self.output_path] + return command def _parse_stdout(self, line): @@ -127,8 +86,10 @@ class AERenderWorker(BaseRenderWorker): if __name__ == '__main__': logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=logging.DEBUG) - r = AERenderWorker('/Users/brett/Desktop/Youtube_Vids/Film_Formats/Frame_Animations.aep', '"Film Pan"', - '"Draft Settings"', '"ProRes"', '/Users/brett/Desktop/test_render') + r = AERenderWorker(input_path='/Users/brett/Desktop/tc_title.aep', + output_path='/Users/brett/Desktop/testing_output/tc_title.mp4', + engine_path=AERenderWorker.engine.default_renderer_path()) + r.start() while r.is_running(): time.sleep(0.1) diff --git a/src/engines/blender/blender_worker.py b/src/engines/blender/blender_worker.py index 1a5db5e..54a6e72 100644 --- a/src/engines/blender/blender_worker.py +++ b/src/engines/blender/blender_worker.py @@ -12,7 +12,8 @@ class BlenderRenderWorker(BaseRenderWorker): engine = Blender def __init__(self, input_path, output_path, engine_path, args=None, parent=None, name=None): - super(BlenderRenderWorker, self).__init__(input_path=input_path, output_path=output_path, engine_path=engine_path, args=args, parent=parent, name=name) + super(BlenderRenderWorker, self).__init__(input_path=input_path, output_path=output_path, + engine_path=engine_path, args=args, parent=parent, name=name) # Stats self.__frame_percent_complete = 0.0