Files
ReadMeABook/src/lib/interfaces/download-client.interface.ts
T
kikootwo 789a2e50ef Add sourceHeaders and conditional OIDC groups
Add support for passing sourceHeaders when fetching NZB/torrent files: extend AddDownloadOptions and SABnzbd AddNZBOptions, forward headers in sabnzbd and nzbget clients, and populate sourceHeaders in download-torrent.processor (injecting Prowlarr API key as X-Api-Key for proxy URLs). Make OIDC request scope conditional: only include the 'groups' scope when group-based access control or admin-claim is enabled (update provider logic, add tests, and update setup UI text). Also remove explicit take:100 in Plex processors and add CLAUDE guidance about requesting approval before implementing code changes.
2026-03-09 10:33:52 -04:00

205 lines
6.6 KiB
TypeScript

/**
* Component: Download Client Interface
* Documentation: documentation/phase3/download-clients.md
*
* Defines the contract all download clients must implement.
* Enables protocol-agnostic download management across torrent and usenet clients.
*/
// =========================================================================
// TYPE DEFINITIONS
// =========================================================================
/** Supported download client types — single source of truth */
export const SUPPORTED_CLIENT_TYPES = ['qbittorrent', 'sabnzbd', 'nzbget', 'transmission', 'deluge'] as const;
/** Identifies the specific download client software */
export type DownloadClientType = (typeof SUPPORTED_CLIENT_TYPES)[number];
/** Human-readable display names for each client type */
export const CLIENT_DISPLAY_NAMES: Record<DownloadClientType, string> = {
qbittorrent: 'qBittorrent',
sabnzbd: 'SABnzbd',
nzbget: 'NZBGet',
transmission: 'Transmission',
deluge: 'Deluge',
};
/** Get display name for a client type, falling back to the raw type */
export function getClientDisplayName(type: string): string {
return CLIENT_DISPLAY_NAMES[type as DownloadClientType] || type;
}
/** The download protocol a client operates on */
export type ProtocolType = 'torrent' | 'usenet';
/** Maps each client type to its download protocol */
export const CLIENT_PROTOCOL_MAP: Record<DownloadClientType, ProtocolType> = {
qbittorrent: 'torrent',
sabnzbd: 'usenet',
nzbget: 'usenet',
transmission: 'torrent',
deluge: 'torrent',
};
/** Unified download status across all clients */
export type DownloadStatus =
| 'downloading'
| 'completed'
| 'seeding'
| 'paused'
| 'queued'
| 'failed'
| 'processing'
| 'checking';
// =========================================================================
// DATA INTERFACES
// =========================================================================
/**
* Unified download information returned by all clients.
* Normalizes torrent and NZB data into a single shape.
*/
export interface DownloadInfo {
/** Client-assigned identifier (torrent hash or NZB ID) */
id: string;
/** Display name of the download */
name: string;
/** Total size in bytes */
size: number;
/** Bytes downloaded so far */
bytesDownloaded: number;
/** Download progress from 0.0 to 1.0 */
progress: number;
/** Normalized download status */
status: DownloadStatus;
/** Current download speed in bytes/sec */
downloadSpeed: number;
/** Estimated time remaining in seconds */
eta: number;
/** Category/label assigned to this download */
category: string;
/** Filesystem path where download is stored (available after completion) */
downloadPath?: string;
/** Configured save directory (torrent clients only, used for path readiness detection) */
savePath?: string;
/** When the download completed */
completedAt?: Date;
/** Error message if download failed */
errorMessage?: string;
/** Time spent seeding in seconds (torrent clients only) */
seedingTime?: number;
/** Upload/download ratio (torrent clients only) */
ratio?: number;
}
/** Options for adding a new download */
export interface AddDownloadOptions {
/** Category/label to assign */
category?: string;
/** Priority level (interpretation varies by client) */
priority?: string;
/** Whether to add in paused state */
paused?: boolean;
/** Headers to include when fetching the source file (e.g. Prowlarr API key for proxy URLs) */
sourceHeaders?: Record<string, string>;
}
/** Result of a connection test */
export interface ConnectionTestResult {
success: boolean;
message?: string;
version?: string;
}
// =========================================================================
// DOWNLOAD CLIENT INTERFACE
// =========================================================================
/**
* IDownloadClient — the contract every download client must implement.
*
* Provides a unified API for managing downloads across different protocols
* and client software. Processors interact with this interface exclusively,
* enabling new download clients to be added without modifying consumer code.
*
* To add a new client (e.g., Transmission):
* 1. Create a service class implementing IDownloadClient
* 2. Add the type to DownloadClientType
* 3. Add factory case in DownloadClientManager
*/
export interface IDownloadClient {
/** Identifies the client software (e.g., 'qbittorrent', 'sabnzbd') */
readonly clientType: DownloadClientType;
/** The protocol this client operates on */
readonly protocol: ProtocolType;
/**
* Test the connection to the download client.
* @returns Connection test result with success/failure and optional version
*/
testConnection(): Promise<ConnectionTestResult>;
/**
* Add a new download.
* @param url - Download URL (magnet link, .torrent URL, or .nzb URL)
* @param options - Optional download settings
* @returns Client-assigned download ID (torrent hash or NZB ID)
*/
addDownload(url: string, options?: AddDownloadOptions): Promise<string>;
/**
* Get current status of a download.
* Includes retry logic for race conditions (e.g., torrent not immediately available after adding).
* @param id - Download ID returned by addDownload
* @returns Download info, or null if not found
*/
getDownload(id: string): Promise<DownloadInfo | null>;
/**
* Pause a download.
* @param id - Download ID
*/
pauseDownload(id: string): Promise<void>;
/**
* Resume a paused download.
* @param id - Download ID
*/
resumeDownload(id: string): Promise<void>;
/**
* Delete a download from the client.
* @param id - Download ID
* @param deleteFiles - Whether to also delete downloaded files (default: false)
*/
deleteDownload(id: string, deleteFiles?: boolean): Promise<void>;
/**
* Perform post-download cleanup specific to the client.
* - qBittorrent: No-op (torrents continue seeding, handled by cleanup job)
* - SABnzbd: Archives the completed NZB from history
* @param id - Download ID
*/
postProcess(id: string): Promise<void>;
/**
* Get available categories/labels from the download client.
* - qBittorrent: Returns configured category names
* - Transmission: Returns empty array (uses free-form labels)
* - Usenet clients: Returns empty array (feature scoped to torrent clients)
*/
getCategories(): Promise<string[]>;
/**
* Set the category/label for a download.
* - qBittorrent: Sets torrent category
* - Transmission: Sets torrent label
* - Usenet clients: No-op
* @param id - Download ID
* @param category - Category/label name to assign
*/
setCategory(id: string, category: string): Promise<void>;
}