npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

andrade-soulseek-downloader

v1.0.28

Published

Simple, safe Soulseek download library with built-in rate limiting to prevent bans

Readme

🎵 Soulseek Downloader

npm version npm downloads license node version TypeScript Tests Architecture PRs Welcome

🚀 Enterprise-grade Soulseek downloader with automatic quality selection, ban protection, and clean architecture

InstallationQuick StartFeaturesAPIArchitectureExamples


📖 Table of Contents

⚡ Key Features

| Feature | Description | |---------|-------------| | 🎯 Quality-First Downloads | Automatically downloads the highest quality available (FLAC → 320kbps → 256kbps → 192kbps) | | 🛡️ Ban Protection | Built-in rate limiting and queue management to prevent Soulseek bans | | 📊 Smart Selection | Intelligent file selection based on bitrate, availability, speed, and filename match | | 🔄 Auto-Retry Logic | Tries multiple sources with progressive quality fallback | | 🎨 Beautiful UI | Colored output, progress bars, and status indicators | | ⚡ Simple API | Just one function: soulseekDownload(artist, title) | | 🔐 Safe Defaults | Conservative rate limits and single connection by default | | 📈 Progress Tracking | Real-time download progress with speed indicators | | 🏗️ Clean Architecture | Hexagonal architecture with SOLID principles | | 🔷 TypeScript First | Full TypeScript support with comprehensive type definitions | | 🧪 Well Tested | 42 comprehensive unit tests with high coverage | | 📦 Barrel Exports | Clean imports with organized module structure |

🏗️ Architecture Highlights

This project follows enterprise-grade software architecture principles:

🔷 Hexagonal Architecture (Ports & Adapters)

  • Domain Layer: Pure business logic with entities and services
  • Application Layer: Use cases and orchestration
  • Infrastructure Layer: External adapters (Soulseek, filesystem, logging)
  • Presentation Layer: CLI and API interfaces

🔧 SOLID Principles Applied

  • Single Responsibility: Each class has one clear purpose
  • Open/Closed: Extensible through interfaces
  • Liskov Substitution: Proper inheritance and polymorphism
  • Interface Segregation: Focused, minimal interfaces
  • Dependency Inversion: Depend on abstractions, not concretions

🏭 Dependency Injection

  • Uses InversifyJS for clean dependency management
  • Testable and mockable components
  • Easy to extend and modify

📂 Clean File Organization

  • One symbol per file for maximum clarity
  • kebab-case naming following Node.js conventions
  • Barrel files for clean imports
  • Structured by layer not by feature

🛡️ Ban Protection

This library includes automatic protection against Soulseek bans:

graph LR
    A[Search Request] --> B{Rate Limiter}
    B -->|Wait 5s| C[Execute Search]
    C --> D[Download Request]
    D --> E{Rate Limiter}
    E -->|Wait 3s| F[Execute Download]
    F --> G{Success?}
    G -->|No| H[Error Cooldown 10s]
    H --> D
    G -->|Yes| I[Complete]
    
    style B fill:#ff9999
    style E fill:#ff9999
    style H fill:#ffcc99

Protection Features:

  • ⏱️ 5-second delay between searches
  • ⏱️ 3-second delay between downloads
  • ⏱️ 10-second cooldown after errors
  • 🔒 Single connection limit
  • 📦 Queue management for multiple requests
  • 🔄 Progressive backoff on repeated failures

📦 Installation

# pnpm (recommended)
pnpm add andrade-soulseek-downloader

# npm
npm install andrade-soulseek-downloader

# yarn
yarn add andrade-soulseek-downloader

TypeScript Support

TypeScript definitions are included automatically - no need for separate @types packages!

🚀 Quick Start

1️⃣ Set up environment variables

Create a .env file in your project root:

# Required
SOULSEEK_USER=your_username
SOULSEEK_PASSWORD=your_password
SOULSEEK_SHARED_MUSIC_DIR=/path/to/shared/music
SOULSEEK_DOWNLOAD_DIR=/path/to/downloads

