diff --git a/dashboard.py b/dashboard.py index d58545b..e106b63 100755 --- a/dashboard.py +++ b/dashboard.py @@ -206,7 +206,7 @@ class RenderDashboard: return sorted_jobs def get_data(self): - all_data = self.request_data('full_status') + all_data = self.request_data('full_status', timeout=5) return all_data @@ -275,17 +275,30 @@ if __name__ == '__main__': else: header_text.append("(Remote)", style="magenta") - layout["header"].update(Panel(Text("Zordon Render Client - Version 0.0.1 alpha", justify="center"))) - with Live(console=console, screen=False, refresh_per_second=1, transient=True) as live: - while True: + cached_server_data = None + + while True: server_data = client.get_data() + if server_data: + cached_server_data = server_data + server_data['online'] = True + else: + server_data = cached_server_data + if server_data: + server_data['online'] = False + try: if server_data: layout["body"].update(create_jobs_table(server_data)) layout["side_top"].update(Panel(create_node_tree(server_data))) layout["side_bottom"].update(Panel(create_status_panel(server_data))) + + online_text = "Online" if server_data['online'] else "Offline" + online_color = "green" if server_data['online'] else "red" + layout["header"].update(Panel(Text(f"Zordon Render Client - Version 0.0.1 alpha - {online_text}", + justify="center", style=online_color))) live.update(layout, refresh=False) except Exception as e: print(f"Exception updating table: {e}") diff --git a/subway.png b/subway.png new file mode 100644 index 0000000..0a588dc Binary files /dev/null and b/subway.png differ diff --git a/utilities/aerender_worker.py b/utilities/aerender_worker.py index 14a371a..6b30083 100644 --- a/utilities/aerender_worker.py +++ b/utilities/aerender_worker.py @@ -1,10 +1,11 @@ #! /usr/bin/python -from utilities.render_worker import * import glob import json import re import time +from utilities.render_worker import * + def aerender_path(): paths = glob.glob('/Applications/*After Effects*/aerender') @@ -16,7 +17,7 @@ def aerender_path(): return paths[0] -class AERenderWorker(RenderWorker): +class AERenderWorker(BaseRenderWorker): @staticmethod def version(): @@ -34,12 +35,12 @@ class AERenderWorker(RenderWorker): render_engine = 'aerender' supported_extensions = ['.aep'] - def __init__(self, input_path, output_path, args=None): - super(AERenderWorker, self).__init__(input_path=input_path, output_path=output_path, args=args) + def __init__(self, project, comp, render_settings, omsettings, output): + super(AERenderWorker, self).__init__(input=project, output=output) - self.comp = self.args.get('comp') - self.render_settings = self.args.get('render_settings') - self.omsettings = self.args.get('omsettings') + self.comp = comp + self.render_settings = render_settings + self.omsettings = omsettings self.progress = 0 self.progress_history = [] diff --git a/utilities/blender_worker.py b/utilities/blender_worker.py index d2c03d6..ebfa503 100644 --- a/utilities/blender_worker.py +++ b/utilities/blender_worker.py @@ -6,7 +6,7 @@ SUPPORTED_FORMATS = ['TGA', 'RAWTGA', 'JPEG', 'IRIS', 'IRIZ', 'AVIRAW', 'AVIJPEG 'OPEN_EXR', 'OPEN_EXR_MULTILAYER', 'MPEG', 'CINEON', 'DPX', 'DDS', 'JP2'] -class BlenderRenderWorker(RenderWorker): +class BlenderRenderWorker(BaseRenderWorker): def version(self): version = None @@ -22,14 +22,14 @@ class BlenderRenderWorker(RenderWorker): supported_extensions = ['.blend'] install_paths = ['/Applications/Blender.app/Contents/MacOS/Blender'] - def __init__(self, input_path, output_path, args=None): + def __init__(self, input_path, output_path, args=None, render_all_frames=False, engine='BLENDER_EEVEE'): super(BlenderRenderWorker, self).__init__(input_path=input_path, output_path=output_path, args=args) - self.engine = self.args.get('engine', 'BLENDER_EEVEE') + self.engine = engine # or 'CYCLES' self.format = 'JPEG' self.frame = 0 - self.render_all_frames = self.args.get('render_all_frames', False) + self.render_all_frames = render_all_frames # Stats self.current_frame = -1 @@ -67,7 +67,7 @@ class BlenderRenderWorker(RenderWorker): sample_string = line.split('|')[-1].strip() if "sample" in sample_string.lower(): - samples = re.sub(r'[^\d/]', '', sample_string) + samples = re.sub(r'[^/d/]', '', sample_string) self.frame_percent_complete = int(samples.split('/')[0]) / int(samples.split('/')[-1]) diff --git a/utilities/ffmpeg_worker.py b/utilities/ffmpeg_worker.py index fbc6dfe..833a622 100644 --- a/utilities/ffmpeg_worker.py +++ b/utilities/ffmpeg_worker.py @@ -1,13 +1,11 @@ -#! /usr/bin/python +import logging import re import time - import ffmpeg - from utilities.render_worker import * -class FFMPEGRenderWorker(RenderWorker): +class FFMPEGRenderWorker(BaseRenderWorker): def version(self): version = None @@ -62,7 +60,7 @@ class FFMPEGRenderWorker(RenderWorker): if __name__ == '__main__': - logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=logging.INFO) + logging.basicConfig(format='%(asctime)s - %(message)s', datefmt='%d-%b-%y %H:%M:%S', level=logging.DEBUG) test_movie = '/Users/brettwilliams/Desktop/dark_knight_rises.mp4' diff --git a/utilities/render_worker.py b/utilities/render_worker.py index 6145dbb..e740af7 100644 --- a/utilities/render_worker.py +++ b/utilities/render_worker.py @@ -1,4 +1,3 @@ -from datetime import datetime import io import logging import os @@ -28,9 +27,9 @@ def string_to_status(string): return RenderStatus.ERROR -class RenderWorker(object): +class BaseRenderWorker(object): - renderer = 'GenericRenderer' + renderer = 'BaseRenderWorker' render_engine = None supported_extensions = [] install_paths = [] @@ -57,7 +56,7 @@ class RenderWorker(object): # Ranges self.total_frames = 0 - self.last_frame = 0 + self.current_frame = 0 # Logging self.log_path = None @@ -118,10 +117,11 @@ class RenderWorker(object): # Setup logging try: - log_dir = os.path.join(os.path.dirname(self.input), 'logs') - if not os.path.exists(log_dir): - os.makedirs(log_dir) - self.log_path = os.path.join(log_dir, os.path.basename(self.input)) + '.log' + if not self.log_path: + log_dir = os.path.join(os.path.dirname(self.input), 'logs') + if not os.path.exists(log_dir): + os.makedirs(log_dir) + self.log_path = os.path.join(log_dir, os.path.basename(self.input)) + '.log' logger.info('Logs saved in {}'.format(self.log_path)) except Exception as e: logger.error("Error setting up logging: {}".format(e)) @@ -134,38 +134,41 @@ class RenderWorker(object): # Start process and get updates subprocess_cmds = self._generate_subprocess() logger.debug("Renderer commands generated - {}".format(" ".join(subprocess_cmds))) - self.process = subprocess.Popen(subprocess_cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=False) + self.process = subprocess.Popen(subprocess_cmds, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, + universal_newlines=False) self.start_time = datetime.now() - f = open(self.log_path, "a") - f.write("{3} - Starting {0} {1} Render for {2}\n".format(self.renderer, self.version(), self.input, self.start_time.isoformat())) - for c in io.TextIOWrapper(self.process.stdout, encoding="utf-8"): # or another encoding - f.write(c) - logger.debug("RENDERER: {}".format(c.strip())) - self.last_output = c.strip() - self._parse_stdout(c.strip()) - f.write('\n') - # Check return codes - return_code = self.process.wait() - self.end_time = datetime.now() - # Return early if job was cancelled - if self.status is RenderStatus.CANCELLED: - self.is_finished = True - return + with open(self.log_path, "a") as f: - duration = self.end_time - self.start_time + f.write("{3} - Starting {0} {1} Render for {2}\n".format(self.renderer, self.version(), self.input, + self.start_time.isoformat())) + for c in io.TextIOWrapper(self.process.stdout, encoding="utf-8"): # or another encoding + f.write(c) + logger.debug(f"{self.renderer}Worker: {c.strip()}") + self.last_output = c.strip() + self._parse_stdout(c.strip()) + f.write('\n') - if return_code: - message = f"{self.renderer} render failed with return_code {return_code} after {duration}" - logger.error(message) - self.failed_attempts = self.failed_attempts + 1 - else: - message = f"{self.renderer} render completed successfully in {duration}" - logger.info(message) - self.status = RenderStatus.COMPLETED + # Check return codes + return_code = self.process.wait() + self.end_time = datetime.now() + # Return early if job was cancelled + if self.status is RenderStatus.CANCELLED: + self.is_finished = True + return - f.write(message) - f.close() + duration = self.end_time - self.start_time + + if return_code: + message = f"{self.renderer} render failed with return_code {return_code} after {duration}" + logger.error(message) + self.failed_attempts = self.failed_attempts + 1 + else: + message = f"{self.renderer} render completed successfully in {duration}" + logger.info(message) + self.status = RenderStatus.COMPLETED + + f.write(message) if self.failed_attempts >= self.maximum_attempts and self.status is not RenderStatus.CANCELLED: logger.error('{} Render of {} failed after {} attempts'.format(self.renderer, self.input, self.failed_attempts))