From 6def135bbcb07d167f6e01b772b7a447f323bebc Mon Sep 17 00:00:00 2001 From: Nicolas Predella Date: Wed, 20 May 2026 21:46:44 +0300 Subject: [PATCH] up --- core/nodeslicer/nodes.py | 20 ++++--------- infra/networking/gcode_utils.py | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 14 deletions(-) create mode 100644 infra/networking/gcode_utils.py diff --git a/core/nodeslicer/nodes.py b/core/nodeslicer/nodes.py index a3e885f..cf437a2 100644 --- a/core/nodeslicer/nodes.py +++ b/core/nodeslicer/nodes.py @@ -963,9 +963,11 @@ class SLICENODE_GcodeToFile(ExecSliceNode): def evaluate(self, operator=None): from ...infra.networking.bgcode import convert_to_bgcode + from ...infra.networking.gcode_utils import get_gcode_name_from_metadata from pathlib import Path + import os - gcodes: str = self.resolve_multi_input('Gcode') + gcodes: list[str] = [gc for gc in self.resolve_multi_input('Gcode') if gc] folder: str = resolve_input(self.inputs.get("Folder")) if not gcodes: @@ -976,18 +978,7 @@ class SLICENODE_GcodeToFile(ExecSliceNode): return 'error' for i, gc in enumerate(gcodes): - - import re, json - parts_match = re.search(r"; objects_info = (.*)", gc) - name: str = "" - if parts_match: - gcode_info = json.loads(parts_match.group(1)) - names: list[str] = [str(v['name']) for v in gcode_info['objects']] - from collections import Counter - counts = Counter(names) - name = "-".join(f"{c}x{n}" if c > 1 else n for n, c in counts.items()) - else: - name = 'object_'+str(i) + name = get_gcode_name_from_metadata(gc, default=f'object_{i}') # User's requested logic: .split('.')[0] folder_path = Path(bpy.path.abspath(f"//{folder}")) @@ -1012,11 +1003,12 @@ class SLICENODE_GcodeToFile(ExecSliceNode): with open(filepath, "w", encoding="utf-8", newline="\n") as f: f.write(gc) if operator: operator.report({'INFO'}, f"G-code saved to {filepath}") - return 'ok' except Exception as e: if operator: operator.report({'ERROR'}, str(e)) return 'error' + return 'ok' + @register_class class SLICENODE_GcodeToTextBlock(ExecSliceNode): bl_label = "Gcode to Text Block" diff --git a/infra/networking/gcode_utils.py b/infra/networking/gcode_utils.py new file mode 100644 index 0000000..c4dd900 --- /dev/null +++ b/infra/networking/gcode_utils.py @@ -0,0 +1,50 @@ +import re +import json +from collections import Counter +from typing import Any + +def parse_gcode_metadata(gcode: str) -> dict[str, Any]: + """Extracts metadata fields from G-code comments.""" + fields = {} + + # 1. Time per print (decimal hours) + time_match = re.search(r"; estimated printing time \(normal mode\) = (.*)", gcode) + if time_match: + time_str = time_match.group(1) + h = re.search(r"(\d+)h", time_str) + m = re.search(r"(\d+)m", time_str) + s = re.search(r"(\d+)s", time_str) + total_hours = 0.0 + if h: total_hours += float(h.group(1)) + if m: total_hours += float(m.group(1)) / 60.0 + if s: total_hours += float(s.group(1)) / 3600.0 + fields["Time per print"] = round(total_hours, 2) + + # 2. Parts per print + parts_match = re.search(r"; objects_info = (.*)", gcode) + if parts_match: + try: + info = json.loads(parts_match.group(1)) + fields["Parts per print"] = len(info.get("objects", [])) + fields["objects_info"] = info + except Exception: pass + + # 3. Weight per print + weight_match = re.search(r"; total filament used \[g\] = ([\d\.]+)", gcode) + if weight_match: + fields["Weight per print"] = int(float(weight_match.group(1))) + + return fields + +def get_gcode_name_from_metadata(gcode: str, default: str = "output") -> str: + """Generates a descriptive name for the G-code based on its objects_info metadata.""" + parts_match = re.search(r"; objects_info = (.*)", gcode) + if parts_match: + try: + gcode_info = json.loads(parts_match.group(1)) + names: list[str] = [str(v['name']) for v in gcode_info['objects']] + counts = Counter(names) + return "-".join(f"{c}x{n}" if c > 1 else n for n, c in counts.items()) + except: + pass + return default