Remove Old Multi-Client Code / Refactoring (#13)

* Remove a lot of old code from render_queue regarding clients

* More code cleanup

* More code cleanup

* Move everything around

* Minor log change
This commit is contained in:
2023-06-11 14:50:20 -05:00
committed by GitHub
parent 86a1dae5b6
commit 94bb1e4362
22 changed files with 66 additions and 210 deletions

0
lib/engines/__init__.py Normal file
View File

View File

@@ -0,0 +1,26 @@
try:
from .base_engine import *
except ImportError:
from base_engine import *
class AERender(BaseRenderEngine):
supported_extensions = ['.aep']
@classmethod
def version(cls):
version = None
try:
render_path = cls.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()
except Exception as e:
logger.error(f'Failed to get {cls.name()} version: {e}')
return version
@classmethod
def get_output_formats(cls):
# todo: create implementation
return []

View File

@@ -0,0 +1,46 @@
import logging
import os
import subprocess
logger = logging.getLogger()
SUBPROCESS_TIMEOUT = 5
class BaseRenderEngine(object):
install_paths = []
supported_extensions = []
@classmethod
def name(cls):
return cls.__name__.lower()
@classmethod
def renderer_path(cls):
path = None
try:
path = subprocess.check_output(['which', cls.name()], timeout=SUBPROCESS_TIMEOUT).decode('utf-8').strip()
except subprocess.CalledProcessError:
for p in cls.install_paths:
if os.path.exists(p):
path = p
except Exception as e:
logger.exception(e)
return path
@classmethod
def version(cls):
raise NotImplementedError("version not implemented")
@classmethod
def get_help(cls):
path = cls.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')
return help_doc
@classmethod
def get_output_formats(cls):
raise NotImplementedError(f"get_output_formats not implemented for {cls.__name__}")

View File

@@ -0,0 +1,104 @@
try:
from .base_engine import *
except ImportError:
from base_engine import *
import json
import re
import logging
logger = logging.getLogger()
class Blender(BaseRenderEngine):
install_paths = ['/Applications/Blender.app/Contents/MacOS/Blender']
supported_extensions = ['.blend']
@classmethod
def version(cls):
version = None
try:
render_path = cls.renderer_path()
if render_path:
ver_out = subprocess.check_output([render_path, '-v'], timeout=SUBPROCESS_TIMEOUT)
version = ver_out.decode('utf-8').splitlines()[0].replace('Blender', '').strip()
except Exception as e:
logger.error(f'Failed to get Blender version: {e}')
return version
@classmethod
def get_output_formats(cls):
format_string = cls.get_help().split('Format Options')[-1].split('Animation Playback Options')[0]
formats = re.findall(r"'([A-Z_0-9]+)'", format_string)
return formats
@classmethod
def run_python_expression(cls, project_path, python_expression, timeout=None):
if os.path.exists(project_path):
try:
return subprocess.run([cls.renderer_path(), '-b', project_path, '--python-expr', python_expression],
capture_output=True, timeout=timeout)
except Exception as e:
logger.warning(f"Error running python expression in blender: {e}")
pass
else:
raise FileNotFoundError(f'Project file not found: {project_path}')
@classmethod
def run_python_script(cls, project_path, script_path, timeout=None):
if os.path.exists(project_path) and os.path.exists(script_path):
try:
return subprocess.run([cls.renderer_path(), '-b', project_path, '--python', script_path],
capture_output=True, timeout=timeout)
except Exception as e:
logger.warning(f"Error running python expression in blender: {e}")
pass
elif not os.path.exists(project_path):
raise FileNotFoundError(f'Project file not found: {project_path}')
elif not os.path.exists(script_path):
raise FileNotFoundError(f'Python script not found: {script_path}')
raise Exception("Uncaught exception")
@classmethod
def get_scene_info(cls, project_path, timeout=10):
scene_info = {}
try:
results = cls.run_python_script(project_path, os.path.join(os.path.dirname(os.path.realpath(__file__)),
'scripts', 'blender', 'get_file_info.py'), timeout=timeout)
result_text = results.stdout.decode()
for line in result_text.splitlines():
if line.startswith('SCENE_DATA:'):
raw_data = line.split('SCENE_DATA:')[-1]
scene_info = json.loads(raw_data)
break
elif line.startswith('Error'):
logger.error(f"get_scene_info error: {line.strip()}")
except Exception as e:
logger.error(f'Error getting file details for .blend file: {e}')
return scene_info
@classmethod
def pack_project_file(cls, project_path, timeout=30):
# Credit to L0Lock for pack script - https://blender.stackexchange.com/a/243935
try:
logger.info(f"Starting to pack Blender file: {project_path}")
results = cls.run_python_script(project_path, os.path.join(os.path.dirname(os.path.realpath(__file__)),
'scripts', 'blender', 'pack_project.py'), timeout=timeout)
result_text = results.stdout.decode()
dir_name = os.path.dirname(project_path)
# report any missing textures
not_found = re.findall("(Unable to pack file, source path .*)\n", result_text)
for err in not_found:
logger.error(err)
p = re.compile('Saved to: (.*)\n')
match = p.search(result_text)
if match:
new_path = os.path.join(dir_name, match.group(1).strip())
logger.info(f'Blender file packed successfully to {new_path}')
return new_path
except Exception as e:
logger.error(f'Error packing .blend file: {e}')
return None

View File

@@ -0,0 +1,41 @@
try:
from .base_engine import *
except ImportError:
from base_engine import *
import re
class FFMPEG(BaseRenderEngine):
@classmethod
def version(cls):
version = None
try:
ver_out = subprocess.check_output([cls.renderer_path(), '-version'],
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
match = re.match(".*version\s*(\S+)\s*Copyright", ver_out)
if match:
version = match.groups()[0]
except Exception as e:
logger.error("Failed to get FFMPEG version: {}".format(e))
return version
@classmethod
def get_encoders(cls):
encoders_raw = subprocess.check_output([cls.renderer_path(), '-encoders'], stderr=subprocess.DEVNULL,
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
pattern = '(?P<type>[VASFXBD.]{6})\s+(?P<name>\S{2,})\s+(?P<description>.*)'
encoders = [m.groupdict() for m in re.finditer(pattern, encoders_raw)]
return encoders
@classmethod
def get_all_formats(cls):
formats_raw = subprocess.check_output([cls.renderer_path(), '-formats'], stderr=subprocess.DEVNULL,
timeout=SUBPROCESS_TIMEOUT).decode('utf-8')
pattern = '(?P<type>[DE]{1,2})\s+(?P<name>\S{2,})\s+(?P<description>.*)'
formats = [m.groupdict() for m in re.finditer(pattern, formats_raw)]
return formats
@classmethod
def get_output_formats(cls):
return [x for x in cls.get_all_formats() if 'E' in x['type'].upper()]

View File

@@ -0,0 +1,29 @@
import json
import bpy
# Get all cameras
cameras = []
for cam_obj in bpy.data.cameras:
user_map = bpy.data.user_map(subset={cam_obj}, value_types={'OBJECT'})
for data_obj in user_map[cam_obj]:
cam = {'name': data_obj.name,
'cam_name': cam_obj.name,
'cam_name_full': cam_obj.name_full,
'lens': cam_obj.lens,
'lens_unit': cam_obj.lens_unit,
'sensor_height': cam_obj.sensor_height,
'sensor_width': cam_obj.sensor_width}
cameras.append(cam)
scene = bpy.data.scenes[0]
data = {'cameras': cameras,
'engine': scene.render.engine,
'frame_start': scene.frame_start,
'frame_end': scene.frame_end,
'resolution_x': scene.render.resolution_x,
'resolution_y': scene.render.resolution_y,
'resolution_percentage': scene.render.resolution_percentage,
'fps': scene.render.fps}
data_string = json.dumps(data)
print("SCENE_DATA:" + data_string)

View File

@@ -0,0 +1,53 @@
import bpy
import os
import shutil
import zipfile
def zip_files(paths, output_zip_path):
with zipfile.ZipFile(output_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
for path in paths:
if os.path.isfile(path):
# If the path is a file, add it to the zip
zipf.write(path, arcname=os.path.basename(path))
elif os.path.isdir(path):
# If the path is a directory, add all its files and subdirectories
for root, dirs, files in os.walk(path):
for file in files:
full_path = os.path.join(root, file)
zipf.write(full_path, arcname=os.path.join(os.path.basename(path), os.path.relpath(full_path, path)))
# Get File path
project_path = str(bpy.data.filepath)
# Pack Files
bpy.ops.file.pack_all()
bpy.ops.file.make_paths_absolute()
# Temp dir
tmp_dir = os.path.join(os.path.dirname(project_path), 'tmp')
asset_dir = os.path.join(tmp_dir, 'assets')
os.makedirs(tmp_dir, exist_ok=True)
# Find images we could not pack - usually videos
for img in bpy.data.images:
if not img.packed_file and img.filepath and img.users:
os.makedirs(asset_dir, exist_ok=True)
shutil.copy2(img.filepath, os.path.join(asset_dir, os.path.basename(img.filepath)))
print(f"Copied {os.path.basename(img.filepath)} to tmp directory")
img.filepath = '//' + os.path.join('assets', os.path.basename(img.filepath))
# Save Output
bpy.ops.wm.save_as_mainfile(filepath=os.path.join(tmp_dir, os.path.basename(project_path)), compress=True, relative_remap=False)
# Save Zip
zip_path = os.path.join(os.path.dirname(project_path), f"{os.path.basename(project_path).split('.')[0]}.zip")
zip_files([os.path.join(tmp_dir, os.path.basename(project_path)), asset_dir], zip_path)
if os.path.exists(zip_path):
print(f'Saved to: {zip_path}')
else:
print("Error saving zip file!")
# Cleanup
shutil.rmtree(tmp_dir, ignore_errors=True)