Milestone 3: Navidrome (OpenSubsonic) playback provider
Replace the directory-scan queue with a real ingestion pipeline: provider -> fetcher -> cache -> ready queue, driven by a background prefetch thread. - subsonic.py: minimal OpenSubsonic client (salted-token auth, getPlaylists/getPlaylist, raw streaming download). - providers/navidrome.py: pick tracks from a playlist (by name or id), with anti-repeat and periodic playlist reload. - fetchers/subsonic.py: atomic download into the shared cache. - db.py: SQLite state — append-only play history (anti-repeat + stats) and cache_files LRU retention (keep the N most recently played). - queue.py: prefetch buffer + retention on play; graceful degradation to the stream's local-cache fallback when no source is configured. - api.py: GET /next now carries real title/artist metadata. - Config via .env (Navidrome credentials), persistent state/ volume, httpx dependency. Verified end-to-end against a live Navidrome: playlist resolved, tracks downloaded and broadcast, retention and history correct. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
f8eb0655eb
commit
8c27498632
17 changed files with 594 additions and 71 deletions
40
README.md
40
README.md
|
|
@ -46,29 +46,43 @@ The stream is MP3 at 192 kbps. Multiple clients can listen at the same time.
|
|||
New files dropped into `cache/` are picked up automatically (the playlist is
|
||||
reloaded when the directory changes).
|
||||
|
||||
## Configuration
|
||||
|
||||
Copy `.env.example` to `.env` and fill in your Navidrome details:
|
||||
|
||||
```sh
|
||||
cp .env.example .env
|
||||
# edit .env: RADIEO_NAVIDROME_URL / USER / PASSWORD / PLAYLIST
|
||||
```
|
||||
|
||||
If the Navidrome variables are left empty, the source is simply disabled and
|
||||
the stream plays whatever is already in `cache/` (the milestone-1/2 behaviour).
|
||||
|
||||
## Current status
|
||||
|
||||
**Milestone 2 — ingestion daemon: done.**
|
||||
**Milestone 3 — Navidrome provider: done.**
|
||||
|
||||
- `ingest` (Python) container exposes `GET /next`, returning the next track as
|
||||
an annotated Liquidsoap URI (or an empty body when nothing is ready).
|
||||
- `stream` (Liquidsoap v2.4.5) pulls from `ingest` via a `request.dynamic`
|
||||
source, and falls back to the local `cache/` directory when the daemon has
|
||||
nothing to offer.
|
||||
- HTTP stream served at `http://localhost:8000/radio.mp3` (MP3, 192 kbps).
|
||||
- Continuous output guaranteed: silence rather than a crash when everything is
|
||||
empty (`mksafe`).
|
||||
- Multiple simultaneous listeners supported.
|
||||
- `ingest` pulls tracks from an OpenSubsonic playlist (Navidrome), downloading
|
||||
them into the shared cache ahead of playback (prefetch buffer).
|
||||
- Play history and LRU retention are tracked in a SQLite database under
|
||||
`state/`: only the N most recently played files are kept on disk
|
||||
(`RADIEO_RETENTION_KEEP`, default 20); anti-repeat avoids replaying a track
|
||||
seen among the last plays.
|
||||
- `GET /next` returns the next track as an annotated Liquidsoap URI with real
|
||||
title/artist metadata (or an empty body when nothing is ready).
|
||||
- `stream` (Liquidsoap v2.4.5) pulls via `request.dynamic` and falls back to the
|
||||
local `cache/` directory; `mksafe` guarantees silence rather than a crash.
|
||||
- HTTP stream served at `http://localhost:8000/radio.mp3` (MP3, 192 kbps),
|
||||
multiple simultaneous listeners supported.
|
||||
|
||||
At this stage the daemon just cycles through the files already in `cache/`; the
|
||||
download providers (Navidrome, yt-dlp, ListenBrainz) come next.
|
||||
The yt-dlp and ListenBrainz sources come next.
|
||||
|
||||
## Roadmap
|
||||
|
||||
1. ✅ **Broadcasting skeleton** — Liquidsoap serving the cache directory.
|
||||
2. ✅ **Ingestion daemon** — Python daemon exposing `GET /next`; Liquidsoap
|
||||
switches to a `request.dynamic` source with the cache as fallback.
|
||||
3. **Navidrome provider** — play from an OpenSubsonic playlist, with caching,
|
||||
3. ✅ **Navidrome provider** — play from an OpenSubsonic playlist, with caching,
|
||||
LRU retention and play history.
|
||||
4. **yt-dlp provider** — fetch tracks from a maintained URL/artist list; weighted
|
||||
mixing between sources.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue