Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

andrade-soulseek-downloader

andrade028MIT1.0.28TypeScript support: included

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

soulseek, download, music, p2p, slsk, rate-limit, file-sharing

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

// 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