# Explo: ListenBrainz-Driven Music Discovery for Navidrome, Jellyfin and Subsonic

> Explo is a Go service that pulls ListenBrainz recommendation playlists, downloads the missing tracks through yt-dlp, Soulseek or Lidarr, and writes the result back into your self-hosted music system. It is useful if you already scrobble; it is close to useless if you do not.

**LumePart/Explo** — Spotify's "Discover Weekly" for self-hosted music systems

- Repository: https://github.com/LumePart/Explo
- Stars: 2,001 · Forks: 51
- Language: Go
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/lumepart-explo

## The gap Explo fills between ListenBrainz and your music server

ListenBrainz already produces recommendation playlists. The README names three: Weekly Exploration, Weekly Jams and Daily Jams. What it does not do is put the audio on your disk. You get a list of recording IDs, and the work of turning that list into files your Navidrome, Jellyfin, Emby, Plex, Airsonic or MPD instance can play is left to you.

Explo is the automation layer for that gap. The README describes its main function as acting as a self-hosted alternative to Spotify's Discover Weekly, automating discovery from your listening history. The intended user is someone who runs a music server, scrobbles to ListenBrainz, and wants a scheduled job that ends with a new playlist in the library rather than a browser tab full of track names. The repository topics list the target systems directly: airsonic, emby, jellyfin, listenbrainz, mpd, navidrome, plex-media-server, subsonic.

There is a second, less obvious use case in the feature list. Explo can also import custom playlists from Apple Music, ListenBrainz and Spotify. That makes it a general playlist-to-library pipeline, not only a recommendation engine. If your problem is "I have a playlist somewhere and half the tracks are not in my library", that is the same pipeline with a different source.

## How the pipeline works: recommend, match, download, tag, publish

The data flow visible in the repository is a chain of stages, each of which can fail on its own.

First, Explo fetches a recommendation or custom playlist. For recommendations this is the ListenBrainz API. For custom imports the sources are Apple Music, ListenBrainz and Spotify.

Second, it diffs the playlist against what you already have, then requests the missing tracks. The README gives three acquisition routes: YouTube and Soulseek for individual tracks, or albums through Lidarr. The Dockerfile shows how the YouTube route is wired: the runtime image is python:3.12-alpine with ffmpeg, yt-dlp and ytmusicapi installed via apk and pip, and a helper script copied to the working directory as search_ytmusic.py. The Go side is bound to yt-dlp through the goutubedl wrapper and to FFmpeg through ffmpeg-go, both listed in the acknowledgements.

Third, downloaded tracks get metadata added. Fourth, Explo creates playlists in your music system. Optionally it keeps previous playlists for later listening.

Scheduling is internal. The go.mod requires gocron v2, and the README's acknowledgement list calls it "Internal cron scheduling". The docker-compose file comments the older WEEKLY_EXPLORATION_SCHEDULE, WEEKLY_JAMS_SCHEDULE and DAILY_JAMS_SCHEDULE variables as legacy, noting that schedules are managed through the web UI and that the environment variables take precedence over the UI when set. That precedence rule is worth reading twice: a leftover line in your .env silently overrides whatever you configure in the browser.

Configuration is loaded by cleanenv and godotenv, so a .env file is the expected input. The compose file mounts it at /opt/explo/.env.

## Installing Explo with Docker Compose

The README points to the wiki Quick Start for running Explo with Docker, and the repository ships a docker-compose.yaml. The image is published as ghcr.io/lumepart/explo:latest on port 7288.

The compose file expects three mounts. The .env file, a config directory that the comment marks as required because it stores the playlist cache and cover art, and a music folder. The music path has a constraint worth quoting: it "has to be in the same path you have your music system pointed to", and the comment recommends putting Explo under a subfolder. In other words, the container writes into the library the server is already scanning, so both processes must agree on the path.

```yaml
services:
  explo:
    image: ghcr.io/lumepart/explo:latest
    restart: unless-stopped
    ports:
      - "7288:7288"
    volumes:
      - /path/to/.env:/opt/explo/.env
      - /path/to/explo/config:/opt/explo/config
      - /path/to/musiclibrary/explo:/data/
```

Two environment variables matter at first start. TZ should match the timezone set in ListenBrainz, since the compose comment notes the default is UTC. WEB_UI=true enables the browser interface. PUID and PGID default to root (0:0) for backwards compatibility, and the comment recommends setting them to the owner of your music and data folders instead.

```yaml
    environment:
      - TZ=UTC
      - WEB_UI=true
      - PUID=0
      - PGID=0
```

After docker compose up, the web UI is on port 7288. The UI_USERNAME and UI_PASSWORD variables are described as optional credentials. The README does not document what happens when they are left unset, so treat exposure of that port as a decision you make deliberately rather than one the documentation makes for you.

If you run Kubernetes, the README gives the Helm route directly:

```bash
helm repo add explo https://lumepart.github.io/Explo && helm repo update
helm install explo explo/explo --namespace explo --create-namespace
```

## Where Explo breaks, and when it is the wrong tool

The dependency on ListenBrainz is the sharpest limitation. Explo reads recommendations from ListenBrainz, not from your media server. If your play counts live inside Plex or Jellyfin and never reach ListenBrainz, the recommendation side has nothing to work with and you are left with the custom playlist import feature. The README does not describe any fallback that derives recommendations from local playback data.

