diff --git a/renderer/app.js b/renderer/app.js index 50bc7b4..b75c87d 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -99,6 +99,7 @@ async function init() { syncSelectedUploadHosters(); restoreQueueStateFromConfig(); await _autoDeduplicateFromLog(); + _hydrateMissingJobSizes(); renderHosterSummary(); renderHosterModal(); renderSettings(); @@ -997,12 +998,54 @@ function scheduleStatusChangeUpdate() { }); } +function _hydrateMissingJobSizes(jobsLike) { + if (!window.api || !window.api.getFileSizes) return; + const paths = []; + const seen = new Set(); + const source = Array.isArray(jobsLike) ? jobsLike : queueJobs; + for (const j of source) { + if (!j || !j.file) continue; + if (j.bytesTotal && j.bytesTotal > 0) continue; + if (seen.has(j.file)) continue; + seen.add(j.file); + paths.push(j.file); + } + if (paths.length === 0) return; + window.api.getFileSizes(paths).then((sizeMap) => { + if (!sizeMap || typeof sizeMap !== 'object') return; + let changed = false; + for (const j of queueJobs) { + if (sizeMap[j.file] && (!j.bytesTotal || j.bytesTotal === 0)) { + j.bytesTotal = sizeMap[j.file]; + changed = true; + } + } + for (const f of selectedFiles) { + if (sizeMap[f.path] && (!f.size || f.size === 0)) f.size = sizeMap[f.path]; + } + if (changed) { + _queueStatsCache = null; + if (typeof renderQueueTable === 'function') renderQueueTable(); + if (typeof updateStatusBar === 'function') updateStatusBar(); + } + }).catch(() => {}); +} + +function _formatUploadedSize(job) { + const bt = job.bytesTotal || 0; + const bu = job.bytesUploaded || 0; + const s = job.status; + if (s === 'preview') return bt > 0 ? formatSize(bt) : '...'; + if (s === 'queued' || s === 'getting-server' || s === 'retrying') { + return bt > 0 ? `${formatSize(bu)} / ${formatSize(bt)}` : '...'; + } + return `${formatSize(bu)} / ${formatSize(bt)}`; +} + function buildRowHtml(job) { const statusClass = `status-${job.status}`; const rowClass = `queue-row ${statusClass}${selectedJobIds.has(job.id) ? ' selected' : ''}`; - const uploadedSize = job.status === 'preview' - ? (job.bytesTotal > 0 ? formatSize(job.bytesTotal) : '...') - : `${formatSize(job.bytesUploaded)} / ${formatSize(job.bytesTotal)}`; + const uploadedSize = _formatUploadedSize(job); const statusText = getStatusText(job); const elapsed = formatTime(job.elapsed); const remaining = formatTime(job.remaining); @@ -1032,9 +1075,7 @@ function buildRowHtml(job) { // In-place update of a single row's cells (avoids full innerHTML rebuild) function _updateRowInPlace(tr, job) { const statusClass = `status-${job.status}`; - const uploadedSize = job.status === 'preview' - ? (job.bytesTotal > 0 ? formatSize(job.bytesTotal) : '...') - : `${formatSize(job.bytesUploaded)} / ${formatSize(job.bytesTotal)}`; + const uploadedSize = _formatUploadedSize(job); const statusText = getStatusText(job); const elapsed = formatTime(job.elapsed); const remaining = formatTime(job.remaining); @@ -1728,6 +1769,7 @@ async function startUpload() { if (uploading) return; uploading = true; // set immediately to prevent double-click race updateQueueActionButtons(); + _hydrateMissingJobSizes(); const hosters = getSelectedHosters(); if (queueJobs.length === 0 && selectedFiles.length > 0) { @@ -1800,6 +1842,7 @@ function _markSkippedJobs(result) { async function startSelectedUpload() { if (uploading) { + _hydrateMissingJobSizes(); const addable = queueJobs.filter(j => selectedJobIds.has(j.id) && isStartableQueueStatus(j.status)); if (addable.length === 0) { if (selectedJobIds.size > 0) showCopyToast('Keine startbaren Jobs ausgewählt (alle laufen schon oder sind fertig).');