Implements support for configuring both qBittorrent and SABnzbd simultaneously, including migration from legacy config, protocol-aware routing, and protocol filtering. Adds new CRUD API routes for download clients, new UI management components, and updates setup and settings flows to use the new multi-client architecture. Updates documentation to describe the new structure and usage.
5.9 KiB
Multi-Download-Client Support
Status: ✅ Implemented | Simultaneous qBittorrent + SABnzbd support
Overview
Users can configure both qBittorrent (torrents) and SABnzbd (Usenet) simultaneously. System selects best release across all indexer types regardless of protocol.
Constraint: 1 client per type (torrent/usenet) for now; architecture supports future expansion.
Key Details
Configuration Structure
Key: download_clients (JSON array, replaces legacy flat keys)
interface DownloadClientConfig {
id: string; // UUID
type: 'qbittorrent' | 'sabnzbd';
name: string; // User-friendly name
enabled: boolean;
url: string;
username?: string; // qBittorrent only
password: string; // Password or API key
disableSSLVerify: boolean;
remotePathMappingEnabled: boolean;
remotePath?: string;
localPath?: string;
category?: string; // Default: 'readmeabook'
}
Download Client Manager Service
File: src/lib/services/download-client-manager.service.ts
Methods:
getClientForProtocol(protocol: 'torrent' | 'usenet')- Get client by protocolhasClientForProtocol(protocol)- Check if protocol configuredgetAllClients()- List all configstestConnection(config)- Test specific configinvalidate()- Clear cache on config changegetClientServiceForProtocol(protocol)- Get instantiated service
Singleton Pattern: Uses caching with invalidation on config changes.
Protocol Filtering
File: src/lib/integrations/prowlarr.service.ts:379
Logic:
- Both clients configured: Return all results (mixed torrent + NZB)
- Only torrent client: Filter for torrent results only
- Only usenet client: Filter for NZB results only
- No clients: Return empty
Download Routing
File: src/lib/processors/download-torrent.processor.ts:44
Logic:
- Detect protocol from result (
ProwlarrService.isNZBResult()) - Get appropriate client via manager (
getClientForProtocol()) - Route to qBittorrent or SABnzbd service
- Create download history record
Migration
Auto-migration from legacy single-client config to new JSON array format on first access:
- Reads legacy keys:
download_client_type,download_client_url, etc. - Converts to single-client array
- Saves as
download_clientsJSON - Legacy keys remain for backward compatibility (cleaned up on migration)
API Routes
GET /api/admin/settings/download-clients - List all configured clients POST /api/admin/settings/download-clients - Add new client PUT /api/admin/settings/download-clients/[id] - Update client by ID DELETE /api/admin/settings/download-clients/[id] - Delete client by ID POST /api/admin/settings/download-clients/test - Test connection
Validation:
- Only 1 client per type allowed (enforced on add)
- Test connection required before save
- Password masking in responses (
********)
UI Components
Directory: src/components/admin/download-clients/
| Component | Purpose |
|---|---|
DownloadClientManagement.tsx |
Container with add buttons + configured cards |
DownloadClientCard.tsx |
Card with name, type badge, edit/delete |
DownloadClientModal.tsx |
Add/edit modal with type-specific fields |
UI Flow:
- Add Client Section: Two cards (qBittorrent, SABnzbd) with "Add" button or "Already configured" badge
- Configured Clients: Grid of cards showing name, type, URL, status
- Modal: Type-specific fields, SSL toggle, path mapping, test connection
Integration Points
Settings Tab
File: src/app/admin/settings/tabs/DownloadTab/DownloadTab.tsx
Replaced legacy form with <DownloadClientManagement mode="settings" />
Wizard Step
File: src/app/setup/steps/DownloadClientStep.tsx
Replaced single-client form with <DownloadClientManagement mode="wizard" />
Validation: At least 1 enabled client required to proceed
Setup Complete API
File: src/app/api/setup/complete/route.ts
Accepts both legacy single client and new array format:
- Legacy: Converts to array on save
- New: Saves directly as
download_clientsJSON
Edge Cases
Single client: Works exactly as before (protocol filtering active) No clients: Wizard requires one; settings shows warning Client disabled: Results for that protocol filtered out Connection failure: Per-download error handling (existing) Mixed results: Best release selected regardless of protocol when both clients configured
Verification Steps
- Migration: Existing single-client users see config as card after update
- Single client: Configure only qBittorrent → only torrent results shown
- Both clients: Configure both → mixed results, best selected across protocols
- Download routing: Torrent result → qBittorrent; NZB result → SABnzbd
- Wizard: Must add at least one client to proceed
- Settings: Can add/edit/delete/test clients; changes persist
Critical Files
| File | Changes |
|---|---|
src/lib/services/download-client-manager.service.ts |
NEW - Core multi-client service |
src/lib/integrations/prowlarr.service.ts:379 |
Protocol filtering logic (both clients = all results) |
src/lib/processors/download-torrent.processor.ts:44 |
Download routing (detect protocol → route) |
src/app/api/admin/settings/download-clients/* |
NEW - CRUD API routes |
src/components/admin/download-clients/* |
NEW - UI components (card-based) |
src/app/admin/settings/tabs/DownloadTab/DownloadTab.tsx |
Replaced with management component |
src/app/setup/steps/DownloadClientStep.tsx |
Replaced with management component |
src/app/api/setup/complete/route.ts |
Save as JSON array, support legacy |
Related
- qBittorrent Integration - Torrent client details
- SABnzbd Integration - Usenet client details
- Prowlarr Integration - Indexer search