Download music through slskd using Spotify URLs
Project description
slskify
Download music from Spotify URLs directly through a running slskd instance (Soulseek daemon).
Give it a Spotify track, album, playlist, or artist link — slskify fetches the track list, searches the Soulseek network, scores every result, and queues the best matches for download.
Features
- All Spotify resource types — tracks, albums, playlists, artists
- Smart candidate scoring — ranks results by title match, album match, track number, artist, codec, and quality; penalises version mismatches (live, remix, acoustic, etc.)
- Album cohesion — for album downloads, prefers files from a single consistent rip/source
- Concurrent searches — configurable worker pool for fast playlist downloads
- Flexible codec/bitrate preferences — prefer FLAC, 320 kbps MP3, etc.
- Zero credentials in shell history — all secrets are read from environment variables or a
.envfile
Requirements
- Python 3.12+
- A running slskd instance with API access enabled
- A Spotify app (free) for the Client Credentials flow
Installation
pip install slskify
Or install from source:
git clone https://github.com/cmerk2021/slskify.git
cd slskify
pip install -e .
Configuration
slskify reads credentials from environment variables or a .env file in the working directory.
Copy the example and fill in your values:
cp .env.example .env
# Spotify — https://developer.spotify.com/dashboard
SPOTIFY_CLIENT_ID=your_spotify_client_id
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret
# slskd instance
SLSKD_URL=http://localhost:5030
SLSKD_API_KEY=your_slskd_api_key
All four values can alternatively be passed as CLI flags (see slskify --help).
Usage
slskify [OPTIONS] URL
URL can be any Spotify track, album, playlist, or artist link.
Options
| Flag | Default | Description |
|---|---|---|
--codec CODEC |
— | Preferred codec (flac, mp3, aac, …). Other codecs score 0. |
--bitrate KBPS |
— | Preferred bitrate in kbps (e.g. 320). Used to rank lossy files. |
--slskd-url URL |
SLSKD_URL env |
Base URL of the slskd instance. |
--slskd-api-key KEY |
SLSKD_API_KEY env |
slskd API key. |
--spotify-client-id ID |
SPOTIFY_CLIENT_ID env |
Spotify app client ID. |
--spotify-client-secret SECRET |
SPOTIFY_CLIENT_SECRET env |
Spotify app client secret. |
--search-timeout SECONDS |
30 |
Per-query search timeout sent to slskd. |
--workers N |
4 |
Max concurrent searches for multi-track downloads. |
-v, --verbose |
off | Log every HTTP request and internal scoring decision. |
-V, --version |
— | Show version and exit. |
-h, --help |
— | Show help and exit. |
Examples
# Download an album, prefer FLAC
slskify https://open.spotify.com/album/4LH4d3cOWNNsVw41Gqt2kv --codec flac
# Download a playlist, prefer 320 kbps MP3
slskify https://open.spotify.com/playlist/37i9dQZF1DXcBWIGoYBM5M --codec mp3 --bitrate 320
# Download a single track
slskify https://open.spotify.com/track/4cOdK2wGLETKBW3PvgPWqT
# Download all tracks by an artist
slskify https://open.spotify.com/artist/06HL4z0CvFAxyc27GXpf02
# Show version
slskify --version
How it works
- Resolve — the Spotify URL is parsed and the full track list is fetched via the Spotify Web API (Client Credentials; no login needed).
- Search — for each track, several queries of varying specificity are sent to slskd (e.g.
"Artist Title","Artist Album","Title"). Results are deduplicated. - Score — each audio file candidate is scored across six weighted components: title match, album match, track number, artist match, codec preference, and audio quality. Version mismatches (live, remix, acoustic, etc.) incur a large penalty.
- Album cohesion — for album downloads, a single user+folder source that covers the most tracks is identified and preferred, so all files come from one consistent rip.
- Queue — the best candidate above the minimum score threshold is queued for download via slskd's REST API.
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Run tests with coverage
pytest --cov=slskify --cov-report=term-missing
Publishing a new release
Releases are published to PyPI automatically via GitHub Actions when you create a GitHub Release.
One-time setup (PyPI Trusted Publishing)
- Go to https://pypi.org and create an account / log in.
- On PyPI → Your project → Publishing → add a Trusted Publisher:
- Publisher: GitHub Actions
- Repository owner:
YOUR_USERNAME - Repository name:
slskify - Workflow name:
publish.yml - Environment name:
pypi
- In your GitHub repo → Settings → Environments → create an environment named
pypi.
Releasing
- Bump the version in
slskify/version.pyandpyproject.toml. - Commit and push.
- On GitHub, go to Releases → Draft a new release.
- Create a new tag (e.g.
v0.2.0), write release notes, and click Publish release. - The Actions workflow builds the wheel + sdist and uploads to PyPI automatically.
First manual release (before Trusted Publishing is set up)
pip install build twine
python -m build
twine upload dist/*
License
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file slskify-0.1.0.tar.gz.
File metadata
- Download URL: slskify-0.1.0.tar.gz
- Upload date:
- Size: 27.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c51078cea8935bc6b3a4e82ea063dcc9faf8610c9733571b4c976f6ac4eb09d9
|
|
| MD5 |
02590ee35f146721602b74ff0e47d061
|
|
| BLAKE2b-256 |
5db6e3223368fca439623cf71e6eca48e49a8d099061c81f7c98f25acdd7fc36
|
Provenance
The following attestation bundles were made for slskify-0.1.0.tar.gz:
Publisher:
publish.yml on cmerk2021/slskify
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slskify-0.1.0.tar.gz -
Subject digest:
c51078cea8935bc6b3a4e82ea063dcc9faf8610c9733571b4c976f6ac4eb09d9 - Sigstore transparency entry: 2169447919
- Sigstore integration time:
-
Permalink:
cmerk2021/slskify@f868ad1daaeb8c182b804acb1ed0e87f5bb60697 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/cmerk2021
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f868ad1daaeb8c182b804acb1ed0e87f5bb60697 -
Trigger Event:
release
-
Statement type:
File details
Details for the file slskify-0.1.0-py3-none-any.whl.
File metadata
- Download URL: slskify-0.1.0-py3-none-any.whl
- Upload date:
- Size: 28.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
17e4ce8fc75b4dd06733eaf32753c42485fbe17ae0942ee5b914e8bd85cfcffb
|
|
| MD5 |
84cfcb5c1fbd978ad2d1a3e5f1aa7b51
|
|
| BLAKE2b-256 |
a62413b458081d853e27191f6376aacfa593bfe134e98c1f111776cf1e33ea76
|
Provenance
The following attestation bundles were made for slskify-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on cmerk2021/slskify
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
slskify-0.1.0-py3-none-any.whl -
Subject digest:
17e4ce8fc75b4dd06733eaf32753c42485fbe17ae0942ee5b914e8bd85cfcffb - Sigstore transparency entry: 2169447934
- Sigstore integration time:
-
Permalink:
cmerk2021/slskify@f868ad1daaeb8c182b804acb1ed0e87f5bb60697 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/cmerk2021
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f868ad1daaeb8c182b804acb1ed0e87f5bb60697 -
Trigger Event:
release
-
Statement type: