diff --git a/server/services/DownloadBuilder.js b/server/services/DownloadBuilder.js index 64fc235..fce6509 100644 --- a/server/services/DownloadBuilder.js +++ b/server/services/DownloadBuilder.js @@ -1,9 +1,21 @@ // Copyright (c) 2026 Gordon Bolton. MIT License. + +/** + * DownloadBuilder - Aggregates and matches download data from multiple sources. + * This service processes cached data from SABnzbd, qBittorrent, Sonarr, and Radarr to build + * a unified view of downloads for each user, matching downloads to media metadata via tags. + */ + const { mapTorrentToDownload } = require('../utils/qbittorrent'); const TagMatcher = require('./TagMatcher'); const DownloadAssembler = require('./DownloadAssembler'); -// Build series map from queue and history records +/** + * Builds a Map of series metadata from Sonarr queue and history records. + * @param {Array} queueRecords - Sonarr queue records + * @param {Array} historyRecords - Sonarr history records + * @returns {Map} Map of seriesId to series object + */ function buildSeriesMapFromRecords(queueRecords, historyRecords) { const seriesMap = new Map(); for (const r of queueRecords) { @@ -15,7 +27,12 @@ function buildSeriesMapFromRecords(queueRecords, historyRecords) { return seriesMap; } -// Build movies map from queue and history records +/** + * Builds a Map of movie metadata from Radarr queue and history records. + * @param {Array} queueRecords - Radarr queue records + * @param {Array} historyRecords - Radarr history records + * @returns {Map} Map of movieId to movie object + */ function buildMoviesMapFromRecords(queueRecords, historyRecords) { const moviesMap = new Map(); for (const r of queueRecords) { @@ -27,7 +44,14 @@ function buildMoviesMapFromRecords(queueRecords, historyRecords) { return moviesMap; } -// Get slot status and speed based on queue status +/** + * Determines the status and speed for a SABnzbd slot based on queue state. + * @param {Object} slot - SABnzbd queue slot + * @param {string} queueStatus - Overall queue status (e.g., 'Paused') + * @param {string} queueSpeed - Queue speed string + * @param {string} queueKbpersec - Queue speed in KB/s + * @returns {Object} Object with status and speed properties + */ function getSlotStatusAndSpeed(slot, queueStatus, queueSpeed, queueKbpersec) { if (queueStatus === 'Paused') { return { status: 'Paused', speed: '0' }; @@ -38,7 +62,12 @@ function getSlotStatusAndSpeed(slot, queueStatus, queueSpeed, queueKbpersec) { }; } -// Match SABnzbd queue slots to Sonarr/Radarr activity +/** + * Matches SABnzbd queue slots to Sonarr/Radarr activity using download IDs and title matching. + * @param {Array} slots - SABnzbd queue slots + * @param {Object} context - Matching context with records, maps, and user info + * @returns {Array} Array of matched download objects + */ function matchSabSlots(slots, context) { const { sonarrQueueRecords, @@ -215,7 +244,12 @@ function matchSabSlots(slots, context) { return matched; } -// Match SABnzbd history slots to Sonarr/Radarr activity +/** + * Matches SABnzbd history slots to Sonarr/Radarr activity using title matching. + * @param {Array} slots - SABnzbd history slots + * @param {Object} context - Matching context with records, maps, and user info + * @returns {Array} Array of matched download objects + */ function matchSabHistory(slots, context) { const { sonarrHistoryRecords, @@ -313,7 +347,12 @@ function matchSabHistory(slots, context) { return matched; } -// Match qBittorrent torrents to Sonarr/Radarr activity +/** + * Matches qBittorrent torrents to Sonarr/Radarr activity using title matching. + * @param {Array} torrents - qBittorrent torrent list + * @param {Object} context - Matching context with records, maps, and user info + * @returns {Array} Array of matched download objects + */ function matchTorrents(torrents, context) { const { sonarrQueueRecords, @@ -529,9 +568,31 @@ function matchTorrents(torrents, context) { return matched; } -// Build user downloads from cache snapshot +/** + * Builds a unified list of downloads for a user from multiple download clients. + * Matches SABnzbd and qBittorrent downloads to Sonarr/Radarr activity using tags. + * @param {Object} cacheSnapshot - Cached data from all services + * @param {Object} options - User context and metadata maps + * @param {string} options.username - Lowercase username for tag matching + * @param {string} options.usernameSanitized - Original username + * @param {boolean} options.isAdmin - Whether user is admin + * @param {boolean} options.showAll - Whether to show all users' downloads + * @param {Map} options.seriesMap - Map of seriesId to series object + * @param {Map} options.moviesMap - Map of movieId to movie object + * @param {Map} options.sonarrTagMap - Map of Sonarr tag IDs to labels + * @param {Map} options.radarrTagMap - Map of Radarr tag IDs to labels + * @param {Map} options.embyUserMap - Map of Emby users for admin view + * @returns {Array} Array of download objects for the user + */ function buildUserDownloads(cacheSnapshot, { username, usernameSanitized, isAdmin, showAll, seriesMap, moviesMap, sonarrTagMap, radarrTagMap, embyUserMap }) { - // Handle null/undefined cache data + // Input validation + if (!cacheSnapshot || typeof cacheSnapshot !== 'object') { + console.error('[DownloadBuilder] Invalid cacheSnapshot provided'); + return []; + } + + try { + // Handle null/undefined cache data const sabnzbdQueue = cacheSnapshot.sabnzbdQueue || { data: { queue: { slots: [] } } }; const sabnzbdHistory = cacheSnapshot.sabnzbdHistory || { data: { history: { slots: [] } } }; const sonarrQueue = cacheSnapshot.sonarrQueue || { data: { records: [] } }; @@ -599,7 +660,11 @@ function buildUserDownloads(cacheSnapshot, { username, usernameSanitized, isAdmi } } - return userDownloads; + return userDownloads; + } catch (error) { + console.error('[DownloadBuilder] Error building user downloads:', error.message); + return []; + } } module.exports = {