Commit Graph

308 Commits

Author SHA1 Message Date
Administrator
2d8b3f1bf9 perf: final sweep — hot-path allocation, cached log target, sort-header skip
Last round of targeted wins:

  - upload-manager progress callback was allocating a fresh
    { jobId, speedKbs, bytesUploaded } object on every fs stream chunk
    (hundreds of times per second per active job). Now a single entry
    is created at job start and mutated in place — zero allocations
    on the steady-state progress tick.

  - upload-manager stats timer's two separate activeJobs.values()
    scans (globalSpeedKbs + inProgressBytes) merged into one pass.

  - clouddrop-upload.js reuses a single Buffer.allocUnsafe(chunkSize)
    across all chunks, taking subarray() only for the tail chunk.
    A 1 GB upload no longer allocates 64× 16 MB = 1 GB of short-lived
    buffers — real GC relief during many-file batches.

  - _resolveUploadLogTarget is now cached; the fallback ladder runs
    once per session (or when the user changes the log path / daily-log
    date rolls), not on every 500ms flush.

  - renderRecentUploadsPanel skips updateRecentSortHeaders on the
    append-only fast path — sort state hasn't changed, headers don't
    need recomputing.
2026-04-19 14:02:34 +02:00
Administrator
c73108afff release: v2.8.8 2026-04-19 13:56:02 +02:00
Administrator
f16dd9ffa6 perf: lazy history refresh + append-only recent panel + queue-cleanup merge
Three more targeted wins:

  - loadHistory() was called unconditionally on every handleBatchDone,
    doing an IPC roundtrip + full history-table rebuild even when the
    user is on the Upload tab and can't see it. Now it sets a dirty
    flag and the actual refresh is deferred until the user switches
    to the Verlauf tab. On a fresh tab click it always runs.

  - renderRecentUploadsPanel append-only fast path: when the sort is
    'date desc' (the default) and the dataset only grew, the panel
    inserts the new rows at the top via insertAdjacentHTML instead
    of rebuilding the 5000-row tbody from scratch. Length shrinks or
    sort-change still trigger a full rebuild.

  - handleBatchDone's removeFromQueueOnDone cleanup now does one pass
    (build keep-list + detach from index together) instead of two
    separate filter() scans over queueJobs.
2026-04-19 13:55:37 +02:00
Administrator
1bcd7a2078 release: v2.8.7 2026-04-19 13:39:02 +02:00
Administrator
879f6ade0e perf: O(1) lookups for selection buttons, applySummaryResults, file-drop dedup; batched upload log
Four more wins targeting batch-heavy paths:

  - updateQueueActionButtons replaced three O(n) queueJobs.some() scans
    with a single O(|selection|) pass over selectedJobIds, using the
    existing _jobIndexById map. Selection change cost on a 1000-job
    queue drops from ~3000 comparisons to |selection|.

  - applySummaryResults built a (fileName+hoster)→job Map once per call
    instead of running queueJobs.find() per result. Big batches
    (hundreds of files × multiple hosters) no longer scale O(n²).

  - addPathsToQueue and the folder-monitor auto-queue path built their
    dedup Set up front instead of running .find() per incoming path.
    Picking a folder with thousands of files now dedups in O(n+m)
    instead of O(n×m).

  - appendUploadLog became async + buffered like debugLog. A burst of
    20 files completing within a second becomes one fs.appendFile
    instead of 20 fs.appendFileSync that each blocked the main event
    loop. Fallback ladder (primary → Desktop → userData) is preserved;
    pending buffer flushes synchronously on before-quit.
2026-04-19 13:38:39 +02:00
Administrator
73e7190913 release: v2.8.6 2026-04-19 13:19:28 +02:00
Administrator
8f304f91d8 perf: buffered debug-log writer, scroll rAF-throttle, Set dedup for recent panel
Three more rounds of lag removal aimed at heavy upload sessions:

  - main-process debugLog() was doing fs.appendFileSync on every call
    and was firing hundreds of times per second during busy uploads
    (progress transitions, unhandled rejection traces, folder-monitor
    events). Replaced with an in-memory buffer flushed every 500ms via
    async appendFile — the main event loop is no longer blocked per
    line. Buffered entries flush synchronously on before-quit.

  - the renderer's 'RX upload-progress' / 'RX upload-stats' listeners
    were emitting one IPC roundtrip per event. For 20 concurrent jobs
    that's 80 IPC messages/sec just for logging. They now skip the
    debug call on the hot 'uploading' tick and only log transitions.

  - _onQueueScroll now coalesces scroll events via requestAnimationFrame
    so a fast trackpad fling triggers one virtual render per frame
    instead of one per wheel event.

  - maybeAddSessionFile switched from O(n) sessionFilesData.some() dedup
    to an O(1) Set lookup keyed on (link, filename, host). Adding 1000
    results to an already-populated panel drops from ~500ms to <5ms.
2026-04-19 13:19:04 +02:00
Administrator
ae46d90dc2 release: v2.8.5 2026-04-19 12:59:33 +02:00
Administrator
9158949480 perf: memoize queue sort, dedup stats scan per tick, skip no-op DOM writes
Three more wins on top of the previous pass:
  - sortQueueJobs memoizes the result for static sort keys
    (filename, host, size) — these don't change during upload, so
    every 200ms progress render now reuses the same sorted array
    instead of running an O(n log n) Collator compare.
  - _computeQueueStats caches within a single tick via queueMicrotask.
    updateStatusBar + updateStatsPanel are always called back-to-back
    and now share one queue scan instead of running two.
  - _updateRowInPlace writes DOM values only when they actually
    changed. Idle/queued/done rows (the majority) incur zero DOM
    mutations per progress tick.
2026-04-19 12:59:10 +02:00
Administrator
571d507889 release: v2.8.4 2026-04-19 12:27:46 +02:00
Administrator
85287aa620 perf: kill lag with 1000s of rows during upload
The two worst hot paths were:
  - clicking a row triggered a full table rebuild with sort+innerHTML
    (queue AND recent panel), and the opposite panel got cleared with
    another full rebuild
  - every upload progress tick (4/sec) scanned queueJobs twice and
    filtered sessionFilesData twice just to update the status bar

Fixes:
  - applyQueueSelectionClasses / applyRecentSelectionClasses toggle the
    .selected class on existing rows instead of rebuilding the tbody.
    Click selection is now O(rendered rows) instead of O(total × sort).
  - maybeAddSessionFile schedules renderRecentUploadsPanel via rAF so
    a batch of 1000 successful uploads coalesces into one render.
  - sortRecentFiles memoizes its result per (sortKey, direction, len)
    — unchanged sort state + unchanged length returns the cached array
    instead of re-sorting thousands of entries.
  - _computeQueueStats now also returns inProgressBytes, dropping the
    second queueJobs scan in updateStatusBar.
  - session done/error counts are maintained incrementally, replacing
    two sessionFilesData.filter().length calls every status-bar tick.
  - handleRowClick uses the _jobIndexById map instead of Array.find.
2026-04-19 12:27:16 +02:00
Administrator
7dc68c7615 release: v2.8.3 2026-04-19 11:54:26 +02:00
Administrator
60ceea41d7 fix: encrypt hoster credentials at rest; history CSV Link column urls-only
Two issues:
1. Verlauf-Export CSV put the opaque file_code in the Link column when
   the upload had no real URL, so the column looked like just a bunch
   of IDs. Now only real http(s) URLs land in that column.
2. Hoster passwords and API keys were stored as plaintext in
   electron-config.json. Now wrapped with Electron's safeStorage (DPAPI
   on Windows, Keychain on macOS, libsecret on Linux) and stored as
   'enc:v1:<base64>'.

Credentials are decrypted on load so in-memory flows stay unchanged,
and backups still export plaintext inside the existing .mhu envelope
so they remain portable between machines/users. Legacy plaintext
configs auto-migrate on next write.
2026-04-19 11:53:59 +02:00
Administrator
b80ca7238d release: v2.8.2 2026-04-19 11:47:17 +02:00
Administrator
415162e058 fix(log): fall back to user's Desktop before AppData, keep daily-log naming
If the configured log path (or the default exe-adjacent path) isn't
writable, we now try the current user's Desktop first — that's where
users actually look — and only fall back to AppData if Desktop is
also unavailable. The daily-log filename suffix is preserved on the
fallback file so the format stays consistent.
2026-04-19 11:46:50 +02:00
Administrator
fdac28040d release: v2.8.1 2026-04-19 11:43:00 +02:00
Administrator
3472f4e1ed fix(import): strip machine-specific paths when importing backup
A backup made on 'Server A' carries absolute paths (logFilePath,
folderMonitor.folderPath, pendingQueue file paths) that do not exist
on 'Server B' — leading to silent log-write failures, folder-monitor
start errors on missing directories, and queue jobs pointing at
non-existent files.

On import, now:
  - clear logFilePath if its parent directory doesn't exist here
  - clear folderMonitor.folderPath + disable it if the directory is missing
  - clear pendingQueue (queue state is inherently per-machine)

Also harden startup: folder-monitor auto-start now verifies the path
exists and persists enabled=false if not, so one missing-path launch
doesn't keep retrying forever.
2026-04-19 11:42:33 +02:00
Administrator
62a459353a release: v2.8.0 2026-04-19 11:36:09 +02:00
Administrator
9a7354fc55 feat(recent): export all recent uploads (name+link+hoster+time)
Adds an 'Exportieren' button next to 'Alle entfernen' that writes a
pipe-delimited log of every row currently shown in the recent-uploads
panel — so session data doesn't get lost if the log file path is wrong.

Also fixes appendUploadLog silently failing: if the configured path is
unwritable (e.g. C:/Users/<nonexistent>/...), entries now go to
<userData>/fileuploader-fallback.log and the renderer warns once.
2026-04-19 11:35:41 +02:00
Administrator
299fa8a4e5 release: v2.7.9 2026-04-17 16:55:18 +02:00
Administrator
161357522e fix(backup): don't pass click event as legacy password
addEventListener('click', doBackupImport) was passing the MouseEvent
as the first argument, which got forwarded to pbkdf2 as an Object.
2026-04-17 16:54:53 +02:00
Administrator
e3c8ccdca4 release: v2.7.8 2026-04-17 11:23:01 +02:00
Administrator
edb614f985 feat(backup): import legacy password-encrypted backups
Try app-internal key first (new format); on failure, signal the
renderer to prompt for the old password and retry. Lets users import
.mhu files that were exported with a custom password in v2.7.6 or
earlier without downgrading.
2026-04-17 11:22:33 +02:00
Administrator
90c7fe297d release: v2.7.7 2026-04-17 11:17:53 +02:00
Administrator
3e9483e222 feat(backup): drop password prompt on export/import
File stays AES-GCM encrypted with a fixed app-internal key — opaque
without the app, which is the only protection we actually need for
locally-stored API keys. Removes the modal and both password dialogs.
2026-04-17 11:17:21 +02:00
Administrator
43433cbc00 release: v2.7.6 2026-04-11 15:09:43 +02:00
Administrator
6780cf3261 fix(clouddrop): route chunk PUTs via upload.clouddrop.cc (bypass CF)
Only the 16 MB chunk stream needs the upload subdomain; init and
complete are tiny and can stay on the main host.
2026-04-11 15:09:13 +02:00
Administrator
0bf3061852 release: v2.7.5 2026-04-11 07:31:11 +02:00
Administrator
79cf8ad002 fix(clouddrop): never throw after all chunks uploaded
/upload/complete was failing (non-JSON response, missing fileId, or
post-processing timeout) after all bytes were already on the server,
causing upload-manager to retry the entire multi-GB upload — which
corrupts the server-side file since two uploads end up interleaved.

Now /complete failures are swallowed and sessionId is used as the
file_code fallback. Upload is considered done once all chunks are in.
2026-04-11 07:30:39 +02:00
Administrator
215a10186e release: v2.7.4 2026-04-11 07:25:50 +02:00
Administrator
f955064524 fix(clouddrop): only upload, skip share-link generation entirely 2026-04-11 07:25:23 +02:00
Administrator
c6c59ce868 release: v2.7.3 2026-04-11 07:18:13 +02:00
Administrator
cba69a7806 fix(clouddrop): retry share-link during post-processing, never fail upload
Upload completes on server but file is still being processed, so
share-link fails. Retry up to 6x with backoff; on final failure, use
fileId-based fallback URL instead of throwing — prevents upload-manager
from retrying the entire multi-GB upload.
2026-04-11 07:17:45 +02:00
Administrator
bc32f4dc95 release: v2.7.2 2026-04-11 07:14:57 +02:00
Administrator
7db08a6ab3 fix(clouddrop): trailing slash on /files endpoint to avoid 301 2026-04-11 07:14:30 +02:00
Administrator
237da99523 release: v2.7.1 2026-04-11 07:12:55 +02:00
Administrator
ff8b0799e0 fix(clouddrop): cap concurrent TCP connections at 50 via undici Agent
Defensive guard to stay under server's cd_conn 100/IP limit even
with aggressive parallel uploads and keep-alive pooling.
2026-04-11 07:12:25 +02:00
Administrator
84f117584c release: v2.7.0 2026-04-11 06:55:52 +02:00
Administrator
1164da37ea feat: add Clouddrop.cc as upload hoster (API key auth, chunked uploads)
- New lib/clouddrop-upload.js with chunked upload support (16 MB chunks)
- Auth via Bearer token (cd_XXX format)
- Files < 16 MB: simple multipart POST /api/cloud/upload
- Files > 16 MB: chunked protocol (init → PUT chunks → complete)
- After upload: auto-creates permanent share link via /api/cloud/share-link
- Health check verifies API key by listing root files

Registered in:
- lib/config-store.js (HOSTER_NAMES, templates, DEFAULTS)
- main.js (hosterAccountHasCreds, checkClouddropHealth, runHosterHealthCheck)
- lib/upload-manager.js (_executeUpload dispatch)
- renderer/app.js (HOSTERS, HOSTER_ADD_OPTIONS, getHosterLabel)

Tests: 74/74 pass. ESLint: 0/0.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 06:55:21 +02:00
Administrator
eba85fc924 release: v2.6.9 2026-04-06 23:26:11 +02:00
Administrator
849b1e340b feat: 'Alle entfernen' button for recent files panel
Adds a red 'Alle entfernen' button next to the 'Zuletzt erzeugte
Upload-Links' label that clears all entries from the recent files
panel after confirmation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:25:42 +02:00
Administrator
6af0463425 release: v2.6.8 2026-04-06 23:14:08 +02:00
Administrator
e7dd91ae59 feat: resizable queue table columns (JDownloader-style)
Drag the right edge of any queue column header to resize it. Cursor
changes to col-resize on hover. Widths are saved to localStorage and
restored on next launch.

- Resizer handles in all 8 queue table columns
- Resize state visible via dragging class + body cursor override
- Min width 40px, no max (table can scroll horizontally)
- Click on resizer doesn't trigger column sort
- Persisted across sessions via localStorage

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 23:13:40 +02:00
Administrator
e02926e849 release: v2.6.7 2026-04-06 23:02:20 +02:00
Administrator
31d157b695 test: 3 new tests for addJobs (74/74 pass)
- addJobs injects new tasks into running batch (verified concurrent execution)
- addJobs rejects duplicate jobIds already in batch
- addJobs returns added=0 when not running

These tests verify the fix in v2.6.3 (files added during upload now
get injected into the running batch via addJobsToBatch).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:56:26 +02:00
Administrator
cb6d61a406 🐛 fix: files added during upload now actually get uploaded
When user added new files during an active upload (drag-drop, picker
or folder monitor with pre-selected hosters), the files were pushed to
selectedFiles but NO queue jobs were created (because updateUploadView
skips buildQueuePreview during uploading=true).

The files briefly showed up via folder monitor's direct buildQueuePreview
call, but then handleBatchDone → syncSelectedFilesFromQueue removed them
from selectedFiles because they had no queue jobs.

Now: applyHosterSelection() and folder monitor both detect added files
during upload and:
1. Build preview jobs for the new files
2. Reset them to 'queued' status
3. Inject them into the running batch via addJobsToBatch IPC

The upload-manager has duplicate protection so re-injection is safe.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 22:46:31 +02:00
Administrator
00bf6f126d release: v2.6.6 2026-03-28 19:49:14 +01:00
Administrator
c197a004c8 Add full upload history export and keep complete history 2026-03-28 19:48:28 +01:00
Administrator
29ab989cbe release: v2.6.5 2026-03-26 11:08:48 +01:00
Administrator
b75930cb29 refactor: unify queue start status handling 2026-03-26 11:08:01 +01:00