github mescon/Healarr v1.3.6

5 hours ago

A focused bug-fix release tightening up five rough edges visible in the v1.3.5 production rollout: nested SPA routes serving a blank page, three different numbers shown for the same scan-progress quantity, scans being abandoned on abrupt container restarts even when they had hours of saved progress, the per-instance webhook URL in the UI pointing at the wrong credential (causing Sonarr/Radarr connection tests to fail with 401), and noisy DB lines in the log viewer that looked like errors but were not.

Fixed

  • Nested routes like /scans/<id> no longer render as a blank page (#291). The Vite build was configured with base: './' (relative asset paths) on the theory that this would support a sub-path mount like /healarr/. In practice it broke every nested route: when the browser is at /scans/1 it resolves ./assets/index.js as /scans/assets/index.js, the Go SPA fallback returns index.html for that path, and the browser refuses the import on MIME-type grounds. The "sub-path mount" promise was already broken by SPA routing semantics, so the build now uses an absolute base: '/'. Nested routes load assets identically to the root route. Real sub-path mount support would need a build-time env var plus a server-side index.html base-href rewrite and is now explicitly out of scope.
  • The scan-detail page shows one consistent file-scanned count instead of three slightly-different numbers (#289). The header progress bar (Running (X/Y)), the "Files scanned" stat card, and the "Healthy files" stat card were each computed from a different source at a different cadence: in-memory WebSocket FilesDone (per-file), the scans.files_scanned column (persisted only every 10 files), and a live COUNT(scan_files) (per-file). On a long-running scan you would routinely see e.g. Running (1855/31107), Files scanned: 1791, Healthy files: 1792. The handler now derives files_scanned and corruptions_found from the same GROUP BY status over scan_files that produces the per-status breakdown, so files_scanned == healthy + corrupt + skipped + inaccessible by construction. The cached column is kept as a fallback for the unlikely case where the count query errors.
  • Scans that were running when the container was killed abruptly now auto-resume on the next start instead of being marked cancelled (#292). When docker kill / SIGKILL / OOM-kill / host crash takes the container down, the graceful-shutdown handler that calls MarkInterrupted never runs. The startup reconcile (ReconcileOrphanScans, originally #259) caught these orphan running rows but marked them all 'cancelled' (terminal), so a multi-hour scan with thousands of files done was wasted on every hard restart. The reconcile now splits by progress: rows with a saved file_list and current_file_index > 0 are demoted to 'interrupted' and picked up by the existing ResumeInterruptedScans sweep on the same startup. Rows with no resumable state (mid-enumerate, or zero progress) still get cancelled. Both updates run in a single transaction so a partial reconcile cannot leave a row stuck between states.
  • The webhook URL shown in each Arr-instance row now uses the per-instance webhook secret, not the master API key (#293). The UI was hardcoded to splice ${apiKeyData.api_key} into the copy field for every instance. When the instance had a per-instance webhook_secret (the default for any instance created after the per-instance-secret migration), the backend correctly rejected the master-key URL with 401 Invalid webhook secret, but the user had no way to discover the right URL from the UI. Sonarr/Radarr connection tests therefore failed for every freshly-created Healarr instance. The per-row field now prefers arr.webhook_secret and falls back to the master api_key only for legacy rows that have no per-instance secret. The Config-page "Webhook API Key" card is renamed to "Master API Key" and reframed as the fallback-for-legacy path it actually is. Closes #286.
  • The in-app log viewer no longer fills with misleading database is locked (SQLITE_BUSY) lines (#288). Authenticated requests bump sessions.last_used_at as a best-effort diagnostic ("when did this session last act?"). Under page-load fanout the frontend fires several parallel API calls that all race on the same UPDATE; SQLite's WAL serializes writers, so all but the winner get SQLITE_BUSY. The bump error was already discarded, but the log line at DEBUG level was passed through to the log file and surfaced in the in-app viewer where it read like a real database error. The line is now silenced. No behavior change — the bump was already fire-and-forget.

Documentation

  • Hardware acceleration setup guide (#284). New "Hardware Acceleration" section in the README with ready-to-paste compose snippets for NVIDIA (NVIDIA Container Toolkit + runtime: nvidia), Intel QSV (/dev/dri device map), and VAAPI (/dev/dri + LIBVA_DRIVER_NAME). A matching accordion in the in-app Help page covers vendor selection, the HEALARR_HEALTH_CHECK_HWACCEL env var, and how to verify hwaccel is engaging by spotting -c:v <codec>_cuvid in the live ps output. The header sells the actual win: AV1 thorough scans drop from CPU-bound to GPU-bound, taking the per-file decode from tens of seconds to under one.

Full Changelog: v1.3.5...v1.3.6

Don't miss a new Healarr release

NewReleases is sending notifications on new releases.