diff --git a/docker-compose.yml b/docker-compose.yml index cc7356b..e2323fc 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,3 +8,13 @@ services: volumes: - ./rtl_airband.conf:/app/rtl_airband.conf:ro - /home/m/recordings:/recordings + + web: + image: nginx:alpine + container_name: sdr-web + restart: unless-stopped + ports: + - "8080:80" + volumes: + - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro + - /home/m/recordings:/recordings:ro diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 0000000..8ff264e --- /dev/null +++ b/nginx.conf @@ -0,0 +1,8 @@ +server { + listen 80; + + location / { + alias /recordings/; + autoindex on; + } +} diff --git a/openspec/changes/archive/2026-03-19-web-hosting-recordings/.openspec.yaml b/openspec/changes/archive/2026-03-19-web-hosting-recordings/.openspec.yaml new file mode 100644 index 0000000..4e61834 --- /dev/null +++ b/openspec/changes/archive/2026-03-19-web-hosting-recordings/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-03-19 diff --git a/openspec/changes/archive/2026-03-19-web-hosting-recordings/design.md b/openspec/changes/archive/2026-03-19-web-hosting-recordings/design.md new file mode 100644 index 0000000..ba0665f --- /dev/null +++ b/openspec/changes/archive/2026-03-19-web-hosting-recordings/design.md @@ -0,0 +1,34 @@ +## Context + +RTLSDR-Airband records CB transmissions as MP3 files into `/home/m/recordings/` on the Pi, organized by channel subdirectories with dated subdirectories inside. The recorder runs as a Docker container via `docker-compose.yml`. + +## Goals / Non-Goals + +**Goals:** +- Serve the recordings directory over HTTP with browsable directory listings +- Allow MP3 playback via the browser's native audio handling +- Deploy as a Docker container alongside the existing `sdr-recorder` service + +**Non-Goals:** +- Custom web UI, styling, or JavaScript +- Authentication (local network only) +- Modifying, uploading, or deleting recordings +- Live streaming or transcription + +## Decisions + +### Use Nginx with HTML autoindex, no custom frontend + +**Decision**: Use `nginx:alpine` with `autoindex on` to serve the recordings directory. No custom HTML, JS, or CSS. + +**Rationale**: Nginx's built-in directory listing is fully functional for browsing channel/date directories. Modern browsers play MP3 files natively when clicked. This requires only an Nginx config file and a docker-compose service — zero application code. + +**Alternatives considered**: +- **Custom SPA frontend**: Adds complexity (build tools, JS code) for marginal UX improvement over native directory listing. +- **Python http.server**: Simpler but less performant and no Alpine image parity. + +## Risks / Trade-offs + +- **[No search or filtering]** → Users browse by directory structure. Acceptable given the channel/date organization. +- **[Plain directory listing]** → No styled UI. Acceptable for a local utility tool. +- **[No auth]** → Anyone on the LAN can access. Acceptable per non-goals. diff --git a/openspec/changes/archive/2026-03-19-web-hosting-recordings/proposal.md b/openspec/changes/archive/2026-03-19-web-hosting-recordings/proposal.md new file mode 100644 index 0000000..9555a86 --- /dev/null +++ b/openspec/changes/archive/2026-03-19-web-hosting-recordings/proposal.md @@ -0,0 +1,23 @@ +## Why + +Recordings from the RTLSDR-Airband CB scanner are stored as MP3 files on the Pi's filesystem (`/home/m/recordings/`), organized by channel and date. There's currently no way to browse or listen to them without SSH access. A web server with directory listing would make recordings browsable and playable from any device on the local network. + +## What Changes + +- Add an Nginx container to `docker-compose.yml` that serves the recordings directory with autoindex enabled +- Users browse directories and click MP3 files to play them natively in the browser + +## Capabilities + +### New Capabilities +- `recording-browser`: Nginx autoindex serving the recordings directory over HTTP, with browser-native MP3 playback + +### Modified Capabilities + +_(none)_ + +## Impact + +- **Docker deployment**: New Nginx service added to `docker-compose.yml`, sharing the `/home/m/recordings` volume (read-only) +- **Pi resources**: Negligible — Nginx Alpine uses ~2MB RAM +- **Network**: Exposes HTTP port on the Pi's local network diff --git a/openspec/changes/archive/2026-03-19-web-hosting-recordings/specs/recording-browser/spec.md b/openspec/changes/archive/2026-03-19-web-hosting-recordings/specs/recording-browser/spec.md new file mode 100644 index 0000000..6e0e23d --- /dev/null +++ b/openspec/changes/archive/2026-03-19-web-hosting-recordings/specs/recording-browser/spec.md @@ -0,0 +1,34 @@ +## ADDED Requirements + +### Requirement: Serve recordings directory over HTTP +The system SHALL serve the contents of the recordings directory via an Nginx web server with directory listing enabled. + +#### Scenario: Browse channel directories +- **WHEN** a user navigates to the root URL of the web server +- **THEN** the server displays a directory listing showing the channel subdirectories + +#### Scenario: Browse date directories within a channel +- **WHEN** a user clicks a channel directory +- **THEN** the server displays a directory listing of date subdirectories for that channel + +#### Scenario: Browse recording files within a date +- **WHEN** a user clicks a date directory +- **THEN** the server displays a listing of MP3 recording files + +### Requirement: Browser-native MP3 playback +The system SHALL serve MP3 files with correct MIME type so browsers can play them natively. + +#### Scenario: Play a recording +- **WHEN** a user clicks an MP3 file link in the directory listing +- **THEN** the browser opens and plays the MP3 file using its native audio player + +### Requirement: Docker deployment +The web server SHALL run as a Docker container defined in `docker-compose.yml`, mounting the recordings directory read-only. + +#### Scenario: Start alongside recorder +- **WHEN** a user runs `docker compose up` on the Pi +- **THEN** the Nginx service starts alongside the `sdr-recorder` service and is accessible via HTTP + +#### Scenario: Read-only access to recordings +- **WHEN** the Nginx container accesses the recordings volume +- **THEN** the volume is mounted read-only, preventing modification of recording files diff --git a/openspec/changes/archive/2026-03-19-web-hosting-recordings/tasks.md b/openspec/changes/archive/2026-03-19-web-hosting-recordings/tasks.md new file mode 100644 index 0000000..4e2ca93 --- /dev/null +++ b/openspec/changes/archive/2026-03-19-web-hosting-recordings/tasks.md @@ -0,0 +1,11 @@ +## 1. Nginx Configuration + +- [x] 1.1 Create `nginx.conf` with a server block that serves `/recordings` with `autoindex on` and correct MIME type for MP3 files + +## 2. Docker Integration + +- [x] 2.1 Add an `nginx` service to `docker-compose.yml` using `nginx:alpine`, mounting `/home/m/recordings` to `/recordings:ro` and `./nginx.conf` to the Nginx config path, exposing port 8080 + +## 3. Deploy and Verify + +- [x] 3.1 Deploy to the Pi and verify directory browsing and MP3 playback work at `http://sdr-pi:8080` diff --git a/openspec/specs/recording-browser/spec.md b/openspec/specs/recording-browser/spec.md new file mode 100644 index 0000000..e44459e --- /dev/null +++ b/openspec/specs/recording-browser/spec.md @@ -0,0 +1,32 @@ +### Requirement: Serve recordings directory over HTTP +The system SHALL serve the contents of the recordings directory via an Nginx web server with directory listing enabled. + +#### Scenario: Browse channel directories +- **WHEN** a user navigates to the root URL of the web server +- **THEN** the server displays a directory listing showing the channel subdirectories + +#### Scenario: Browse date directories within a channel +- **WHEN** a user clicks a channel directory +- **THEN** the server displays a directory listing of date subdirectories for that channel + +#### Scenario: Browse recording files within a date +- **WHEN** a user clicks a date directory +- **THEN** the server displays a listing of MP3 recording files + +### Requirement: Browser-native MP3 playback +The system SHALL serve MP3 files with correct MIME type so browsers can play them natively. + +#### Scenario: Play a recording +- **WHEN** a user clicks an MP3 file link in the directory listing +- **THEN** the browser opens and plays the MP3 file using its native audio player + +### Requirement: Docker deployment +The web server SHALL run as a Docker container defined in `docker-compose.yml`, mounting the recordings directory read-only. + +#### Scenario: Start alongside recorder +- **WHEN** a user runs `docker compose up` on the Pi +- **THEN** the Nginx service starts alongside the `sdr-recorder` service and is accessible via HTTP + +#### Scenario: Read-only access to recordings +- **WHEN** the Nginx container accesses the recordings volume +- **THEN** the volume is mounted read-only, preventing modification of recording files