Automated music downloader that searches the Soulseek network for albums and tracks via the slskd API, applying intelligent quality filtering, speed checking, and library upgrade scanning.
- Dual search modes —
manualmode searches for a single artist or album on demand;automaticmode scans an existing music library directory and upgrades every album it finds. - Preferred-user fast-path — seakarr remembers reliable uploaders across runs. On subsequent searches it probes those users directly (no network search) before falling back to the full Soulseek network.
- Quality filtering — restrict results by file extension (e.g.
flac), minimum bitrate (kbps), and minimum bit depth (e.g. 24-bit). Locked/private files are excluded by default. - Speed checking — after a transfer begins, seakarr measures the real upload rate and cancels
connections that fall below
--min-upload-speed. When more than--min-filtered-user-countcandidates are available the fastest is automatically selected; below that threshold the check is skipped so you never get stuck with no candidates. - Multi-candidate fallback — if a candidate fails (timeout, error, or slow speed) seakarr moves on to the next ranked candidate automatically. If every candidate is rejected by the speed check, the fastest of them is retried without the speed floor rather than giving up entirely.
- Artist-only search fallback — if an artist + album query returns no results, seakarr re-tries with an artist-only query and filters by album directory name, maximising the chance of finding obscure or misspelled albums.
- Disc/box-set merging — multi-disc releases stored in
Disc 1/CD 1subdirectories are transparently merged into a single candidate so they download as a complete set. - File organisation — completed downloads can be automatically moved into a structured directory tree
under
--slskd-completed-pathusing a configurable path pattern with%user%,%artist%, and%album%placeholders. - Tag stripping — optionally remove all embedded metadata tags from organised files, useful when a downstream tagger (e.g. MusicBrainz Picard, Beets) will re-tag from scratch.
- SQLite tracking — every successfully downloaded album is recorded in a local SQLite database so seakarr never re-downloads the same album, even across restarts.
- Graceful cleanup on failure — if a download is cancelled, times out, or errors, all partially transferred files are removed from the slskd completed directory automatically.
- Keyword exclusion — filter out candidates whose filenames contain unwanted words
(e.g.
vinyl,live,demo).
- Python 3.12+
- Astral uv (optional)
- A running slskd instance with an API key
git clone https://github.com/binhex/seakarr
cd seakarr
uv venv --quiet
uv syncgit clone https://github.com/binhex/seakarr
cd seakarr
python -m venv .venv
source .venv/bin/activate
pip install .seakarr --helpManual search for a single album:
seakarr \
--slskd-api-key YOUR_KEY \
--search-mode manual \
--search-artist "Pink Floyd" \
--search-title "The Wall"Automatic library upgrade scan:
seakarr \
--slskd-api-key YOUR_KEY \
--search-mode automatic \
--music-library-path /mnt/music \
--allowed-extensions flac \
--min-bitrate 320 \
--slskd-completed-path /downloads/complete \
--completed-pattern "%artist%/%album%"| Option | Description | Default | Example | Type |
|---|---|---|---|---|
--slskd-url ✱ |
URL of the slskd server. | http://localhost:8983 |
http://192.168.1.10:8983 |
string |
--slskd-api-key ✱ |
slskd API key (16–255 characters). Can also be set via the SLSKD_API_KEY environment variable. |
— | abc123def456ghi7 |
string |
--slskd-url-base |
URL base path when slskd is served from a subdirectory (e.g. behind a reverse proxy). | / |
/slskd |
string |
--slskd-completed-path |
Local filesystem path where slskd saves completed downloads. Required when --completed-pattern is set. |
— | /downloads/complete |
path |
--search-mode |
manual searches for a single artist/album; automatic scans --music-library-path for albums to upgrade. |
manual |
automatic |
choice |
--search-artist ✱† |
Artist name to search for. Required when --search-mode=manual. |
— | "Pink Floyd" |
string |
--search-title |
Album or track title to search for. When omitted in manual mode, all content from the artist is returned. | — | "The Wall" |
string |
--search-user |
Restrict the search to a single Soulseek user's shared files (skips the network-wide search). | — | someuser123 |
string |
--response-limit |
Maximum number of search responses to collect from the Soulseek network. | 500 |
1000 |
integer |
--search-timeout |
Seconds to wait for the Soulseek network search to complete. | 30 |
60 |
integer |
--search-type |
Filter candidates by track count: album keeps results with 5+ tracks, single keeps 1–4 tracks, any applies no restriction. |
any |
album |
choice |
--allowed-extensions |
Comma-separated list of permitted file extensions. | flac |
flac,mp3 |
string |
--min-bitrate |
Minimum bitrate in kbps. Files with a lower bitrate are excluded. | — | 320 |
integer |
--min-bitdepth |
Minimum bit depth in bits. Files with a lower bit depth are excluded. | — | 24 |
integer |
--include-locked |
Include locked (private) files in search results. Locked files are excluded by default. | false |
— | flag |
--exclude-words |
Comma-separated list of words to exclude from filenames (case-insensitive). | — | vinyl,live,demo |
string |
--max-queue-length |
Maximum accepted upload queue length for a peer. 0 requires a free upload slot; values above 0 allow queues up to that length. |
0 |
10 |
integer |
--max-start-time |
Maximum time to wait after a file reaches the front of the remote user's upload queue before the transfer actually starts. | 60 |
120 |
integer |
--min-upload-speed |
Minimum measured transfer speed in KB/s. Peers below this threshold are cancelled and the next candidate is tried. Set to 0 to disable the speed check entirely. |
250 |
500 |
integer |
--speed-check-wait |
Seconds to wait after a transfer starts before measuring its speed. | 30 |
60 |
integer |
--min-filtered-user-count |
Minimum number of filtered candidates required before the speed check is applied. Below this threshold the check is skipped to avoid leaving no viable candidates. | 10 |
20 |
integer |
--max-retries |
Maximum per-file retry attempts on a transfer error. | 3 |
5 |
integer |
--retry-delay |
Seconds to wait between retry attempts. | 5 |
10 |
integer |
--download-timeout |
Inactivity timeout in seconds. The download is cancelled if no track has completed and no transfer is actively in-flight for this long. | 180 |
300 |
integer |
--max-download-time |
Hard wallclock ceiling in minutes for a single album download. Cancels the session regardless of in-progress transfer state. | 120 |
240 |
integer |
--clear-completed |
Remove all completed transfers from slskd after each album download. Warning: this is a global operation that clears all completed transfers, not only those started by seakarr. | false |
— | flag |
--completed-pattern |
Relative path pattern for organising downloaded files under --slskd-completed-path. Supports %user%, %artist%, and %album% placeholders. Requires --slskd-completed-path. |
— | %artist%/%album% |
string |
--strip-tags |
Strip all embedded metadata tags from downloaded files after they are organised. Requires --completed-pattern. |
false |
— | flag |
--music-library-path ✱‡ |
Path to an existing music library. Each subdirectory is treated as an artist, and each of its subdirectories as an album to search for and upgrade. Required when --search-mode=automatic. |
— | /mnt/music |
path |
--database-path |
Path to the SQLite database file used to track downloaded albums and preferred users. | ~/.seakarr/db/seakarr.db |
/var/lib/seakarr/seakarr.db |
path |
--log-level |
Console logging level. Choices: debug, info, success, warning, error. |
INFO |
debug |
choice |
--log-path |
Path to the log file. | ~/.seakarr/logs/seakarr.log |
/var/log/seakarr.log |
path |
✱ Required. † Required only when --search-mode=manual. ‡ Required only when --search-mode=automatic.
Note:
--slskd-api-keycan also be supplied via theSLSKD_API_KEYenvironment variable instead of the command-line flag.
Seakarr processes each album target through two main phases: finding the best candidate on the network, then downloading and organising the files.
flowchart TD
A([Start]) --> B{--search-mode?}
B -- manual --> C[Build query from\n--search-artist +\n--search-title]
B -- automatic --> D[Scan --music-library-path\nfor artist/album directories]
D --> E{Already in DB?\nDownloaded or skipped?}
E -- Yes --> F([⏭ Skip album])
E -- No --> E2{Album on disk?\nautomatic mode +\n%artist%+%album% in pattern}
E2 -- Yes --> E3[Backfill DB sentinel] --> F
E2 -- No / check skipped --> G
C --> G{Next album target}
G --> H{DB preferred users\navailable?}
H -- "Yes (no search-user)" --> I[Browse preferred user\nfiles directly]
I --> J{Album found &\nquality criteria met?}
J -- No, try next --> I
J -- All failed --> K{--search-user set?}
H -- No --> K
K -- Yes --> L[Browse single user's\nshared files]
K -- No --> M[Network search\nfor artist + album]
M --> N{Any results?}
N -- No or density-rejected --> O[Artist-only fallback\nsearch + album dir filter]
N -- Yes --> P[Album density filter:\nreject wrong-album results]
O --> P
P --> Q[build_candidates:\ngroup by dir · filter by ext /\nbitrate / bitdepth / lock / queue]
L --> Q
Q --> R{Any candidates\nsurvive filtering?}
R -- No --> S([⚠️ Record skip in DB])
R -- Yes --> T([Ranked candidate list\nready for download])
flowchart TD
A([Ranked candidates]) --> B[Integrity check\non candidate files]
B -- Fail --> C[Try next candidate]
B -- Pass --> D{candidates >=\n--min-filtered-user-count?}
D -- Yes --> E[Start download · wait\n--speed-check-wait · measure rate]
D -- No --> F[Start download\nskip speed check]
E --> G{Speed >=\n--min-upload-speed?}
G -- Below threshold --> H[Cancel + record\nspeed failure]
H --> C
G -- Above threshold --> I[Continue download]
F --> I
I --> J{File error?}
J -- Yes, retries remain --> K[Re-enqueue file\nwait --retry-delay]
K --> I
J -- Yes, retries exhausted --> L[Cleanup staged files]
L --> C
J -- Timeout or cancelled --> M[Cleanup staged files]
M --> C
J -- All succeeded --> N{--completed-pattern set?}
C --> O{More candidates?}
O -- No, speed-cancelled exist --> P[Retry fastest candidate\nwithout speed floor]
P --> N
O -- No, all failed --> Q{Artist-only fallback\nnot yet tried?}
Q -- Yes --> R[Artist-only network search\nrefilter · retry from top]
R --> A
Q -- No --> S([❌ Record skip in DB])
N -- No --> T[Write DB success record]
N -- Yes --> U[Move files using\n--completed-pattern path]
U --> V{--strip-tags set?}
V -- Yes --> W[Strip all embedded tags\nfrom organised files]
W --> T
V -- No --> T
T --> X[Promote user to\npreferred in DB]
X --> Y([✅ Album complete])
If a download is cancelled, times out, or errors, all partially transferred files are cleaned up from slskd's completed directory automatically before the next candidate is tried.
git clone https://github.com/binhex/seakarr
cd seakarr
uv venv --quiet
uv sync --extra devIf you wish to perform linting on all files before committing (PRs will not be accepted if they do not
pass all linting) then run pre-commit run --all-files.
Q: My album has multiple discs — will seakarr handle it?
Seakarr automatically merges multi-disc releases stored in Disc 1 / Disc 2 or CD 1 / CD 2
subdirectories into a single unified candidate so the whole set downloads together.
Q: How do I prevent seakarr from re-downloading albums I already have?
Every successfully downloaded album is recorded in the SQLite database (see --database-path). Seakarr
checks this record before each search and skips any album already marked as downloaded. In automatic
mode, if --completed-pattern contains both %artist% and %album%, seakarr also checks the
organised library on disk — useful when the database has been wiped or albums were added manually.
Albums found on disk are backfilled into the database so subsequent runs use the faster DB check.
Q: What happens when slskd returns a 500 error mid-transfer?
Per-file errors trigger an automatic retry up to --max-retries times (with --retry-delay seconds
between attempts). If retries are exhausted the candidate is abandoned, staged files are cleaned up, and
seakarr moves on to the next ranked candidate.
Q: Can I run seakarr without the speed check?
Set --min-upload-speed 0 to disable the speed check entirely. All candidates will be downloaded
regardless of their measured transfer rate.
Q: The --completed-pattern placeholders look like %%artist%% in some places — why?
Click escapes % to %% in help text. When passing the option on the command line use single percent
signs, e.g. --completed-pattern "%artist%/%album%".