CLI tool
fiso64/sockseek avatar
fiso64/sockseek

Sockseek, a scriptable downloader that ranks before it fetches

Advanced download tool for Soulseek, soon a client.

1,128 stars68 forksC#AGPL-3.0

At a glance

What is it?
Sockseek is a C# command line tool for the Soulseek peer-to-peer network. You give it a search string, a playlist, a CSV, a Bandcamp page or a MusicBrainz release, it searches the network, ranks the candidates against your preferences and filters, and downloads the best match. The interesting parts are the recall-first ranking, the index file that makes repeat runs cheap, and a daemon mode that is not yet a client.
Who is it for?
Sockseek fits a user of the Soulseek network who wants scripted, reproducible retrieval rather than a graphical client, and the ranking, the strict filters and the index file are the features that make bulk runs predictable. It does not fit someone who wants a complete Soulseek client, because the tool does not share your music folders yet and the daemon mode is only the path toward that.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 7 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Point it at something, it searches, it ranks, it fetches

Sockseek is described as a command line downloader for Soulseek that will, soon, be a client. The workflow is one sentence: point it at a search string, a Spotify playlist, a YouTube playlist, a CSV file, a Bandcamp page, a MusicBrainz release or a Soulseek link, and it searches the network, ranks candidate files using your preferences, and downloads the best match, automatically or interactively.

Three properties of that sentence matter. It is scriptable, so the same command runs from a cron job or a shell script. It is configurable, so the ranking preferences and the filters are yours to set. And it can run either as a one-shot command or as a persistent daemon, which is the difference between a tool you invoke and a service that holds a connection open.

The tool has been renamed more than once. It was formerly sldl, and slsk-batchdl before that, and the readme links to a note explaining why it was renamed to something dumb. The name history is a reminder that this is a tool with an active user base rather than a fresh project.

The Soulseek network is a peer-to-peer file sharing network where users publish their own collections, so what a query returns depends on who is online and what they are sharing. That is the single most important fact for understanding every design decision in the tool, and the readme is upfront about it: if the file you want exists on Soulseek, Sockseek will find and download it correctly, most of the time.

Spotify and YouTube are metadata, not sources

The input types are the part of the design that surprises people, so the readme spells it out: Sockseek searches the Soulseek peer-to-peer network, and Spotify, YouTube and similar inputs are used only as metadata sources to drive the search, not as audio sources.

That distinction removes any confusion about where the bytes come from. A YouTube playlist URL is a list of track names and artists, and the tool turns each entry into a Soulseek search. A Spotify playlist works the same way. A Bandcamp page and a MusicBrainz release are the same idea from the other direction, a list of tracks with metadata attached.

The input type is usually determined automatically, and you can set it manually with --input-type. The documented types are CSV file, YouTube, Spotify, Bandcamp, MusicBrainz, Soulseek Link, Search string and List file.

The CSV path is worth a note, because it is the one designed for bulk work. Only the title or album column is required, and extra information may improve search result ranking. If the columns have common names such as Artist, Title, Album or Length, they do not have to be specified, otherwise you must provide at least --title-col or --album-col. And the rows determine their own shape: rows with a track title are song downloads, and rows without a title are album downloads. A single file can therefore mix a track list and an album list.

For a plain search string, the hyphen separated form carries meaning. The readme says the ` - ` separator determines what part of the input is the artist and the title, which can be important for ranking and filtering, and it recommends it for albums too.

The default favours recall, and the strict flags pull it back

The tuning default is stated openly: the default settings favour recall over precision. When the correct file is available in the results, it will almost always be ranked first. The tradeoff is that if the correct file is absent and something else loosely passes the filters, that something else gets downloaded.

That is a deliberate choice, and it is the right default for a peer-to-peer network, where a missing file is a common outcome and a wrong file is merely annoying. But it means a user who wants the opposite has to ask for it, and the flags exist.

For a wrong song or album, the readme recommends strict filters:

bash
sockseek "https://open.spotify.com/playlist/blah" --strict-title --strict-artist

