From da675231709333e4fc4ce6ad903bd39377e18993 Mon Sep 17 00:00:00 2001 From: Jonathan Schuster Date: Sun, 26 Apr 2026 13:10:14 +0200 Subject: [PATCH] fix: Docker volume path, graceful shutdown deadline, inline stream headers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit docker-compose.yml: mount ./recordings at /app/recordings (matches output_directory = recordings in config.ini); previously the recorder wrote to /app/recordings while the web container read from /recordings, causing all files to appear missing — explaining the 9-byte Not-found download from /stream/ and the 0-byte recordings in the UI. Add stop_grace_period: 30s so Docker waits long enough for files to close. isr.py: replace per-thread join(timeout=5) with a shared 25 s deadline; with N recorders the old code could exceed Docker's SIGKILL window and leave WAV/FLAC files unclosed (corrupt headers). web.py: add Content-Disposition: inline to /stream/ responses so browsers never treat the audio response as a file download. CLAUDE.md: document web.py endpoints, status.json lifecycle, corrected Docker volume layout, and web.py CLI flags. --- CLAUDE.md | 22 +++++++++++++++++----- docker-compose.yml | 3 ++- isr.py | 6 +++++- web.py | 2 ++ 4 files changed, 26 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e1b6473..57f5f87 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,8 +15,10 @@ python isr.py myconfig.ini # custom config file python isr.py --list-devices # list available ALSA devices # Run the web UI -python web.py # http://localhost:8080 -python web.py --dir recordings # custom recordings directory +python web.py # http://localhost:8080 +python web.py --dir recordings # custom recordings directory +python web.py --port 8888 # custom port +python web.py --threshold 0.03 # loudness threshold (0-1, default 0.05) # Stop: Ctrl+C (or docker compose down) @@ -53,6 +55,16 @@ docker compose down - OGG/Opus/FLAC headers captured from first ~16 KB of stream and prepended to each split file - File splits aligned to time period boundaries (`get_next_split_time()`) - SIGTERM handled in `main()` so Docker `docker compose down` shuts down cleanly +- `RecorderManager._write_status()` atomically writes `recordings/status.json` every 2 s while running; deleted on clean shutdown so the web UI shows no stale active-recording badges + +### Web UI (web.py) +- **`GET /`** — Single-page archive table; lists all recordings sorted newest first +- **`GET /api/files`** — JSON list of file metadata (name, size, date, duration, ext, recording flag) +- **`GET /api/analyze?file=`** — RMS loudness analysis for WAV and FLAC files; returns waveform data, loud sections, and duration. Requires `numpy` and `soundfile` for FLAC. +- **`GET /api/status`** — Returns `{"active": [...]}` from `status.json`; used by the UI to animate the REC badge on in-progress files (polled every 5 s) +- **`GET /stream/`** — Serves audio for inline `