All apps · 0 apps
Octave
Docker app from johagan's Repository
Overview
Readme
View on GitHub
Octave
Spotify → Jellyfin + Lidarr sync. With ListenBrainz & Last.fm enrichment.
Spotify playlist ──► match against Jellyfin library ──► add to Jellyfin playlist
│ └──► set cover art
└──► request missing albums in Lidarr
└──► ListenBrainz MBID resolution
└──► Last.fm similar-artist discovery
Octave keeps your Spotify playlists in Jellyfin. When tracks are missing from your library, it can request albums in Lidarr and track them across runs until they appear. One container, local-first, with a web UI for setup.
Features
- Web UI — onyx dark dashboard, playlist manager, live log tail, config editor
- Per-playlist sync modes —
add_only(safe),full_sync(mirror),rebuild(wipe/recreate) - Bulk playlist management — select multiple, change mode, or remove in one click
- Scheduled sync — cron via
SYNC_SCHEDULE(default: 2 AM UTC) - Manual trigger — sync all or a single playlist from the dashboard
- Fuzzy matching — RapidFuzz title + artist scoring with tuned thresholds
- Track cache — persistent spotify_id → jellyfin_id mapping; >10× faster on warm runs
- Persistent library index — Jellyfin library cached to disk for instant warm starts
- Parallel Lidarr requests — up to 4 concurrent album lookups
- Cover art — automatically pulled from Spotify and uploaded to Jellyfin playlists
- Missing tracks view — browse unmatched tracks per playlist, download CSV
- Duplicate detection — warns on in-playlist dupes; prevents cross-run Lidarr spam
- waiting_for_lidarr — tracks queued albums across runs so you know what's in flight
- Compilation guard — avoids matching compilation albums to wrong artists
- SQLite history — every run stored; survives restarts cleanly
- HTTP Basic Auth — optional browser-native auth for exposed deployments
- PKCE Spotify OAuth — no client secret required for normal setup
- Sync all playlists — discover owned/followed Spotify playlists automatically
- Optional ListenBrainz — MBID resolution, global popularity data
- Optional Last.fm — playcounts, similar track/artist discovery
- Fully responsive — works on phone, tablet, and desktop
Quick start
1 — Clone and start
git clone https://github.com/jackohagan94-afk/octave.git
cd octave
cp .env.example .env
mkdir -p config data logs
# Linux only: make bind mounts writable by the container user.
sudo chown -R 1000:1000 config data logs
docker compose up -d --build
2 — Configure in the web UI
Open http://localhost:8000, then fill in Settings:
- Spotify: create a Spotify app, paste its Client ID in Settings, then click Connect Spotify. PKCE does not need a Client Secret, though Octave still accepts one for legacy setups.
- Jellyfin: URL, API key, and user ID.
- Lidarr: URL and API key if you want missing albums requested automatically.
See docs/SETUP.md for a full walkthrough.
3 — Linux volume permissions
If you skipped the permission step before first start, run it and restart:
mkdir -p config data logs
sudo chown -R 1000:1000 config data logs
docker compose restart
4 — Add playlists
Browse to http://localhost:8000 → Playlists → paste a Spotify URL or ID.
Sync modes
| Mode | Behaviour |
|---|---|
add_only |
Tracks are only ever added. Manual Jellyfin edits preserved. |
full_sync |
Mirrors Spotify exactly — removals from Spotify are reflected. |
rebuild |
Deletes and recreates the Jellyfin playlist from scratch every run. |
Optional integrations
| Service | Env var | What it does |
|---|---|---|
| Spotify | SPOTIFY_CLIENT_ID |
Your Spotify app Client ID for PKCE auth |
| ListenBrainz | LISTENBRAINZ_TOKEN |
MusicBrainz ID resolution, global popularity stats |
| Last.fm | LASTFM_API_KEY |
Playcounts, similar tracks/artists, scrobble metadata |
Environment variables
See docs/ENVIRONMENT.md for the full reference.
| Variable | Default | Notes |
|---|---|---|
SYNC_SCHEDULE |
0 2 * * * |
Cron for auto-sync. Empty to disable. |
SYNC_ON_STARTUP |
false |
Trigger sync immediately on boot. |
TZ |
UTC |
Timezone for cron and log timestamps. |
AUTH_USERNAME |
octave |
HTTP Basic Auth username. |
AUTH_PASSWORD |
(empty) | Empty disables auth; set a password before exposing Octave. |
LISTENBRAINZ_TOKEN |
(empty) | Optional — enables MBID/popularity features. |
LASTFM_API_KEY |
(empty) | Optional — enables playcounts/discovery. |
LASTFM_USERNAME |
(empty) | Optional — used for Last.fm scrobble import workflows. |
Docs
License
MIT
Install Octave on Unraid in a few clicks.
Find Octave in Community Apps on your Unraid server, review the template, and click Install. Unraid handles the Docker app or plugin setup from the published template.
Related apps
Explore more like this
Explore allDetails
ghcr.io/johagan94/octave:latestRuntime arguments
- Web UI
http://[IP]:[PORT:8000]- Network
bridge- Shell
bash- Privileged
- false
Template configuration
Octave web interface and API.
- Target
- 8000
- Default
- 8000
- Value
- 8000
Stores config.json (non-secret settings: Jellyfin library ID, playlists list).
- Target
- /app/config
- Default
- /mnt/user/appdata/octave/config
- Value
- /mnt/user/appdata/octave/config
Runtime data: SQLite sync history, credentials (settings.json), Spotify PKCE token, track cache.
- Target
- /app/data
- Default
- /mnt/user/appdata/octave/data
- Value
- /mnt/user/appdata/octave/data
Octave log files (rotated automatically).
- Target
- /app/logs
- Default
- /mnt/user/appdata/octave/logs
- Value
- /mnt/user/appdata/octave/logs
Required to connect Spotify. Create a free app at developer.spotify.com/dashboard, copy its Client ID here (or into Settings later), and add your Octave callback URL — http://SERVER-IP:8000/callback — to that app's Redirect URIs. PKCE is used, so no client secret is needed.
- Target
- SPOTIFY_CLIENT_ID
Optional. Leave blank to let Octave infer the callback URI. Set this explicitly when using a reverse proxy, e.g. https://octave.example.com/callback.
- Target
- SPOTIFY_REDIRECT_URI
Optional — use 'Sign in to Jellyfin' in the Settings UI to configure automatically. URL reachable from the Octave container, e.g. http://192.168.1.10:8096 or http://jellyfin:8096.
- Target
- JELLYFIN_URL
Optional — auto-filled by 'Sign in to Jellyfin' in Settings. Jellyfin Dashboard → API Keys.
- Target
- JELLYFIN_API_KEY
Optional — auto-filled by 'Sign in to Jellyfin' in Settings. The user ID that will own created playlists.
- Target
- JELLYFIN_USER_ID
Optional — leave unset to disable Lidarr integration. URL reachable from the Octave container, e.g. http://lidarr:8686.
- Target
- LIDARR_URL
Optional Lidarr API key. Lidarr → Settings → General → Security → API Key.
- Target
- LIDARR_API_KEY
HTTP Basic Auth username for the web UI. Defaults to 'octave'.
- Target
- AUTH_USERNAME
- Default
- octave
- Value
- octave
SECURITY: blank = NO authentication (anyone on the network can access Octave). Set a password before exposing Octave beyond a trusted LAN. Leave blank only for an isolated/LAN-trust setup.
- Target
- AUTH_PASSWORD
Cron schedule for automatic sync (uses container TZ). Default: 2:00 AM daily. Leave blank to disable scheduled sync.
- Target
- SYNC_SCHEDULE
- Default
- 0 2 * * *
- Value
- 0 2 * * *
Set to 'true' to run a sync when the container starts.
- Target
- SYNC_ON_STARTUP
- Default
- false
- Value
- false
Set to 'true' to discover and sync every Spotify playlist the connected account can see. Spotify-owned editorial playlists are skipped automatically.
- Target
- SYNC_ALL_PLAYLISTS
IANA timezone string for logs and scheduled syncs, e.g. Australia/Sydney.
- Target
- TZ
- Default
- UTC
- Value
- UTC
Python logging level: DEBUG, INFO, WARNING, or ERROR.
- Target
- LOG_LEVEL
- Default
- INFO
- Value
- INFO
Optional. ListenBrainz user token from listenbrainz.org/profile/ — enables MusicBrainz ID resolution for better Lidarr matching.
- Target
- LISTENBRAINZ_TOKEN
Optional. Last.fm API key from last.fm/api/account/create — enables playcounts and similar-artist discovery.
- Target
- LASTFM_API_KEY
Optional. Last.fm username for scrobble history lookups.
- Target
- LASTFM_USERNAME