diff --git a/documentation/phase3/qbittorrent.md b/documentation/phase3/qbittorrent.md index fbdd083..aaa6426 100644 --- a/documentation/phase3/qbittorrent.md +++ b/documentation/phase3/qbittorrent.md @@ -30,24 +30,42 @@ Free, open-source BitTorrent client with comprehensive Web API. **Auth:** Cookie-based (login required) **POST /auth/login** - Get session cookie -**POST /torrents/add** - Add torrent (supports `urls` and `torrents` params) +**POST /torrents/add** - Add torrent (supports `urls` and `torrents` params, `savepath` override) **GET /torrents/info?hashes={hash}** - Get status/progress **POST /torrents/pause** - Pause torrent **POST /torrents/resume** - Resume **POST /torrents/delete** - Delete torrent **GET /torrents/files** - Get file list -**POST /torrents/setCategory** - Set category +**POST /torrents/createCategory** - Create category with save path +**POST /torrents/editCategory** - Update category save path +**POST /torrents/setCategory** - Set category for torrent ## Config **Required (database only, no env fallbacks):** -- `qbittorrent_url` -- `qbittorrent_username` -- `qbittorrent_password` -- `paths_downloads` +- `download_client_url` - qBittorrent Web UI URL +- `download_client_username` - qBittorrent username +- `download_client_password` - qBittorrent password +- `download_dir` - Download save path (passed to qBittorrent for all torrents) Validation: All fields checked before service initialization. +## Category Management + +**Category:** `readmeabook` (auto-created for all torrents) + +**Save Path Synchronization:** +- Category created/updated on every torrent addition +- Category save path always synced with `download_dir` config +- Handles config changes: if user changes `download_dir`, category updates automatically +- Uses both `createCategory` and `editCategory` APIs for reliability + +**Why Both Create and Edit:** +1. Create: Ensures category exists (idempotent, won't fail if exists) +2. Edit: Updates save path to match current config (handles user changing settings) + +This prevents issues where category retains old save path after user changes `download_dir` setting. + ## Data Models ```typescript @@ -79,6 +97,7 @@ type TorrentState = 'downloading' | 'uploading' | 'stalledDL' | **6. Race condition on torrent availability** - Fixed with 3s initial delay + exponential backoff retry (500ms, 1s, 2s) **7. Error logging during duplicate check** - Removed console.error in getTorrent() during expected "not found" cases (duplicate checking) **8. Prowlarr magnet link redirects** - Some indexers return HTTP URLs that redirect to magnet: links. Fixed by intercepting 3xx redirects before axios follows them, extracting the Location header, and routing to magnet flow if target is a magnet: link +**9. Category save path not updating** - When user changes `download_dir` setting, category keeps old path. Fixed by calling both `createCategory` and `editCategory` on every torrent addition to ensure category path matches current config ## Tech Stack diff --git a/src/lib/integrations/qbittorrent.service.ts b/src/lib/integrations/qbittorrent.service.ts index 28e0a79..c6812cb 100644 --- a/src/lib/integrations/qbittorrent.service.ts +++ b/src/lib/integrations/qbittorrent.service.ts @@ -369,7 +369,8 @@ export class QBittorrentService { } /** - * Ensure category exists in qBittorrent + * Ensure category exists in qBittorrent with correct save path + * Always updates the category's save path to match current config */ private async ensureCategory(category: string): Promise { if (!this.cookie) { @@ -377,7 +378,7 @@ export class QBittorrentService { } try { - // Create category (this is idempotent - won't fail if it already exists) + // Try to create category first (idempotent - won't fail if exists) await this.client.post( '/torrents/createCategory', new URLSearchParams({ @@ -392,11 +393,34 @@ export class QBittorrentService { } ); - console.log(`[qBittorrent] Category "${category}" ensured`); + console.log(`[qBittorrent] Category "${category}" created/exists`); } catch (error) { - // Ignore errors - category might already exist + // Category might already exist - that's OK console.log(`[qBittorrent] Category creation returned:`, error); } + + // Always update the category's save path to ensure it matches current config + // This handles cases where download_dir was changed after category was created + try { + await this.client.post( + '/torrents/editCategory', + new URLSearchParams({ + category, + savePath: this.defaultSavePath, + }), + { + headers: { + Cookie: this.cookie, + 'Content-Type': 'application/x-www-form-urlencoded', + }, + } + ); + + console.log(`[qBittorrent] Category "${category}" save path updated to: ${this.defaultSavePath}`); + } catch (error) { + console.warn(`[qBittorrent] Failed to update category save path:`, error); + // Don't throw - torrents can still be added with per-torrent savepath parameter + } } /**