# Optional (defaults shown)
SOULSEEK_MIN_QUALITY_BITRATE=128      # Minimum acceptable quality
SOULSEEK_SEARCH_DELAY=5000            # ms between searches
SOULSEEK_DOWNLOAD_DELAY=3000          # ms between downloads
SOULSEEK_MAX_ATTEMPTS=10              # Max download attempts
SOULSEEK_DOWNLOAD_TIMEOUT=120000      # Download timeout in ms

2️⃣ Use the Simple API

import { soulseekDownload } from 'andrade-soulseek-downloader';

async function downloadTrack() {
  const filePath = await soulseekDownload('Daft Punk', 'One More Time');
  
  if (filePath) {
    console.log(`✅ Downloaded to: ${filePath}`);
  } else {
    console.log('❌ Download failed');
  }
}

downloadTrack();

3️⃣ Or use CommonJS

const { soulseekDownload } = require('andrade-soulseek-downloader');

async function downloadTrack() {
  const filePath = await soulseekDownload('Daft Punk', 'One More Time');
  
  if (filePath) {
    console.log(`✅ Downloaded to: ${filePath}`);
  } else {
    console.log('❌ Download failed');
  }
}

downloadTrack();

🎯 How It Works

flowchart TD
    A[Start Download] --> B[Search Soulseek Network]
    B --> C{Results Found?}
    C -->|No| D[Return null]
    C -->|Yes| E[Group by Quality]
    E --> F[Sort by Availability & Speed]
    F --> G[Try Highest Quality First]
    G --> H{Download Success?}
    H -->|Yes| I[Return File Path]
    H -->|No| J{More Options?}
    J -->|Yes| K[Try Next Quality]
    K --> G
    J -->|No| L[Progressive Fallback]
    L --> G
    
    style E fill:#e1f5fe
    style F fill:#e8f5e8
    style G fill:#fff3e0
    style H fill:#fce4ec

Quality Selection Algorithm

  1. 🔍 Search Phase: Finds all available files
  2. 📊 Quality Grouping: Groups files by bitrate (FLAC, 320kbps, 256kbps, etc.)
  3. ⭐ Smart Scoring: Scores each file based on:
    • Bitrate quality (50 points max)
    • Slot availability (25 points)
    • Connection speed (15 points)
    • Filename match (10 points)
  4. 🎯 Progressive Download: Tries best options first, falls back gracefully

📚 API Reference

Simple API (Recommended)

// Single function for most use cases
soulseekDownload(artist: string, title: string): Promise<string | null>

// Clean up when done
soulseekDisconnect(): Promise<void>

Advanced API

import { 
  SoulseekDownloader, 
  DownloadConfig,
  SearchOptions,
  SoulseekSearchResult 
} from 'andrade-soulseek-downloader';

const downloader = new SoulseekDownloader({
  maxAttempts: 10,
  downloadTimeout: 120000,
  preferSlotsAvailable: true,
  minSpeed: 100000,
  searchDelay: 5000,
  downloadDelay: 3000,
  maxConcurrent: 1,
  cooldownAfterError: 10000
});

// Manual control
await downloader.connect();
const results = await downloader.search(options);
const filePath = await downloader.download(result, artist, title);
await downloader.disconnect();

⚙️ Configuration

Environment Variables

| Variable | Default | Description | |----------|---------|-------------| | SOULSEEK_USER | (required) | Your Soulseek username | | SOULSEEK_PASSWORD | (required) | Your Soulseek password | | SOULSEEK_SHARED_MUSIC_DIR | (required) | Directory to share (can be empty) | | SOULSEEK_DOWNLOAD_DIR | (required) | Where to save downloads | | SOULSEEK_MIN_QUALITY_BITRATE | 128 | Minimum acceptable bitrate (kbps) | | SOULSEEK_SEARCH_DELAY | 5000 | Delay between searches (ms) | | SOULSEEK_DOWNLOAD_DELAY | 3000 | Delay between downloads (ms) | | SOULSEEK_MAX_ATTEMPTS | 10 | Maximum download attempts | | SOULSEEK_DOWNLOAD_TIMEOUT | 120000 | Download timeout (ms) |

