mirror of
https://github.com/blw1138/Zordon.git
synced 2026-06-10 14:09:24 -05:00
Add Job Window Redesign (#128)
* Initial refactor of add_job_window * Improved project naming and fixed Blender engine issue * Improve time representation in main window * Cleanup Blender job creation * Send resolution / fps data in job submission * More window improvements * EngineManager renaming and refactoring * FFMPEG path fixes for ffprobe * More backend refactoring / improvements * Performance improvements / API refactoring * Show current job count in add window UI before submission * Move some UI update code out of background thread * Move some main window UI update code out of background thread
This commit is contained in:
+93
-21
@@ -309,6 +309,12 @@ def add_job_handler():
|
||||
new_job = DistributedJobManager.create_render_job(processed_job_data, loaded_project_local_path)
|
||||
created_jobs.append(new_job)
|
||||
|
||||
# Save notes to .txt
|
||||
if processed_job_data.get("notes"):
|
||||
parent_dir = os.path.dirname(os.path.dirname(loaded_project_local_path))
|
||||
notes_name = processed_job_data['name'] + "-notes.txt"
|
||||
with open(os.path.join(parent_dir, notes_name), "w") as f:
|
||||
f.write(processed_job_data["notes"])
|
||||
return [x.json() for x in created_jobs]
|
||||
except Exception as e:
|
||||
logger.exception(f"Error creating render job: {e}")
|
||||
@@ -374,6 +380,26 @@ def delete_job(job_id):
|
||||
# Engine Info and Management:
|
||||
# --------------------------------------------
|
||||
|
||||
@server.get('/api/engine_for_filename')
|
||||
def get_engine_for_filename():
|
||||
filename = request.args.get("filename")
|
||||
if not filename:
|
||||
return "Error: filename is required", 400
|
||||
found_engine = EngineManager.engine_class_for_project_path(filename)
|
||||
if not found_engine:
|
||||
return f"Error: cannot find a suitable engine for '{filename}'", 400
|
||||
return found_engine.name()
|
||||
|
||||
@server.get('/api/installed_engines')
|
||||
def get_installed_engines():
|
||||
result = {}
|
||||
for engine_class in EngineManager.supported_engines():
|
||||
data = EngineManager.all_version_data_for_engine(engine_class.name())
|
||||
if data:
|
||||
result[engine_class.name()] = data
|
||||
return result
|
||||
|
||||
|
||||
@server.get('/api/engine_info')
|
||||
def engine_info():
|
||||
response_type = request.args.get('response_type', 'standard')
|
||||
@@ -383,7 +409,7 @@ def engine_info():
|
||||
def process_engine(engine):
|
||||
try:
|
||||
# Get all installed versions of the engine
|
||||
installed_versions = EngineManager.all_versions_for_engine(engine.name())
|
||||
installed_versions = EngineManager.all_version_data_for_engine(engine.name())
|
||||
if not installed_versions:
|
||||
return None
|
||||
|
||||
@@ -414,7 +440,7 @@ def engine_info():
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching details for engine '{engine.name()}': {e}")
|
||||
raise e
|
||||
return {}
|
||||
|
||||
engine_data = {}
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
@@ -428,14 +454,69 @@ def engine_info():
|
||||
return engine_data
|
||||
|
||||
|
||||
@server.get('/api/<engine_name>/info')
|
||||
def get_engine_info(engine_name):
|
||||
try:
|
||||
response_type = request.args.get('response_type', 'standard')
|
||||
# Get all installed versions of the engine
|
||||
installed_versions = EngineManager.all_version_data_for_engine(engine_name)
|
||||
if not installed_versions:
|
||||
return {}
|
||||
|
||||
result = { 'is_available': RenderQueue.is_available_for_job(engine_name),
|
||||
'versions': installed_versions
|
||||
}
|
||||
|
||||
if response_type == 'full':
|
||||
with concurrent.futures.ThreadPoolExecutor() as executor:
|
||||
engine_class = EngineManager.engine_class_with_name(engine_name)
|
||||
en = EngineManager.get_latest_engine_instance(engine_class)
|
||||
future_results = {
|
||||
'supported_extensions': executor.submit(en.supported_extensions),
|
||||
'supported_export_formats': executor.submit(en.get_output_formats),
|
||||
'system_info': executor.submit(en.system_info),
|
||||
'options': executor.submit(en.ui_options)
|
||||
}
|
||||
|
||||
for key, future in future_results.items():
|
||||
result[key] = future.result()
|
||||
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching details for engine '{engine_name}': {e}")
|
||||
return {}
|
||||
|
||||
|
||||
@server.get('/api/<engine_name>/is_available')
|
||||
def is_engine_available(engine_name):
|
||||
return {'engine': engine_name, 'available': RenderQueue.is_available_for_job(engine_name),
|
||||
'cpu_count': int(psutil.cpu_count(logical=False)),
|
||||
'versions': EngineManager.all_versions_for_engine(engine_name),
|
||||
'versions': EngineManager.all_version_data_for_engine(engine_name),
|
||||
'hostname': server.config['HOSTNAME']}
|
||||
|
||||
|
||||
@server.get('/api/engine/<engine_name>/args')
|
||||
def get_engine_args(engine_name):
|
||||
try:
|
||||
engine_class = EngineManager.engine_class_with_name(engine_name)
|
||||
return engine_class().get_arguments()
|
||||
except LookupError:
|
||||
return f"Cannot find engine '{engine_name}'", 400
|
||||
|
||||
|
||||
@server.get('/api/engine/<engine_name>/help')
|
||||
def get_engine_help(engine_name):
|
||||
try:
|
||||
engine_class = EngineManager.engine_class_with_name(engine_name)
|
||||
return engine_class().get_help()
|
||||
except LookupError:
|
||||
return f"Cannot find engine '{engine_name}'", 400
|
||||
|
||||
# --------------------------------------------
|
||||
# Engine Downloads and Updates:
|
||||
# --------------------------------------------
|
||||
|
||||
@server.get('/api/is_engine_available_to_download')
|
||||
def is_engine_available_to_download():
|
||||
available_result = EngineManager.version_is_available_to_download(request.args.get('engine'),
|
||||
@@ -476,24 +557,6 @@ def delete_engine_download():
|
||||
(f"Error deleting {json_data.get('engine')} {json_data.get('version')}", 500)
|
||||
|
||||
|
||||
@server.get('/api/engine/<engine_name>/args')
|
||||
def get_engine_args(engine_name):
|
||||
try:
|
||||
engine_class = EngineManager.engine_with_name(engine_name)
|
||||
return engine_class().get_arguments()
|
||||
except LookupError:
|
||||
return f"Cannot find engine '{engine_name}'", 400
|
||||
|
||||
|
||||
@server.get('/api/engine/<engine_name>/help')
|
||||
def get_engine_help(engine_name):
|
||||
try:
|
||||
engine_class = EngineManager.engine_with_name(engine_name)
|
||||
return engine_class().get_help()
|
||||
except LookupError:
|
||||
return f"Cannot find engine '{engine_name}'", 400
|
||||
|
||||
|
||||
# --------------------------------------------
|
||||
# Miscellaneous:
|
||||
# --------------------------------------------
|
||||
@@ -568,6 +631,15 @@ def handle_detached_instance(_):
|
||||
return "Unavailable", 503
|
||||
|
||||
|
||||
@server.errorhandler(404)
|
||||
def handle_404(error):
|
||||
url = request.url
|
||||
err_msg = f"404 Not Found: {url}"
|
||||
if 'favicon' not in url:
|
||||
logger.warning(err_msg)
|
||||
return err_msg, 404
|
||||
|
||||
|
||||
@server.errorhandler(Exception)
|
||||
def handle_general_error(general_error):
|
||||
err_msg = f"Server error: {general_error}"
|
||||
|
||||
@@ -43,9 +43,9 @@ class JobImportHandler:
|
||||
raise FileNotFoundError("Cannot find any valid project paths")
|
||||
|
||||
# Prepare the local filepath
|
||||
cleaned_path_name = os.path.splitext(referred_name)[0].replace(' ', '-')
|
||||
cleaned_path_name = job_name.replace(' ', '-')
|
||||
job_dir = os.path.join(upload_directory, '-'.join(
|
||||
[datetime.now().strftime("%Y.%m.%d_%H.%M.%S"), engine_name, cleaned_path_name]))
|
||||
[cleaned_path_name, engine_name, datetime.now().strftime("%Y.%m.%d_%H.%M.%S")]))
|
||||
os.makedirs(job_dir, exist_ok=True)
|
||||
project_source_dir = os.path.join(job_dir, 'source')
|
||||
os.makedirs(project_source_dir, exist_ok=True)
|
||||
|
||||
+27
-10
@@ -247,16 +247,19 @@ class RenderServerProxy:
|
||||
# Engines:
|
||||
# --------------------------------------------
|
||||
|
||||
def is_engine_available(self, engine_name):
|
||||
return self.request_data(f'{engine_name}/is_available')
|
||||
def get_engine_for_filename(self, filename, timeout=5):
|
||||
response = self.request(f'engine_for_filename?filename={os.path.basename(filename)}', timeout)
|
||||
return response.text
|
||||
|
||||
def get_all_engines(self):
|
||||
# todo: this doesnt work
|
||||
return self.request_data('all_engines')
|
||||
def get_installed_engines(self, timeout=5):
|
||||
return self.request_data(f'installed_engines', timeout)
|
||||
|
||||
def get_engine_info(self, response_type='standard', timeout=5):
|
||||
def is_engine_available(self, engine_name:str, timeout=5):
|
||||
return self.request_data(f'{engine_name}/is_available', timeout)
|
||||
|
||||
def get_all_engine_info(self, response_type='standard', timeout=5):
|
||||
"""
|
||||
Fetches engine information from the server.
|
||||
Fetches all engine information from the server.
|
||||
|
||||
Args:
|
||||
response_type (str, optional): Returns standard or full version of engine info
|
||||
@@ -268,19 +271,33 @@ class RenderServerProxy:
|
||||
all_data = self.request_data(f"engine_info?response_type={response_type}", timeout=timeout)
|
||||
return all_data
|
||||
|
||||
def delete_engine(self, engine, version, system_cpu=None):
|
||||
def get_engine_info(self, engine_name:str, response_type='standard', timeout=5):
|
||||
"""
|
||||
Fetches specific engine information from the server.
|
||||
|
||||
Args:
|
||||
engine_name (str): Name of the engine
|
||||
response_type (str, optional): Returns standard or full version of engine info
|
||||
timeout (int, optional): The number of seconds to wait for a response from the server. Defaults to 5.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the engine information.
|
||||
"""
|
||||
return self.request_data(f'{engine_name}/info?response_type={response_type}', timeout)
|
||||
|
||||
def delete_engine(self, engine_name:str, version:str, system_cpu=None):
|
||||
"""
|
||||
Sends a request to the server to delete a specific engine.
|
||||
|
||||
Args:
|
||||
engine (str): The name of the engine to delete.
|
||||
engine_name (str): The name of the engine to delete.
|
||||
version (str): The version of the engine to delete.
|
||||
system_cpu (str, optional): The system CPU type. Defaults to None.
|
||||
|
||||
Returns:
|
||||
Response: The response from the server.
|
||||
"""
|
||||
form_data = {'engine': engine, 'version': version, 'system_cpu': system_cpu}
|
||||
form_data = {'engine': engine_name, 'version': version, 'system_cpu': system_cpu}
|
||||
return requests.post(f'http://{self.hostname}:{self.port}/api/delete_engine', json=form_data)
|
||||
|
||||
# --------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user