mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-06 14:11:35 +02:00
Add library file support to print queue scheduler
The print queue now supports two sources: - archive_id: Print from existing archive (existing behavior) - library_file_id: Print from file manager library files (NEW) Previously, queue items from the file manager failed with "Archive not found" because the scheduler only handled archive-based prints. Changes: - Add LibraryFile model import - Update _start_print() to handle both archive and library file sources - Handle absolute vs relative file paths correctly - Update logging and MQTT notifications to use correct filename Fixes GitHub issue #163
This commit is contained in:
@@ -10,6 +10,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from backend.app.core.config import settings
|
||||
from backend.app.core.database import async_session
|
||||
from backend.app.models.archive import PrintArchive
|
||||
from backend.app.models.library import LibraryFile
|
||||
from backend.app.models.print_queue import PrintQueueItem
|
||||
from backend.app.models.printer import Printer
|
||||
from backend.app.models.smart_plug import SmartPlug
|
||||
@@ -220,22 +221,15 @@ class PrintScheduler:
|
||||
await tasmota_service.turn_off(plug)
|
||||
|
||||
async def _start_print(self, db: AsyncSession, item: PrintQueueItem):
|
||||
"""Upload file and start print for a queue item."""
|
||||
"""Upload file and start print for a queue item.
|
||||
|
||||
Supports two sources:
|
||||
- archive_id: Print from an existing archive
|
||||
- library_file_id: Print from a library file (file manager)
|
||||
"""
|
||||
logger.info(f"Starting queue item {item.id}")
|
||||
|
||||
# Get archive
|
||||
result = await db.execute(select(PrintArchive).where(PrintArchive.id == item.archive_id))
|
||||
archive = result.scalar_one_or_none()
|
||||
if not archive:
|
||||
item.status = "failed"
|
||||
item.error_message = "Archive not found"
|
||||
item.completed_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
logger.error(f"Queue item {item.id}: Archive {item.archive_id} not found")
|
||||
await self._power_off_if_needed(db, item)
|
||||
return
|
||||
|
||||
# Get printer
|
||||
# Get printer first (needed for both paths)
|
||||
result = await db.execute(select(Printer).where(Printer.id == item.printer_id))
|
||||
printer = result.scalar_one_or_none()
|
||||
if not printer:
|
||||
@@ -257,11 +251,60 @@ class PrintScheduler:
|
||||
await self._power_off_if_needed(db, item)
|
||||
return
|
||||
|
||||
# Get file path
|
||||
file_path = settings.base_dir / archive.file_path
|
||||
# Determine source: archive or library file
|
||||
archive = None
|
||||
library_file = None
|
||||
file_path = None
|
||||
filename = None
|
||||
|
||||
if item.archive_id:
|
||||
# Print from archive
|
||||
result = await db.execute(select(PrintArchive).where(PrintArchive.id == item.archive_id))
|
||||
archive = result.scalar_one_or_none()
|
||||
if not archive:
|
||||
item.status = "failed"
|
||||
item.error_message = "Archive not found"
|
||||
item.completed_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
logger.error(f"Queue item {item.id}: Archive {item.archive_id} not found")
|
||||
await self._power_off_if_needed(db, item)
|
||||
return
|
||||
file_path = settings.base_dir / archive.file_path
|
||||
filename = archive.filename
|
||||
|
||||
elif item.library_file_id:
|
||||
# Print from library file (file manager)
|
||||
result = await db.execute(select(LibraryFile).where(LibraryFile.id == item.library_file_id))
|
||||
library_file = result.scalar_one_or_none()
|
||||
if not library_file:
|
||||
item.status = "failed"
|
||||
item.error_message = "Library file not found"
|
||||
item.completed_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
logger.error(f"Queue item {item.id}: Library file {item.library_file_id} not found")
|
||||
await self._power_off_if_needed(db, item)
|
||||
return
|
||||
# Library files store absolute paths
|
||||
from pathlib import Path
|
||||
|
||||
lib_path = Path(library_file.file_path)
|
||||
file_path = lib_path if lib_path.is_absolute() else settings.base_dir / library_file.file_path
|
||||
filename = library_file.filename
|
||||
|
||||
else:
|
||||
# Neither archive nor library file specified
|
||||
item.status = "failed"
|
||||
item.error_message = "No source file specified"
|
||||
item.completed_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
logger.error(f"Queue item {item.id}: No archive_id or library_file_id specified")
|
||||
await self._power_off_if_needed(db, item)
|
||||
return
|
||||
|
||||
# Check file exists on disk
|
||||
if not file_path.exists():
|
||||
item.status = "failed"
|
||||
item.error_message = "Archive file not found on disk"
|
||||
item.error_message = "Source file not found on disk"
|
||||
item.completed_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
logger.error(f"Queue item {item.id}: File not found: {file_path}")
|
||||
@@ -270,7 +313,7 @@ class PrintScheduler:
|
||||
|
||||
# Upload file to printer via FTP
|
||||
# Use a clean filename to avoid issues with double extensions like .gcode.3mf
|
||||
base_name = archive.filename
|
||||
base_name = filename
|
||||
if base_name.endswith(".gcode.3mf"):
|
||||
base_name = base_name[:-10] # Remove .gcode.3mf
|
||||
elif base_name.endswith(".3mf"):
|
||||
@@ -332,9 +375,11 @@ class PrintScheduler:
|
||||
return
|
||||
|
||||
# Register as expected print so we don't create a duplicate archive
|
||||
from backend.app.main import register_expected_print
|
||||
# Only applicable for archive-based prints
|
||||
if archive:
|
||||
from backend.app.main import register_expected_print
|
||||
|
||||
register_expected_print(item.printer_id, remote_filename, archive.id)
|
||||
register_expected_print(item.printer_id, remote_filename, archive.id)
|
||||
|
||||
# Parse AMS mapping if stored
|
||||
ams_mapping = None
|
||||
@@ -364,7 +409,7 @@ class PrintScheduler:
|
||||
item.status = "printing"
|
||||
item.started_at = datetime.utcnow()
|
||||
await db.commit()
|
||||
logger.info(f"Queue item {item.id}: Print started - {archive.filename}")
|
||||
logger.info(f"Queue item {item.id}: Print started - {filename}")
|
||||
|
||||
# MQTT relay - publish queue job started
|
||||
try:
|
||||
@@ -372,7 +417,7 @@ class PrintScheduler:
|
||||
|
||||
await mqtt_relay.on_queue_job_started(
|
||||
job_id=item.id,
|
||||
filename=archive.filename,
|
||||
filename=filename,
|
||||
printer_id=printer.id,
|
||||
printer_name=printer.name,
|
||||
printer_serial=printer.serial_number,
|
||||
|
||||
Reference in New Issue
Block a user