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 <noreply@anthropic.com>
This commit is contained in:
Administrator 2026-03-11 01:48:39 +01:00
parent 6fbfa4b61e
commit f7e8f9a56c
4 changed files with 41 additions and 10 deletions

View File

@ -67,9 +67,24 @@ class UploadManager extends EventEmitter {
// Start global stats emitter // Start global stats emitter
this._startStatsTimer(); this._startStatsTimer();
// Create job promises — semaphore controls concurrency per hoster // Group tasks by file to process files top-to-bottom
const promises = tasks.map((task) => this._runJob(task, results, signal)); // 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); await Promise.allSettled(promises);
}
this._stopStatsTimer(); this._stopStatsTimer();
this.running = false; this.running = false;

View File

@ -1,6 +1,6 @@
{ {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "1.5.1", "version": "1.5.2",
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously", "description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {

View File

@ -200,7 +200,7 @@ function applyHosterSelection() {
} }
renderHosterSummary(); renderHosterSummary();
updateUploadView(); updateUploadView();
persistQueueStateSoon(); persistQueueStateSoon(true); // immediate persist after adding files
document.getElementById('hosterModal').style.display = 'none'; document.getElementById('hosterModal').style.display = 'none';
} }
@ -297,8 +297,12 @@ async function persistQueueStateNow() {
await window.api.saveGlobalSettings(globalSettings); await window.api.saveGlobalSettings(globalSettings);
} }
function persistQueueStateSoon() { function persistQueueStateSoon(immediate) {
clearTimeout(queuePersistTimer); clearTimeout(queuePersistTimer);
if (immediate) {
persistQueueStateNow().catch(() => {});
return;
}
// Use longer debounce during uploads to reduce disk I/O // Use longer debounce during uploads to reduce disk I/O
const delay = uploading ? 3000 : 500; const delay = uploading ? 3000 : 500;
queuePersistTimer = setTimeout(() => { 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 --- // --- Setup Listeners ---
function setupListeners() { function setupListeners() {
document.getElementById('addFilesBtn').addEventListener('click', pickFiles); document.getElementById('addFilesBtn').addEventListener('click', pickFiles);

View File

@ -175,8 +175,9 @@ body {
flex-direction: column; flex-direction: column;
} }
.queue-container { .queue-container {
flex: 1; flex: 1 1 50%;
min-height: 220px; min-height: 150px;
max-height: 50%;
overflow: auto; overflow: auto;
padding: 0; padding: 0;
background: rgba(255, 255, 255, 0.02); background: rgba(255, 255, 255, 0.02);
@ -290,12 +291,13 @@ body {
} }
.recent-files-panel { .recent-files-panel {
min-height: 220px; flex: 1 1 auto;
max-height: 280px; min-height: 150px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
background: linear-gradient(180deg, rgba(255,255,255,0.015), rgba(0,0,0,0.12)); background: linear-gradient(180deg, rgba(255,255,255,0.015), rgba(0,0,0,0.12));
overflow: auto;
} }
.recent-files-header { .recent-files-header {
display: flex; display: flex;