Pluggable Download Client Architecture (PDCA) – Unified Interface + Expanded Client Support #18
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem Statement
Sofarr currently handles download clients in a semi-coupled way:
SABnzbd logic lives mostly inside the poller.
qBittorrent has its own dedicated client class (recently enhanced with the Sync API).
This makes adding new clients (rtorrent, uTorrent, Transmission, Deluge) expensive and risks inconsistent data shapes in the cache and dashboard. Every new client duplicates authentication, error handling, normalization, and caching logic.
Goal
Introduce a clean, pluggable abstraction layer for all download clients (Usenet + BitTorrent) so that:
The poller and cache become client-agnostic.
Adding a new client is a matter of implementing a small, well-defined interface.
All clients produce a normalized download object that the rest of the application can consume without knowing the underlying client.
Scope
Define a DownloadClient abstract base class / interface with these core methods:
Refactor existing clients to implement the interface:
Create a DownloadClientFactory + registry (config-driven).
Update the poller to iterate over registered clients generically.
Normalize all download objects to a common schema (see below).
Comprehensive unit + integration tests for the new abstraction.
Update ARCHITECTURE.md and add a small “Adding a New Download Client” guide.
Normalized Download Object (Proposed Schema)
All clients must return objects matching this shape (extensible via raw or clientSpecific):
Success Metrics