Browse Source

Merge pull request #274 from MisterBeardy/fix/print-queue-time

Fix/print-queue-time
MartinNYHC 3 months ago
parent
commit
bada186101
1 changed files with 66 additions and 1 deletions
  1. 66 1
      backend/app/api/routes/print_queue.py

+ 66 - 1
backend/app/api/routes/print_queue.py

@@ -6,7 +6,7 @@ import zipfile
 from datetime import datetime
 from datetime import datetime
 from pathlib import Path
 from pathlib import Path
 
 
-import defusedxml.ElementTree as ET
+from defusedxml import ElementTree as ET
 from fastapi import APIRouter, Depends, HTTPException, Query
 from fastapi import APIRouter, Depends, HTTPException, Query
 from sqlalchemy import func, select
 from sqlalchemy import func, select
 from sqlalchemy.ext.asyncio import AsyncSession
 from sqlalchemy.ext.asyncio import AsyncSession
@@ -98,6 +98,58 @@ def _extract_filament_types_from_3mf(file_path: Path, plate_id: int | None = Non
     return sorted(types)
     return sorted(types)
 
 
 
 
+def _extract_print_time_from_3mf(file_path: Path, plate_id: int | None = None) -> int | None:
+    """Extract print time (prediction) from a 3MF file.
+
+    Args:
+        file_path: Path to the 3MF file
+        plate_id: Optional plate index to filter for (for multi-plate files)
+
+    Returns:
+        Print time in seconds, or None if not found
+    """
+    try:
+        with zipfile.ZipFile(file_path, "r") as zf:
+            if "Metadata/slice_info.config" not in zf.namelist():
+                return None
+
+            content = zf.read("Metadata/slice_info.config").decode()
+            root = ET.fromstring(content)
+
+            if plate_id is not None:
+                for plate_elem in root.findall(".//plate"):
+                    plate_index = None
+                    for meta in plate_elem.findall("metadata"):
+                        if meta.get("key") == "index":
+                            try:
+                                plate_index = int(meta.get("value", "0"))
+                            except ValueError:
+                                pass
+                            break
+
+                    if plate_index == plate_id:
+                        for meta in plate_elem.findall("metadata"):
+                            if meta.get("key") == "prediction":
+                                try:
+                                    return int(meta.get("value", "0"))
+                                except ValueError:
+                                    return None
+                        break
+            else:
+                plate_elem = root.find(".//plate")
+                if plate_elem is not None:
+                    for meta in plate_elem.findall("metadata"):
+                        if meta.get("key") == "prediction":
+                            try:
+                                return int(meta.get("value", "0"))
+                            except ValueError:
+                                return None
+    except Exception as e:
+        logger.warning(f"Failed to extract print time from {file_path}: {e}")
+
+    return None
+
+
 def _enrich_response(item: PrintQueueItem) -> PrintQueueItemResponse:
 def _enrich_response(item: PrintQueueItem) -> PrintQueueItemResponse:
     """Add nested archive/printer/library_file info to response."""
     """Add nested archive/printer/library_file info to response."""
     # Parse ams_mapping from JSON string BEFORE model_validate
     # Parse ams_mapping from JSON string BEFORE model_validate
@@ -153,6 +205,12 @@ def _enrich_response(item: PrintQueueItem) -> PrintQueueItemResponse:
         response.archive_name = item.archive.print_name or item.archive.filename
         response.archive_name = item.archive.print_name or item.archive.filename
         response.archive_thumbnail = item.archive.thumbnail_path
         response.archive_thumbnail = item.archive.thumbnail_path
         response.print_time_seconds = item.archive.print_time_seconds
         response.print_time_seconds = item.archive.print_time_seconds
+        if item.plate_id:
+            archive_path = settings.base_dir / item.archive.file_path
+            if archive_path.exists():
+                plate_time = _extract_print_time_from_3mf(archive_path, item.plate_id)
+                if plate_time is not None:
+                    response.print_time_seconds = plate_time
     if item.library_file:
     if item.library_file:
         response.library_file_name = (
         response.library_file_name = (
             item.library_file.file_metadata.get("print_name") if item.library_file.file_metadata else None
             item.library_file.file_metadata.get("print_name") if item.library_file.file_metadata else None
@@ -163,6 +221,13 @@ def _enrich_response(item: PrintQueueItem) -> PrintQueueItemResponse:
         # Get print time from library file metadata if no archive
         # Get print time from library file metadata if no archive
         if not item.archive and item.library_file.file_metadata:
         if not item.archive and item.library_file.file_metadata:
             response.print_time_seconds = item.library_file.file_metadata.get("print_time_seconds")
             response.print_time_seconds = item.library_file.file_metadata.get("print_time_seconds")
+        if item.plate_id:
+            lib_path = Path(item.library_file.file_path)
+            library_file_path = lib_path if lib_path.is_absolute() else settings.base_dir / item.library_file.file_path
+            if library_file_path.exists():
+                plate_time = _extract_print_time_from_3mf(library_file_path, item.plate_id)
+                if plate_time is not None:
+                    response.print_time_seconds = plate_time
     if item.printer:
     if item.printer:
         response.printer_name = item.printer.name
         response.printer_name = item.printer.name
     return response
     return response