Commit Graph

22 Commits

Author SHA1 Message Date
larssand
7f267e17fe fix(settings): open the right Settings tab from the update link and Race Day
The sidebar update notice now lands on System & backup at Updates, and
Race Day's decoder/backend/audio fix buttons open the matching tab,
instead of whichever tab was used last.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:44:28 +02:00
larssand
9d79bcb4d3 feat(layouts): optional min/max lap time per track layout for practice
Each layout can carry its own lap window (set on creation, editable in
Settings, saved from Race Day during practice). Open/Free practice on
that layout uses it; races always keep the event's values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 20:33:22 +02:00
larssand
aaca5e8c63 feat(audio): passing tone only during races and remove legacy audio
Adds 'Calls during a race' (default: passing tone only, like timing
systems) that drops name/personal best/leader/position calls in race
sessions; practice keeps them. Removes the legacy audio panel and
fallbacks, including its 'Sound on' switch that silently muted every
race-audio voice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 21:47:40 +02:00
larssand
e8a2799a92 feat(audio): add offline local neural voice via Piper (sv + en)
Announcements can use Piper, a free local neural TTS, instead of the browser's system
voice. No account, no paid service, and it keeps working with no internet at the track.

- npm run tts:install (or Settings -> Audio -> Install) downloads the standalone Piper
  release for Linux/Windows/macOS plus Swedish and English voices into piper/ once
- server/tts.js generates each line once, one at a time, and caches it as WAV under
  data/tts/; a new line takes ~0.3 s with the standalone build
- src/piper_speech.js plays it and falls back to the browser voice if Piper is missing,
  errors, or takes over 2.5 s, so no announcement is lost and timing is never held up
- "Pre-generate phrases and driver names" renders every fixed phrase and name in both
  languages before race day

Browser voice stays the default. Generation routes fall under the admin PIN.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 19:28:15 +02:00
larssand
9016ce02e4 feat(auth): add optional admin PIN for all API writes
Off by default. Once a PIN is set in Settings -> System & backup, every non-GET /api/*
request (plus GET /api/ammc/config) needs a signed 30-day HttpOnly cookie, which also
closes the unauthenticated /api/update/run restart trigger. A 401 opens a PIN dialog
and the pending save is retried after login. Reads stay open because the public overlay
hydrates through GET /api/state. Optional RC_ADMIN_ALLOWED_CIDRS restricts the same
routes by client address.

The PIN hash and signing secret live in data/, outside the app_state blob, so they
never leak through GET /api/state, exports or backups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-24 22:14:58 +02:00
larssand
f988ad2690 Fix race-audio Test buttons silently saving settings to the database
Clicking a Test button (general or per-event) in the race-sounds table
called persistRaceAudioFormValues, which both applied the form's
current values and saved them to the backend on every click. A sound
preview should only apply values in memory, not persist them - split
into an apply-only helper used by the Test buttons, keeping the
existing save behavior for the explicit Save button and field changes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 19:28:46 +02:00
larssand
cc9f5c380b Group Settings into tabs instead of one long scroll
Splits the eleven stacked panel sections into four tabs (Connection,
Audio, Appearance & overlay, System & backup) so a specific setting
is a click away rather than a long scroll, per user feedback. Purely
a layout change - no section's markup, ids, or event bindings moved.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 19:19:34 +02:00
larssand
fd6efe2c7e Add track layout tracking so lap-time stats stay comparable
Clubs that reconfigure their track (e.g. running indoors in the same
building) can now add named track layouts under Settings, each with
just a start date/time - layouts are contiguous, so a layout's end is
implicitly the next one's start, with no separate field to keep in
sync. Every session freezes which layout was active when it started,
so the "track record" audio cue and the Results Archive (which now
shows each session's layout) only compare laps run on the same
physical track. With no layouts configured, everything behaves
exactly as before - the feature is fully inert until a club uses it.

Design settled through conversation with the user: global scope (not
per class), start-date-only (no redundant stop date), and no changes
needed to driver/transponder mapping, since that's already fully
independent of track geometry in this app.

Deliberately out of scope for this pass: the mobile/driver training
profile's own cross-session personal-best trend stats still compare
across a driver's whole lap ledger regardless of layout - logged in
ROADMAP.md as a real remaining gap for a later pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-10 14:17:06 +02:00
larssand
4c463485e0 Add in-app update checker and one-click updater
Settings now shows when a newer version is available, with the real
version number read from the remote's package.json (via the git
binary already required for this deployment model, so it works
against any remote, not just GitHub), and an "Uppdatera nu" button
that stops the server, pulls, reinstalls dependencies and restarts
automatically - warning explicitly if a race is currently active.
The existing app-version poller already reloads the page once a
restart is detected, so no new client-side polling was needed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 22:05:13 +02:00
larssand
be9a2de31a Explain a Backend URL/page-origin mismatch instead of a bare fetch error
A real Windows install had sync and backups fail everywhere with
"Failed to fetch" while the server itself was fully healthy - confirmed
via Invoke-WebRequest returning 200 for every endpoint the browser
couldn't reach. The page was opened via a LAN IP while Settings still
had the Backend URL set to 127.0.0.1 from an earlier session; browsers
treat those as different origins, so the server's CORS check correctly
rejected the requests, but a CORS rejection surfaces to fetch() as an
unexplained generic error with no indication of the real cause.

Settings now detects this mismatch on every render and shows the page's
actual address with a one-click button to fix it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-09 12:06:58 +02:00
larssand
a0c3d3039e Separat status och mottagningsräknare för varje kanal.
Senaste råmeddelande, fel och ignoreringsorsaker.
Pausa visning, rensa och kopiera logg.
Uppdateras utan att störa inställningsfält eller tidtagning.
2026-09-08 18:37:47 +02:00
larssand
f561dd8feb new raceday and backup 2026-09-01 07:07:23 +02:00
larssand
5ed193cdeb fix import av csv 2026-08-30 16:14:45 +02:00
larssand
3cf68cf34a branding och namechange 2026-08-28 20:56:58 +02:00
larssand
34e55ff7f6 add custome voice 2026-08-28 13:47:25 +02:00
larssand
fa3e5ee379 add save sound 2026-08-28 13:39:12 +02:00
larssand
5f79228941 Add configurable manifest-driven race audio system 2026-08-28 13:29:27 +02:00
larssand
e5af42ce2d Add CSV imports and granular competition data cleanup 2026-08-27 17:56:50 +02:00
larssand
a87c64a47c Improve decoder setup UI and add configurable training timers 2026-08-27 17:29:44 +02:00
larssand
8ea8b3a84e Add multi-decoder split and pit timing support 2026-08-25 19:45:40 +02:00
larssand
355a1ad3b0 Förbättrat ljudsystemet 2026-08-24 19:40:39 +02:00
larssand
7d6f75422f Modularize overlays, settings and race setup UI 2026-03-25 19:40:02 +01:00