113 lines
4.3 KiB
JavaScript
113 lines
4.3 KiB
JavaScript
// 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 DownloadMatcher = require('./DownloadMatcher');
|
|
|
|
/**
|
|
* 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 }) {
|
|
// 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: [] } };
|
|
const sonarrHistory = cacheSnapshot.sonarrHistory || { data: { records: [] } };
|
|
const radarrQueue = cacheSnapshot.radarrQueue || { data: { records: [] } };
|
|
const radarrHistory = cacheSnapshot.radarrHistory || { data: { records: [] } };
|
|
const qbittorrentTorrents = cacheSnapshot.qbittorrentTorrents || [];
|
|
|
|
// Get queue status for SABnzbd
|
|
const queueStatus = sabnzbdQueue.data?.queue?.status || null;
|
|
const queueSpeed = sabnzbdQueue.data?.queue?.speed || null;
|
|
const queueKbpersec = sabnzbdQueue.data?.queue?.kbpersec || null;
|
|
|
|
// Build context for matching functions
|
|
const context = {
|
|
sonarrQueueRecords: sonarrQueue.data?.records || [],
|
|
sonarrHistoryRecords: sonarrHistory.data?.records || [],
|
|
radarrQueueRecords: radarrQueue.data?.records || [],
|
|
radarrHistoryRecords: radarrHistory.data?.records || [],
|
|
seriesMap: seriesMap || new Map(),
|
|
moviesMap: moviesMap || new Map(),
|
|
sonarrTagMap: sonarrTagMap || new Map(),
|
|
radarrTagMap: radarrTagMap || new Map(),
|
|
username,
|
|
isAdmin,
|
|
showAll,
|
|
embyUserMap: embyUserMap || new Map(),
|
|
queueStatus,
|
|
queueSpeed,
|
|
queueKbpersec
|
|
};
|
|
|
|
// Match all download sources
|
|
const userDownloads = [];
|
|
const seenDownloadKeys = new Set();
|
|
|
|
if (sabnzbdQueue.data?.queue?.slots) {
|
|
const sabMatches = DownloadMatcher.matchSabSlots(sabnzbdQueue.data.queue.slots, context);
|
|
for (const dl of sabMatches) {
|
|
const key = `${dl.type}:${dl.title}`;
|
|
if (!seenDownloadKeys.has(key)) {
|
|
seenDownloadKeys.add(key);
|
|
userDownloads.push(dl);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sabnzbdHistory.data?.history?.slots) {
|
|
const sabHistoryMatches = DownloadMatcher.matchSabHistory(sabnzbdHistory.data.history.slots, context);
|
|
for (const dl of sabHistoryMatches) {
|
|
const key = `${dl.type}:${dl.title}`;
|
|
if (!seenDownloadKeys.has(key)) {
|
|
seenDownloadKeys.add(key);
|
|
userDownloads.push(dl);
|
|
}
|
|
}
|
|
}
|
|
|
|
const torrentMatches = DownloadMatcher.matchTorrents(qbittorrentTorrents, context);
|
|
for (const dl of torrentMatches) {
|
|
const key = `${dl.type}:${dl.title}`;
|
|
if (!seenDownloadKeys.has(key)) {
|
|
seenDownloadKeys.add(key);
|
|
userDownloads.push(dl);
|
|
}
|
|
}
|
|
|
|
return userDownloads;
|
|
} catch (error) {
|
|
console.error('[DownloadBuilder] Error building user downloads:', error.message);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
buildUserDownloads
|
|
};
|