andrew 1f733d6e91 Add README and proper favicon/PWA icon set
README covers what alembic does, prerequisites, a full deploy quickstart,
credential setup, and a page-by-page usage tour, written for someone
running Docker but not necessarily comfortable coding or sysadmin work.

Favicon/icons were prepared in a separate theme scratch dir but never
wired in; moved them into app/static and pointed base.html at the full
icon set (SVG, PNG fallbacks, apple-touch-icon, manifest) instead of the
single inline data-URI SVG it had before.
2026-07-09 09:51:43 -06:00

alembic logo

alembic

A self-hosted control panel that turns your Spotify playlists into a real, well-tagged music library on your own server, downloaded automatically, kept up to date, and free of duplicate junk.

No terminal required for day-to-day use. Everything, adding playlists, fixing a mislabeled song, cleaning up duplicates, happens through a web page.


Table of contents


What alembic does

Give alembic a Spotify playlist link, and from then on it will:

  • Download every track in the playlist automatically, over Soulseek
  • Tag each file properly (artist, title, album, genre) using Spotify's own metadata, so your library looks clean instead of a pile of "Track 01.mp3" files
  • Import everything into your music library, ready to show up in Navidrome or any other music server that reads a normal folder-based library
  • Rebuild the playlist as a real M3U file, so it plays back in the right order in your music app
  • Keep checking on a schedule, so when you add new songs to the Spotify playlist, they show up in your library on their own
  • Find duplicate copies of songs (the same track downloaded twice, or in two different formats) and let you review and clean them up, nothing gets deleted without your say-so
  • Let you fix things by hand when needed: correct a tag, re-tag a track from a URL, manually import a file you dropped in yourself, or delete something you don't want

It also keeps a dashboard showing what's in your library, what got downloaded recently, and the history of every automated job it's run.

Everything runs in one Docker container. There's no separate database to install and no cron jobs to hand-edit, alembic manages all of that internally.

What you need before you start

alembic is built to slot into a home server that already has a few things running. It is not a starting point for a music server from scratch, it's the automation layer on top of one.

Before you begin, make sure you have:

  1. A server that runs Docker, with docker compose available. Any Linux box, NAS, or mini PC works.
  2. A music server that reads a plain folder of tagged files, such as Navidrome. alembic builds your library on disk; Navidrome (or similar) is what you actually listen with.
  3. A Soulseek account. This is how tracks get downloaded. Sign up free at soulseek.com.
  4. A free Spotify Developer app. This lets alembic read playlist contents (it does not download from Spotify itself, only Soulseek). Takes two minutes, see the credentials section below.
  5. A login provider that speaks OpenID Connect (OIDC). alembic doesn't have its own username/password login, it delegates to something you already trust. Pocket ID is a small self-hosted option built exactly for this, but Authentik, Keycloak, Authelia, or any other OIDC provider works too.

Optional, add these later if you want them:

  • A Bandcamp account, if you want to also sync your Bandcamp purchases into the library automatically.
  • AzuraCast or Qobuz credentials, if you use either of those.
  • A Telegram bot, if you want job notifications sent to you.
  • A VPN container (such as gluetun), if you want Soulseek's network traffic routed through a VPN. Not required to get started.

Quickstart

1. Get the image

Clone this repository onto your Docker host and build the image locally:

git clone <this-repo-url> alembic
cd alembic
docker build -t alembic:latest .

This takes a few minutes the first time. You don't need to touch anything inside the app/ or pipeline/ folders, the Dockerfile handles all of it.

2. Create your folders

alembic needs exactly two places to store things:

  • A music folder — where your actual songs live. If you already have a music library, point at it directly.
  • A config folder — where alembic keeps its own database, your saved credentials, and logs.
mkdir -p /path/to/your/music
mkdir -p /path/to/alembic-config

Everything else (which playlists you follow, your credentials, scheduling) is stored inside that config folder, so if you ever need to move alembic to a new machine, copying those two folders is all it takes.

3. Generate a master key

alembic encrypts every credential you give it (Spotify keys, Soulseek password, and so on) before storing it. It needs a key to do that:

openssl rand -base64 32 > /path/to/alembic-config/master.key
chmod 600 /path/to/alembic-config/master.key

Keep this file safe. If you lose it, alembic can no longer read your saved credentials and you'll need to re-enter them.

4. Set up login (OIDC)

Register alembic as an application in your OIDC provider (Pocket ID, Authentik, whichever you use). You'll need to tell it:

  • Redirect URI: https://<wherever-you-host-alembic>/auth/callback
  • Scopes: openid profile email

