Skip to content

binhex/seakarr

Repository files navigation

Seakarr

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.

Features

  • Dual search modesmanual mode searches for a single artist or album on demand; automatic mode 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-count candidates 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 1 subdirectories 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-path using 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).

Prerequisites

Quick start

Installation using uv (recommended)

git clone https://github.com/binhex/seakarr
cd seakarr
uv venv --quiet
uv sync

Installation using pip

git clone https://github.com/binhex/seakarr
cd seakarr
python -m venv .venv
source .venv/bin/activate
pip install .

Usage

seakarr --help

Manual 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%"

Options

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-key can also be supplied via the SLSKD_API_KEY environment variable instead of the command-line flag.

How it works

Seakarr processes each album target through two main phases: finding the best candidate on the network, then downloading and organising the files.

Search and candidate selection

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])
Loading

Download and organisation

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])
Loading

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.

Development

git clone https://github.com/binhex/seakarr
cd seakarr
uv venv --quiet
uv sync --extra dev

If 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.

FAQ

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%".

About

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.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages