From f7e8f9a56c6213a341431cbc1c11e1986a29f849 Mon Sep 17 00:00:00 2001 From: Administrator Date: Wed, 11 Mar 2026 01:48:39 +0100 Subject: [PATCH] fix: split layout, top-to-bottom queue processing, persist queue on close - Queue table limited to 50% height with scrollbar, links panel below - Upload processes files sequentially (file1 all hosters, then file2, etc.) - Queue state persists immediately after adding files (not debounced) - Add beforeunload handler to flush pending queue state Co-Authored-By: Claude Opus 4.6 --- lib/upload-manager.js | 21 ++++++++++++++++++--- package.json | 2 +- renderer/app.js | 18 ++++++++++++++++-- renderer/styles.css | 10 ++++++---- 4 files changed, 41 insertions(+), 10 deletions(-) diff --git a/lib/upload-manager.js b/lib/upload-manager.js index e8c4275..304a616 100644 --- a/lib/upload-manager.js +++ b/lib/upload-manager.js @@ -67,9 +67,24 @@ class UploadManager extends EventEmitter { // Start global stats emitter this._startStatsTimer(); - // Create job promises — semaphore controls concurrency per hoster - const promises = tasks.map((task) => this._runJob(task, results, signal)); - await Promise.allSettled(promises); + // Group tasks by file to process files top-to-bottom + // Within each file, all hosters run in parallel + const fileOrder = []; + const tasksByFile = new Map(); + for (const task of tasks) { + if (!tasksByFile.has(task.file)) { + tasksByFile.set(task.file, []); + fileOrder.push(task.file); + } + tasksByFile.get(task.file).push(task); + } + + for (const file of fileOrder) { + if (signal.aborted) break; + const fileTasks = tasksByFile.get(file); + const promises = fileTasks.map((task) => this._runJob(task, results, signal)); + await Promise.allSettled(promises); + } this._stopStatsTimer(); this.running = false; diff --git a/package.json b/package.json index 924f34c..3c1eca7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "multi-hoster-uploader", - "version": "1.5.1", + "version": "1.5.2", "description": "Upload files to doodstream, voe, vidmoly, byse simultaneously", "main": "main.js", "scripts": { diff --git a/renderer/app.js b/renderer/app.js index b8d590d..3f7f7c1 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -200,7 +200,7 @@ function applyHosterSelection() { } renderHosterSummary(); updateUploadView(); - persistQueueStateSoon(); + persistQueueStateSoon(true); // immediate persist after adding files document.getElementById('hosterModal').style.display = 'none'; } @@ -297,8 +297,12 @@ async function persistQueueStateNow() { await window.api.saveGlobalSettings(globalSettings); } -function persistQueueStateSoon() { +function persistQueueStateSoon(immediate) { clearTimeout(queuePersistTimer); + if (immediate) { + persistQueueStateNow().catch(() => {}); + return; + } // Use longer debounce during uploads to reduce disk I/O const delay = uploading ? 3000 : 500; queuePersistTimer = setTimeout(() => { @@ -1515,6 +1519,16 @@ function sortHistoryRows(rows) { }); } +// Flush pending queue state on window close +window.addEventListener('beforeunload', () => { + if (queuePersistTimer) { + clearTimeout(queuePersistTimer); + queuePersistTimer = null; + // Synchronous-ish: fire and forget since window is closing + persistQueueStateNow().catch(() => {}); + } +}); + // --- Setup Listeners --- function setupListeners() { document.getElementById('addFilesBtn').addEventListener('click', pickFiles); diff --git a/renderer/styles.css b/renderer/styles.css index 1bd74e7..8dbfb32 100644 --- a/renderer/styles.css +++ b/renderer/styles.css @@ -175,8 +175,9 @@ body { flex-direction: column; } .queue-container { - flex: 1; - min-height: 220px; + flex: 1 1 50%; + min-height: 150px; + max-height: 50%; overflow: auto; padding: 0; background: rgba(255, 255, 255, 0.02); @@ -290,12 +291,13 @@ body { } .recent-files-panel { - min-height: 220px; - max-height: 280px; + flex: 1 1 auto; + min-height: 150px; display: flex; flex-direction: column; border-top: 1px solid var(--border); background: linear-gradient(180deg, rgba(255,255,255,0.015), rgba(0,0,0,0.12)); + overflow: auto; } .recent-files-header { display: flex;