- Replace blocking stdout.read() with select()-based non-blocking reads
so the decode thread responds to stop within 0.5s
- Make stop() non-blocking by releasing the lock before terminating the
process and removing the redundant wait()
- Move initial scanning SSE event from start() into the decode thread so
it fires after the frontend EventSource connects
- Update frontend stop() to give immediate UI feedback before the fetch
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
rtl_fm subprocess failures (missing tool, no SDR hardware) were silent —
add tool-path check and post-spawn health check in _start_pipeline(),
show errors prominently in the strip status bar (red text + red dot),
and include error detail in scheduler skip events.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flash the Start button itself with amber pulse when clicked without a
station selected, and show "Select Station" in the strip status text
right next to the button so the error is immediately visible.
Add a 24-hour timeline bar with broadcast window markers, red UTC time
cursor, and countdown boxes (HRS/MIN/SEC) that tick down to the next
broadcast. Broadcasts show as amber blocks on the timeline track with
imminent/active visual states matching the weather satellite pattern.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix silent failure when starting without station/frequency selected by
flashing amber on status text and dropdowns. Add auto-capture scheduler
that uses fixed UTC broadcast schedules from station data to
automatically start/stop WeFax decoding at broadcast times.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implement HF radiofax decoding with custom Python DSP pipeline
(rtl_fm USB → Goertzel/Hilbert demodulation), 33-station database
with broadcast schedules, audio waveform scope, live image preview,
and decoded image gallery. Amber/gold UI theme for HF distinction.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>