From 1645de4cadbe2380d6dbb318fb2cd9c40e782df9 Mon Sep 17 00:00:00 2001 From: viewit Date: Wed, 27 May 2026 23:38:05 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20Review-Fixes=20f=C3=BCr=20PR=20#32=20(Co?= =?UTF-8?q?ntent-Disposition=20+=20DE-=C3=9Cbersetzungen)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nach Squash-Merge von #32 die Reviews-Anpassungen nachgereicht, die im Dev-Repo (viewit/KX-Bridge@7c834bc) bereits enthalten waren: - Content-Disposition mit RFC5987 filename*=UTF-8 + ASCII-Fallback - DE-Strings im Verify-Dialog übersetzt (msg/confirm/abort) --- config.ini.example | 62 +++++++++++++++++++++++++++++++++-- kobrax_moonraker_bridge.py | 11 +++++-- web/themes/default/app.js | 6 ++-- web/themes/default/index.html | 8 ++--- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/config.ini.example b/config.ini.example index bf338b4..f0fa3b3 100644 --- a/config.ini.example +++ b/config.ini.example @@ -2,8 +2,10 @@ # Kopiere diese Datei nach config.ini und trage deine Werte ein: # cp config.ini.example config.ini # -# Credentials mit extract_credentials.exe (Windows) oder -# extract_credentials (Linux) aus dem laufenden AnycubicSlicerNext auslesen. +# Credentials automatisch eintragen: +# python3 tools/fetch_credentials.py --ip 192.168.x.x --write-config +# Alternativ (Windows, ohne Drucker-IP bekannt): +# extract_credentials.exe --write-env (liest aus laufendem AnycubicSlicerNext) [connection] # IP-Adresse des Druckers im lokalen Netzwerk @@ -29,9 +31,65 @@ default_ams_slot = auto # Auto-Leveling vor jedem Druck (1 = an, 0 = aus) auto_leveling = 1 +# Kamera-Stream bei Druckstart automatisch einschalten (1 = an, 0 = aus) +camera_on_print = 0 + # Warnung vor Druck von Web-Uploads (1 = an, 0 = aus) web_upload_warning = 1 [bridge] # Poll-Intervall in Sekunden poll_interval = 3 + +# ─── Multi-Printer (optional) ────────────────────────────────────────────────── +# Mehrere Drucker können als [printer_1], [printer_2], … definiert werden. +# Jede Bridge-Instanz verbindet sich mit einem Drucker (je eigener Port). +# bridge_url zeigt auf die jeweilige Bridge-Instanz (für den /kx/printers-Endpunkt). +# Die [connection]-Sektion wird weiterhin als Fallback für diese Instanz verwendet. +# +# Beispiel: +# [printer_1] +# name = Kobra X Links +# bridge_url = http://192.168.178.95:7125 +# printer_ip = 192.168.178.95 +# mqtt_port = 9883 +# username = userXXXXXXXXXX +# password = XXXXXXXXXXXXXXX +# device_id = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +# mode_id = 20030 +# +# [printer_2] +# name = Kobra X Rechts +# bridge_url = http://192.168.178.96:7125 +# printer_ip = 192.168.178.96 +# mqtt_port = 9883 +# username = userYYYYYYYYYY +# password = YYYYYYYYYYYYYYY +# device_id = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy +# mode_id = 20030 + +[ace_dry_presets] +# Vordefinierte Dry-Set Presets (Temp in °C, Dauer in Sekunden) +pla_temp = 45 +pla_duration_sec = 14400 +pla_plus_temp = 45 +pla_plus_duration_sec = 14400 +petg_temp = 50 +petg_duration_sec = 14400 +tpu_temp = 55 +tpu_duration_sec = 14400 +abs_asa_temp = 45 +abs_asa_duration_sec = 28800 +pa_pc_temp = 55 +pa_pc_duration_sec = 43200 + +# Custom Presets (Name + Temp + Dauer) +custom_1_name = Custom 1 +custom_1_temp = 45 +custom_1_duration_sec = 14400 +custom_2_name = Custom 2 +custom_2_temp = 45 +custom_2_duration_sec = 14400 +custom_3_name = Custom 3 +custom_3_temp = 45 +custom_3_duration_sec = 14400 diff --git a/kobrax_moonraker_bridge.py b/kobrax_moonraker_bridge.py index 43dd03a..369be86 100644 --- a/kobrax_moonraker_bridge.py +++ b/kobrax_moonraker_bridge.py @@ -45,6 +45,7 @@ import tempfile import time import threading import html +from urllib.parse import quote # Bei PyInstaller-Binary liegt alles neben sys.executable, sonst neben __file__ _BASE = os.path.dirname(sys.executable) if getattr(sys, "frozen", False) else os.path.dirname(os.path.abspath(__file__)) @@ -1523,9 +1524,13 @@ class KobraXBridge: if not path or not os.path.isfile(path): return self._json_cors({"error": "not found"}, status=404) filename = os.path.basename(f.get("filename") or path) - return web.FileResponse(path, headers={ - "Content-Disposition": f'attachment; filename="{filename}"' - }) + # RFC 5987: filename* mit URL-encoding für Sonderzeichen/UTF-8, + # plus ASCII-fallback (alle " und \ aus filename strippen für den + # quoted-string-Part). + ascii_fallback = filename.encode("ascii", "replace").decode("ascii").replace('"', "").replace("\\", "") + encoded = quote(filename, safe="") + disposition = f'attachment; filename="{ascii_fallback}"; filename*=UTF-8\'\'{encoded}' + return web.FileResponse(path, headers={"Content-Disposition": disposition}) async def handle_kx_file_verify(self, request): file_id = request.match_info["file_id"] diff --git a/web/themes/default/app.js b/web/themes/default/app.js index 25848f1..611e22c 100644 --- a/web/themes/default/app.js +++ b/web/themes/default/app.js @@ -150,9 +150,9 @@ var LANG_DE={ store_delete_confirm:'Datei löschen?', store_print_confirm:'Datei drucken?', store_web_verify_title:'Datei verifizieren', - store_web_verify_msg:'Please verify this file was made for Anycubic Kobra X.', - store_web_verify_confirm:'Confirm', - store_web_verify_abort:'Abort', + store_web_verify_msg:'Bitte bestätige, dass diese Datei für den Anycubic Kobra X erstellt wurde.', + store_web_verify_confirm:'Bestätigen', + store_web_verify_abort:'Abbrechen', store_no_results:'Keine Dateien gefunden.', store_never:'noch nicht gedruckt', sf_all:'Alle',sf_ok:'✓ Erfolgreich',sf_err:'✗ Fehler',sf_new:'Neu', diff --git a/web/themes/default/index.html b/web/themes/default/index.html index 88ec038..3aad280 100644 --- a/web/themes/default/index.html +++ b/web/themes/default/index.html @@ -465,18 +465,18 @@ - +