Initial Commit

This commit is contained in:
twotalesanimation
2026-07-04 15:54:19 +02:00
commit 1a2ece6f12
17 changed files with 1844 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
"""
nuke_runner.py — Launch Nuke in terminal mode and stream its output.
Nuke is started ONCE with:
Nuke.exe -t process.py jobs.json
stdout/stderr are merged and forwarded line-by-line via Qt signals so the
GUI log window updates in real time. Progress is inferred from the
structured output lines that process.py prints.
"""
from __future__ import annotations
import re
import subprocess
from PySide6.QtCore import QThread, Signal
# Lines emitted by process.py that carry progress information:
# [3/10] Rendering: UNG_101_012_010_BG01_TT_v001
# [3/10] Done: UNG_101_012_010_BG01_TT_v001
_RENDERING_RE = re.compile(r"^\[(\d+)/(\d+)\]\s+Rendering:\s+(.+)$")
_DONE_RE = re.compile(r"^\[(\d+)/(\d+)\]\s+Done:\s+(.+)$")
class NukeRunner(QThread):
"""Runs a single Nuke process and emits its output as Qt signals.
Signals
-------
log_message(str)
Each non-empty output line from Nuke.
progress_update(int, int)
(jobs_done, jobs_total) whenever a job completes.
job_started(str)
basename of the job Nuke has just started rendering.
job_done(str)
basename of the job Nuke has just finished.
finished_signal(bool)
True if Nuke exited with code 0, False otherwise.
"""
log_message: Signal = Signal(str)
progress_update: Signal = Signal(int, int)
job_started: Signal = Signal(str)
job_done: Signal = Signal(str)
finished_signal: Signal = Signal(bool)
def __init__(
self,
nuke_exe: str,
process_script: str,
jobs_file: str,
total: int = 0,
parent=None,
) -> None:
super().__init__(parent)
self.nuke_exe = nuke_exe
self.process_script = process_script
self.jobs_file = jobs_file
self.total = total
def set_total(self, total: int) -> None:
self.total = total
# ── Thread entry point ────────────────────────────────────────────
def run(self) -> None:
cmd = [self.nuke_exe, "--indie", "-t", self.process_script, self.jobs_file]
self.log_message.emit("Launching: " + " ".join(cmd))
try:
proc = subprocess.Popen(
cmd,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
bufsize=1,
)
except FileNotFoundError:
self.log_message.emit(
f"ERROR: Nuke executable not found: {self.nuke_exe}"
)
self.finished_signal.emit(False)
return
except OSError as exc:
self.log_message.emit(f"ERROR: Could not launch Nuke: {exc}")
self.finished_signal.emit(False)
return
for raw_line in proc.stdout:
line = raw_line.rstrip()
if not line:
continue
self.log_message.emit(line)
m = _DONE_RE.match(line)
if m:
current, total, basename = int(m.group(1)), int(m.group(2)), m.group(3)
self.total = total
self.progress_update.emit(current, total)
self.job_done.emit(basename.strip())
continue
m = _RENDERING_RE.match(line)
if m:
basename = m.group(3)
self.job_started.emit(basename.strip())
proc.wait()
self.finished_signal.emit(proc.returncode == 0)