diff --git a/CLAUDE.md b/CLAUDE.md index 57f5f87..299fb8c 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +## Rules + +- **Always update `README.md`** whenever user-facing behaviour changes (new flags, new endpoints, changed Docker setup, new features). The README is the primary external reference; CLAUDE.md documents internals. +- **Always commit `README.md`** in the same commit as the code changes it documents — never let the README fall behind. + ## Project Overview ISR is a Python audio recording application that captures from multiple simultaneous sources (Icecast/HTTP streams and ALSA soundcard devices) with time-based file splitting. All application code is in two files: `isr.py` (recorder) and `web.py` (archive browser UI). diff --git a/README.md b/README.md index 43049b5..ff93e95 100644 --- a/README.md +++ b/README.md @@ -33,19 +33,26 @@ python web.py # start web UI at http://localhost:8080 ```bash cp config.example.ini config.ini -# In config.ini set: output_directory = /recordings -# Optionally set: log_file = /recordings/recorder.log +# edit config.ini to add your sources (no path changes needed for Docker) docker compose up -d # recorder starts immediately; web UI at http://:8080 docker compose logs -f # tail logs from both services -docker compose down # graceful stop +docker compose down # graceful stop (waits up to 30 s for files to close) ``` -Recordings land in `./recordings/` on the host (bind-mounted into both containers). +Recordings land in `./recordings/` on the host (bind-mounted into both containers at different internal paths — no config changes required vs. bare-metal). If you only record streams (no soundcard), comment out the `devices` block in `docker-compose.yml`. +**Updating a running deployment:** +```bash +git pull +docker compose down +docker compose up -d --build +``` +`docker compose down` is required — Docker won't apply changed volume mounts to existing containers without recreating them. + --- ## Configuration @@ -56,13 +63,13 @@ If you only record streams (no soundcard), comment out the `devices` block in `d | Key | Default | Description | |-----|---------|-------------| -| `output_directory` | `recordings` | Output path. Use `/recordings` in Docker. | +| `output_directory` | `recordings` | Output path relative to the working directory (or absolute). The Docker setup mounts `./recordings` at `/app/recordings` so this default works unchanged. | | `split_minutes` | `60` | Split into a new file every N minutes, aligned to clock boundaries (e.g. 60 → files start at :00, 30 → at :00 and :30). | | `filename_pattern` | `%Y%m%d_%H%M%S` | strftime pattern; file extension is appended automatically. | | `max_retries` | `10` | Give up after this many consecutive failures per source. | | `retry_delay_seconds` | `5` | Wait between retries. | | `log_level` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` / `CRITICAL` | -| `log_file` | `recorder.log` | Log file path. Use `/recordings/recorder.log` in Docker. | +| `log_file` | `recorder.log` | Log file path. In Docker, logs also go to stdout and are visible via `docker compose logs`. | ### `type = stream` @@ -146,9 +153,12 @@ python web.py --port 8888 # custom port python web.py --threshold 0.03 # loudness threshold 0–1 (default 0.05) ``` -Shows a table of all recordings sorted newest-first with file size, duration (WAV only), and a waveform analysis button. Analysis computes RMS per 100 ms window and highlights contiguous sections above the loudness threshold. +Shows a table of all recordings sorted newest-first. Features: -Waveform analysis is WAV-only; numpy speeds it up significantly (pure-Python fallback available without it). +- **Inline playback** — collapsible `▶ Play` button per row; audio loads lazily via a seekable `/stream/` endpoint with HTTP Range support. +- **Waveform analysis** — on demand per file; computes RMS per 100 ms window and highlights loud sections. Supported for WAV and FLAC (FLAC requires `numpy` + `soundfile`). Pure-Python fallback for WAV when numpy is absent. +- **Live REC badge** — files currently being written by `isr.py` show an animated REC indicator, polled every 5 seconds via `/api/status`. +- **WCAG-compliant** — skip link, `aria-expanded`/`aria-controls` on the player toggle, `aria-live` status, focus management, `role=img` on SVG waveforms. --- @@ -174,7 +184,7 @@ ls -la /dev/snd # check device nodes **Stream-only deployments:** If you don't use soundcard recording, remove the `devices` block from `docker-compose.yml` — the image works fine without it. -**Log file in Docker:** Set `log_file = /recordings/recorder.log` in `config.ini` so logs survive container restarts. Alternatively, use `docker compose logs` (the recorder always logs to stdout as well). +**Log file in Docker:** The recorder always logs to stdout, so `docker compose logs -f` shows live output. To persist logs on the host, set `log_file = /app/recordings/recorder.log` in `config.ini` (the `recordings` directory is the bind mount). **File retention:** ISR never deletes recordings. Add a cron job on the host if needed: ```bash