Add Docker support, fix stale docs, translate UI to English

- Dockerfile + docker-compose.yml: two services (recorder + web) sharing
  ./recordings bind mount; recorder maps /dev/snd for ALSA soundcard access
- requirements.txt: requests, numpy, soundfile
- .dockerignore, updated .gitignore (add __pycache__, .pytest_cache)
- isr.py: add SIGTERM handler for clean Docker shutdown; fix stale error
  message that referenced removed PulseAudio/PipeWire/PortAudio backends
- web.py: translate all German UI strings to English
- config.example.ini: remove PipeWire/PulseAudio/PortAudio backend refs,
  simplify soundcard tips to ALSA only
- README.md: full rewrite as user guide (quick start, config reference,
  Docker notes, how it works)
- CLAUDE.md: update architecture section to reflect ALSA-only backend
- Delete changelog.txt and guide.md (internal session notes)
This commit is contained in:
2026-04-26 10:56:55 +02:00
parent da5197d96d
commit 8254ccde86
12 changed files with 2729 additions and 1 deletions
+69
View File
@@ -0,0 +1,69 @@
# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 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).
## Commands
```bash
# Run the recorder
python isr.py # uses config.ini
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
# Stop: Ctrl+C (or docker compose down)
# Install dependencies
pip install requests # for stream recording
pip install numpy soundfile # for FLAC output and web waveform analysis (optional)
# Docker
docker compose up -d
docker compose logs -f
docker compose down
```
## Architecture
### Audio Backend System
- **AudioDevice** — Dataclass: id, name, channels, sample_rate, backend type
- **AudioBackend** (ABC) — Abstract base for audio capture backends
- **ALSABackend** — Native ALSA support via `arecord` subprocess (the only backend)
- **ALSAStream** — Context manager that wraps an `arecord` subprocess and reads PCM in a thread
- **AudioSystem** — Discovers available backends, lists devices, resolves device specs
### Recorder Classes
- **BaseRecorder** (ABC) — Common settings, `get_next_split_time()`, `generate_filename()`, `record()` interface
- **StreamRecorder(BaseRecorder)** — Records HTTP/Icecast streams with format auto-detection and OGG/FLAC header injection
- **SoundcardRecorder(BaseRecorder)** — Records from ALSA devices; outputs WAV or FLAC via `_AudioFileWriter`
- **_AudioFileWriter** — Unified write/close interface for wave (WAV) and soundfile (FLAC)
- **RecorderManager** — Loads config, creates recorders, manages threads, handles shutdown
### Key Implementation Details
- ALSA backend spawns `arecord` as a subprocess; raw PCM is read in 100 ms chunks via a reader thread
- Device selection: `default`, `monitor` (loopback), partial name match, or exact `hw:X,Y` ID
- Thread-safe audio buffering with `threading.Lock()`
- 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
## Configuration
Copy `config.example.ini` to `config.ini`. Each section defines a recording source:
- `type = stream` — HTTP/Icecast stream recording
- `type = soundcard` — ALSA device recording
In Docker, set `output_directory = /recordings` and `log_file = /recordings/recorder.log`.
## Docker
Two services share a `./recordings` bind mount:
- `recorder` — runs `isr.py`, maps `/dev/snd` for ALSA access
- `web` — runs `web.py`, read-only access to recordings, exposes port 8080