diff --git a/app/services/download_manager.py b/app/services/download_manager.py index 86faf66..e7c45f1 100644 --- a/app/services/download_manager.py +++ b/app/services/download_manager.py @@ -71,6 +71,11 @@ class DownloadManager: def add_to_queue(self, item_type: str, item_id: str): task_id = f"{item_type}_{item_id}" + + # Prevent duplicate tasks + if task_id in self.active_downloads: + return self.active_downloads[task_id] + task = { "id": task_id, "type": item_type, @@ -93,19 +98,28 @@ class DownloadManager: break task_id = task["id"] - self.active_downloads[task_id]["status"] = "downloading" + + # Ensure task is tracked in active_downloads + if task_id not in self.active_downloads: + self.active_downloads[task_id] = task + + task["status"] = "downloading" try: self._process_download(task) - self.active_downloads[task_id]["status"] = "completed" - self.active_downloads[task_id]["progress"] = 100 + task["status"] = "completed" + task["progress"] = 100 except Exception as e: logger.error(f"Download failed: {e}") - self.active_downloads[task_id]["status"] = "failed" - self.active_downloads[task_id]["error"] = str(e) + task["status"] = "failed" + task["error"] = str(e) finally: # Move to history - self.history.append(self.active_downloads.pop(task_id)) + # Only pop if the current task in active_downloads is the one we just processed + if task_id in self.active_downloads and self.active_downloads[task_id] is task: + self.history.append(self.active_downloads.pop(task_id)) + else: + self.history.append(task) self.queue.task_done() def cancel_task(self, task_id: str): @@ -158,14 +172,14 @@ class DownloadManager: if key == "progress": # For single track, this is the main progress if task["type"] == "track": - self.active_downloads[task["id"]]["progress"] = value + task["progress"] = value elif key == "name": # Update status with current track name - self.active_downloads[task["id"]]["current_item"] = value + task["current_item"] = value elif key == "list_progress": # For albums/playlists, this is the main progress if task["type"] != "track": - self.active_downloads[task["id"]]["progress"] = value + task["progress"] = value mock_progress = MockProgressBars(update_task) diff --git a/app/templates/index.html b/app/templates/index.html index 0bcddcc..c17d447 100644 --- a/app/templates/index.html +++ b/app/templates/index.html @@ -29,8 +29,15 @@
-

Download Queue

-
+

Downloads

+
+ Active Queue +
+
+
+ History +
+
@@ -171,20 +178,35 @@ const response = await fetch('/download/queue'); const queue = await response.json(); - const list = document.getElementById('queue-list'); - list.innerHTML = ''; + const queueList = document.getElementById('queue-list'); + const historyList = document.getElementById('history-list'); + + queueList.innerHTML = ''; + historyList.innerHTML = ''; + + let activeCount = 0; + let historyCount = 0; queue.forEach(item => { const div = document.createElement('div'); div.className = 'queue-item'; let controls = ''; - if (item.status === 'downloading' || item.status === 'queued') { + + // Determine if active or history + // Active: queued, downloading + // History: completed, failed, cancelled + const isHistory = ['completed', 'failed', 'cancelled'].includes(item.status); + + if (!isHistory) { + activeCount++; if (item.control === 'pause') { controls += ``; } else { controls += ``; } controls += ``; + } else { + historyCount++; } div.innerHTML = ` @@ -203,8 +225,16 @@ `; - list.appendChild(div); + + if (!isHistory) { + queueList.appendChild(div); + } else { + historyList.appendChild(div); + } }); + + document.getElementById('queue-count').textContent = `(${activeCount})`; + document.getElementById('history-count').textContent = `(${historyCount})`; } async function controlTask(id, action) {