# radieo A personal music radio: an always-on HTTP audio stream, automatically fed from several sources and broadcast with [Liquidsoap](https://www.liquidsoap.info/). The goal is a hassle-free stream that always has something playing, where the next track is picked automatically. It is meant for personal use (a couple of simultaneous listeners), not for public broadcasting. ## How it works radieo is built as two layers, each running in its own Docker container and sharing a cache volume: - **`ingest`** (Python) — the brain. It decides what to play next, resolves and downloads tracks into a local cache, keeps a pre-filled queue, and exposes the next track over HTTP at `GET /next`. *(currently it only serves the cache directory; the download providers come in later milestones — see roadmap)* - **`stream`** (Liquidsoap) — deliberately dumb. It pulls the next track from the `ingest` daemon, broadcasts the audio over HTTP, and falls back to the already-aired tracks (via `/fallback.m3u`) if the daemon has nothing ready. Playback sources (planned): a [Navidrome](https://www.navidrome.org/) library via the OpenSubsonic API, arbitrary tracks fetched with [yt-dlp](https://github.com/yt-dlp/yt-dlp) (Bandcamp, SoundCloud, YouTube…), and listening suggestions from a ListenBrainz RSS feed. ## Usage Requirements: Docker with Compose v2. ```sh # Drop some .mp3 files into the cache directory cp /path/to/music/*.mp3 cache/ # Build and start the stream docker compose up -d # Listen (VLC, a browser, any audio player) # http://localhost:8000/radio.mp3 ``` Stop it with `docker compose down`. 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). For the yt-dlp source, list the URLs to draw from in `config/urls.txt` (copy `config/urls.txt.example`). Each line is either a direct track URL or a container URL (playlist, album, label, artist page) from which one track is picked at random. For the ListenBrainz source, set `RADIEO_LISTENBRAINZ_URL` to your recommendations feed (the Atom syndication URL, e.g. `https://listenbrainz.org/syndication-feed/user//recommendations/weekly-exploration`, or a local file path under `config/` for testing). ListenBrainz only *names* tracks, so each suggestion is resolved to a real file: Navidrome first (a `search3` lookup), then yt-dlp (`ytsearch1:`) as a fallback. The MusicBrainz recording MBID that the feed already carries is used as the track's canonical identity (no extra lookup needed). The relative mix between sources is set by `RADIEO_WEIGHT_NAVIDROME` / `RADIEO_WEIGHT_YTDLP` / `RADIEO_WEIGHT_LISTENBRAINZ` (a weight of 0 disables a source); an empty URL / missing file also disables the corresponding source. Open the player at `http://localhost:8000/` — a small web page with an `