Programmatic Configuration

const config: DownloadConfig = {
  maxAttempts: 15,          // Try up to 15 different sources
  downloadTimeout: 180000,  // 3 minute timeout per download
  preferSlotsAvailable: true, // Prefer users with open slots
  minSpeed: 500000,         // Minimum 500kb/s connection
  searchDelay: 3000,        // 3 second delay between searches
  downloadDelay: 2000,      // 2 second delay between downloads
  maxConcurrent: 1,         // Always 1 to prevent bans
  cooldownAfterError: 15000 // 15 second cooldown after errors
};

💡 Examples

Basic Usage

import { soulseekDownload, soulseekDisconnect } from 'andrade-soulseek-downloader';

// Download a single track
const file1 = await soulseekDownload('The Beatles', 'Hey Jude');
const file2 = await soulseekDownload('Pink Floyd', 'Comfortably Numb');

// Clean up when done
await soulseekDisconnect();

Batch Downloads

import { soulseekDownload, soulseekDisconnect } from 'andrade-soulseek-downloader';

const tracks = [
  { artist: 'The Beatles', title: 'Hey Jude' },
  { artist: 'Pink Floyd', title: 'Comfortably Numb' },
  { artist: 'Led Zeppelin', title: 'Stairway to Heaven' }
];

for (const track of tracks) {
  console.log(`Downloading ${track.artist} - ${track.title}...`);
  const filePath = await soulseekDownload(track.artist, track.title);
  
  if (filePath) {
    console.log(`✅ Downloaded: ${filePath}`);
  } else {
    console.log(`❌ Failed: ${track.artist} - ${track.title}`);
  }
}

await soulseekDisconnect();

Advanced Configuration

import { 
  SoulseekDownloader,
  DownloadConfig,
  SearchOptions 
} from 'andrade-soulseek-downloader';

const config: DownloadConfig = {
  maxAttempts: 20,
  downloadTimeout: 300000, // 5 minutes
  preferSlotsAvailable: true,
  minSpeed: 1000000, // 1 MB/s minimum
  searchDelay: 2000,
  downloadDelay: 1000
};

const downloader = new SoulseekDownloader(config);

try {
  await downloader.connect();
  
  const searchOptions: SearchOptions = {
    artist: 'Daft Punk',
    title: 'One More Time',
    minBitrate: 320, // Only high quality
    timeout: 60000,
    maxResults: 50,
    strictMatching: true
  };
  
  const results = await downloader.search(searchOptions);
  console.log(`Found ${results.length} high-quality results`);
  
  if (results.length > 0) {
    const bestResult = results[0]; // Already sorted by quality
    const filePath = await downloader.download(bestResult, 'Daft Punk', 'One More Time');
    console.log(`Downloaded: ${filePath}`);
  }
  
} finally {
  await downloader.disconnect();
}

CLI Usage

# Global installation
pnpm install -g andrade-soulseek-downloader

# Command line usage
soulseek-download "The Beatles" "Hey Jude"

# Or run directly with pnpm
pnpm start "The Beatles" "Hey Jude"

📊 Architecture

This project demonstrates professional software architecture patterns:

graph TB
    subgraph "Presentation Layer"
        CLI[CLI Handler]
        API[API Handler]
    end
    
    subgraph "Application Layer"
        UC[Use Cases]
        DTO[DTOs]
    end
    
    subgraph "Domain Layer"
        E[Entities]
        VO[Value Objects]
        DS[Domain Services]
        R[Repository Interfaces]
    end
    
    subgraph "Infrastructure Layer"
        REPO[Soulseek Repository]
        LOG[Console Logger]
        RL[Rate Limiter]
        DI[DI Container]
    end
    
    CLI --> UC
    API --> UC
    UC --> DS
    UC --> R
    DS --> E
    DS --> VO
    R --> REPO
    UC --> LOG
    UC --> RL
    
    style CLI fill:#e3f2fd
    style API fill:#e3f2fd
    style UC fill:#e8f5e8
    style E fill:#fff3e0
    style VO fill:#fff3e0
    style DS fill:#fff3e0
    style REPO fill:#fce4ec

