andrade-soulseek-downloader
Version:
Simple, safe Soulseek download library with built-in rate limiting to prevent bans
753 lines (583 loc) โข 21.9 kB
Markdown
# ๐ต Soulseek Downloader
<div align="center">




[](https://www.typescriptlang.org/)
[](#testing)
[](#architecture)
[](http://makeapullrequest.com)
**๐ Enterprise-grade Soulseek downloader with automatic quality selection, ban protection, and clean architecture**
[Installation](#-installation) โข [Quick Start](#-quick-start) โข [Features](#-features) โข [API](#-api-reference) โข [Architecture](#-architecture) โข [Examples](#-examples)
</div>
---
## ๐ Table of Contents
- [โก Key Features](#-key-features)
- [๐๏ธ Architecture Highlights](#๏ธ-architecture-highlights)
- [๐ก๏ธ Ban Protection](#๏ธ-ban-protection)
- [๐ฆ Installation](#-installation)
- [๐ Quick Start](#-quick-start)
- [๐ฏ How It Works](#-how-it-works)
- [๐ API Reference](#-api-reference)
- [โ๏ธ Configuration](#๏ธ-configuration)
- [๐ก Examples](#-examples)
- [๐จ Quality Selection](#-quality-selection-algorithm)
- [๐ Architecture](#-architecture)
- [๐งช Testing](#-testing)
- [๐ง Advanced Usage](#-advanced-usage)
- [๐ TypeScript Support](#-typescript-support)
- [โ FAQ](#-faq)
- [๐ Troubleshooting](#-troubleshooting)
- [๐ค Contributing](#-contributing)
## โก 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**
- **S**ingle Responsibility: Each class has one clear purpose
- **O**pen/Closed: Extensible through interfaces
- **L**iskov Substitution: Proper inheritance and polymorphism
- **I**nterface Segregation: Focused, minimal interfaces
- **D**ependency 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:
```mermaid
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
```bash
# 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:
```env
# 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
```typescript
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
```javascript
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
```mermaid
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)
```typescript
// Single function for most use cases
soulseekDownload(artist: string, title: string): Promise<string | null>
// Clean up when done
soulseekDisconnect(): Promise<void>
```
### Advanced API
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```bash
# 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:
```mermaid
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**:
```bash
# 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**:
```typescript
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
```typescript
// 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
```typescript
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
```typescript
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
```typescript
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**
```bash
Error: Failed to connect to Soulseek
```
**Solution**: Check your username/password and network connection.
#### **No Results Found**
```bash
No tracks found
```
**Solutions**:
- Try broader search terms
- Lower the minimum bitrate requirement
- Check if the artist/track exists on Soulseek
#### **Download Timeouts**
```bash
Download timeout for user X
```
**Solutions**:
- Increase `SOULSEEK_DOWNLOAD_TIMEOUT`
- The library will automatically try other sources
#### **Rate Limit Warnings**
```bash
Warning: Multiple SoulseekDownloader instances detected!
```
**Solution**: Use only one instance of SoulseekDownloader, or use the simple API functions.
### Debug Mode
Enable debug logging:
```bash
DEBUG=true pnpm start "Artist" "Title"
```
Or programmatically:
```typescript
process.env.DEBUG = 'true';
import { soulseekDownload } from 'andrade-soulseek-downloader';
```
## ๐ค Contributing
We welcome contributions! Here's how to get started:
### Development Setup
```bash
# 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](https://github.com/andrade)
---
<div align="center">
**โญ Star this repo if you found it helpful!**
[Report Bug](https://github.com/andrade/soulseek-downloader/issues) โข [Request Feature](https://github.com/andrade/soulseek-downloader/issues) โข [Contribute](https://github.com/andrade/soulseek-downloader/pulls)
</div>