Changelog
All notable changes to GlueArrow Box OS will be documented in this file.
The format is based on Keep a Changelog.
[1.6.6] - 2026-05-01
Fixed — Tauri sidecar lifecycle (root cause of every "Connect screen scans forever" report since v1.6.0)
src-tauri/src/main.rs stored the spawned CommandChild as a local variable inside setup(). Tauri's CommandChild::Drop kills the spawned process — so the moment setup() returned, the api.exe sidecar got killed and the connect screen had nothing to find. Pressing "Launch OS" at the end of the wizard then opened the main window pointing at http://localhost:5002/, which loaded blank (dead socket). Fix: CommandChild now lives in a Tauri-managed handle that keeps it alive for the app's lifetime. Receiver is drained on tauri::async_runtime and forwarded into the log file as [sidecar] lines.
Fixed — complete_setup blank-window race
After Launch OS, complete_setup opened the main window before the sidecar was actually ready. The new window loaded a dead socket and rendered blank — even on machines where the sidecar would have come up a second later. complete_setup and complete_dj_setup now wait for the sidecar to bind before opening the window.
Fixed — Tauri updater plugin actually fires now
The endpoint + pubkey was wired since v1.6.0 but the plugin never queried — Tauri v2's updater plugin requires explicit plugin:updater|check invocation; endpoint config alone is not enough. frontend/connect.html now invokes the check 2 seconds after DOMContentLoaded and surfaces a confirm dialog when an update is available. From v1.6.6 onward OTA works without uninstall + reinstall.
Fixed — Phone field is no longer Ghana-only
v1.6.5 had +233 XX XXX XXXX as the phone placeholder + a Ghana-only regex. The platform ships globally per pricing v1.3 (Africa GHS + Diaspora USD). v1.6.6 replaces the input with a country-code dropdown (15 starter countries) plus a local-part input. New /api/setup/geo-default endpoint auto-defaults the dropdown to the operator's network country with a graceful fallback to GH if the IP lookup fails.
[1.6.5] - 2026-04-29
Added — Live system telemetry on the producer-desk status bar
- CPU / MEM / DISK percentages now populate on every
sync_pulse—_update_system_telemetry()runs once perrun_automation()tick (~1 s cadence) and writespsutil.cpu_percent(),psutil.virtual_memory().percent,psutil.disk_usage(...).percentontoSERVER_STATE. The producer-desk JS already gated ondata.cpu !== undefinedso the status bar lit up immediately after the first pulse instead of staying on--%forever. - psutil is lazy-imported inside the helper — first attempt put
import psutil+ a pre-warmcpu_percent(interval=None)at module load, which made the PyInstaller--onefilebundle hang silently at boot before reachingsocketio.run(). The fix moves the import inside_get_psutil()so the Flask app is up and serving long before psutil is touched. Any future bundling-side issue with psutil's native.pydsurfaces as a logged exception during the firstsync_pulserather than an opaque silent boot hang.
Operational note — first-boot time on Defender-active machines
PyInstaller --onefile extracts the bundle (~645 MB) to %TEMP%\_MEIxxxxxx\ on every spawn. On Windows machines with active real-time antivirus scanning, that extraction can take several minutes the first time as Defender inspects every freshly-written .pyd and .dll. Subsequent launches reuse the cached extraction and are fast. If first-boot consistently exceeds 5 minutes, add a Defender exclusion for %TEMP%\_MEI* and C:\Program Files\GlueArrow Control\ (admin-required).
[1.6.4] - 2026-04-29
Added — Pre-ship smoke test gate
tools/preship_smoke_test.py— every shippable bundle is now gated by a static + runtime test suite. Static checks readtauri.conf.json,api.py,templates/setup.html, andfrontend/connect.htmland refuse the build if any historical fix from v1.6.0–v1.6.3 has regressed (CSPconnect-src http:,flask_cors.CORS(app), custom User-Agent on cloud calls,focusFirstInput()+autofocus). Runtime checks bootdist/api.exeon a free port and probe/health(incl. ACAO header),/api/station/config,/api/license/validate. Optional Playwright check drives headless Chromium against/setupand asserts the licence input accepts keyboard input.build.py--smokegate —build.pyrunspreship_smoke_test.pyafter every build and exits non-zero if it fails.--no-smokeexists for local iteration only; never used for shipped builds.
Fixed
- Setup wizard licence input dropped keyboard focus on first paint — WebView2 sometimes leaves the page focused but no element selected after a navigation, so the operator could click the licence field and see no keystrokes register.
focusFirstInput()now runs after each step transition (goTo()), onDOMContentLoaded, and on the first user interaction (mousemove/focus) as a belt-and-braces fallback. The licence input also gets theautofocusHTML attribute. Same fix mirrored tofrontend/connect.htmlfor the manual-IP input. - Cloudflare WAF blocked outbound licence calls with HTTP 403 (error 1010) —
cloud.gluearrow.comis fronted by Cloudflare, whose default ruleset blocks any User-Agent matchingPython-urllib/x.y. The Box's licence-validate proxy now sendsUser-Agent: GlueArrow-Box-OS/1.6.4on every cloud call. Workaround for v1.6.3 installs: setcloud_urlin%APPDATA%\glueArrow Box OS\station_config.jsontohttps://gluearrow-admin-h5ouzu4p7q-uc.a.run.app(no Cloudflare).
[1.6.3] - 2026-04-29
Fixed
- Tauri webview couldn't read sidecar responses — v1.6.2 fixed the CSP at the webview layer but the Python sidecar still rejected the cross-origin request. Wired
flask_cors.CORS(app, resources={r"/*": {"origins": "*"}})so every endpoint servesAccess-Control-Allow-Origin. Same change openssocketio = SocketIO(app, cors_allowed_origins="*", ...). Box OS only runs on the operator's own machine + LAN so a permissive policy is correct here. build.pypicked stale.sigfiles —os.listdir()is unordered, so when both v1.6.2 and v1.6.3.sigfiles were left in the bundle dir from successive builds,[0]would silently grab the older one and write it intolatest-tauri.jsonalongside the new MSI URL — Tauri then refused every OTA update because the downloaded MSI's bytes didn't match the embedded signature. Sort sig files by mtime descending so the freshest always wins.
[1.6.2] - 2026-04-29
Fixed
- Tauri webview blocked
fetch()to the local sidecar — added an explicitapp.security.csptosrc-tauri/tauri.conf.jsonwithconnect-src 'self' tauri: http: https: ws: wss:. Without this the webview default CSP blocked every fetch fromconnect.htmltohttp://127.0.0.1:5002/health, so the connect screen always showed "No boxes found / Could not reach GlueArrow Box at 127.0.0.1:5002" even when the sidecar was healthy. build.pybundled staleapi.exeunder the target-triple name — Tauri'sexternalBinlookup expectsapi-x86_64-pc-windows-msvc.exe.build.pywas only copying toapi.exe, leaving the older target-triple file in place and shipping a broken sidecar. Now copies to both names every build.
Added
- UTF-8 stdio everywhere —
launch.bat,start_server.bat,main.js(Electron path), anddeploy/gluearrow-box-os.servicenow setPYTHONUTF8=1+PYTHONIOENCODING=utf-8so the Python sidecar's emoji prints don't crash boot on Windows under cp1252 codepage.
[1.6.1] - 2026-04-28
Fixed
- First-install MSI shipped with a broken sidecar — v1.6.0's bundled
api.exewas missing thepython-engineiopacket drivers because the rebuild skipped the PyInstaller step that copies the sidecar intosrc-tauri/binaries/. v1.6.1 rebuilds the sidecar from clean and verifies it boots before signing the Tauri MSI. v1.6.0 installs need a one-time manual reinstall before OTA can take over.
[1.6.0] - 2026-03-27
Added
- AES-256-CTR encryption —
.gluev2 format for audio file protection, matching SmartVault v2 implementation; cryptographically secure, 141x faster than v1 XOR
Changed
- v1 backward compatibility — existing XOR-encrypted
.gluev1 files remain readable; all new encryptions use AES-256-CTR v2
[1.5.0] - 2026-03-26
Added — Geo-Priority Scanning, Artist Reference & Cloud Scan Log
- Baked-in artist reference (
artist_reference.py) — 200+ major artists across all continents with country codes and genres; ships with every Box OS build; works fully offline for artist recognition from filenames - Geo-priority scanning — vault scanner sorts audio files by country relevance before processing. Three-layer scoring: exact artist match from baked-in reference (+20), partial match in filename (+15), folder keyword hints (+10)
- Auto-detect country from IP — when
STATION_COUNTRYenv var is not set, falls back to ip-api.com detection before scanning - Cloud scan log — every file scanned (matched/duplicate/submitted/audd) is logged to Playtunes cloud
vault_scan_logwith original_name, corrected_title, match_method, country_hint, session_id, and status - Cloud artist merge — fetches
/artists/countriesfrom Playtunes when online and merges new artist data into the baked-in reference - Country keyword hints — 8 countries supported (GH, NG, KE, ZA, TZ, US, GB, JM) with genre and location-based folder matching
[1.4.0] - 2026-03-24
Added — PlaytunesDJ Workspace, Production Engine & Bug Fixes
- PlaytunesDJ workspace — new
ws_playtunesdj.html+ws_playtunesdj.cssfor music library browsing, playback queue, and vault scan trigger; 14th workspace in the control panel /api/music/libraryendpoint — returns paginated local music library (tracks + total) for PlaytunesDJ workspace, backed byfingerprint_db.get_all_tracks()- Command Center (Owner) workspace updates — new
ws_owner.htmlwith network overview and cloud control features - PlaytunesDJ play context + vault ownership — play context integration for DJ sessions with SmartVault ownership tracking
- Constants re-export shim —
static/js/constants.jsre-exports fromcontrol/constants.jsto fix broken ES module resolution for viewer-side video.js - Logo placeholder — transparent 1x1 PNG at
static/graphics/logo.pngprevents 404 noise in graphics overlay templates (replace with station logo)
Changed
- Heartbeat exponential backoff —
_cloud_heartbeat_loop()now backs off from 10s to 5 minutes on repeated failures (doubles each cycle), resets to 10s on success; only logs the first failure to eliminate log spam when offline /newsendpoint fix — replacedsqlite3.Row.get()calls (which don't exist) with directrow["key"]access; fixesAttributeErrorthat caused the endpoint to return empty data
Fixed
/newsreturning emptydefault_scheduleandcalendardue tosqlite3.Rownot supporting.get()method- Heartbeat flooding logs with warnings every 10 seconds per station when cloud is unreachable
/static/js/constants.jsreturning 404 due tostatic/js/video.jsimporting./constants.jsrelative to itself/static/graphics/logo.pngreturning 404 in lower-third overlay templates
[1.3.0] - 2026-03-21
Added — SmartVault Pro Integration & Build Pipeline
- SmartVault Pro batch scanner — new
batch_scanner.pyruns gevent-based batch scanning with pause/resume, incremental scans, and intra-session deduplication; processes 40,000+ songs in batches with persistent per-file status tracking - FTS5 full-text search — new
fingerprint_db.pywith SQLite FTS5 virtual table for sub-200ms search across title, artist, album, genre; includes cursor-based pagination for 1M+ row result sets - Scan session management — new
scan_db.pytracks scan sessions with drive fingerprinting (survives USB drive letter changes), file registration in 500-file chunks, and batch processing with resume - Offline submission queue — new
offline_manager.pydetects connectivity loss, queues vault submissions, and retries up to 3 times when connection restores - Virtual scroller component — new
frontend/js/virtual-scroller.jsrenders 40,000+ songs with only 15-20 DOM elements at 60 FPS; fixed 44px row height with 5-row buffer - Live scanner dashboard — new
frontend/stream-scanner.htmlwith SSE-powered real-time drive discovery, song count, elapsed time, and drive selection - Library scanner page — new
frontend/library.htmlwith session history, status filters (identified/pending/unidentified/error/duplicate), file detail expansion, CSV export, and jump-to-page pagination - 25+ new API endpoints — batch scan control (
/api/batch/scan/*), session queries (/api/batch/session/*), file detail/retry (/api/batch/file/*), FTS5 search (/api/search,/api/search/cursor), connectivity (/api/connectivity), SSE song discovery (/api/songs/stream), fingerprint stats, submission status - Tauri scanner/library windows —
open_scannerandopen_librarycommands registered inmain.rsfor native desktop window management - OTA auto-update system —
launch.batchecks GCS for sidecar updates with SHA-256 verification and atomic swap;deploy/update-box-os.shfor Linux/Korra OS with automatic rollback on failure - systemd update timer —
deploy/gluearrow-update.timerchecks for updates every 6 hours with 30-minute randomized delay to prevent thundering herd - Build pipeline — new
build.pywith version stamping across api.py, tauri.conf.json, package.json; PyInstaller sidecar compilation; SHA-256 manifest generation - Cloud Build CI/CD — new
cloudbuild.yamlwith test, syntax check, sidecar build, Linux tarball packaging, and optional GCS publish steps - Release publishing — new
publish_update.pyuploads versioned builds to GCS with channel support (stable/beta/dev)
Changed
api.py— imported and initialized SmartVault Pro modules (fingerprint_db, scan_db, offline_manager, batch_scanner); added all batch scan routes, SSE streaming, FTS5 search, and connectivity endpointsmain.rs— registeredopen_scannerandopen_libraryTauri commands; added window builders for scanner (1200x800) and library (1200x800) windowsdeploy/install-linux.sh— now copies SmartVault Pro modules (fingerprint_db.py, scan_db.py, offline_manager.py, batch_scanner.py) and frontend/ directory; installs OTA update timerrequirements.txt— added qrcode[pil] for DJ registration QR codesapi.spec— superseded bybuild.py(dynamic PyInstaller invocation with hidden imports and data bundling)
[1.2.0] - 2026-03-21
Added -- Cross-Platform Support & Linux Appliance Architecture
- Platform compatibility layer -- new
platform_compat.pyauto-detects Windows, macOS, or Linux and provides correct config paths, FFmpeg capture inputs (gdigrab/avfoundation/v4l2+pulse), subprocess flags, process priority, and network interface detection - Device scanner -- new
device_scanner.pyenumerates audio/video capture devices on all three platforms (dshow on Windows, avfoundation on macOS, v4l2-ctl + pactl on Linux) GET /api/devicesendpoint -- returns available audio and video devices for the setup wizard- macOS support -- config stored in
~/Library/Application Support/GlueArrow Box OS/, video capture via avfoundation, audio via avfoundation - Linux production deployment -- config in
/etc/gluearrow-box-os/, data in/var/lib/gluearrow-box-os/, video via V4L2, audio via PulseAudio - systemd service -- new
deploy/gluearrow-box-os.servicereplacesservice_wrapper.pyandwatchdog.pyon Linux with built-in auto-restart (Restart=always), hardware watchdog (WatchdogSec=30), and rapid-restart protection (StartLimitBurst) - HDMI kiosk mode -- new
deploy/gluearrow-kiosk.serviceanddeploy/gluearrow-kiosk.shlaunch Chromium in full-screen kiosk mode showing God Mode (?ws=god) when an HDMI monitor is plugged in; auto-detects display connection, hides cursor after 3s inactivity, recovers from crashes - Linux installer -- new
deploy/install-linux.shone-command script installs all system dependencies (Python, FFmpeg, Chromium, PulseAudio, V4L2, X11), createsgluearrowsystem user, sets up Python venv, and enables both systemd services - Dynamic VLAN interface detection --
sync_engine.pysetup_linux_vlans()now auto-detects the primary network interface instead of hardcodingeth0
Changed
api.py,streamer.py,sync_engine.py,restream_engine.py,obs_bridge.py-- replaced hardcoded%APPDATA%config paths withplatform_compat.get_config_path()for cross-platform supportstreamer.py-- FFmpeg pipeline now uses platform-detected video/audio inputs, subprocess launch flags, and process priority boosting viaplatform_compat; reads device names fromstation_config.jsonREADME.md-- rewritten with cross-platform architecture diagram, workspace table, and dual deployment instructions (Windows + Linux)STATION_ONBOARDING.md-- rewritten as v2.0 with separate instructions for GlueArrow Box hardware (plug-and-play) and Windows PC deployment
[1.1.0] - 2026-03-18
Added — Speaker Calibration, Show Lineups & Tally-to-Speaker Bridge
- Speaker sync —
sync_engine.pynow pullscalibrated_speakersandshow_lineupsfrom Cloud PostgreSQL to local SQLite (local_speakers,local_show_lineups) with MD5 hash-based change detection - Speaker creation with cloud push —
POST /api/speakerscreates speakers locally and pushes to Cloud API; uses negative temp IDs as offline fallback - Voice sample capture —
POST /api/speakers/<id>/voicesaves.webmvoice recordings locally and proxies to Cloud - Cross-station speaker search —
GET /api/speakers/searchproxies to Cloud for network-wide search with local fallback when offline - Show lineup management —
GET/PUT /api/shows/<id>/lineupandGET /api/shows/current/lineupfor assigning speakers to shows with mic channel mapping - Tally-to-speaker bridge —
_resolve_speaker_from_source()maps tally camera sources (cam1-8, mic_ptt, desktop) to calibrated speakers via current show lineup;broadcast_tally()now emitsspeaker_activewith real speaker IDs - PTT speaker resolution —
radio.jsfetches current show lineup on init and resolves PTT speaker ID frommic_pttchannel assignment instead of hardcoded"presenter" - Planner lineup UI —
ws_planner.htmlshow detail panel now includes lineup management with search (local + network-wide), mic channel dropdown, inline "Calibrate New" quick-add, and drag-to-reorder - Producer desk wiring —
ws_producer.htmlguest calibration now persists to backend via/api/speakers, searches calibrated speakers network-wide (shows "CALIBRATED" badge), captures 10-second voice samples during mic preview, and auto-loads current show lineup on workspace open
[1.0.0] - 2026-03-13
Added
- Broadcast automation engine with schedule-driven show switching, 5-tier video failover (stream, camera, main file, program backup, general fallback, system loop), and gevent-based real-time loop
- Flask-SocketIO control plane for real-time broadcast commands between controller UI and server
- RTMP/HLS streaming via FFmpeg-based
RTMPStreamerwith live encoding and segment output - Schedule management with SQLite-backed local schedule, CRUD API, Excel import, downloadable templates, and per-show source mode configuration (file, link, camera)
- Show planner with per-show configuration for video sources, headlines, fallback paths, stream URLs, camera devices, and social metadata overrides
- Tally system with program/preview bus state, TSL UMD address mapping, and real-time tally API
- Vision mixer controls — take (cut), fade, and stinger transitions between preview and program via SocketIO
- Source switching — set preview and program sources (cam1-3, desktop, fallback, bars, black, graphics) with SocketIO events
- OBS Studio bridge connecting to OBS WebSocket v5 for scene switching, stream start/stop, and status monitoring
- Restream engine with Restream.io API v2 integration, OAuth2 token lifecycle, multi-platform metadata push (titles, descriptions, hashtags), and auto-social on show change
- Cloud Relay pusher — background thread watches local HLS folder and pushes
.tssegments +.m3u8playlists to cloud CDN, with 5-second heartbeat - YouTube integration with API key storage and stream status monitoring
- Multi-destination streaming — manage multiple RTMP destinations with CRUD API
- Station registration with cloud sync, QR-code pairing flow, and Bearer token authentication for all cloud API calls
- Station configuration API with local config persistence in
station_config.json - User authentication with local registration, login, QR-session claiming, and user listing
- License validation endpoint for station licensing
- Sync engine — bidirectional PostgreSQL-to-SQLite schedule synchronization with cloud, offline-first architecture, VLAN-aware networking
- SmartVault scanner — standalone drive scanner generating Chromaprint DNA fingerprints, Playtunes DB fingerprint checks, AudD API fallback identification, and pending track submission
- Music library with drive detection, audio file scanning (mp3, flac, wav, aac, ogg, m4a, aiff, wv, opus), search, and local HTML5 playback with path traversal protection
- DJ setup workflow for music library configuration
- Vault scan jobs with SSE (Server-Sent Events) progress streaming
- Play logging with local ledger and cloud sync via
/api/music/sync-ledger - Playtunes API proxy forwarding requests to GlueArrow Cloud Playtunes endpoints
- Artist claims system with local CRUD and cloud sync
- Music clips per-show assignment with ordering and CRUD operations
- Ad bid management — create, list, accept/reject ad bids with expiration tracking
- Marketplace bookings — view, accept/reject bookings, and slot management with cloud sync
- Traffic log API aggregating daily play counts, ad impressions, and revenue from local database
- Front desk with visitor check-in, clock-in/out, and attendance tracking
- QR check-in system with QR code generation and SocketIO-based scan handling
- Staff check-in via PIN verification with SocketIO events
- Owner dashboard APIs for detection history and team management
- News ticker API serving current headlines from schedule data
- AI Verify content safety system with keyword-based flagging (banned terms) and review queuing (sensitive terms)
- Prometheus metrics endpoint (
/metrics) with circuit breaker failure tracking - Health check endpoint for service monitoring
- VLAN setup wizard with managed switch auto-detection
- Watchdog process monitor with auto-restart, rapid-restart protection, and Windows Task Scheduler compatibility
- Service wrapper for running Box OS as a Windows background service
- Structured logging with JSON format for production (GCP Cloud Logging compatible)
- Producer commands via SocketIO for remote show control
- Caller/speaker management via SocketIO for live call-in shows
- Station heartbeat system for cloud connectivity monitoring
- Test suite with pytest for API routes, streamer, and sync engine
Security
- Bearer token authentication for all cloud API calls using
station_tokenfrom local config - Path traversal protection on music file serving (realpath validation against allowed root)
- Drive path validation blocking
..directory traversal on scan endpoints - Circuit breaker pattern on schedule API with Prometheus failure tracking