diff --git a/deploy/worker-windows/RippyWorkerSetup.exe b/deploy/worker-windows/RippyWorkerSetup.exe index 609c0ae..7d35f27 100644 Binary files a/deploy/worker-windows/RippyWorkerSetup.exe and b/deploy/worker-windows/RippyWorkerSetup.exe differ diff --git a/docker/worker/gui.py b/docker/worker/gui.py index 91b549e..dc3fa74 100644 --- a/docker/worker/gui.py +++ b/docker/worker/gui.py @@ -6,6 +6,7 @@ import time import urllib.request import json import webbrowser +import re import flet as ft # Tray-Icon: pystray + PIL fuer das Icon-Bild @@ -313,12 +314,35 @@ def main(page: ft.Page): height=120, ) + # Live Log Regex and Layout + # [2026-07-26 20:34:00,093: INFO/MainProcess] message... + LOG_REGEX = re.compile(r"^\[.*? (\d{2}:\d{2}:\d{2}),.*?: (INFO|WARNING|ERROR|SUCCESS).*?\] (.*)") + log_view = ft.ListView(expand=1, spacing=2, auto_scroll=True) queue_view = ft.ListView(height=120, spacing=4, auto_scroll=False) def add_log(zeile): - # Zeilen anfügen und limitieren - log_view.controls.append(ft.Text(zeile.strip(), color=c_muted, size=12, font_family="Consolas")) + z = zeile.strip() + if not z: return + + match = LOG_REGEX.match(z) + if match: + zeit, level, msg = match.groups() + color = c_text + if level == "INFO": color = "#38bdf8" # sky-400 + elif level == "WARNING": color = "#fbbf24" # amber-400 + elif level == "ERROR": color = "#f87171" # red-400 + elif level == "SUCCESS": color = "#34d399" # emerald-400 + + row = ft.Row([ + ft.Text(zeit, color=c_muted, size=12, font_family="Consolas"), + ft.Text(f"[{level}]", color=color, size=12, font_family="Consolas", weight=ft.FontWeight.BOLD), + ft.Text(msg, color=c_text, size=12, font_family="Consolas", expand=True) + ], spacing=10, vertical_alignment=ft.CrossAxisAlignment.START) + log_view.controls.append(row) + else: + log_view.controls.append(ft.Text(z, color=c_muted, size=12, font_family="Consolas")) + if len(log_view.controls) > 200: log_view.controls.pop(0) try: @@ -327,23 +351,20 @@ def main(page: ft.Page): pass def toggle_worker(e): - if worker_laeuft(): - worker_stoppen() - btn_toggle.text = "Worker Starten" - btn_toggle.icon = ft.icons.PLAY_ARROW - btn_toggle.bgcolor = c_success - else: + if not worker_laeuft(): worker_starten(add_log) - btn_toggle.text = "Worker Stoppen" - btn_toggle.icon = ft.icons.STOP - btn_toggle.bgcolor = c_danger + btn_toggle.text = "Worker läuft" + btn_toggle.icon = ft.icons.CHECK + btn_toggle.bgcolor = "#1e293b" + btn_toggle.disabled = True page.update() btn_toggle = ft.ElevatedButton( - text="Worker Stoppen" if worker_laeuft() else "Worker Starten", - icon=ft.icons.STOP if worker_laeuft() else ft.icons.PLAY_ARROW, - bgcolor=c_danger if worker_laeuft() else c_success, + text="Worker läuft" if worker_laeuft() else "Worker Starten", + icon=ft.icons.CHECK if worker_laeuft() else ft.icons.PLAY_ARROW, + bgcolor="#1e293b" if worker_laeuft() else c_success, color="white", + disabled=worker_laeuft(), on_click=toggle_worker ) @@ -400,12 +421,15 @@ def main(page: ft.Page): alignment=ft.MainAxisAlignment.SPACE_BETWEEN ) + active_poster = ft.Image(src="", visible=False, width=64, height=96, border_radius=8, fit=ft.ImageFit.COVER) + dashboard_card = ft.Container( content=ft.Column([ status_text, machine_info, ft.Container(height=5), ft.Row([ + active_poster, progress_stack, ft.Column([job_title, eta_text], alignment=ft.MainAxisAlignment.CENTER, spacing=10) ], alignment=ft.MainAxisAlignment.START, spacing=30), @@ -471,7 +495,16 @@ def main(page: ft.Page): queue_view.controls.append(ft.Text("Keine Aufgaben in Rippy", color=c_muted, font_family="Consolas", size=13)) else: for j in jobs[:8]: - queue_view.controls.append(ft.Text(" " + job_text(j), color=c_muted, font_family="Consolas", size=13)) + poster = None + if j.get("meta") and j["meta"].get("poster_path"): + p = j["meta"]["poster_path"] + poster = p if p.startswith("http") else f"https://image.tmdb.org/t/p/w342{p}" + + row_items = [] + if poster: + row_items.append(ft.Image(src=poster, width=40, height=60, border_radius=5, fit=ft.ImageFit.COVER)) + row_items.append(ft.Text(job_text(j), color=c_muted, font_family="Consolas", size=13, expand=True)) + queue_view.controls.append(ft.Row(row_items, alignment=ft.MainAxisAlignment.START, spacing=15)) # Update status if not worker_laeuft(): @@ -481,11 +514,17 @@ def main(page: ft.Page): progress_percentage.value = "0%" job_title.value = "Nichts in Arbeit" eta_text.value = "Bereit" + active_poster.visible = False + btn_toggle.disabled = False + btn_toggle.text = "Worker Starten" + btn_toggle.icon = ft.icons.PLAY_ARROW + btn_toggle.bgcolor = c_success elif not online: status_text.value = "Nicht mit Rippy verbunden (offline)" status_text.color = c_warning progress_ring.value = 0 progress_percentage.value = "0%" + active_poster.visible = False elif job: status_text.value = "Aktiv: Komprimiert" status_text.color = c_success @@ -496,13 +535,31 @@ def main(page: ft.Page): job_title.value = titel eta = job.get("eta_text") or "Restzeit wird berechnet..." eta_text.value = f"Verbleibend: {eta}" + + # Update Active Poster + poster = None + if job.get("meta") and job["meta"].get("poster_path"): + p = job["meta"]["poster_path"] + poster = p if p.startswith("http") else f"https://image.tmdb.org/t/p/w342{p}" + + if poster: + active_poster.src = poster + active_poster.visible = True + else: + active_poster.visible = False else: status_text.value = "Verbunden & Bereit" status_text.color = c_accent progress_ring.value = 0 progress_percentage.value = "0%" - job_title.value = "Warte auf Aufträge..." + job_title.value = "Warte auf Encoder-Aufträge..." eta_text.value = "Nichts in Arbeit" + active_poster.visible = False + + btn_toggle.disabled = True + btn_toggle.text = "Worker läuft" + btn_toggle.icon = ft.icons.CHECK + btn_toggle.bgcolor = "#1e293b" page.update() except Exception as e: