Major file reorganization
@@ -17,7 +17,7 @@ from rich.table import Table
|
||||
from rich.text import Text
|
||||
from rich.tree import Tree
|
||||
|
||||
from utilities.render_worker import RenderStatus, string_to_status
|
||||
from lib.render_workers.render_worker import RenderStatus, string_to_status
|
||||
from start_server import start_server
|
||||
|
||||
"""
|
||||
|
||||
@@ -6,7 +6,7 @@ import os
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
from utilities.render_worker import RenderStatus, RenderWorkerFactory
|
||||
from .render_workers.render_worker import RenderStatus, RenderWorkerFactory
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ from datetime import datetime
|
||||
import psutil
|
||||
import requests
|
||||
|
||||
from lib.render_job import RenderJob
|
||||
from utilities.render_worker import RenderStatus
|
||||
from .render_job import RenderJob
|
||||
from .render_workers.render_worker import RenderStatus
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import json
|
||||
import re
|
||||
import time
|
||||
|
||||
from utilities.render_worker import *
|
||||
from .render_worker import *
|
||||
|
||||
|
||||
def aerender_path():
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import re
|
||||
from utilities.render_worker import *
|
||||
from .render_worker import *
|
||||
|
||||
|
||||
class BlenderRenderWorker(BaseRenderWorker):
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import re
|
||||
import time
|
||||
from utilities.render_worker import *
|
||||
from .render_worker import *
|
||||
|
||||
|
||||
class FFMPEGRenderWorker(BaseRenderWorker):
|
||||
@@ -218,9 +218,9 @@ class RenderWorkerFactory:
|
||||
@staticmethod
|
||||
def supported_classes():
|
||||
# to add support for any additional RenderWorker classes, import their classes and add to list here
|
||||
from utilities.blender_worker import BlenderRenderWorker
|
||||
from utilities.aerender_worker import AERenderWorker
|
||||
from utilities.ffmpeg_worker import FFMPEGRenderWorker
|
||||
from .blender_worker import BlenderRenderWorker
|
||||
from .aerender_worker import AERenderWorker
|
||||
from .ffmpeg_worker import FFMPEGRenderWorker
|
||||
classes = [BlenderRenderWorker, AERenderWorker, FFMPEGRenderWorker]
|
||||
return classes
|
||||
|
||||
0
lib/server/__init__.py
Normal file
@@ -4,10 +4,13 @@ import logging
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
import json2html
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
from zipfile import ZipFile
|
||||
|
||||
import json2html
|
||||
import requests
|
||||
import yaml
|
||||
from flask import Flask, request, render_template, send_file, after_this_request, Response, redirect, url_for, abort
|
||||
@@ -15,11 +18,11 @@ from werkzeug.utils import secure_filename
|
||||
|
||||
from lib.render_job import RenderJob
|
||||
from lib.render_queue import RenderQueue, JobNotFoundError
|
||||
from lib.server_helper import post_job_to_server, generate_thumbnail_for_job
|
||||
from utilities.render_worker import RenderWorkerFactory, string_to_status, RenderStatus
|
||||
from lib.render_workers.render_worker import RenderWorkerFactory, string_to_status, RenderStatus
|
||||
from lib.utilities.server_helper import post_job_to_server, generate_thumbnail_for_job
|
||||
|
||||
logger = logging.getLogger()
|
||||
server = Flask(__name__, template_folder='../templates')
|
||||
server = Flask(__name__, template_folder='templates', static_folder='static')
|
||||
|
||||
categories = [RenderStatus.RUNNING, RenderStatus.ERROR, RenderStatus.NOT_STARTED, RenderStatus.SCHEDULED,
|
||||
RenderStatus.COMPLETED, RenderStatus.CANCELLED]
|
||||
@@ -43,11 +46,12 @@ def sorted_jobs(all_jobs, sort_by_date=True):
|
||||
@server.route('/index')
|
||||
def index():
|
||||
|
||||
with open('utilities/presets.yaml') as f:
|
||||
with open('config/presets.yaml') as f:
|
||||
presets = yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
return render_template('index.html', all_jobs=sorted_jobs(RenderQueue.job_queue), hostname=RenderQueue.host_name,
|
||||
renderer_info=renderer_info(), render_clients=RenderQueue.render_clients, preset_list=presets)
|
||||
return render_template('index.html', all_jobs=sorted_jobs(RenderQueue.job_queue),
|
||||
hostname=RenderQueue.host_name, renderer_info=renderer_info(),
|
||||
render_clients=RenderQueue.render_clients, preset_list=presets)
|
||||
|
||||
|
||||
@server.route('/ui/job/<job_id>/full_details')
|
||||
@@ -133,11 +137,7 @@ def get_job_logs(job_id):
|
||||
|
||||
@server.get('/api/job/<job_id>/file_list')
|
||||
def get_file_list(job_id):
|
||||
found_job = RenderQueue.job_with_id(job_id)
|
||||
if found_job:
|
||||
return '\n'.join(found_job.file_list())
|
||||
else:
|
||||
return f'Cannot find job with ID {job_id}', 400
|
||||
return RenderQueue.job_with_id(job_id)
|
||||
|
||||
|
||||
@server.route('/api/job/<job_id>/download_all')
|
||||
@@ -439,3 +439,47 @@ def renderer_info():
|
||||
def upload_file_page():
|
||||
return render_template('upload.html', render_clients=RenderQueue.render_clients,
|
||||
supported_renderers=RenderWorkerFactory.supported_renderers())
|
||||
|
||||
|
||||
def start_server(background_thread=False):
|
||||
def eval_loop(delay_sec=1):
|
||||
while True:
|
||||
RenderQueue.evaluate_queue()
|
||||
time.sleep(delay_sec)
|
||||
|
||||
with open('config/config.yaml') as f:
|
||||
config = yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(module)s: %(message)s', datefmt='%d-%b-%y %H:%M:%S',
|
||||
level=config.get('server_log_level', 'INFO').upper())
|
||||
|
||||
server.config['UPLOAD_FOLDER'] = os.path.expanduser(config['upload_folder'])
|
||||
server.config['THUMBS_FOLDER'] = os.path.join(os.path.expanduser(config['upload_folder']), 'thumbs')
|
||||
server.config['MAX_CONTENT_PATH'] = config['max_content_path']
|
||||
|
||||
# Get hostname and render clients
|
||||
RenderQueue.host_name = socket.gethostname()
|
||||
server.config['HOSTNAME'] = RenderQueue.host_name
|
||||
if not RenderQueue.render_clients:
|
||||
RenderQueue.render_clients = [RenderQueue.host_name]
|
||||
|
||||
# disable most Flask logging
|
||||
flask_log = logging.getLogger('werkzeug')
|
||||
flask_log.setLevel(config.get('flask_log_level', 'ERROR').upper())
|
||||
|
||||
# Set up the RenderQueue object
|
||||
RenderQueue.load_state()
|
||||
|
||||
thread = threading.Thread(target=eval_loop, kwargs={'delay_sec': config.get('queue_eval_seconds', 1)}, daemon=True)
|
||||
thread.start()
|
||||
|
||||
logging.info(f"Starting Zordon Render Server - Hostname: '{RenderQueue.host_name}'")
|
||||
|
||||
if background_thread:
|
||||
server_thread = threading.Thread(
|
||||
target=lambda: server.run(host='0.0.0.0', port=RenderQueue.port, debug=False, use_reloader=False))
|
||||
server_thread.start()
|
||||
server_thread.join()
|
||||
else:
|
||||
server.run(host='0.0.0.0', port=RenderQueue.port, debug=config.get('flask_debug_enable', False),
|
||||
use_reloader=False, threaded=True)
|
||||
|
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 |
@@ -50,19 +50,10 @@ columns: [
|
||||
</div>
|
||||
`),
|
||||
sort: false
|
||||
}
|
||||
},
|
||||
{ id: 'owner', name: 'Owner' }
|
||||
],
|
||||
style: {
|
||||
table: {
|
||||
'white-space': 'nowrap'
|
||||
},
|
||||
th: {
|
||||
'vertical-align': 'middle',
|
||||
},
|
||||
td: {
|
||||
'vertical-align': 'middle',
|
||||
}
|
||||
},
|
||||
autoWidth: true,
|
||||
server: {
|
||||
url: '/api/jobs',
|
||||
then: results => results,
|
||||
@@ -30,7 +30,7 @@
|
||||
});
|
||||
}
|
||||
if (startingStatus == 'running'){
|
||||
var renderingTimer = setInterval(update_job, 2000);
|
||||
var renderingTimer = setInterval(update_job, 1000);
|
||||
};
|
||||
</script>
|
||||
</div>
|
||||
0
lib/utilities/__init__.py
Normal file
@@ -1,4 +1,5 @@
|
||||
import ffmpeg
|
||||
import subprocess
|
||||
import ffmpeg # todo: remove all references to ffmpeg library and instead use direct subprocesses
|
||||
|
||||
|
||||
def file_info(path):
|
||||
@@ -9,6 +10,11 @@ def file_info(path):
|
||||
return None
|
||||
|
||||
|
||||
def image_sequence_to_video(source_glob_pattern, output_path, framerate="24", encoder="libx264"):
|
||||
subprocess.run(['ffmpeg', "-y", "-framerate", framerate, "-pattern_type", "glob", "-i", f"{source_glob_pattern}",
|
||||
"-c:v", encoder, output_path])
|
||||
|
||||
|
||||
def save_first_frame(source_path, dest_path, max_width=1280, run_async=False):
|
||||
stream = ffmpeg.input(source_path)
|
||||
stream = ffmpeg.output(stream, dest_path, **{'vf': f'format=yuv420p,scale={max_width}:trunc(ow/a/2)*2',
|
||||
@@ -1,10 +1,12 @@
|
||||
import subprocess
|
||||
import requests
|
||||
import os
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import threading
|
||||
from utilities.render_worker import RenderStatus
|
||||
from utilities.ffmpeg_presets import generate_thumbnail, save_first_frame
|
||||
|
||||
import requests
|
||||
|
||||
from .ffmpeg_helper import generate_thumbnail, save_first_frame
|
||||
from lib.render_workers.render_worker import RenderStatus
|
||||
|
||||
|
||||
def post_job_to_server(input_path, job_list, client, server_port=8080):
|
||||
@@ -6,17 +6,16 @@ import pathlib
|
||||
import socket
|
||||
from tkinter import *
|
||||
from tkinter import filedialog, messagebox
|
||||
from tkinter.ttk import Frame, Label, Entry, Combobox
|
||||
from tkinter.simpledialog import askstring
|
||||
from tkinter.ttk import Frame, Label, Entry, Combobox
|
||||
|
||||
import psutil
|
||||
import requests
|
||||
|
||||
from lib.job_server import post_job_to_server
|
||||
from lib.utilities.server_helper import post_job_to_server
|
||||
|
||||
logger = logging.getLogger()
|
||||
|
||||
prefs_name = '.scheduler_prefs'
|
||||
prefs_name = 'config/.scheduler_prefs'
|
||||
label_width = 7
|
||||
header_padding = 6
|
||||
server_setup_timeout = 5
|
||||
@@ -244,7 +243,7 @@ class ScheduleJob(Frame):
|
||||
|
||||
# get file stats
|
||||
if self.chosen_file:
|
||||
from utilities.blender_worker import get_scene_info
|
||||
from lib.render_workers.blender_worker import get_scene_info
|
||||
scene_data = get_scene_info(self.chosen_file)
|
||||
|
||||
# blender settings
|
||||
@@ -317,7 +316,7 @@ class ScheduleJob(Frame):
|
||||
temp_files = []
|
||||
if renderer == 'blender':
|
||||
if self.blender_pack_textures.get():
|
||||
from utilities.blender_worker import pack_blender_files
|
||||
from lib.render_workers.blender_worker import pack_blender_files
|
||||
new_path = pack_blender_files(path=input_path)
|
||||
if new_path:
|
||||
logger.info(f'Packed Blender file successfully: {new_path}')
|
||||
|
||||
@@ -1,57 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import logging
|
||||
import os
|
||||
import socket
|
||||
import threading
|
||||
import time
|
||||
import yaml
|
||||
from lib.job_server import server
|
||||
from lib.render_queue import RenderQueue
|
||||
|
||||
|
||||
def start_server(background_thread=False):
|
||||
def eval_loop(delay_sec=1):
|
||||
while True:
|
||||
RenderQueue.evaluate_queue()
|
||||
time.sleep(delay_sec)
|
||||
|
||||
with open('config.yaml') as f:
|
||||
config = yaml.load(f, Loader=yaml.FullLoader)
|
||||
|
||||
logging.basicConfig(format='%(asctime)s: %(levelname)s: %(module)s: %(message)s', datefmt='%d-%b-%y %H:%M:%S',
|
||||
level=config.get('server_log_level', 'INFO').upper())
|
||||
|
||||
server.config['UPLOAD_FOLDER'] = os.path.expanduser(config['upload_folder'])
|
||||
server.config['THUMBS_FOLDER'] = os.path.join(os.path.expanduser(config['upload_folder']), 'thumbs')
|
||||
server.config['MAX_CONTENT_PATH'] = config['max_content_path']
|
||||
|
||||
# Get hostname and render clients
|
||||
RenderQueue.host_name = socket.gethostname()
|
||||
server.config['HOSTNAME'] = RenderQueue.host_name
|
||||
if not RenderQueue.render_clients:
|
||||
RenderQueue.render_clients = [RenderQueue.host_name]
|
||||
|
||||
# disable most Flask logging
|
||||
flask_log = logging.getLogger('werkzeug')
|
||||
flask_log.setLevel(config.get('flask_log_level', 'ERROR').upper())
|
||||
|
||||
# Set up the RenderQueue object
|
||||
RenderQueue.load_state()
|
||||
|
||||
thread = threading.Thread(target=eval_loop, kwargs={'delay_sec': config.get('queue_eval_seconds', 1)}, daemon=True)
|
||||
thread.start()
|
||||
|
||||
logging.info(f"Starting Zordon Render Server - Hostname: '{RenderQueue.host_name}'")
|
||||
|
||||
if background_thread:
|
||||
server_thread = threading.Thread(
|
||||
target=lambda: server.run(host='0.0.0.0', port=RenderQueue.port, debug=False, use_reloader=False))
|
||||
server_thread.start()
|
||||
server_thread.join()
|
||||
else:
|
||||
server.run(host='0.0.0.0', port=RenderQueue.port, debug=config.get('flask_debug_enable', False),
|
||||
use_reloader=True, threaded=True)
|
||||
|
||||
from lib.server.job_server import start_server
|
||||
|
||||
if __name__ == '__main__':
|
||||
start_server()
|
||||
|
||||