scan_external_folder stored raw 3MF metadata containing _thumbnail_data
bytes directly in the JSON column, causing a serialization error. Applied
the same clean_metadata() pattern used by upload/zip extraction and
removed the call to the non-existent parser.extract_thumbnail().
The archives page only fetched the 50 most recent prints due to a
hardcoded API limit default. Added client-side pagination with
configurable page sizes (25/50/100/200/All) and bumped the fetch
limit to return all archives. Page size is persisted to localStorage.
Queue page redesign: compact stats bar replaces summary cards, color-
coded left borders for status scanning, collapsible history with
condensed rows, and a new production schedule timeline view (#823)
showing estimated completion times grouped by hour with filter tabs
and day navigation. i18n keys added for all 7 languages.
Fix plate thumbnails returning 401 in print modal when auth is enabled
(missing stream token). Fix schedule calendar picker opening off-screen
(hidden input positioned with sr-only instead of near the date field).
on_print_complete returned early when no archive_id was found (auto-
archive off), skipping both internal inventory tracking (AMS remain%
deltas) and Spoolman usage reporting. Moved the filament usage tracking
block to run before the archive_id early-return so consumption is
always recorded regardless of the auto-archive setting.
When adding a print to the queue for multiple printers, users can now
enable "Stagger printer starts" to avoid power spikes from simultaneous
bed heating. Configurable group size and interval — first group starts
immediately (ASAP) or at scheduled time, subsequent groups get offset
scheduled_time values. No backend queue/scheduler changes — leverages
existing scheduled_time field.
Also adds a dedicated Queue tab in Settings (stagger defaults + auto-
drying moved from Filament tab), i18n keys for all 7 locales, frontend
and backend tests.
- Round scale weight to integer before sending to backend (Pydantic
rejects non-whole floats for int fields), move modal close to finally
block, add error toast with actual API message
- Fix null-field crash in SpoolInfoCard prop construction: pick one
source object instead of per-field ?? fallbacks that crash when
displayedSpool has null subtype/brand/rgba and matchedSpool is null
- Add React ErrorBoundary to App so crashes show error instead of
black screen
- Remove --max-old-space-size=128 and --enable-low-end-device-mode
from kiosk Chromium flags (crashed renderer/display)
- Append kiosk flags to Pi GPU defaults instead of resetting them
- Add wlr-randr keep-alive and screenBlankTimeout=0 to prevent
display blanking on labwc 0.9.x
- Fix tests: add ToastProvider to Dashboard test wrapper, update
StatusBar tests for removed animate-pulse class
Corrected left/right nozzle labels in ams_mapping2 comment
(255=main/right, 254=deputy/left). Added [0.2.2.2] release header
and #836 changelog entry noting the nozzle routing fix was already
included via the #797 ams_mapping2 format change.
The _is_docker_environment() fallback assumed Docker when .git/ was
absent, which is also true for native installs in Proxmox LXC
containers. Replace the .git/ fallback with a check of
/run/systemd/container (only matches docker/podman/oci, not lxc).
Frontend: replace expensive idle dashboard animations (3x animate-ping
with scale transforms, blur-2xl glow, continuous animate-pulse on
status dots) with static NFC rings and slow 5s color-cycling spool.
Chromium: add --disable-extensions, --disable-background-timer-throttling,
--memory-pressure-off, --disable-renderer-backgrounding, --disable-breakpad,
and --js-flags=--max-old-space-size=128. Install script: mask stripped
services (not just disable) to prevent socket/dbus reactivation; use
/etc/systemd/user/ global overrides for user services instead of
unreliable su-based systemctl --user. Remove chromium/upower from
strip_packages since kiosk reinstalls them immediately.
Add Chromium flags to cut overhead on Pi: disable extensions, crash
reporter, background timer throttling, renderer backgrounding, and cap
V8 heap at 128MB. Mask (not just disable) stripped system services to
prevent socket/dbus reactivation, and add xdg-permission-store to the
disable list. Remove chromium and upower from strip_packages since the
kiosk needs them — they were being uninstalled then immediately
reinstalled on every run.
reporter, background timer throttling, renderer backgrounding, and cap
V8 heap at 128MB. Also mask (not just disable) stripped system services
to prevent socket/dbus reactivation, and add xdg-permission-store to
the disable list.
Camera streams, snapshots, thumbnails, timelapse videos, photos, QR
codes, and cover images served via <img>/<video> tags were previously
unauthenticated because browser media elements cannot send Authorization
headers. When auth is enabled, these endpoints are now protected by a
reusable stream token (?token=xxx) obtained from POST
/printers/camera/stream-token (requires CAMERA_VIEW permission).
Replace Chromium with cog (WPE WebKit) for the kiosk browser. Cog is
purpose-built for embedded kiosk displays with a fraction of Chromium's
CPU and memory footprint on Pi hardware.
Add React Query `select` to SpoolBuddyLayout and SpoolBuddyDashboard
printer status queries so only `connected` is extracted. Temperature,
fan, and progress changes no longer trigger re-renders on every MQTT
tick.
Expand service/package stripping to disable pipewire audio stack, CUPS
printing, rpcbind, upower, polkit, accounts-daemon, xdg-desktop-portal,
and mpris-proxy. Add user-level service masking for pipewire/portals.
Update SSH update cache clearing to handle both WPE WebKit and legacy
Chromium cache paths.
Chromium: override Debian defaults via /etc/chromium.d/spoolbuddy-kiosk
to disable GPU rasterization, enable low-end device mode, and disable
smooth scrolling/background networking. The system default
--enable-gpu-rasterization conflicted with per-launch flags.
WebSocket: add React Query `select` to SpoolBuddyLayout and
SpoolBuddyDashboard printer status queries so only `connected` is
extracted. Temperature/fan/progress changes no longer trigger
re-renders on every MQTT tick (~10/sec idle).
Services: expand install script to strip pipewire, CUPS, rpcbind,
upower, polkit, accounts-daemon, xdg-desktop-portal, mpris-proxy.
Add user-level service masking for pipewire/portals.
Override Debian's default Chromium flags via /etc/chromium.d/spoolbuddy-kiosk
to disable GPU rasterization, enable low-end device mode, and disable smooth
scrolling/background networking. The system default --enable-gpu-rasterization
conflicted with per-launch flags — the new config replaces all system defaults
so kiosk flags take effect cleanly.
Expand service/package stripping to disable pipewire audio stack, CUPS
printing, rpcbind, upower, polkit, accounts-daemon, xdg-desktop-portal,
and mpris-proxy. Add user-level service masking for pipewire/portals
that system-level disable misses.
Add Chromium performance flags (disable-gpu-rasterization,
enable-low-end-device-mode, disable-smooth-scrolling,
disable-background-networking, disable-dev-shm-usage) to reduce
CPU load from ~54% to manageable levels on Pi 4B.
Expand service/package stripping to disable pipewire audio stack,
CUPS printing, rpcbind, upower, polkit, accounts-daemon,
xdg-desktop-portal, and mpris-proxy. Add user-level service
masking for pipewire/portals that system-level disable misses.
Filenames with spaces (e.g. "Junktion Box PRO 90.3mf") broke the MQTT
print command because the url field (ftp://file name.3mf) contained
unencoded spaces the firmware can't parse. FTP upload succeeded but the
printer silently ignored the command and stayed IDLE. Replace spaces
with underscores in the remote filename before upload and print command.
Virtual keyboard now participates in flex layout instead of fixed
overlay, eliminating dead space between content and keyboard. Bottom
nav and status bar hide when keyboard is open. Number inputs (e.g.
Weight field on Write Tag) now accept virtual keyboard input.
Auto-off now has a "Keep Enabled" toggle that keeps it active between
prints instead of disabling after each use (one-shot). Useful for HA
accessories like BentoBox filters that should always power off after
prints. Default behavior (one-shot) is unchanged.
Catalog-style spool grid with colored spool circles (matching AMS page
style), material/subtype labels, color dots, fill level bars, remaining
weight percentages, and AMS location badges. Touch-friendly search bar
and inline filter pills (All, In AMS, per-material). Full-screen detail
view with slicer filament, PA K-profiles, weight breakdown, temperature,
cost, tag ID, AMS assignment, and notes — updates live from query data.
Shows Spoolman iframe when Spoolman is enabled. Navigation item added
between Write and Settings in the bottom bar.
Catalog-style spool grid with colored spool icons, material/subtype
labels, color dots, remaining weight percentages, and AMS location
badges. Search bar with inline filter pills (All, In AMS, per-material).
Detail bottom sheet on tap. Shows Spoolman iframe when enabled.
Navigation item added between Write and Settings in the bottom bar.
New page at /spoolbuddy/inventory with compact 2-column spool card grid,
search bar, material filter chips, sort options, and tap-to-open detail
sheet. Shows Spoolman iframe when Spoolman is enabled. Navigation item
added between Write and Settings in the bottom bar.
The stale connection fix force-closed the socket on every frontend
status poll, causing a tight close→reconnect→stale→close loop. Added
a 30-second cooldown between stale reconnect attempts so paho has time
to re-establish the connection. Also added reconnect backoff (1-30s)
and unique-per-process MQTT client IDs to prevent broker session
takeovers.
The stale connection fix (6ac375a) force-closed the socket to trigger
paho reconnect, but paho's disconnect callback redundantly broadcast
state changes, causing rapid connected/disconnected cycling in the UI.
Now sets a flag before the force-close so _on_disconnect skips the
redundant broadcast. Also relaxed keepalive from 15s to 30s — the
aggressive interval caused spurious disconnects on transient hiccups.
Moved _disconnection_event.set() to the top of _on_disconnect so no
early-return filter can prevent it from unblocking disconnect() callers.
Removed leftover debug payload dump.
New splash shows only the SpoolBuddy logo with green glow bloom,
radial gradient, light rays, and vignette. Removed Bambuddy branding.
Includes generator script for easy customization.
Defers initramfs rebuild during install until after Plymouth theme
is configured, avoiding redundant rebuilds from apt hooks.
New splash shows only the SpoolBuddy logo with green glow bloom,
radial gradient, light rays, and vignette. Removed Bambuddy branding.
Includes generator script for easy customization.
Defers initramfs rebuild during install until after Plymouth theme
is configured, avoiding redundant rebuilds from apt hooks.
Reverts the fim/fbi experiment — Plymouth is the only splash tool
that reliably handles Pi KMS/DRM from early boot. install.sh is
restored to the original Plymouth setup. The new polished splash
image and generator script are kept.
New splash shows only the SpoolBuddy logo with baked-in green glow,
radial gradient background, subtle light rays, and vignette effects
(66KB vs 205KB). Removed Bambuddy branding. Includes generator
script for easy customization.
Plymouth ran as a persistent daemon throughout boot, consuming memory
and competing for framebuffer allocation. fim renders via DRM (Pi KMS
doesn't expose a usable legacy framebuffer), displays the image, and
exits — zero ongoing resource cost.
New splash image shows only the SpoolBuddy logo with baked-in glow,
radial gradient, light rays, and vignette effects (66KB vs 205KB).
Install script auto-purges Plymouth on existing installs in a single
pass to avoid redundant initramfs rebuilds.
Plymouth ran as a persistent daemon throughout boot, consuming memory
and competing for framebuffer allocation. fbi writes pixels directly
to the framebuffer and exits — zero ongoing resource cost.
New splash image shows only the SpoolBuddy logo with baked-in glow,
radial gradient, light rays, and vignette effects (66KB vs 205KB).
Install script auto-purges Plymouth on existing installs in a single
pass to avoid redundant initramfs rebuilds.
Plymouth ran as a persistent daemon throughout boot, consuming memory
and competing for framebuffer allocation. fbi writes pixels directly
to the framebuffer and exits — zero ongoing resource cost.
New splash image shows only the SpoolBuddy logo with baked-in glow,
radial gradient, light rays, and vignette effects (66KB vs 205KB).
Install script auto-removes Plymouth on existing installs.
Narrowed CSS selector to only target max-w-2xl modals (Assign Spool)
not max-w-sm ones (slot action picker). Removed inner max-h-96 on
the spool grid to eliminate nested scrollbars.
CSS rules scoped via data-spoolbuddy-kiosk force the modal panel to
90vh with flex column layout. Content area scrolls, header/footer
pinned. Uses height (not just max-height) so flex-basis auto works
correctly. No flash — CSS applies before paint.
useEffect in SpoolBuddyAmsPage applies inline styles to the modal
panel after render (requestAnimationFrame + setTimeout) to cap it
at 90vh with scrollable content. Targets the DOM directly to avoid
CSS specificity issues with Tailwind v4.
Used a ref callback wrapper in SpoolBuddyAmsPage to directly apply
inline styles (max-height 90vh, flex column, scrollable content) to
the shared AssignSpoolModal DOM elements without modifying the
shared component.
Added data-spoolbuddy-kiosk attribute to the SpoolBuddy layout and
global CSS rules that cap modals at 90vh with scrollable content on
the small touchscreen, without modifying shared components.
Added scoped CSS in SpoolBuddyAmsPage that constrains the shared
AssignSpoolModal to 90vh with scrollable content and pinned
header/footer, without modifying the shared component.
Added scoped CSS in SpoolBuddyAmsPage that constrains the shared
AssignSpoolModal to 90vh with scrollable content, without modifying
the shared component used by the main Bambuddy frontend.