Compare commits

...

2 Commits

Author SHA1 Message Date
Administrator
4bb18f7abc release: v3.3.46 2026-06-07 20:59:34 +02:00
Administrator
125e5f55ea fix(perf): kill per-progress renderer-to-main IPC + drop redundant queued emit + cache fileSize 2026-06-07 20:59:07 +02:00
4 changed files with 15 additions and 31 deletions

View File

@ -355,7 +355,12 @@ class UploadManager extends EventEmitter {
const fileName = path.basename(task.file); const fileName = path.basename(task.file);
let fileSize = 0; let fileSize = 0;
let fileNotFound = false; let fileNotFound = false;
const cachedResult = results && results.get(task.file);
if (cachedResult && typeof cachedResult.size === 'number' && cachedResult.size > 0) {
fileSize = cachedResult.size;
} else {
try { fileSize = fs.statSync(task.file).size; } catch { fileNotFound = true; } try { fileSize = fs.statSync(task.file).size; } catch { fileNotFound = true; }
}
const maxAttempts = Math.max(1, (settings.retries || 0) + 1); const maxAttempts = Math.max(1, (settings.retries || 0) + 1);
const jobAbortController = new AbortController(); const jobAbortController = new AbortController();
@ -420,23 +425,13 @@ class UploadManager extends EventEmitter {
return; return;
} }
this._emitProgress(uploadId, fileName, task.hoster, { accountId: task.accountId, // The initial 'queued' emit per job is suppressed: with N=2000+ tasks
jobId, // it produces 2000+ main→renderer IPCs back-to-back at startBatch and
status: 'queued', // freezes the renderer event loop for tens of seconds. The renderer
progress: 0, // already holds each job in 'queued'/'preview' state from its own
bytesUploaded: 0, // queueJobs array; the first event it actually needs from main is the
bytesTotal: fileSize, // 'getting-server' / 'uploading' transition for the jobs that the
speedKbs: 0, // semaphore lets through.
elapsed: 0,
remaining: 0,
error: null,
result: null,
attempt: 0,
maxAttempts
});
// Acquire hoster semaphore first so jobs waiting for a hoster slot
// don't waste global slots (prevents underutilization)
await hosterSemaphore.acquire(signal); await hosterSemaphore.acquire(signal);
hosterSlotAcquired = true; hosterSlotAcquired = true;

View File

@ -1,6 +1,6 @@
{ {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "3.3.45", "version": "3.3.46",
"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

@ -108,24 +108,13 @@ async function init() {
window.api.onUpdateAvailable(showUpdateBanner); window.api.onUpdateAvailable(showUpdateBanner);
window.api.onUpdateProgress(handleUpdateProgress); window.api.onUpdateProgress(handleUpdateProgress);
// Upload event listeners — debug log only on state transitions; the 'uploading'
// tick fires 4×/sec per active job and an IPC roundtrip per event would
// backlog the renderer↔main channel with hundreds of messages/sec.
window.api.onUploadProgress((data) => { window.api.onUploadProgress((data) => {
if (data.status !== 'uploading') {
window.api.debugLog('RX upload-progress: ' + data.status + ' ' + data.hoster + ' ' + (data.fileName || ''));
}
handleProgress(data); handleProgress(data);
}); });
window.api.onUploadBatchDone((data) => { window.api.onUploadBatchDone((data) => {
window.api.debugLog('RX upload-batch-done');
handleBatchDone(data); handleBatchDone(data);
}); });
window.api.onUploadStats((data) => { window.api.onUploadStats((data) => {
// Stats fire every second per upload session — skip while uploading.
if (data.state !== 'uploading') {
window.api.debugLog('RX upload-stats: state=' + data.state + ' active=' + data.activeJobs);
}
handleStats(data); handleStats(data);
}); });
window.api.onShutdownCountdown(handleShutdownCountdown); window.api.onShutdownCountdown(handleShutdownCountdown);

View File

@ -55,8 +55,8 @@ describe('UploadManager', () => {
]); ]);
const statuses = events.map(e => e.status); const statuses = events.map(e => e.status);
assert.ok(statuses.includes('queued'), 'should have queued status');
assert.ok(statuses.includes('done'), 'should have done status'); assert.ok(statuses.includes('done'), 'should have done status');
assert.ok(events.length > 0, 'should emit at least one progress event');
}); });
it('emits batch-done with correct summary', async () => { it('emits batch-done with correct summary', async () => {