"""Concise console progress; does not depend on Unreal or its log format.""" import json from pathlib import Path import time class ProgressDisplay: LABELS = { "starting": "Uruchamianie UE...", "preparing": "Przygotowywanie sceny i sekwencji...", "preparing_render": "Przygotowywanie renderu...", "rendering": "Renderowanie...", "encoding": "Render zakonczony. Skladanie MP4...", "closing": "Zamykanie UE...", } def __init__(self, events, clock=time.monotonic, emit=print): self.events = Path(events) self.clock, self.emit = clock, emit self.started = self.last_print = clock() self.position = 0 self.pending = b"" self.state = "starting" self.details = {} self.last_count = -1 self.show(self.LABELS[self.state]) def show(self, message): seconds = int(self.clock() - self.started) self.emit(f"[{seconds // 60:02d}:{seconds % 60:02d}] {message}", flush=True) self.last_print = self.clock() def update(self): try: with self.events.open("rb") as stream: stream.seek(self.position) self.pending += stream.read() self.position = stream.tell() except FileNotFoundError: pass while b"\n" in self.pending: line, self.pending = self.pending.split(b"\n", 1) try: event = json.loads(line) except (ValueError, UnicodeError): continue state = event.get("state") if state in self.LABELS: self.state, self.details = state, event self.last_count = -1 self.show(self.LABELS[state]) elapsed = self.clock() - self.last_print if self.state == "rendering" and elapsed >= 2: output = self.details.get("output") total = self.details.get("frames") if output and total: count = len(list((Path(output) / "frames").glob("frame_*.png"))) if count != self.last_count and count > 0: self.last_count = count self.show(f"Renderowanie: {count}/{total} klatek zapisanych.") return if elapsed >= 10: self.show(self.LABELS[self.state] + " Nadal pracuje.")