New UI Redesign in pyqt6 (#56)

* Initial commit for new UI

* Initial commit for new UI

* WIP

* Status bar updates and has an icon for online / offline

* Add log_viewer.py

* Use JSON for delete_engine_download API

* Fix class issue with Downloaders

* Move Config class to new ui

* Add engine_browser.py

* Add a close event handler to the main window

* Fix issue with engine manager not deleting engines properly

* Rearrange all the files

* Add icons and resources

* Cache system info in RenderServerProxy

* Toolbar polish

* Fix resource path in status bar

* Add config_dir to misc_helper.py

* Add try block to zeroconf setup

* Add add_job.py

* Add raw args to add_job.py
This commit is contained in:
2023-11-04 09:52:15 -05:00
committed by GitHub
parent bc8e88ea59
commit 65c256b641
45 changed files with 1491 additions and 53 deletions

View File

@@ -127,7 +127,7 @@ def process_zipped_project(zip_path):
return extracted_project_path
def create_render_jobs(jobs_list, loaded_project_local_path, job_dir, enable_split_jobs=False):
def create_render_jobs(jobs_list, loaded_project_local_path, job_dir):
results = []
for job_data in jobs_list:
@@ -162,7 +162,7 @@ def create_render_jobs(jobs_list, loaded_project_local_path, job_dir, enable_spl
worker.end_frame = int(job_data.get("end_frame", worker.end_frame))
# determine if we can / should split the job
if enable_split_jobs and (worker.total_frames > 1) and not worker.parent:
if job_data.get("enable_split_jobs", False) and (worker.total_frames > 1) and not worker.parent:
DistributedJobManager.split_into_subjobs(worker, job_data, loaded_project_local_path)
else:
logger.debug("Not splitting into subjobs")

View File

@@ -24,7 +24,8 @@ from src.engines.core.base_worker import string_to_status, RenderStatus
from src.engines.engine_manager import EngineManager
from src.render_queue import RenderQueue, JobNotFoundError
from src.utilities.config import Config
from src.utilities.misc_helper import system_safe_path, current_system_os, current_system_cpu, current_system_os_version
from src.utilities.misc_helper import system_safe_path, current_system_os, current_system_cpu, \
current_system_os_version, config_dir
from src.utilities.server_helper import generate_thumbnail_for_job
from src.utilities.zeroconf_server import ZeroconfServer
@@ -53,7 +54,7 @@ def sorted_jobs(all_jobs, sort_by_date=True):
@server.route('/')
@server.route('/index')
def index():
with open(system_safe_path('config/presets.yaml')) as f:
with open(system_safe_path(os.path.join(config_dir(), 'presets.yaml'))) as f:
render_presets = yaml.load(f, Loader=yaml.FullLoader)
return render_template('index.html', all_jobs=sorted_jobs(RenderQueue.all_jobs()),
@@ -312,8 +313,7 @@ def add_job_handler():
if loaded_project_local_path.lower().endswith('.zip'):
loaded_project_local_path = process_zipped_project(loaded_project_local_path)
results = create_render_jobs(jobs_list, loaded_project_local_path, referred_name,
server.config['enable_split_jobs'])
results = create_render_jobs(jobs_list, loaded_project_local_path, referred_name)
for response in results:
if response.get('error', None):
return results, 400
@@ -417,18 +417,18 @@ def status():
@server.get('/api/renderer_info')
def renderer_info():
return_simple = request.args.get('simple', False)
renderer_data = {}
for engine_name in EngineManager.supported_engines():
engine = EngineManager.engine_with_name(engine_name)
for engine in EngineManager.supported_engines():
# Get all installed versions of engine
installed_versions = EngineManager.all_versions_for_engine(engine_name)
installed_versions = EngineManager.all_versions_for_engine(engine.name())
if installed_versions:
install_path = installed_versions[0]['path']
renderer_data[engine_name] = {'is_available': RenderQueue.is_available_for_job(engine.name()),
'versions': installed_versions,
'supported_extensions': engine.supported_extensions,
'supported_export_formats': engine(install_path).get_output_formats()}
renderer_data[engine.name()] = {'is_available': RenderQueue.is_available_for_job(engine.name()),
'versions': installed_versions}
if not return_simple:
renderer_data[engine.name()]['supported_extensions'] = engine.supported_extensions
renderer_data[engine.name()]['supported_export_formats'] = engine(install_path).get_output_formats()
return renderer_data
@@ -471,19 +471,20 @@ def download_engine():
@server.post('/api/delete_engine')
def delete_engine_download():
delete_result = EngineManager.delete_engine_download(request.args.get('engine'),
request.args.get('version'),
request.args.get('system_os'),
request.args.get('cpu'))
json_data = request.json
delete_result = EngineManager.delete_engine_download(json_data.get('engine'),
json_data.get('version'),
json_data.get('system_os'),
json_data.get('cpu'))
return "Success" if delete_result else \
(f"Error deleting {request.args.get('engine')} {request.args.get('version')}", 500)
(f"Error deleting {json_data.get('engine')} {json_data.get('version')}", 500)
@server.get('/api/renderer/<renderer>/args')
def get_renderer_args(renderer):
try:
renderer_engine_class = EngineManager.engine_with_name(renderer)
return renderer_engine_class.get_arguments()
return renderer_engine_class().get_arguments()
except LookupError:
return f"Cannot find renderer '{renderer}'", 400
@@ -499,13 +500,6 @@ def start_server():
RenderQueue.evaluate_queue()
time.sleep(delay_sec)
# Load Config YAML
config_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), 'config')
Config.load_config(system_safe_path(os.path.join(config_dir, 'config.yaml')))
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(module)s: %(message)s', datefmt='%d-%b-%y %H:%M:%S',
level=Config.server_log_level.upper())
# get hostname
local_hostname = socket.gethostname()
local_hostname = local_hostname + (".local" if not local_hostname.endswith(".local") else "")

