β οΈ This repository is under a strong stage of development, expect constant changes. If you find any mistake or bug, please open an ISSUE.
All-in-one tool for downloading and organizing music with Spotify metadata for Jellyfin.
The app connects to the Spotify and YouTube Music APIs. The goal is to generate an .nfo XML file to complete the metadata required by Jellyfin when building music libraries.
Read this file in Spanish
- β Download audio from YouTube Music with Spotify metadata
- β Synchronized lyrics (.lrc) from LRC Lib
- β
Generation of Jellyfin-compatible
.infofiles (Still some things to work on here!β οΈ ) - β Automatic folder structure (Artist/Album)
- β Command-line interface (CLI)
- β Web interface (UI) with real-time progress
- β RESTful API for integrations
- β Docker support with auto-builds
- β Playlist support
- β MP3 Conversion
- β Support for multiple bitrates (128, 180, 220, etc.)
- Python 3.8+
- FFmpeg
- Spotify Developer Account
# Installation with Poetry (recommended)
git clone https://github.com/gabrielbaute/spotify-saver.git
cd spotify-saver
poetry install
# Or with pip
pip install git+https://github.com/gabrielbaute/spotify-saver.gitOnce in your project directory, run:
spotifysaver initThis will create a local .env file with the environment variables that will be requested:
| Variable | Description | Default Value |
|---|---|---|
SPOTIFY_CLIENT_ID |
ID of the Spotify app you created | - |
SPOTIFY_CLIENT_SECRET |
Secret key generated for your Spotify app | - |
SPOTIFY_REDIRECT_URI |
Spotify API Validation URI | http://localhost:8888/callback |
SPOTIFYSAVER_OUTPUT_DIR |
Custom directory path (optional) | ./Music |
YTDLP_COOKIES_PATH |
Cookie file path (optional) | - |
API_PORT |
API server port (optional) | 8000 |
API_HOST |
Host for the API (optional) | 0.0.0.0 |
UI_ENABLED |
Enable/disable web interface (optional) | true |
The variable YTDLP_COOKIES_PATH will indicate the location of the file with the Youtube Music cookies, in case we have problems with restrictions to yt-dlp, specifically it is for cases in which youtube blocks the app for "behaving like a bot" (which is not entirely false lol)
You can also check the .example.env file
We maintain a documentation with Deepwiki, which constantly tree the repository. You can consult it at all times.
The documentation for using the API, on the other hand, can be found in this same repository here: API Documentation
| Command | Description | Example |
|---|---|---|
init |
Configure environment variables | spotifysaver init" |
download [URL] |
Download track/album from Spotify | spotifysaver download "URL_SPOTIFY" |
inspect |
Shows Spotify metadata (album, playlist) | spotifysaver inspect "URL_SPOTIFY" |
show-log |
Shows the application log | spotifysaver show-log |
version |
Shows the installed version | spotifysaver version |
| Option | Description | Accepted Values ββ |
|---|---|---|
--lyrics |
Download synchronized lyrics (.lrc) | Flag (no value) |
--output DIR |
Output directory | Valid path |
--format FORMAT |
Audio format | m4a (default), mp3 |
--cover |
Saves the cover album in de directoy (.jpg) | Flag (no value) |
--nfo |
Generates a .nfo metadata file in the JellyFin format | Flag (no value) |
--explain |
Show score breakdown for each track without downloading (for error analysis) | Flag (no value) |
--dry-run |
Simulate download without saving files | Flag (no value) |
| Option | Description | Accepted Values ββ |
|---|---|---|
--lines |
Number of log lines to display | --lines 25 --> int |
--level |
Filter by log level | INFO, WARNING, DEBUG, ERROR |
--path |
Displays the location of the log file | Flag (no value) |
# Set spotifysaver configuration
spotifysaver init
# Download album with synchronized lyrics
spotifysaver download "https://open.spotify.com/album/..." --lyrics
# Download album with album cover and metadata file
spotifysaver download "https://open.spotify.com/album/..." --nfo --cover
# Download song in MP3 format
spotifysaver download "https://open.spotify.com/track/..." --format mp3To use the API, you need to have the API server running. You can start it with the following command:
# Start the API server
spotifysaver-apiThe server will run at http://localhost:8000 by default. You can find the API documentation here, which describes the technical aspects and usage in detail.
SpotifySaver now includes a modern web interface that makes it easy to download music without using the command line:
# Start the API server with web interface
spotifysaver-apiThis will start the API server with an integrated web interface that you can access at http://localhost:8000. The web interface provides:
- Easy URL input: Simply paste any Spotify URL (track, album, or playlist)
- Full configuration: All download options available through an intuitive interface
- Real-time progress: Monitor download progress and see detailed logs
- Responsive design: Works on desktop and mobile devices
- Automatic browser opening: Opens your default browser automatically
- β URL validation for Spotify links
- β Configurable audio format (M4A/MP3) and bitrate
- β Toggle lyrics and NFO file generation
- β Custom output directory
- β Real-time download progress
- β Activity log with timestamps
- β Error handling and user feedback
Default Access:
- Web Interface & API:
http://localhost:8000 - API Documentation:
http://localhost:8000/docs
SpotifySaver is available as a Docker container with full web interface support. Choose between GitHub Container Registry or building locally.
- Create configuration files:
# Create directories
mkdir -p music config
# Create environment file
cat > .env << EOF
SPOTIFY_CLIENT_ID=your_client_id_here
SPOTIFY_CLIENT_SECRET=your_client_secret_here
SPOTIFY_REDIRECT_URI=http://localhost:8000/callback
EOF- Run with Docker Compose:
# Using pre-built image from GitHub Registry
docker compose up -d
# Or build locally
docker compose up --build- Access the web interface:
- π Web UI & API: http://localhost:8000
- π API Docs: http://localhost:8000/docs
Pull and run directly:
# Pull latest version
docker pull ghcr.io/gabrielbaute/spotify-saver:latest
# Run container
docker run -d \
--name spotifysaver \
-p 8000:8000 \
-v ./music:/music \
-v ./config:/config \
-e SPOTIFY_CLIENT_ID=your_client_id \
-e SPOTIFY_CLIENT_SECRET=your_client_secret \
ghcr.io/gabrielbaute/spotify-saver:latestAvailable tags:
latest- Latest stable release0.6.3-test-2- Specific version0.6- Major.minor version
| Variable | Description | Default |
|---|---|---|
SPOTIFY_CLIENT_ID |
Spotify API Client ID | Required |
SPOTIFY_CLIENT_SECRET |
Spotify API Client Secret | Required |
SPOTIFY_REDIRECT_URI |
Callback URL | http://localhost:8000/callback |
API_PORT |
API server port (includes web UI) | 8000 |
MUSIC_DIR |
Host music directory | ./music |
CONFIG_DIR |
Host config directory | ./config |
LOG_LEVEL |
Logging level | INFO |
services:
spotifysaver:
container_name: spotifysaver
image: ghcr.io/gabrielbaute/spotify-saver:latest
ports:
- "${API_PORT:-8000}:8000"
environment:
- SPOTIFY_CLIENT_ID=${SPOTIFY_CLIENT_ID}
- SPOTIFY_CLIENT_SECRET=${SPOTIFY_CLIENT_SECRET}
- SPOTIFY_REDIRECT_URI=${SPOTIFY_REDIRECT_URI:-http://localhost:8000/callback}
- SPOTIFYSAVER_LOG_LEVEL=${LOG_LEVEL:-INFO}
volumes:
- ${MUSIC_DIR:-./music}:/music
- ${CONFIG_DIR:-./config}:/config
- spotifysaver_logs:/logs
restart: unless-stopped
security_opt:
- no-new-privileges:true
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
volumes:
spotifysaver_logs:# Clone repository
git clone https://github.com/gabrielbaute/spotify-saver.git
cd spotify-saver
# Build image
docker build -t spotify-saver .
# Run container
docker run -d \
--name spotifysaver \
-p 8000:8000 \
-v ./music:/music \
-v ./config:/config \
-e SPOTIFY_CLIENT_ID=your_client_id \
-e SPOTIFY_CLIENT_SECRET=your_client_secret \
spotify-saverMusic/
βββ Artist/
β βββ Album (Year)/
β β βββ 01 - Song.m4a
β β βββ 01 - Song.lrc
β β βββ album.nfo
β β βββ cover.jpg
β βββ artist_info.nfo
- Fork the project
- Create your branch (
git checkout -b feature/new-feature) - Commit your changes (
git commit -m 'Add awesome feature') - Push to the branch (
git push origin feature/new-feature) - Open a Pull Request
MIT Β© TGabriel Baute