From 7501b46c15bdb3293839bf9fa9c0a33ecc1c0f79 Mon Sep 17 00:00:00 2001 From: Quinta <112334784+Quinta0@users.noreply.github.com> Date: Tue, 28 Apr 2026 20:05:32 +0200 Subject: [PATCH] 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. --- README.md | 267 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) diff --git a/README.md b/README.md index 266b5e5..f2d337d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,269 @@ # 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. + +--- + +## 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