feat(vp): add archive name source toggle (metadata/filename) (#1152)

Slicer-uploaded archives picked up their display name from the 3MF's
  embedded print_name (the creator-baked title); users who renamed a job
  in BambuStudio's "Send to printer" dialog never saw that name surface
  because the FTP filename was only used as a fallback when metadata was
  empty.

  Settings -> Virtual Printer now exposes an Archive name source toggle
  (Metadata / Filename, default Metadata) that flips precedence in
  ArchiveService.archive_print via a new prefer_filename_for_name param.
  All four VP-sourced archive paths read the new
  virtual_printer_archive_name_source setting and forward the flag:
  _archive_file, _add_to_print_queue, POST /pending-uploads/archive-all,
  POST /pending-uploads/{id}/archive.
This commit is contained in:
maziggy
2026-04-29 06:54:08 +02:00
parent 418f5168f5
commit c2e7f8eb4b
15 changed files with 336 additions and 135 deletions
@@ -78,6 +78,8 @@ async def archive_all_pending(
_: User | None = RequirePermissionIfAuthEnabled(Permission.QUEUE_CREATE),
):
"""Archive all pending uploads."""
from backend.app.api.routes.settings import get_setting
result = await db.execute(select(PendingUpload).where(PendingUpload.status == "pending"))
pending_uploads = result.scalars().all()
@@ -85,6 +87,7 @@ async def archive_all_pending(
failed = 0
service = ArchiveService(db)
prefer_filename = (await get_setting(db, "virtual_printer_archive_name_source")) == "filename"
for pending in pending_uploads:
file_path = Path(pending.file_path)
@@ -102,6 +105,7 @@ async def archive_all_pending(
"source": "virtual_printer",
"source_ip": pending.source_ip,
},
prefer_filename_for_name=prefer_filename,
)
if archive:
@@ -193,6 +197,9 @@ async def archive_pending_upload(
raise HTTPException(status_code=404, detail="Upload file not found on disk")
# Archive the file
from backend.app.api.routes.settings import get_setting
prefer_filename = (await get_setting(db, "virtual_printer_archive_name_source")) == "filename"
service = ArchiveService(db)
archive = await service.archive_print(
printer_id=None,
@@ -202,6 +209,7 @@ async def archive_pending_upload(
"source": "virtual_printer",
"source_ip": pending.source_ip,
},
prefer_filename_for_name=prefer_filename,
)
if not archive:
+12
View File
@@ -845,6 +845,7 @@ async def get_virtual_printer_settings(
target_printer_id = await get_setting(db, "virtual_printer_target_printer_id")
remote_interface_ip = await get_setting(db, "virtual_printer_remote_interface_ip")
tailscale_disabled_raw = await get_setting(db, "virtual_printer_tailscale_disabled")
archive_name_source = await get_setting(db, "virtual_printer_archive_name_source")
return {
"enabled": enabled == "true" if enabled else False,
@@ -854,6 +855,7 @@ async def get_virtual_printer_settings(
"target_printer_id": int(target_printer_id) if target_printer_id else None,
"remote_interface_ip": remote_interface_ip or "",
"tailscale_disabled": tailscale_disabled_raw == "true" if tailscale_disabled_raw else True,
"archive_name_source": archive_name_source if archive_name_source in ("metadata", "filename") else "metadata",
"status": virtual_printer_manager.get_status(),
}
@@ -867,6 +869,7 @@ async def update_virtual_printer_settings(
target_printer_id: int = None,
remote_interface_ip: str = None,
tailscale_disabled: bool = None,
archive_name_source: str = None,
db: AsyncSession = Depends(get_db),
_: User | None = RequirePermissionIfAuthEnabled(Permission.SETTINGS_UPDATE),
):
@@ -930,6 +933,13 @@ async def update_virtual_printer_settings(
status_code=400,
content={"detail": "Mode must be 'immediate', 'review', 'print_queue', or 'proxy'"},
)
# Validate archive_name_source
if archive_name_source is not None and archive_name_source not in ("metadata", "filename"):
return JSONResponse(
status_code=400,
content={"detail": "archive_name_source must be 'metadata' or 'filename'"},
)
# Normalize legacy "queue" to "review" for storage
if new_mode == "queue":
new_mode = "review"
@@ -1000,6 +1010,8 @@ async def update_virtual_printer_settings(
await set_setting(db, "virtual_printer_remote_interface_ip", remote_interface_ip)
if tailscale_disabled is not None:
await set_setting(db, "virtual_printer_tailscale_disabled", "true" if tailscale_disabled else "false")
if archive_name_source is not None:
await set_setting(db, "virtual_printer_archive_name_source", archive_name_source)
# Propagate tailscale_disabled to the first VirtualPrinter row so sync_from_db() picks it up
if tailscale_disabled is not None: