Multi-Hoster-Upload/lib/queue-dedup.js
Administrator af51bebaf7 fix(queue): stop auto-dedup from deleting pending jobs on restart/update
Reproduced from a real saved config: pendingQueue held 4 'preview' jobs (one
file across 4 hosters); the queue saved + restored correctly. But
_autoDeduplicateFromLog (runs at init after restore) removed jobs whose
fileName|hoster appeared ANYWHERE in the lifetime fileuploader.log, regardless
of status — so all 4 pending previews were deleted and the queue showed the
empty "Dateien hierhin ziehen" state. Looked update-specific only because the
server restarts on update; a plain restart did the same.

- New lib/queue-dedup.js (pure, dual CJS/window export like queue-prune.js):
  partitionRestoredJobsByLog drops ONLY 'done' jobs that match the log. Pending
  (preview/queued) and failed (error/aborted) jobs always survive — they're
  intentional queued work (often a deliberate re-upload of a previously
  uploaded file). Manual importUploadLog stays separate/explicit.
- renderer wires it in; index.html loads the module before app.js.
- Tests: 5 cases incl. the exact reproduced scenario (4 previews all in log ->
  0 removed). Full suite 162/162.

Verified against the user's real electron-config.json + fileuploader.log: old
logic removed 4/4 (empty queue), new logic removes 0/4 (queue preserved).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 01:08:59 +02:00

66 lines
2.6 KiB
JavaScript

// Startup queue auto-dedup logic. Extracted from renderer/app.js
// _autoDeduplicateFromLog so the decision can be unit-tested without a DOM or
// the renderer's module-level state.
//
// Loaded both as a CommonJS module (Node tests) and as a browser global
// (renderer/app.js via index.html script tag) so a single implementation backs
// runtime and tests — no drift.
//
// Behaviour: on launch the restored queue is compared against the lifetime
// upload log. ONLY genuinely-completed ('done') jobs that also appear in the
// log are dropped — that's pure decluttering of work that already finished.
//
// Pending jobs (preview / queued) and failed ones (error / aborted) are NEVER
// dropped here, even if a same-name+hoster line exists in the log. Those are
// work the user intentionally has queued (often a deliberate re-upload of a
// file that was uploaded before). The old code filtered on log-presence alone,
// regardless of status, so the ENTIRE restored queue vanished on the next
// restart/update whenever the files had been uploaded previously — surfacing as
// an empty "Dateien hierhin ziehen oder klicken" queue. Manual log import
// (importUploadLog) stays separate and explicit for users who do want bulk
// dedup of pending jobs.
(function (root) {
'use strict';
function _key(fileName, hoster) {
return `${String(fileName).toLowerCase()}|${String(hoster).toLowerCase()}`;
}
/**
* Partition restored queue jobs into kept vs removed, given lifetime log
* entries. Removes only 'done' jobs whose fileName|hoster is in the log.
* @param {Array<{status:string,fileName:string,hoster:string}>} jobs
* @param {Array<{fileName:string,hoster:string}>} logEntries
* @returns {{ kept: Array, removed: Array }}
*/
function partitionRestoredJobsByLog(jobs, logEntries) {
const kept = [];
const removed = [];
if (!Array.isArray(jobs) || jobs.length === 0) return { kept, removed };
const logKeys = new Set();
for (const e of (Array.isArray(logEntries) ? logEntries : [])) {
if (e && e.fileName && e.hoster) logKeys.add(_key(e.fileName, e.hoster));
}
for (const job of jobs) {
const isDone = job && job.status === 'done' && job.fileName && job.hoster;
if (isDone && logKeys.has(_key(job.fileName, job.hoster))) {
removed.push(job);
} else {
kept.push(job);
}
}
return { kept, removed };
}
const api = { partitionRestoredJobsByLog };
if (typeof module !== 'undefined' && module.exports) {
module.exports = api;
} else if (root) {
root.QueueDedup = api;
}
})(typeof window !== 'undefined' ? window : this);