The acquisition stage is the second weak point. YouTube and Soulseek are not catalogue sources with stable metadata; they are search-and-download routes, and the Dockerfile shows the YouTube path depends on yt-dlp and ytmusicapi inside the container. The compose file includes a commented volume for an optional cookies.txt file "for yt-dlp", which tells you that unauthenticated requests are not always sufficient. The same file has commented mounts for slskd and Lidarr downloads gated behind SLSKD_MIGRATE_DOWNLOADS and LIDARR_MIGRATE_DOWNLOADS. When those flags are set, the download directories must be mounted, or the migration step has nothing to read.

MPD users have an extra constraint. The compose file shows a commented volume where both sides of the mapping must be the same path, as defined in .env. A path mismatch there is a silent failure mode rather than a startup error.

Finally, the legacy schedule variables. Because they take precedence over the web UI, a migration from an older installation can leave you editing the wrong place. The README does not document a deprecation removal date for them.

Where Explo is simply the wrong tool: if you want to keep a curated library and never let software write into it, or if you have no interest in running a download client alongside your media server, the pipeline has no mode that only suggests tracks.

## Explo compared with the manual ListenBrainz playlist route

The realistic alternative is not another self-hosted discovery daemon. It is doing the same job by hand: take the ListenBrainz recommendation playlist, export it, and feed the missing tracks into whatever download tool you already run, then import the result.

The difference is where the state lives. The manual route keeps a human in the loop at every step, and the failure mode is your own time. Explo moves the schedule, the diffing, the metadata tagging and the playlist creation into one service with a web UI, and the failure mode becomes a container that ran at 01:15 and produced a partially filled playlist. Explo also persists state: the compose comment says the config volume stores the playlist cache and cover art, which is what lets it avoid re-downloading tracks across runs and optionally keep previous playlists.

A second alternative is Lidarr alone. Explo's README lists "albums through Lidarr" as one of its acquisition routes, so Lidarr is a component rather than a competitor in that configuration. If your library is album-oriented and you do not want track-level downloads from YouTube or Soulseek, driving Lidarr directly gives you the same acquisition path without the recommendation layer. You lose the ListenBrainz diffing and the automatic playlist creation, which is exactly the part Explo adds.

## Maintenance, releases and the MIT licence

The repository is not archived, and the last push was on 2026-09-09. Releases are frequent enough to suggest a maintained project: v1.1.2 on 2026-06-16, v1.1.3 on 2026-07-23, and v1.2.0 on 2026-09-09, the same day as the last push. The default branch is dev, so if you build from source rather than pulling the published image, you are tracking a development branch.

Upgrade cost is mostly the container image plus a Go 1.25 toolchain if you build locally. The runtime image carries ffmpeg, yt-dlp and ytmusicapi, which means two of your dependencies move on their own schedule: yt-dlp breaks when YouTube changes, and pip installs during the image build are not pinned in the Dockerfile. Rebuilding the image is therefore part of routine maintenance, not something you do once. The go.mod pins the Go dependencies, including gocron v2.21.1, goutubedl and ffmpeg-go, so the Go side is more predictable than the Python side.

The project is MIT licensed, and the repository carries both a LICENSE file and a licences/ directory. MIT covers Explo's own code. It does not cover the audio the pipeline retrieves, the metadata it writes, or the third-party tools it calls. Downloading tracks from YouTube or Soulseek and writing them into a library raises questions the licence text cannot answer, and this article is not legal advice. The NOTICE file and the licences/ directory are the places to look for the third-party terms that ship with the project.

## Conclusion

Adopt Explo if you already scrobble to ListenBrainz, run a Subsonic-compatible server, and are willing to give a container write access to a subfolder of your music library plus a download client. Do not adopt it if your listening history lives only in Plex or Jellyfin, because the recommendation engine reads ListenBrainz, not your media server. Before you commit, verify three things: that your server is listed in the wiki's supported systems table, that PUID and PGID match the owner of the music folder, and that the config volume is mounted, since the compose file marks it required for the playlist cache and cover art.

## FAQ

### What is Explo used for?

It automates music discovery for self-hosted music systems, acting as a self-hosted alternative to Spotify's Discover Weekly. It fetches personalized playlists from ListenBrainz, downloads the missing tracks through YouTube, Soulseek or Lidarr, and creates the playlist in your music system.

### How is Explo different from a virus?

Explo is an open source Go application published under the MIT licence, distributed as a container image at ghcr.io/lumepart/explo and as a Helm chart. It runs as a service you configure, with its own web UI on port 7288, and it writes into the music library path you mount for it.

### How do I install Explo?

The README points to the wiki Quick Start for running it with Docker, and the repository ships a docker-compose.yaml using the ghcr.io/lumepart/explo:latest image on port 7288. Kubernetes users can add the Helm repository at https://lumepart.github.io/Explo and install the explo chart.

### Which music systems does Explo support?

The repository topics list airsonic, emby, jellyfin, listenbrainz, mpd, navidrome, plex-media-server and subsonic. The README directs readers to the wiki for an overview of supported systems.

### Does Explo need ListenBrainz to work?

The recommendation feature does, since Explo uses the ListenBrainz recommendation engine to retrieve personalized tracks. Without a ListenBrainz history you can still use the custom playlist import from Apple Music, ListenBrainz and Spotify, but the README does not describe a local-playback alternative for recommendations.

## Sources

- [Issues](https://github.com/LumePart/Explo/issues)
- [License: MIT](https://github.com/LumePart/Explo/blob/dev/LICENSE)
- [LumePart/Explo on GitHub](https://github.com/LumePart/Explo)
- [README](https://github.com/LumePart/Explo/blob/dev/README.md)
- [Releases](https://github.com/LumePart/Explo/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lumepart-explo
