Major file reorganization (#26)
* Major file reorganization * Rearrange imports * Fix default log level
@@ -17,9 +17,9 @@ from rich.table import Table
|
|||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
from rich.tree import Tree
|
from rich.tree import Tree
|
||||||
|
|
||||||
from lib.workers.base_worker import RenderStatus, string_to_status
|
from src.workers.base_worker import RenderStatus, string_to_status
|
||||||
from lib.server.server_proxy import RenderServerProxy
|
from src.server_proxy import RenderServerProxy
|
||||||
from lib.utilities.misc_helper import get_time_elapsed
|
from src.utilities.misc_helper import get_time_elapsed
|
||||||
from start_server import start_server
|
from start_server import start_server
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
click~=8.1.3
|
|
||||||
requests==2.31.0
|
requests==2.31.0
|
||||||
psutil==5.9.5
|
psutil==5.9.5
|
||||||
PyYAML~=6.0
|
PyYAML~=6.0
|
||||||
Flask==2.3.2
|
Flask==2.3.2
|
||||||
rich==13.4.1
|
rich==13.4.1
|
||||||
Werkzeug==2.3.5
|
Werkzeug==2.3.5
|
||||||
tkinterdnd2~=0.3.0
|
|
||||||
future==0.18.3
|
future==0.18.3
|
||||||
json2html~=1.3.0
|
json2html~=1.3.0
|
||||||
SQLAlchemy~=2.0.15
|
SQLAlchemy~=2.0.15
|
||||||
Pillow==9.5.0
|
Pillow==9.5.0
|
||||||
zeroconf==0.64.1
|
zeroconf==0.64.1
|
||||||
requests-toolbelt~=1.0
|
Pypubsub~=4.0.3
|
||||||
arrow~=1.2.3
|
|
||||||
@@ -20,16 +20,16 @@ import yaml
|
|||||||
from flask import Flask, request, render_template, send_file, after_this_request, Response, redirect, url_for, abort
|
from flask import Flask, request, render_template, send_file, after_this_request, Response, redirect, url_for, abort
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
|
|
||||||
from lib.distributed_job_manager import DistributedJobManager
|
from src.distributed_job_manager import DistributedJobManager
|
||||||
from lib.render_queue import RenderQueue, JobNotFoundError
|
from src.render_queue import RenderQueue, JobNotFoundError
|
||||||
from lib.server.server_proxy import RenderServerProxy
|
from src.server_proxy import RenderServerProxy
|
||||||
from lib.server.zeroconf_server import ZeroconfServer
|
from src.utilities.server_helper import generate_thumbnail_for_job
|
||||||
from lib.utilities.server_helper import generate_thumbnail_for_job
|
from src.utilities.zeroconf_server import ZeroconfServer
|
||||||
from lib.workers.base_worker import string_to_status, RenderStatus
|
from src.worker_factory import RenderWorkerFactory
|
||||||
from lib.workers.worker_factory import RenderWorkerFactory
|
from src.workers.base_worker import string_to_status, RenderStatus
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
server = Flask(__name__, template_folder='templates', static_folder='static')
|
server = Flask(__name__, template_folder='web/templates', static_folder='web/static')
|
||||||
ssl._create_default_https_context = ssl._create_unverified_context # disable SSL for downloads
|
ssl._create_default_https_context = ssl._create_unverified_context # disable SSL for downloads
|
||||||
|
|
||||||
categories = [RenderStatus.RUNNING, RenderStatus.ERROR, RenderStatus.NOT_STARTED, RenderStatus.SCHEDULED,
|
categories = [RenderStatus.RUNNING, RenderStatus.ERROR, RenderStatus.NOT_STARTED, RenderStatus.SCHEDULED,
|
||||||
@@ -53,13 +53,12 @@ def sorted_jobs(all_jobs, sort_by_date=True):
|
|||||||
@server.route('/')
|
@server.route('/')
|
||||||
@server.route('/index')
|
@server.route('/index')
|
||||||
def index():
|
def index():
|
||||||
|
|
||||||
with open('config/presets.yaml') as f:
|
with open('config/presets.yaml') as f:
|
||||||
presets = yaml.load(f, Loader=yaml.FullLoader)
|
render_presets = yaml.load(f, Loader=yaml.FullLoader)
|
||||||
|
|
||||||
return render_template('index.html', all_jobs=sorted_jobs(RenderQueue.all_jobs()),
|
return render_template('index.html', all_jobs=sorted_jobs(RenderQueue.all_jobs()),
|
||||||
hostname=server.config['HOSTNAME'], renderer_info=renderer_info(),
|
hostname=server.config['HOSTNAME'], renderer_info=renderer_info(),
|
||||||
render_clients=[server.config['HOSTNAME']], preset_list=presets)
|
render_clients=[server.config['HOSTNAME']], preset_list=render_presets)
|
||||||
|
|
||||||
|
|
||||||
@server.get('/api/jobs')
|
@server.get('/api/jobs')
|
||||||
@@ -131,15 +130,15 @@ def job_thumbnail(job_id):
|
|||||||
|
|
||||||
# Misc status icons
|
# Misc status icons
|
||||||
if found_job.status == RenderStatus.RUNNING:
|
if found_job.status == RenderStatus.RUNNING:
|
||||||
return send_file('static/images/gears.png', mimetype="image/png")
|
return send_file('web/static/images/gears.png', mimetype="image/png")
|
||||||
elif found_job.status == RenderStatus.CANCELLED:
|
elif found_job.status == RenderStatus.CANCELLED:
|
||||||
return send_file('static/images/cancelled.png', mimetype="image/png")
|
return send_file('web/static/images/cancelled.png', mimetype="image/png")
|
||||||
elif found_job.status == RenderStatus.SCHEDULED:
|
elif found_job.status == RenderStatus.SCHEDULED:
|
||||||
return send_file('static/images/scheduled.png', mimetype="image/png")
|
return send_file('web/static/images/scheduled.png', mimetype="image/png")
|
||||||
elif found_job.status == RenderStatus.NOT_STARTED:
|
elif found_job.status == RenderStatus.NOT_STARTED:
|
||||||
return send_file('static/images/not_started.png', mimetype="image/png")
|
return send_file('web/static/images/not_started.png', mimetype="image/png")
|
||||||
# errors
|
# errors
|
||||||
return send_file('static/images/error.png', mimetype="image/png")
|
return send_file('web/static/images/error.png', mimetype="image/png")
|
||||||
|
|
||||||
|
|
||||||
# Get job file routing
|
# Get job file routing
|
||||||
@@ -498,7 +497,6 @@ def clear_history():
|
|||||||
|
|
||||||
@server.route('/api/status')
|
@server.route('/api/status')
|
||||||
def status():
|
def status():
|
||||||
|
|
||||||
renderer_data = {}
|
renderer_data = {}
|
||||||
for render_class in RenderWorkerFactory.supported_classes():
|
for render_class in RenderWorkerFactory.supported_classes():
|
||||||
if render_class.engine.renderer_path(): # only return renderers installed on host
|
if render_class.engine.renderer_path(): # only return renderers installed on host
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import tkinter as tk
|
import os
|
||||||
|
import socket
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import socket
|
import tkinter as tk
|
||||||
import os
|
|
||||||
from tkinter import ttk, messagebox, simpledialog
|
from tkinter import ttk, messagebox, simpledialog
|
||||||
|
|
||||||
from PIL import Image, ImageTk
|
from PIL import Image, ImageTk
|
||||||
from lib.client.new_job_window import NewJobWindow
|
|
||||||
from lib.server.server_proxy import RenderServerProxy
|
from src.client.new_job_window import NewJobWindow
|
||||||
from lib.server.zeroconf_server import ZeroconfServer
|
# from src.client.server_details import create_server_popup
|
||||||
from lib.workers.base_worker import RenderStatus
|
from src.server_proxy import RenderServerProxy
|
||||||
from lib.utilities.misc_helper import launch_url, file_exists_in_mounts, get_time_elapsed
|
from src.utilities.misc_helper import launch_url, file_exists_in_mounts, get_time_elapsed
|
||||||
|
from src.utilities.zeroconf_server import ZeroconfServer
|
||||||
|
from src.workers.base_worker import RenderStatus
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -31,7 +34,7 @@ def make_sortable(tree):
|
|||||||
class DashboardWindow:
|
class DashboardWindow:
|
||||||
|
|
||||||
lib_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
lib_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
image_path = os.path.join(lib_path, 'server', 'static', 'images')
|
image_path = os.path.join(lib_path, 'web', 'static', 'images')
|
||||||
default_image = Image.open(os.path.join(image_path, 'desktop.png'))
|
default_image = Image.open(os.path.join(image_path, 'desktop.png'))
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
@@ -4,16 +4,16 @@ import logging
|
|||||||
import os.path
|
import os.path
|
||||||
import pathlib
|
import pathlib
|
||||||
import socket
|
import socket
|
||||||
|
import threading
|
||||||
from tkinter import *
|
from tkinter import *
|
||||||
from tkinter import filedialog, messagebox
|
from tkinter import filedialog, messagebox
|
||||||
from tkinter.ttk import Frame, Label, Entry, Combobox, Progressbar
|
from tkinter.ttk import Frame, Label, Entry, Combobox, Progressbar
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
import requests
|
|
||||||
import threading
|
from src.server_proxy import RenderServerProxy
|
||||||
from lib.workers.blender_worker import Blender
|
from src.workers.blender_worker import Blender
|
||||||
from lib.workers.ffmpeg_worker import FFMPEG
|
from src.workers.ffmpeg_worker import FFMPEG
|
||||||
from lib.server.server_proxy import RenderServerProxy
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -5,11 +5,12 @@ import time
|
|||||||
import zipfile
|
import zipfile
|
||||||
|
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from lib.render_queue import RenderQueue
|
|
||||||
from lib.server.server_proxy import RenderServerProxy
|
from src.render_queue import RenderQueue
|
||||||
from lib.server.zeroconf_server import ZeroconfServer
|
from src.server_proxy import RenderServerProxy
|
||||||
from lib.utilities.misc_helper import get_file_size_human
|
from src.utilities.misc_helper import get_file_size_human
|
||||||
from lib.workers.base_worker import RenderStatus, string_to_status
|
from src.utilities.status_utils import RenderStatus, string_to_status
|
||||||
|
from src.utilities.zeroconf_server import ZeroconfServer
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -4,8 +4,9 @@ from datetime import datetime
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
from sqlalchemy.orm import sessionmaker
|
from sqlalchemy.orm import sessionmaker
|
||||||
|
|
||||||
from lib.workers.base_worker import RenderStatus, BaseRenderWorker, Base
|
from src.utilities.status_utils import RenderStatus
|
||||||
from lib.workers.worker_factory import RenderWorkerFactory
|
from src.worker_factory import RenderWorkerFactory
|
||||||
|
from src.workers.base_worker import Base
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -83,12 +84,20 @@ class RenderQueue:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_state(cls):
|
def load_state(cls):
|
||||||
|
from src.workers.base_worker import BaseRenderWorker
|
||||||
cls.job_queue = cls.session.query(BaseRenderWorker).all()
|
cls.job_queue = cls.session.query(BaseRenderWorker).all()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def save_state(cls):
|
def save_state(cls):
|
||||||
cls.session.commit()
|
cls.session.commit()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def prepare_for_shutdown(cls):
|
||||||
|
running_jobs = cls.jobs_with_status(RenderStatus.RUNNING) # cancel all running jobs
|
||||||
|
for job in running_jobs:
|
||||||
|
cls.cancel_job(job)
|
||||||
|
cls.save_state()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_available_for_job(cls, renderer, priority=2):
|
def is_available_for_job(cls, renderer, priority=2):
|
||||||
if not RenderWorkerFactory.class_for_name(renderer).engine.renderer_path():
|
if not RenderWorkerFactory.class_for_name(renderer).engine.renderer_path():
|
||||||
@@ -96,8 +105,9 @@ class RenderQueue:
|
|||||||
|
|
||||||
instances = cls.renderer_instances()
|
instances = cls.renderer_instances()
|
||||||
higher_priority_jobs = [x for x in cls.running_jobs() if x.priority < priority]
|
higher_priority_jobs = [x for x in cls.running_jobs() if x.priority < priority]
|
||||||
max_renderers = renderer in instances.keys() and instances[renderer] >= cls.maximum_renderer_instances.get(renderer, 1)
|
max_allowed_instances = cls.maximum_renderer_instances.get(renderer, 1)
|
||||||
return not max_renderers and not higher_priority_jobs
|
maxed_out_instances = renderer in instances.keys() and instances[renderer] >= max_allowed_instances
|
||||||
|
return not maxed_out_instances and not higher_priority_jobs
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def evaluate_queue(cls):
|
def evaluate_queue(cls):
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import json
|
|
||||||
import requests
|
|
||||||
import socket
|
import socket
|
||||||
import time
|
|
||||||
import threading
|
import threading
|
||||||
from lib.workers.base_worker import RenderStatus
|
import time
|
||||||
|
|
||||||
|
import requests
|
||||||
from requests_toolbelt.multipart import MultipartEncoder, MultipartEncoderMonitor
|
from requests_toolbelt.multipart import MultipartEncoder, MultipartEncoderMonitor
|
||||||
|
|
||||||
|
from src.utilities.status_utils import RenderStatus
|
||||||
|
|
||||||
status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', RenderStatus.COMPLETED: 'green',
|
status_colors = {RenderStatus.ERROR: "red", RenderStatus.CANCELLED: 'orange1', RenderStatus.COMPLETED: 'green',
|
||||||
RenderStatus.NOT_STARTED: "yellow", RenderStatus.SCHEDULED: 'purple',
|
RenderStatus.NOT_STARTED: "yellow", RenderStatus.SCHEDULED: 'purple',
|
||||||
RenderStatus.RUNNING: 'cyan', RenderStatus.WAITING_FOR_SUBJOBS: 'blue'}
|
RenderStatus.RUNNING: 'cyan', RenderStatus.WAITING_FOR_SUBJOBS: 'blue'}
|
||||||
|
|
||||||
categories = [RenderStatus.RUNNING, RenderStatus.WAITING_FOR_SUBJOBS, RenderStatus.ERROR, RenderStatus.NOT_STARTED, RenderStatus.SCHEDULED,
|
categories = [RenderStatus.RUNNING, RenderStatus.WAITING_FOR_SUBJOBS, RenderStatus.ERROR, RenderStatus.NOT_STARTED,
|
||||||
RenderStatus.COMPLETED, RenderStatus.CANCELLED, RenderStatus.UNDEFINED]
|
RenderStatus.SCHEDULED, RenderStatus.COMPLETED, RenderStatus.CANCELLED, RenderStatus.UNDEFINED]
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
OFFLINE_MAX = 2
|
OFFLINE_MAX = 2
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
from lib.engines.ffmpeg_engine import FFMPEG
|
from src.workers.engines.ffmpeg_engine import FFMPEG
|
||||||
|
|
||||||
|
|
||||||
def image_sequence_to_video(source_glob_pattern, output_path, framerate=24, encoder="prores_ks", profile=4,
|
def image_sequence_to_video(source_glob_pattern, output_path, framerate=24, encoder="prores_ks", profile=4,
|
||||||
@@ -1,13 +1,9 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import socket
|
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
|
|
||||||
import psutil
|
from src.utilities.ffmpeg_helper import generate_thumbnail, save_first_frame
|
||||||
|
|
||||||
from lib.server.server_proxy import RenderServerProxy
|
|
||||||
from lib.utilities.ffmpeg_helper import generate_thumbnail, save_first_frame
|
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
|
|
||||||
@@ -21,8 +17,8 @@ def generate_thumbnail_for_job(job, thumb_video_path, thumb_image_path, max_widt
|
|||||||
try:
|
try:
|
||||||
logger.debug(f"Generating video thumbnail for {source}")
|
logger.debug(f"Generating video thumbnail for {source}")
|
||||||
generate_thumbnail(source_path=source, dest_path=thumb_video_path, max_width=max_width)
|
generate_thumbnail(source_path=source, dest_path=thumb_video_path, max_width=max_width)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as err:
|
||||||
logger.error(f"Error generating video thumbnail for {source}: {e}")
|
logger.error(f"Error generating video thumbnail for {source}: {err}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.remove(in_progress_path)
|
os.remove(in_progress_path)
|
||||||
20
src/utilities/status_utils.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
|
class RenderStatus(Enum):
|
||||||
|
NOT_STARTED = "not_started"
|
||||||
|
RUNNING = "running"
|
||||||
|
COMPLETED = "completed"
|
||||||
|
CANCELLED = "cancelled"
|
||||||
|
ERROR = "error"
|
||||||
|
SCHEDULED = "scheduled"
|
||||||
|
WAITING_FOR_SUBJOBS = "waiting_for_subjobs"
|
||||||
|
CONFIGURING = "configuring"
|
||||||
|
UNDEFINED = "undefined"
|
||||||
|
|
||||||
|
|
||||||
|
def string_to_status(string):
|
||||||
|
for stat in RenderStatus:
|
||||||
|
if stat.value == string:
|
||||||
|
return stat
|
||||||
|
return RenderStatus.UNDEFINED
|
||||||
@@ -59,6 +59,7 @@ class ZeroconfServer:
|
|||||||
@classmethod
|
@classmethod
|
||||||
def _browse_services(cls):
|
def _browse_services(cls):
|
||||||
browser = ServiceBrowser(cls.zeroconf, cls.service_type, [cls._on_service_discovered])
|
browser = ServiceBrowser(cls.zeroconf, cls.service_type, [cls._on_service_discovered])
|
||||||
|
browser.is_alive()
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _on_service_discovered(cls, zeroconf, service_type, name, state_change):
|
def _on_service_discovered(cls, zeroconf, service_type, name, state_change):
|
||||||
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 995 B After Width: | Height: | Size: 995 B |
|
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
@@ -3,9 +3,9 @@ class RenderWorkerFactory:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def supported_classes():
|
def supported_classes():
|
||||||
# to add support for any additional RenderWorker classes, import their classes and add to list here
|
# to add support for any additional RenderWorker classes, import their classes and add to list here
|
||||||
from .blender_worker import BlenderRenderWorker
|
from src.workers.blender_worker import BlenderRenderWorker
|
||||||
from .aerender_worker import AERenderWorker
|
from src.workers.aerender_worker import AERenderWorker
|
||||||
from .ffmpeg_worker import FFMPEGRenderWorker
|
from src.workers.ffmpeg_worker import FFMPEGRenderWorker
|
||||||
classes = [BlenderRenderWorker, AERenderWorker, FFMPEGRenderWorker]
|
classes = [BlenderRenderWorker, AERenderWorker, FFMPEGRenderWorker]
|
||||||
return classes
|
return classes
|
||||||
|
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import glob
|
import glob
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from .base_worker import *
|
from src.workers.base_worker import BaseRenderWorker, timecode_to_frames
|
||||||
from ..engines.aerender_engine import AERender
|
from src.workers.engines.aerender_engine import AERender
|
||||||
|
|
||||||
|
|
||||||
def aerender_path():
|
def aerender_path():
|
||||||
paths = glob.glob('/Applications/*After Effects*/aerender')
|
paths = glob.glob('/Applications/*After Effects*/aerender')
|
||||||
@@ -6,38 +6,19 @@ import os
|
|||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
import psutil
|
import psutil
|
||||||
from pubsub import pub
|
from pubsub import pub
|
||||||
from sqlalchemy import Column, Integer, String, DateTime, JSON
|
from sqlalchemy import Column, Integer, String, DateTime, JSON
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
from lib.utilities.misc_helper import get_time_elapsed
|
from src.utilities.misc_helper import get_time_elapsed
|
||||||
|
from src.utilities.status_utils import RenderStatus, string_to_status
|
||||||
|
|
||||||
logger = logging.getLogger()
|
logger = logging.getLogger()
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
||||||
|
|
||||||
class RenderStatus(Enum):
|
|
||||||
NOT_STARTED = "not_started"
|
|
||||||
RUNNING = "running"
|
|
||||||
COMPLETED = "completed"
|
|
||||||
CANCELLED = "cancelled"
|
|
||||||
ERROR = "error"
|
|
||||||
SCHEDULED = "scheduled"
|
|
||||||
WAITING_FOR_SUBJOBS = "waiting_for_subjobs"
|
|
||||||
CONFIGURING = "configuring"
|
|
||||||
UNDEFINED = "undefined"
|
|
||||||
|
|
||||||
|
|
||||||
def string_to_status(string):
|
|
||||||
for stat in RenderStatus:
|
|
||||||
if stat.value == string:
|
|
||||||
return stat
|
|
||||||
return RenderStatus.UNDEFINED
|
|
||||||
|
|
||||||
|
|
||||||
class BaseRenderWorker(Base):
|
class BaseRenderWorker(Base):
|
||||||
__tablename__ = 'render_workers'
|
__tablename__ = 'render_workers'
|
||||||
|
|
||||||
@@ -121,7 +102,7 @@ class BaseRenderWorker(Base):
|
|||||||
@status.setter
|
@status.setter
|
||||||
def status(self, new_status):
|
def status(self, new_status):
|
||||||
if self._status != new_status.value:
|
if self._status != new_status.value:
|
||||||
old_status = self._status
|
old_status = self.status
|
||||||
self._status = new_status.value
|
self._status = new_status.value
|
||||||
pub.sendMessage('status_change', job_id=self.id, old_status=old_status, new_status=new_status)
|
pub.sendMessage('status_change', job_id=self.id, old_status=old_status, new_status=new_status)
|
||||||
|
|
||||||
@@ -186,7 +167,8 @@ class BaseRenderWorker(Base):
|
|||||||
|
|
||||||
self.status = RenderStatus.RUNNING
|
self.status = RenderStatus.RUNNING
|
||||||
self.start_time = datetime.now()
|
self.start_time = datetime.now()
|
||||||
logger.info(f'Starting {self.engine.name()} {self.engine.version()} Render for {self.input_path} | Frame Count: {self.total_frames}')
|
logger.info(f'Starting {self.engine.name()} {self.engine.version()} Render for {self.input_path} | '
|
||||||
|
f'Frame Count: {self.total_frames}')
|
||||||
self.__thread.start()
|
self.__thread.start()
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
@@ -207,7 +189,7 @@ class BaseRenderWorker(Base):
|
|||||||
f.write(f"Running command: {' '.join(subprocess_cmds)}\n")
|
f.write(f"Running command: {' '.join(subprocess_cmds)}\n")
|
||||||
for c in io.TextIOWrapper(self.__process.stdout, encoding="utf-8"): # or another encoding
|
for c in io.TextIOWrapper(self.__process.stdout, encoding="utf-8"): # or another encoding
|
||||||
f.write(c)
|
f.write(c)
|
||||||
logger.debug(f"{self.engine.name()}Worker: {c.strip()}")
|
# logger.debug(f"{self.engine.name()}Worker: {c.strip()}")
|
||||||
self.last_output = c.strip()
|
self.last_output = c.strip()
|
||||||
self._parse_stdout(c.strip())
|
self._parse_stdout(c.strip())
|
||||||
f.write('\n')
|
f.write('\n')
|
||||||
@@ -220,7 +202,7 @@ class BaseRenderWorker(Base):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if return_code:
|
if return_code:
|
||||||
message = f"{self.engine.name()} render failed with return_code {return_code} after {self.time_elapsed()}"
|
message = f"{self.engine.name()} render failed with code {return_code} after {self.time_elapsed()}"
|
||||||
logger.error(message)
|
logger.error(message)
|
||||||
f.write(message)
|
f.write(message)
|
||||||
self.status = RenderStatus.ERROR
|
self.status = RenderStatus.ERROR
|
||||||
@@ -233,7 +215,7 @@ class BaseRenderWorker(Base):
|
|||||||
f.write(message)
|
f.write(message)
|
||||||
|
|
||||||
if self.children:
|
if self.children:
|
||||||
from lib.distributed_job_manager import DistributedJobManager
|
from src.distributed_job_manager import DistributedJobManager
|
||||||
DistributedJobManager.wait_for_subjobs(local_job=self)
|
DistributedJobManager.wait_for_subjobs(local_job=self)
|
||||||
|
|
||||||
# Post Render Work
|
# Post Render Work
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
import re
|
import re
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
|
||||||
from lib.engines.blender_engine import Blender
|
from src.workers.engines.blender_engine import Blender
|
||||||
from lib.utilities.ffmpeg_helper import image_sequence_to_video
|
from src.utilities.ffmpeg_helper import image_sequence_to_video
|
||||||
from lib.workers.base_worker import *
|
from src.workers.base_worker import *
|
||||||
|
|
||||||
|
|
||||||
class BlenderRenderWorker(BaseRenderWorker):
|
class BlenderRenderWorker(BaseRenderWorker):
|
||||||
@@ -69,17 +69,6 @@ class BlenderRenderWorker(BaseRenderWorker):
|
|||||||
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])
|
self.__frame_percent_complete = int(samples.split('/')[0]) / int(samples.split('/')[-1])
|
||||||
|
|
||||||
# Calculate rough percent based on cycles
|
|
||||||
# EEVEE
|
|
||||||
# 10-Apr-22 22:42:06 - RENDERER: Fra:0 Mem:857.99M (Peak 928.55M) | Time:00:03.96 | Rendering 1 / 65 samples
|
|
||||||
# 10-Apr-22 22:42:10 - RENDERER: Fra:0 Mem:827.09M (Peak 928.55M) | Time:00:07.92 | Rendering 26 / 64 samples
|
|
||||||
# 10-Apr-22 22:42:10 - RENDERER: Fra:0 Mem:827.09M (Peak 928.55M) | Time:00:08.17 | Rendering 51 / 64 samples
|
|
||||||
# 10-Apr-22 22:42:10 - RENDERER: Fra:0 Mem:827.09M (Peak 928.55M) | Time:00:08.31 | Rendering 64 / 64 samples
|
|
||||||
|
|
||||||
# CYCLES
|
|
||||||
# 10-Apr-22 22:43:22 - RENDERER: Fra:0 Mem:836.30M (Peak 1726.13M) | Time:00:01.56 | Remaining:00:30.65 | Mem:588.68M, Peak:588.68M | Scene, View Layer | Sample 1/150
|
|
||||||
# 10-Apr-22 22:43:43 - RENDERER: Fra:0 Mem:836.30M (Peak 1726.13M) | Time:00:22.01 | Remaining:00:03.36 | Mem:588.68M, Peak:588.68M | Scene, View Layer | Sample 129/150
|
|
||||||
|
|
||||||
if int(stats['frame']) > self.current_frame:
|
if int(stats['frame']) > self.current_frame:
|
||||||
self.current_frame = int(stats['frame'])
|
self.current_frame = int(stats['frame'])
|
||||||
logger.debug(
|
logger.debug(
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import re
|
import re
|
||||||
from .base_worker import *
|
import subprocess
|
||||||
from ..engines.ffmpeg_engine import FFMPEG
|
|
||||||
|
from src.workers.base_worker import BaseRenderWorker
|
||||||
|
from src.workers.engines.ffmpeg_engine import FFMPEG
|
||||||
|
|
||||||
|
|
||||||
class FFMPEGRenderWorker(BaseRenderWorker):
|
class FFMPEGRenderWorker(BaseRenderWorker):
|
||||||
@@ -48,18 +50,3 @@ class FFMPEGRenderWorker(BaseRenderWorker):
|
|||||||
time_elapsed = stats['time_elapsed']
|
time_elapsed = stats['time_elapsed']
|
||||||
elif "not found" in line:
|
elif "not found" in line:
|
||||||
self.log_error(line)
|
self.log_error(line)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
print(FFMPEG.full_report())
|
|
||||||
|
|
||||||
# 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'
|
|
||||||
#
|
|
||||||
# r = FFMPEGRenderWorker(test_movie, '/Users/brettwilliams/Desktop/test-ffmpeg.mp4', args=['-c:v', 'libx265', '-vtag', 'hvc1'])
|
|
||||||
# # r = FFMPEGRenderer(test_movie, '/Users/brettwilliams/Desktop/dark_knight_rises-output.mp4')
|
|
||||||
# r.start()
|
|
||||||
# while r.is_running():
|
|
||||||
# time.sleep(1)
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from lib.client.dashboard_window import start_client
|
from src.client.dashboard_window import start_client
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
start_client()
|
start_client()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
from lib.server.api_server import start_server
|
from src.api_server import start_server
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
start_server()
|
start_server()
|
||||||
|
|||||||