Enhance README with system overview and setup instructions
Added detailed documentation about the music discovery and streaming system, including components, folder structure, configuration files, automation scripts, and tips for users.
This commit is contained in:
@@ -1,2 +1,269 @@
|
|||||||
# Ainulindale
|
# Ainulindale
|
||||||
A fully self-hosted, automated music discovery and streaming system. No Spotify. No YouTube Music. No ads. Just your music, your server, your rules.
|
A fully self-hosted, automated music discovery and streaming system. No Spotify. No YouTube Music. No ads. Just your music, your server, your rules.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What This Stack Does
|
||||||
|
|
||||||
|
- **Streams** your music library to any device via a Spotify-like interface
|
||||||
|
- **Automatically discovers** new music weekly based on your listening habits
|
||||||
|
- **Downloads** discovered tracks at high quality (FLAC/WAV preferred, 320kbps minimum) from the Soulseek network
|
||||||
|
- **Scrobbles** everything you listen to Last.fm and ListenBrainz
|
||||||
|
- **Routes all P2P traffic through a VPN** so your real IP is never exposed
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
| Component | Role |
|
||||||
|
|---|---|
|
||||||
|
| **Navidrome** | Music server — indexes your library, streams to clients |
|
||||||
|
| **Substreamer** | Mobile app (iOS/Android) — plays music from Navidrome |
|
||||||
|
| **Pangolin** | Reverse proxy — exposes Navidrome securely to the internet |
|
||||||
|
| **Gluetun** | VPN gateway container — all Soulseek traffic exits via ProtonVPN |
|
||||||
|
| **slskd** | Soulseek client — searches and downloads music from the P2P network |
|
||||||
|
| **Explo** | Discovery engine — connects ListenBrainz recommendations to slskd |
|
||||||
|
| **ListenBrainz** | Open-source scrobbler + recommendation engine |
|
||||||
|
| **Last.fm** | Secondary scrobbler for stats and social features |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Folder Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
/mnt/user/appdata/
|
||||||
|
├── gluetun/ ← VPN state (auto-populated)
|
||||||
|
├── slskd/
|
||||||
|
│ └── slskd.yml ← slskd config
|
||||||
|
└── explo/
|
||||||
|
├── .env ← Explo config
|
||||||
|
└── docker-compose.yml ← Full stack compose file
|
||||||
|
|
||||||
|
/mnt/user/data/media/music/
|
||||||
|
├── incomplete/ ← In-progress downloads (Navidrome ignores these)
|
||||||
|
├── explo/ ← Explo-managed discovery downloads
|
||||||
|
└── (your library)/ ← Everything else
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## docker-compose.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
|
||||||
|
gluetun:
|
||||||
|
image: qmcgaw/gluetun:latest
|
||||||
|
container_name: gluetun
|
||||||
|
cap_add:
|
||||||
|
- NET_ADMIN
|
||||||
|
devices:
|
||||||
|
- /dev/net/tun:/dev/net/tun
|
||||||
|
environment:
|
||||||
|
- VPN_SERVICE_PROVIDER=protonvpn
|
||||||
|
- VPN_TYPE=wireguard
|
||||||
|
- WIREGUARD_PRIVATE_KEY=YOUR_PRIVATE_KEY_HERE
|
||||||
|
- WIREGUARD_ADDRESSES=10.2.0.2/32
|
||||||
|
- SERVER_COUNTRIES=Switzerland
|
||||||
|
- TZ=Europe/Zurich
|
||||||
|
ports:
|
||||||
|
- 5030:5030
|
||||||
|
volumes:
|
||||||
|
- /mnt/user/appdata/gluetun:/gluetun
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
slskd:
|
||||||
|
image: slskd/slskd:latest
|
||||||
|
container_name: slskd
|
||||||
|
network_mode: "service:gluetun"
|
||||||
|
depends_on:
|
||||||
|
gluetun:
|
||||||
|
condition: service_healthy
|
||||||
|
environment:
|
||||||
|
- SLSKD_REMOTE_CONFIGURATION=true
|
||||||
|
volumes:
|
||||||
|
- /mnt/user/appdata/slskd:/app
|
||||||
|
- /mnt/user/data/media/music:/downloads
|
||||||
|
- /mnt/user/data/media/music:/music:ro
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
explo-weekly:
|
||||||
|
image: ghcr.io/lumepart/explo:latest
|
||||||
|
container_name: explo-weekly
|
||||||
|
environment:
|
||||||
|
- EXECUTE_ON_START=true
|
||||||
|
- WEEKLY_EXPLORATION_FLAGS=--playlist=weekly-exploration --persist
|
||||||
|
volumes:
|
||||||
|
- /mnt/user/appdata/explo/.env:/opt/explo/.env
|
||||||
|
- /mnt/user/data/media/music/explo:/data
|
||||||
|
- /mnt/user/data/media/music:/slskd
|
||||||
|
restart: "no"
|
||||||
|
|
||||||
|
explo-daily:
|
||||||
|
image: ghcr.io/lumepart/explo:latest
|
||||||
|
container_name: explo-daily
|
||||||
|
environment:
|
||||||
|
- EXECUTE_ON_START=true
|
||||||
|
- DAILY_JAMS_FLAGS=--playlist=daily-jams --download-mode=skip
|
||||||
|
volumes:
|
||||||
|
- /mnt/user/appdata/explo/.env:/opt/explo/.env
|
||||||
|
- /mnt/user/data/media/music/explo:/data
|
||||||
|
- /mnt/user/data/media/music:/slskd
|
||||||
|
restart: "no"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Explo .env
|
||||||
|
|
||||||
|
```env
|
||||||
|
# --- Discovery ---
|
||||||
|
DISCOVERY_SERVICE=listenbrainz
|
||||||
|
LISTENBRAINZ_USER=your_listenbrainz_username
|
||||||
|
LISTENBRAINZ_DISCOVERY=playlist
|
||||||
|
|
||||||
|
# --- Navidrome (Subsonic API) ---
|
||||||
|
EXPLO_SYSTEM=subsonic
|
||||||
|
SYSTEM_URL=http://192.168.1.x:4533
|
||||||
|
SYSTEM_USERNAME=your_navidrome_username
|
||||||
|
SYSTEM_PASSWORD=your_navidrome_password
|
||||||
|
|
||||||
|
# --- Downloaders (slskd first, YouTube fallback) ---
|
||||||
|
DOWNLOAD_SERVICES=slskd,youtube
|
||||||
|
TRACK_EXTENSION=mp3
|
||||||
|
|
||||||
|
# --- slskd ---
|
||||||
|
SLSKD_URL=http://slskd:5030
|
||||||
|
SLSKD_API_KEY=your_slskd_api_key
|
||||||
|
MIGRATE_DOWNLOADS=true
|
||||||
|
RENAME_TRACK=true
|
||||||
|
|
||||||
|
# --- Quality gates (FLAC/WAV preferred, 320kbps minimum) ---
|
||||||
|
EXTENSIONS=flac,wav,mp3
|
||||||
|
MIN_BITRATE=320
|
||||||
|
MIN_BIT_DEPTH=16
|
||||||
|
|
||||||
|
# --- YouTube fallback (optional) ---
|
||||||
|
YOUTUBE_API_KEY=your_youtube_api_key
|
||||||
|
|
||||||
|
# --- Misc ---
|
||||||
|
SLEEP=2
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## slskd.yml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
soulseek:
|
||||||
|
username: your_soulseek_username
|
||||||
|
password: your_soulseek_password
|
||||||
|
|
||||||
|
web:
|
||||||
|
authentication:
|
||||||
|
username: your_chosen_web_username
|
||||||
|
password: your_chosen_web_password
|
||||||
|
api_keys:
|
||||||
|
explo_key:
|
||||||
|
key: your_api_key_minimum_16_chars_long
|
||||||
|
role: readwrite
|
||||||
|
cidr: 0.0.0.0/0,::/0
|
||||||
|
|
||||||
|
directories:
|
||||||
|
incomplete: /downloads/incomplete
|
||||||
|
downloads: /downloads
|
||||||
|
|
||||||
|
transfers:
|
||||||
|
download:
|
||||||
|
slots: 50
|
||||||
|
upload:
|
||||||
|
slots: 20
|
||||||
|
|
||||||
|
shares:
|
||||||
|
directories:
|
||||||
|
- /music
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Navidrome (Unraid Community Apps)
|
||||||
|
|
||||||
|
Navidrome is installed via Unraid's Community Apps store. Add these extra environment variables in the container template:
|
||||||
|
|
||||||
|
| Variable | Value |
|
||||||
|
|---|---|
|
||||||
|
| `ND_LASTFM_APIKEY` | your Last.fm API key |
|
||||||
|
| `ND_LASTFM_SECRET` | your Last.fm shared secret |
|
||||||
|
| `ND_LASTFM_ENABLED` | `true` |
|
||||||
|
| `ND_SCANSCHEDULE` | `1m` |
|
||||||
|
|
||||||
|
Last.fm API credentials: [last.fm/api/account/create](https://www.last.fm/api/account/create)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Automation — Unraid User Scripts
|
||||||
|
|
||||||
|
Install the **User Scripts** plugin from Community Apps, then add two scripts:
|
||||||
|
|
||||||
|
### Weekly Exploration (every Tuesday at 00:15)
|
||||||
|
Cron: `15 0 * * 2`
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
docker compose -f /mnt/user/appdata/explo/docker-compose.yml up explo-weekly
|
||||||
|
```
|
||||||
|
|
||||||
|
### Daily Jams (every day at 00:15)
|
||||||
|
Cron: `15 0 * * *`
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
docker compose -f /mnt/user/appdata/explo/docker-compose.yml up explo-daily
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## How Discovery Works
|
||||||
|
|
||||||
|
```
|
||||||
|
You listen in Substreamer
|
||||||
|
↓
|
||||||
|
Navidrome scrobbles to Last.fm + ListenBrainz
|
||||||
|
↓
|
||||||
|
ListenBrainz builds your taste profile over time
|
||||||
|
↓
|
||||||
|
Every Monday night: ListenBrainz generates Weekly Exploration playlist
|
||||||
|
↓
|
||||||
|
Tuesday 00:15: Explo pulls recommendations
|
||||||
|
↓
|
||||||
|
slskd searches Soulseek network (behind ProtonVPN)
|
||||||
|
↓
|
||||||
|
Downloads FLAC/WAV/320kbps+ to /mnt/user/data/media/music
|
||||||
|
↓
|
||||||
|
Navidrome scans every 1 minute → appears in Substreamer
|
||||||
|
↓
|
||||||
|
You discover new music 🎵
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tips
|
||||||
|
|
||||||
|
- **ListenBrainz needs time** — it takes a few weeks of scrobbling before Weekly Exploration playlists are generated. Speed this up by importing your Google Takeout YouTube Music watch history via [ytm-extractor](https://community.metabrainz.org/t/ytm-extractor-import-youtube-music-listens-to-listenbrainz/707619).
|
||||||
|
- **Manual downloads** — search for any artist or album directly in the slskd web UI at `http://your-nas-ip:5030`. Downloads land straight in your Navidrome library.
|
||||||
|
- **Playlist import** — use [Soundiiz](https://soundiiz.com) to transfer playlists from YouTube Music/Spotify directly into Navidrome. Tracks already in your library get matched automatically.
|
||||||
|
- **Quality** — slskd is tried first for every download. YouTube is only used as a last resort fallback for tracks not found on Soulseek.
|
||||||
|
- **Sharing** — slskd shares your music library back to the Soulseek network. The more you share, the better your download priority from other peers.
|
||||||
|
- **ProtonVPN** — the WireGuard private key in Gluetun pins you to a specific server. Make sure to use a P2P-capable server when generating your WireGuard config on ProtonVPN's site.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Unraid NAS (or any Linux server with Docker)
|
||||||
|
- ProtonVPN account (paid, for P2P/WireGuard support)
|
||||||
|
- Soulseek account — free at [slsknet.org](https://www.slsknet.org)
|
||||||
|
- ListenBrainz account — free at [listenbrainz.org](https://listenbrainz.org)
|
||||||
|
- Last.fm account — free at [last.fm](https://www.last.fm)
|
||||||
|
- Last.fm API key — free at [last.fm/api](https://www.last.fm/api/account/create)
|
||||||
|
- Substreamer app on your phone
|
||||||
|
- Pangolin or any reverse proxy for external access
|
||||||
|
|||||||
Reference in New Issue
Block a user