github tphakala/birdnet-go nightly-20260524
Nightly Build nightly-20260524

3 hours ago

This release fixes a critical regression where RTSP streams with sample rates below 48 kHz (typical IP cameras send 8-16 kHz audio) cut in and out after the bat detection changes in nightly-20260523. All streams are now probed at startup so resampling only happens when needed. This release also adds time-windowed health evaluation with sparkline visualizations, SQLite corruption detection with auto-recovery at startup, and completes settings hot-reload coverage for the remaining 5 settings that previously required a restart.

New Features

Time-Windowed Health Evaluation with Sparkline Visualization

Health diagnostics no longer evaluate lifetime counters. A past burst of errors previously marked the system as Critical forever until restart; checks now evaluate configurable time windows (15m to 7d, default 1h). The System Health page is redesigned to match the System Overview visual language: a status metric strip replaces the old hero card, diagnostics auto-run on page mount, and counter-based checks show inline SVG sparklines (24 hourly bars, colored by status) with expandable detail panels. The window selector persists to localStorage. 22 new i18n keys fully translated across all 15 locales (#3249).

Complete Settings Hot-Reload Coverage

Five settings categories that were saved to disk but required a restart to take effect now hot-reload at runtime: Log Deduplication, RTSP Health monitoring, MQTT HomeAssistant discovery, System Monitoring, and HLS LiveStream. This brings the hot-reload TODO count from 5 to 0: every setting changed through the UI now takes effect immediately (#3254).

SQLite Corruption Detection at Startup with Auto-Recovery

A synchronous PRAGMA quick_check now runs at startup after migration. When index-level corruption is detected (common from power loss on SD cards), BirdNET-Go attempts automatic recovery via REINDEX. If recovery fails, the system continues in degraded mode so headless users keep web UI access. A corruption flag is latched to suppress duplicate Sentry event floods (prevents the 244+ duplicate events seen in production), and a persistent notification with actionable recovery guidance is sent to the user. A new DatabaseIntegrityCheck appears in the health diagnostics system (#3246).

Security

  • Temp file paths hardened against symlink attacks - Predictable temp file paths across datastore, API prerequisites, and log rotation are replaced with os.CreateTemp (random name + O_EXCL). Backup files and archives now use 0600 permissions instead of the os.Create default. Database connection pools are properly closed when post-Open() initialization fails (#3248).

Bug Fixes

Audio & Streaming

  • RTSP streams with sub-48 kHz sample rates cut in and out - The bat detection changes in nightly-20260523 removed FFmpeg's -ar/-ac output resampling flags for all protocol streams, which broke cameras that send 8-16 kHz audio since the pipeline expects 48 kHz. All streams are now probed via ffprobe at startup to discover actual sample rates. Resampling is applied only when the source rate differs from the target: sub-48 kHz sources get resampled up, 48 kHz sources skip resampling, and high-rate bat sources preserve their ultrasonic content. A new SourceSampleRate field carries the probed rate through the full pipeline. Fixes #3255 (#3256).
  • Model reload used stale settings, locale changes required restart - ReloadModel() read from a stale bn.Settings pointer, so changing the locale or thread count via the UI had no effect until a full restart. All sub-methods now see a fresh settings snapshot. Five stale settings reads in HLS streaming are also fixed (#3253).
  • Duplicate ORT notifications on range filter reload - The v3 geomodel path bypassed the early ONNX Runtime availability check, causing repeated Sentry events and bell notifications on every range filter reload when ORT was unavailable. A single check at the top of model initialization now guards both paths (#3245).

Health Diagnostics

  • Health check endpoint could hang indefinitely - runChecks spawned goroutines with 10s per-check contexts and then called wg.Wait() unconditionally. If a check ignored its context (e.g., gopsutil syscalls), the /api/v2/system/diagnostics/run endpoint blocked forever. A channel-based approach now respects an overall timeout with a 100ms grace period, returning StatusUnknown for unfinished checks. Multi-result slices are defensively copied to prevent data races (#3251).

Don't miss a new birdnet-go release

NewReleases is sending notifications on new releases.