View File

@@ -34,9 +34,14 @@ class RenderServerProxy:
self.__offline_flags = 0
self.update_cadence = 5
# Cache some basic server info
self.system_cpu = None
self.system_cpu_count = None
self.system_os = None
self.system_os_version = None
def connect(self):
status = self.request_data('status')
return status
return self.status()
def is_online(self):
if self.__update_in_background:
@@ -48,7 +53,7 @@ class RenderServerProxy:
if not self.is_online():
return "Offline"
running_jobs = [x for x in self.__jobs_cache if x['status'] == 'running'] if self.__jobs_cache else []
return f"{len(running_jobs)} running" if running_jobs else "Available"
return f"{len(running_jobs)} running" if running_jobs else "Ready"
def request_data(self, payload, timeout=5):
try:
@@ -72,6 +77,8 @@ class RenderServerProxy:
return requests.get(f'http://{self.hostname}:{self.port}/api/{payload}', timeout=timeout)
def start_background_update(self):
if self.__update_in_background:
return
self.__update_in_background = True
def thread_worker():
@@ -113,12 +120,24 @@ class RenderServerProxy:
def cancel_job(self, job_id, confirm=False):
return self.request_data(f'job/{job_id}/cancel?confirm={confirm}')
def delete_job(self, job_id, confirm=False):
return self.request_data(f'job/{job_id}/delete?confirm={confirm}')
def get_status(self):
return self.request_data('status')
status = self.request_data('status')
if not self.system_cpu:
self.system_cpu = status['system_cpu']
self.system_cpu_count = status['cpu_count']
self.system_os = status['system_os']
self.system_os_version = status['system_os_version']
return status
def is_engine_available(self, engine_name):
return self.request_data(f'{engine_name}/is_available')
def get_all_engines(self):
return self.request_data('all_engines')
def notify_parent_of_status_change(self, parent_id, subjob):
return requests.post(f'http://{self.hostname}:{self.port}/api/job/{parent_id}/notify_parent_of_status_change',
json=subjob.json())
@@ -160,3 +179,12 @@ class RenderServerProxy:
f.write(chunk)
return filename
# --- Renderer --- #
def get_renderer_info(self, timeout=5, simple=False):
all_data = self.request_data(f'renderer_info?simple={simple}', timeout=timeout)
return all_data
def delete_engine(self, engine, version, system_cpu=None):
form_data = {'engine': engine, 'version': version, 'system_cpu': system_cpu}
return requests.post(f'http://{self.hostname}:{self.port}/api/delete_engine', json=form_data)