From d21c7c408c9b58346ab53e62eb3eeab3821cce94 Mon Sep 17 00:00:00 2001 From: Gangoke Date: Sun, 17 May 2026 23:32:15 -1000 Subject: [PATCH] maybe uneeded, might have found root issue --- filament-dialog.js | 50 ++++++++++++++++++++ kobrax_moonraker_bridge.py | 93 +++++++++++++++++++++++++++----------- 2 files changed, 116 insertions(+), 27 deletions(-) create mode 100644 filament-dialog.js diff --git a/filament-dialog.js b/filament-dialog.js new file mode 100644 index 0000000..be35051 --- /dev/null +++ b/filament-dialog.js @@ -0,0 +1,50 @@ +// JS: Filament-Dialog für Store-Print (GCode-Filamente + Slots) + +var _filamentDialogMode = 'store'; // 'store' oder 'banner' + +var _gcodeFilaments = []; + +function storePrint(fileId, filename) { + _storeFileId = fileId; + _storeFilename = filename; + _filamentDialogMode = 'store'; + // GCode-Filamente aus Store-Datei holen (für Vorschau im Dialog) + var fileObj = storeFiles.find(function (f) { + return f.id === fileId; + }); + try { + _gcodeFilaments = fileObj && fileObj.gcode_filaments ? JSON.parse(fileObj.gcode_filaments) : []; + } catch (e) { + _gcodeFilaments = []; + } + fetch(_apiUrl('/kx/filament/slots')) + .then(function (r) { + return r.json(); + }) + .then(function (d) { + openFilamentDialog(_gcodeFilaments, d.result || []); + }) + .catch(function () { + openFilamentDialog(_gcodeFilaments, []); + }); +} + +function openFilamentDialog(gcodeFilaments, slots) { + // Update the left side of the UI with gcodeFilaments + updateLeftSideUI(gcodeFilaments); + + // Update the right side of the UI with available slots + updateRightSideUI(slots); +} + +function updateLeftSideUI(gcodeFilaments) { + // Logic to populate the left side of the UI with gcodeFilaments + console.log('Updating left side with GCode filaments:', gcodeFilaments); + // Add your UI update logic here +} + +function updateRightSideUI(slots) { + // Logic to populate the right side of the UI with available slots + console.log('Updating right side with available slots:', slots); + // Add your UI update logic here +} \ No newline at end of file diff --git a/kobrax_moonraker_bridge.py b/kobrax_moonraker_bridge.py index f6070a9..a46d9c0 100644 --- a/kobrax_moonraker_bridge.py +++ b/kobrax_moonraker_bridge.py @@ -212,33 +212,39 @@ def _extract_thumbnail(data: bytes) -> str: def _extract_filament_info(data: bytes) -> list[dict]: - """Liest filament_colour + filament_type aus GCode-Header (OrcaSlicer/PrusaSlicer). + """Liest filament_colour + filament_type aus GCode-Header (OrcaSlicer/PrusaSlicer). - Gibt Liste von {color_hex, material} pro Slot zurück, leer wenn nicht gefunden. - Liest nur die ersten 8KB (Header-Bereich). - """ - try: - header = data[:8192].decode("utf-8", errors="ignore") - colors, materials = [], [] - for line in header.splitlines(): - if line.startswith("; filament_colour"): - val = line.split("=", 1)[-1].strip() - colors = [c.strip().lstrip("#") for c in val.split(";") if c.strip()] - elif line.startswith("; filament_type"): - val = line.split("=", 1)[-1].strip() - materials = [m.strip() for m in val.split(";") if m.strip()] - if not colors: - return [] - result = [] - for i, hex_color in enumerate(colors): - result.append({ - "slot_index": i, - "color_hex": "#" + hex_color.upper() if hex_color else "#FFFFFF", - "material": materials[i] if i < len(materials) else "PLA", - }) - return result - except Exception: - return [] + Gibt Liste von {color_hex, material} pro Slot zurück, leer wenn nicht gefunden. + Sucht sowohl am Anfang als auch am Ende der Datei, da Orca große + Thumbnail-Blöcke einfügen kann und Metadaten dann im Tail stehen. + """ + try: + head = data[:131072] + tail = data[-131072:] if len(data) > 131072 else b"" + header = (head + b"\n" + tail).decode("utf-8", errors="ignore") + colors, materials = [], [] + for line in header.splitlines(): + if re.match(r"^\s*;\s*filament_colour\s*=", line): + val = line.split("=", 1)[-1].strip() + colors = [c.strip().lstrip("#") for c in val.split(";") if c.strip()] + elif re.match(r"^\s*;\s*filament_multi_colour\s*=", line) and not colors: + val = line.split("=", 1)[-1].strip() + colors = [c.strip().lstrip("#") for c in val.split(";") if c.strip()] + elif re.match(r"^\s*;\s*filament_type\s*=", line): + val = line.split("=", 1)[-1].strip() + materials = [m.strip() for m in val.split(";") if m.strip()] + if not colors: + return [] + result = [] + for i, hex_color in enumerate(colors): + result.append({ + "slot_index": i, + "color_hex": "#" + hex_color.upper() if hex_color else "#FFFFFF", + "material": materials[i] if i < len(materials) else "PLA", + }) + return result + except Exception: + return [] class GCodeStore: @@ -351,6 +357,15 @@ class GCodeStore: ) self._conn.commit() + def update_file_filaments(self, file_id: str, gcode_filaments: list | None) -> None: + """Aktualisiert geparste GCode-Filamente für einen bestehenden DB-Eintrag.""" + with self._lock: + self._conn.execute( + "UPDATE gcode_files SET gcode_filaments=? WHERE id=?", + (json.dumps(gcode_filaments) if gcode_filaments else None, file_id), + ) + self._conn.commit() + def delete_file(self, file_id: str) -> bool: row = self.get_file(file_id) if not row: @@ -1137,6 +1152,22 @@ class KobraXBridge: async def handle_kx_files(self, request): files = self._store.list_files() + # Legacy-Einträge ohne gespeicherte Filament-Metadaten nachziehen, + # damit Dialog links die GCode-Farben statt AMS-Slots zeigt. + for f in files: + if f.get("gcode_filaments"): + continue + path = f.get("path") or "" + if not path or not os.path.isfile(path): + continue + try: + with open(path, "rb") as fh: + parsed_filaments = _extract_filament_info(fh.read()) + if parsed_filaments: + f["gcode_filaments"] = json.dumps(parsed_filaments) + self._store.update_file_filaments(f["id"], parsed_filaments) + except Exception: + pass # Letzten Job-Status + Dauer pro Datei ergänzen jobs = self._store.list_jobs(limit=500) last_job: dict = {} @@ -4107,7 +4138,15 @@ function storePrint(fileId, filename){ _filamentDialogMode='store'; // GCode-Filamente aus Store-Datei holen (für Vorschau im Dialog) var fileObj=storeFiles.find(function(f){return f.id===fileId;}); - try{ _gcodeFilaments=fileObj&&fileObj.gcode_filaments?JSON.parse(fileObj.gcode_filaments):[]; } + try{ + if(fileObj&&Array.isArray(fileObj.gcode_filaments)){ + _gcodeFilaments=fileObj.gcode_filaments; + }else if(fileObj&&typeof fileObj.gcode_filaments==='string'&&fileObj.gcode_filaments){ + _gcodeFilaments=JSON.parse(fileObj.gcode_filaments); + }else{ + _gcodeFilaments=[]; + } + } catch(e){ _gcodeFilaments=[]; } fetch(_apiUrl('/kx/filament/slots')).then(function(r){return r.json()}).then(function(d){ openFilamentDialog(d.result||[]);