diff --git a/package.json b/package.json index 3c1eca7..423f35c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "multi-hoster-uploader", - "version": "1.5.2", + "version": "1.5.3", "description": "Upload files to doodstream, voe, vidmoly, byse simultaneously", "main": "main.js", "scripts": { diff --git a/preload.js b/preload.js index d209018..e7b10de 100644 --- a/preload.js +++ b/preload.js @@ -1,4 +1,4 @@ -const { contextBridge, ipcRenderer } = require('electron'); +const { contextBridge, ipcRenderer, webUtils } = require('electron'); contextBridge.exposeInMainWorld('api', { // Config @@ -65,6 +65,8 @@ contextBridge.exposeInMainWorld('api', { onShutdownCountdown: (callback) => { ipcRenderer.on('shutdown-countdown', (_event, data) => callback(data)); }, + // File path from drag & drop (Electron 33+ compatible) + getPathForFile: (file) => webUtils.getPathForFile(file), removeAllListeners: () => { ipcRenderer.removeAllListeners('upload-progress'); ipcRenderer.removeAllListeners('upload-batch-done'); diff --git a/renderer/app.js b/renderer/app.js index 3f7f7c1..0428c40 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -354,10 +354,19 @@ let _pendingFiles = []; // Files waiting for hoster modal confirmation function addDroppedFiles(fileList) { const files = Array.from(fileList); + const existingPaths = new Set([ + ...selectedFiles.map(f => f.path), + ..._pendingFiles.map(f => f.path) + ]); const newFiles = []; for (const file of files) { - if (!selectedFiles.find(f => f.path === file.path) && !_pendingFiles.find(f => f.path === file.path)) { - newFiles.push({ path: file.path, name: file.name, size: file.size }); + // Use webUtils.getPathForFile (Electron 33+) with fallback to file.path + let filePath = ''; + try { filePath = window.api.getPathForFile(file); } catch { filePath = file.path || ''; } + const fileName = file.name || ''; + if (filePath && !existingPaths.has(filePath)) { + newFiles.push({ path: filePath, name: fileName, size: file.size }); + existingPaths.add(filePath); } } if (newFiles.length > 0) { @@ -527,7 +536,8 @@ function renderQueueTable() { tbody.innerHTML = _sortedJobsCache.map(buildRowHtml).join(''); _lastVisibleRange = { start: -1, end: -1 }; } else { - // Virtual scrolling for large queues + // Virtual scrolling for large queues — force re-render + _lastVisibleRange = { start: -1, end: -1 }; _renderVirtualRows(tbody); } @@ -554,9 +564,9 @@ function _renderVirtualRows(tbody) { if (!scrollContainer) return; const totalRows = _sortedJobsCache.length; - const totalHeight = totalRows * VIRTUAL_ROW_HEIGHT; const scrollTop = scrollContainer.scrollTop; - const viewportHeight = scrollContainer.clientHeight; + // Use a minimum viewport height to avoid rendering nothing when container is being laid out + const viewportHeight = Math.max(scrollContainer.clientHeight, 200); const startIdx = Math.max(0, Math.floor(scrollTop / VIRTUAL_ROW_HEIGHT) - VIRTUAL_OVERSCAN); const endIdx = Math.min(totalRows, Math.ceil((scrollTop + viewportHeight) / VIRTUAL_ROW_HEIGHT) + VIRTUAL_OVERSCAN); @@ -566,7 +576,7 @@ function _renderVirtualRows(tbody) { _lastVisibleRange = { start: startIdx, end: endIdx }; const topPad = startIdx * VIRTUAL_ROW_HEIGHT; - const bottomPad = (totalRows - endIdx) * VIRTUAL_ROW_HEIGHT; + const bottomPad = Math.max(0, (totalRows - endIdx) * VIRTUAL_ROW_HEIGHT); let html = ''; if (topPad > 0) html += `