These require that the file path contains the song title and the artist name, case-insensitively. For albums, the cleanest guard is usually the expected track count, with --album-track-count 10 for an exact count, and inequalities such as 10+ or 12- when expanded or incomplete editions are acceptable. The readme's advice is that --strict-album, which requires the album name in the folder path, tends to be less clean than the track count.

For a file that is not found at all, there are two common causes. A length mismatch, where the reported length from Spotify or YouTube differs from the actual file, for example a CD rip, by more than the default three second tolerance, which is fixed with --length-tol 10 or disabled with --length-tol -1. And naming differences, where the network returned nothing for the query, which options like --remove-ft or --regex can help clean up.

The diagnostic tool for all of this is --print results-full, which shows what Soulseek returned without downloading anything, and --print jobs-full for the planned job list, which the readme suggests before committing to a 5000 item playlist.

The index file is what makes a second run cheap

For multi-item inputs such as YouTube or Spotify playlists and CSV or list files, Sockseek writes an _index.csv file next to the download output. Re-running the same input uses that index to skip items that were already downloaded, even without the --skip-music-dir option.

That is a small feature with a large effect on how the tool behaves in practice. A playlist of a few thousand tracks will contain duplicates, remastered versions and tracks that were already retrieved in a previous run, and without a record of what happened, every run is a full re-attempt. With the index, the second run is a diff.

The index location is configurable with --index-path, which matters when you run the same input from different directories or want one shared index across several jobs. The readme describes it as a choice of a shared or custom index location.

The other approach to the same problem is --skip-music-dir, which points at an existing music library and skips tracks that are already in it. The difference is worth understanding. The music directory option compares against files you already have, which is broader and catches material downloaded by other means, while the index compares against what this tool itself did, which is exact and does not need a full library scan. For a scripted workflow that runs the same inputs repeatedly, the index is the one that scales.

Daemon mode, and the sharing feature that is not there yet

The readme carries a note that tells you exactly what the project is and is not. Sockseek does not share your music folders yet, and to keep the Soulseek network healthy, it asks you to also share your collection with a regular client such as Nicotine+ or slskd. Daemon mode is described as the path toward longer-running client features, but sharing is not implemented yet.

That is an unusual admission to find at the top of a tool's documentation, and it is the most useful thing in the file. The Soulseek network works because people share, and a downloader that takes without sharing degrades the thing it depends on. Rather than leave that implicit, the author names it and points at two clients that do it properly.

The daemon mode itself is the architectural direction of travel. A persistent process holds a connection to the network and can serve work over a local interface, which is what you need for anything longer running than a single command. The docker-compose file in the repository shows the shape of that, with a service that builds from the project directory, binds a single port, and mounts a config directory and a data directory:

yaml
services:
  sockseek:
    ports:
    - "127.0.0.1:48721:48721"
    build:
      context: .
    environment:
      - TZ=Etc/GMT
    volumes:
      - ./config:/config
      - ./data:/data

Binding to 127.0.0.1 rather than to every interface is the right default for a service that talks to a network on your behalf, and the separate config and data volumes mirror the two things a long-running instance needs: settings and state.

The .NET build, trimmed and self-contained

The Dockerfile shows how the application is packaged, and it is a two-stage build that produces a single trimmed executable. The build stage uses the .NET 10 SDK alpine image, restores the help generator project, and publishes the CLI project as a single file, trimmed and self-contained, for either a linux-musl-x64 or linux-musl-arm64 runtime depending on the target architecture, with the pdb files removed afterwards.

The runtime stage is built on a LinuxServer.io base image, installs the native runtime packages the executable needs, sets the timezone through a symlink and a timezone file, and copies the published output into /usr/bin. The DOCKER_MODS environment variable points at the LinuxServer universal cron mod, which is how the image supports scheduled runs.

The repository layout is a Visual Studio solution with a project per concern: Sockseek.Cli for the command line, Sockseek.Core for the domain logic, Sockseek.Server for the daemon side, Sockseek.Api, Sockseek.Benchmarks, Sockseek.Packager, and a Sockseek.HelpGenerator, plus test projects for the CLI, the core and the server. That last project is the one worth noting, because the readme contains a marker around the help text in the options reference, which suggests the CLI reference documentation is generated from the code rather than written by hand.

The rest of the root is the usual set: a Directory.Build.props for shared build properties, a TODO.md, a scripts/ directory, a build/ directory, a docker/ directory with the image's root files, docs/ with the Docker guide, and a .vscode directory.

Where Sockseek is the wrong tool

The first limit is the one the readme names. If you want a full Soulseek client, with your library shared, with a queue of what you are offering, and with the network etiquette that keeps it usable, this is not it, and the recommended answer is to run Nicotine+ or slskd alongside it. The daemon mode is the direction the project is heading, not a feature you can rely on today.

The second is that the ranking depends on the network being populated. A query for an obscure album works when somebody online is sharing it, and returns nothing when nobody is. The length tolerance and the strict filters make the results more precise, but they cannot make a file exist, and the readme is honest that a naming difference is a cause of a miss that only a different query or a different network state fixes.

The third is the trust question in the metadata inputs. A Spotify or YouTube playlist gives names and durations, and the tool then looks for something on the network that matches. The recall-first default means the first acceptable match is often the one that gets taken, which is why the strict flags and the track count guard exist, and why a user with a large library and an index will find the tool behaves very differently from a user without one.

The fourth is the licence. AGPL-3.0 is a strong copyleft, and for a tool you run yourself that is a normal choice. It is worth reading the LICENSE file if you intend to modify it and offer the result as a service, since the AGPL obligations attach to network use in a way that permissive licences do not. The readme also links to a releases note about the renames, which is where the project's history and any compatibility notes live.

Editorial conclusion

Sockseek fits a user of the Soulseek network who wants scripted, reproducible retrieval rather than a graphical client, and the ranking, the strict filters and the index file are the features that make bulk runs predictable. It does not fit someone who wants a complete Soulseek client, because the tool does not share your music folders yet and the daemon mode is only the path toward that. Before running it in earnest, set up a separate Soulseek account as the readme advises if you already run a persistent client, decide where your index files live with --index-path, and read the strict filter documentation, because the default favours recall over precision. The licence is AGPL-3.0, v3.0.5 was published on 2026-08-10, and the last push was on 2026-10-15.

Frequently asked questions

How do I install and configure Sockseek?

Download a release for your operating system, then create a config file named sockseek.conf in ~/.config/sockseek/sockseek.conf on Linux, macOS and Windows, or in %APPDATA%\sockseek\sockseek.conf on Windows. The minimal configuration sets your Soulseek username, password and output-dir, with an optional pref-format for the file format you prefer.

How do I download a whole album with Sockseek?

Run sockseek "Artist - Album Title" -t for the interactive mode, or the same command without -t for the automatic one. Separating artist from title with a hyphen surrounded by spaces is recommended because it affects how the results are ranked and filtered.

Sockseek downloaded the wrong file, how do I make it stricter?

The default favours recall over precision. Add --strict-title and --strict-artist, which require the file path to contain the title and artist names case-insensitively, or for albums use --album-track-count with a number or an inequality such as 10+ or 12-. You can inspect what the network returned without downloading with --print results-full.

Does Sockseek share my music library with the network?

Not yet. The readme states that sharing is not implemented and asks you to share your collection with a regular client such as Nicotine+ or slskd to keep the Soulseek network healthy, and it describes daemon mode as the path toward longer-running client features.

Can Sockseek run in Docker?

Yes. The repository includes a Dockerfile that publishes the CLI as a single trimmed self-contained .NET executable for x64 or arm64, and a docker-compose file that binds port 48721 on 127.0.0.1 and mounts a config directory and a data directory.

Official sources

  1. fiso64/sockseek on GitHub
  2. Issues
  3. License: AGPL-3.0
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/fiso64-sockseek.svg)](https://hysenlabs.com/projects/fiso64-sockseek)

Was this useful?