In return, it will give you three values you'll need in the next step:

  • An issuer URL (something like https://id.example.com)
  • A client ID
  • A client secret

5. Write your docker-compose file

Create a docker-compose.yml next to your alembic folder:

services:
  alembic:
    image: alembic:latest
    container_name: alembic
    ports:
      - "8420:8420"
    environment:
      - POCKETID_ISSUER=https://id.example.com
      - POCKETID_CLIENT_ID=your-client-id
      - POCKETID_CLIENT_SECRET=your-client-secret
      - SESSION_SECRET=some-long-random-string
      # Optional: lock login to a single email, recommended for a personal server
      - ALLOWED_EMAIL=you@example.com
    volumes:
      - /path/to/your/music:/data/music
      - /path/to/alembic-config:/config
    secrets:
      - alembic_master_key
    restart: unless-stopped

secrets:
  alembic_master_key:
    file: /path/to/alembic-config/master.key

A few notes on the environment values:

  • SESSION_SECRET can be any long random string, generate one with openssl rand -base64 32.
  • ALLOWED_EMAIL is optional but recommended. Even if your OIDC provider only has your account today, this makes sure only that one email can ever log in.
  • If you want to route Soulseek traffic through a VPN container instead of exposing alembic's port directly, see the comments in docker-compose.snippet.yml in this repo for the network_mode: "service:<vpn-container>" pattern. Most people can skip this and use the simple port mapping above.

6. Start it up

docker compose up -d

On first boot, alembic seeds a few default config files into your config folder and sets up its internal database automatically. Check that it started cleanly:

docker compose logs -f alembic

You should see Uvicorn running on http://0.0.0.0:8420 with no errors.

7. Log in

Open http://<your-server>:8420 in a browser. You'll be redirected to your OIDC provider to log in, then dropped onto the alembic dashboard.

Setting up your credentials

Once logged in, go to Manage credentials and fill in each service you plan to use. Nothing here is required all at once, add them as you need them. Values are write-only: once saved, they're encrypted and never shown back to you in the browser (you'll just see a "set" badge).

Service What to enter Where to get it
Spotify Client ID, Client Secret Create a free app at developer.spotify.com/dashboard. You don't need any special access, the basic free tier is enough to read playlist contents.
Soulseek Username, Password Your normal Soulseek login.
Navidrome Base URL, admin username, admin password The address of your Navidrome server and an admin account on it. Used so alembic can trigger a library rescan after downloads.
Bandcamp (optional) Username, format preference, cookies Export your Bandcamp cookies while logged into bandcamp.com in your browser, using an extension like "Get cookies.txt LOCALLY", and paste the contents in. Format preference is a space-separated list like flac mp3-320.
AzuraCast (optional) API key From your AzuraCast station's API settings, if you run one.
Qobuz (optional) Token, App ID, region From your Qobuz account, if you use it.
Telegram (optional) Bot token, chat ID Create a bot via @BotFather if you want job notifications sent to a chat.

Adding your first playlist

  1. Go to Manage playlistsAdd playlist.
  2. Paste the Spotify playlist URL and give it a name (this name becomes the folder/tag name in your library).
  3. Pick a daily sync time.
  4. Save.

That's it. On its next scheduled run (or immediately, using the Run now button on the playlist's page), alembic will download every track in the playlist, tag it, import it into your library, and build a matching .m3u8 playlist file.

Using alembic day to day

  • Dashboard — a snapshot of your library: track counts, formats, what got downloaded in the last 24 hours, and recent job activity.
  • Playlists — add, pause, or remove synced Spotify playlists, and see per-playlist download status.
  • Library — browse and search everything in your library. Fix tags on a track, re-tag it from a URL, or delete it entirely.
  • Import — drop a file into your import folder (or upload it through the browser) to manually add something outside of the normal playlist flow.
  • Dedup — review duplicate tracks alembic has found. Nothing is ever deleted automatically, you approve each deletion, or mark a pair as "keep both" if it's not actually a duplicate.
  • Genres — review genre tags alembic has written or wants to write, and lock an artist's genre so it's never changed again.
  • Jobs — see the history and status of every scheduled and manual job, with full logs.

Updating alembic

Pull the latest code, rebuild, and restart:

cd alembic
git pull
docker build -t alembic:latest .
docker compose up -d --force-recreate alembic

Your library, credentials, and settings all live in your two mounted folders, so updating the image never touches your data.

Troubleshooting

I can't log in / get redirected in a loop. Double check the redirect URI registered with your OIDC provider exactly matches https://<your-host>/auth/callback, including http vs https.

A playlist says it's synced but nothing downloaded. Check that playlist's job history under Jobs, the log will usually show whether Soulseek couldn't find a track, or a credential is missing.

Dedup found something that isn't actually a duplicate. Use the "Keep both" button on that pair. alembic will remember your decision and won't flag that exact pair again.

I dropped files in the import folder and they're not showing up. Go to the Import page and confirm you don't have leftover files that failed a previous import, check that page's status for any error before re-running.

S
Description
The control plane for the music pipeline (playlists, credentials, per-track download status, manual tag fixes/imports, dedup/genre review, scheduling)
Readme 13 MiB
0.6.9 Latest
2026-07-16 11:51:55 -06:00
Languages
Python 66.5%
Shell 20.6%
HTML 8.6%
CSS 4%
Dockerfile 0.3%