Directory Structure

src/
├── presentation/           # User interfaces
│   ├── api/               # HTTP/Function API
│   └── cli/               # Command line interface
├── application/           # Use cases & orchestration
│   ├── use-cases/         # Business workflows
│   └── dto/               # Data transfer objects
├── domain/                # Core business logic
│   ├── entities/          # Business objects
│   ├── value-objects/     # Immutable values
│   ├── services/          # Domain services
│   └── repositories/      # Repository interfaces (ports)
├── infrastructure/        # External concerns
│   ├── repositories/      # Repository implementations (adapters)
│   ├── services/          # External services
│   └── container/         # Dependency injection
├── shared/                # Shared utilities
│   ├── interfaces/        # Common interfaces
│   └── types/             # Type definitions
└── core/                  # Core components

Benefits of This Architecture

  • 🧪 Highly Testable: Easy to mock and test each layer
  • 🔧 Maintainable: Clear separation of concerns
  • 🔄 Flexible: Easy to swap implementations
  • 📈 Scalable: Can grow with your needs
  • 🛡️ Robust: Handles errors gracefully
  • 📝 Self-Documenting: Clear intent and structure

🧪 Testing

The project includes comprehensive test coverage:

# Run all tests
pnpm test

# Run tests with coverage
pnpm test:coverage

# Run specific test suites
pnpm test:unit
pnpm test:integration

# Watch mode for development
pnpm test:watch

Test Statistics

  • 42 Tests across all layers
  • 4 Test Suites covering domain, application, and infrastructure
  • High Coverage on critical business logic
  • Fast Execution (< 1 second)

Test Architecture

  • Unit Tests: Domain entities, value objects, services
  • Integration Tests: Use cases with mocked dependencies
  • Mocking: Comprehensive mocks for external dependencies
  • Test Utilities: Shared test factories and helpers

📝 TypeScript Support

Built-in Type Definitions

Full TypeScript support is included by default:

import { 
  soulseekDownload,           // Function
  SoulseekDownloader,         // Class
  DownloadConfig,             // Interface
  SearchOptions,              // Interface
  SoulseekSearchResult,       // Interface
  RateLimiter                 // Class
} from 'andrade-soulseek-downloader';

// All types are automatically available
const config: DownloadConfig = {
  maxAttempts: 10,
  downloadTimeout: 120000
  // TypeScript will provide IntelliSense here
};

Type Safety Features

  • Comprehensive Interfaces: All public APIs are fully typed
  • Generic Support: Type-safe generic functions where applicable
  • Strict Null Checks: Proper handling of nullable values
  • IntelliSense Support: Full autocomplete in supported editors
  • Compile-time Safety: Catch errors before runtime

Import Options

// Barrel imports (recommended)
import { Track, Bitrate } from 'andrade-soulseek-downloader/domain';
import { DownloadTrackUseCase } from 'andrade-soulseek-downloader/application';

// Specific imports
import { soulseekDownload } from 'andrade-soulseek-downloader/presentation/api';
import { SoulseekDownloader } from 'andrade-soulseek-downloader/core';

// Root imports (simple)
import { soulseekDownload, SoulseekDownloader } from 'andrade-soulseek-downloader';

🔧 Advanced Usage

Custom Rate Limiting

import { RateLimiter, RateLimitConfig } from 'andrade-soulseek-downloader';

const customConfig: RateLimitConfig = {
  searchDelay: 2000,      // Faster searches (be careful!)
  downloadDelay: 4000,    // Slower downloads (safer)
  maxConcurrent: 1,       // Always 1 for safety
  cooldownAfterError: 20000 // Longer cooldown
};

const rateLimiter = RateLimiter.getInstance(customConfig);

// Use with your own functions
const results = await rateLimiter.executeSearch(async () => {
  return await customSearchFunction();
});

Extending the Domain

import { Track, TrackSelectionService } from 'andrade-soulseek-downloader/domain';

class CustomTrackSelectionService extends TrackSelectionService {
  selectBestTracks(tracks: Track[], maxPerBitrate: number = 5): Track[] {
    // Your custom selection logic
    const filtered = tracks.filter(track => 
      track.getBitrate().getValue() >= 256 && 
      track.hasAvailableSlots()
    );
    
    return super.selectBestTracks(filtered, maxPerBitrate);
  }
}

Custom Logging

import { ILogger } from 'andrade-soulseek-downloader/shared';

class CustomLogger implements ILogger {
  info(message: string): void {
    // Send to your logging service
    console.log(`[INFO] ${new Date().toISOString()} ${message}`);
  }
  
  success(message: string): void {
    // Custom success handling
    console.log(`[SUCCESS] ${message}`);
  }
  
  // ... implement other methods
}

// Use with dependency injection
container.bind<ILogger>('ILogger').to(CustomLogger);

❓ FAQ

Q: Is this safe to use? Will I get banned?

A: Yes, it's designed with safety first. The built-in rate limiting prevents bans by enforcing conservative delays between operations.

Q: What audio quality can I expect?

A: The library automatically finds the highest quality available, preferring lossless formats (FLAC) when possible, then falling back to 320kbps, 256kbps, etc.

Q: Can I use this in production?

A: Yes! The architecture is enterprise-grade with proper error handling, logging, and testing. However, always respect Soulseek's terms of service.

Q: Does it work with TypeScript?

A: Absolutely! Full TypeScript support is built-in with comprehensive type definitions.

Q: Can I customize the download behavior?

A: Yes, the architecture is designed for extensibility. You can inject custom services, modify selection algorithms, or add your own retry logic.

Q: How do I report issues?

A: Please open an issue on GitHub with detailed information about your problem, including logs and environment details.

🐛 Troubleshooting

Common Issues

Connection Problems

Error: Failed to connect to Soulseek

Solution: Check your username/password and network connection.

No Results Found

No tracks found

Solutions:

  • Try broader search terms
  • Lower the minimum bitrate requirement
  • Check if the artist/track exists on Soulseek

Download Timeouts

Download timeout for user X

Solutions:

  • Increase SOULSEEK_DOWNLOAD_TIMEOUT
  • The library will automatically try other sources

Rate Limit Warnings

Warning: Multiple SoulseekDownloader instances detected!

Solution: Use only one instance of SoulseekDownloader, or use the simple API functions.

Debug Mode

Enable debug logging:

DEBUG=true pnpm start "Artist" "Title"

Or programmatically:

process.env.DEBUG = 'true';
import { soulseekDownload } from 'andrade-soulseek-downloader';

🤝 Contributing

We welcome contributions! Here's how to get started:

Development Setup

# Clone the repository
git clone https://github.com/andrade/soulseek-downloader.git
cd soulseek-downloader

# Install dependencies
pnpm install

# Run tests
pnpm test

# Build the project
pnpm build

# Run in development
pnpm dev

Code Standards

  • TypeScript: All code must be in TypeScript
  • Architecture: Follow hexagonal architecture patterns
  • Testing: Maintain high test coverage
  • Formatting: Code is automatically formatted
  • Conventions: Use kebab-case for files, PascalCase for classes

Submitting Changes

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature/amazing-feature
  3. Make your changes following the architecture patterns
  4. Add tests for new functionality
  5. Ensure all tests pass: pnpm test
  6. Build successfully: pnpm build
  7. Commit your changes: git commit -m 'Add amazing feature'
  8. Push to the branch: git push origin feature/amazing-feature
  9. Open a Pull Request

Architecture Guidelines

When contributing, please:

  • Keep domain logic pure (no external dependencies)
  • Use dependency injection for external concerns
  • Follow the single responsibility principle
  • Add comprehensive tests for new features
  • Update documentation for API changes

📄 License

MIT © andrade


⭐ Star this repo if you found it helpful!

Report BugRequest FeatureContribute