diff --git a/main.js b/main.js index 2709d4a..b8304e2 100644 --- a/main.js +++ b/main.js @@ -845,6 +845,32 @@ ipcMain.handle('import-backup', async (_event, password) => { return { ok: true, config: configStore.load() }; }); +ipcMain.handle('import-upload-log', async () => { + const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, { + title: 'Upload-Log importieren', + filters: [ + { name: 'Log-Dateien', extensions: ['log', 'txt'] }, + { name: 'Alle Dateien', extensions: ['*'] } + ], + properties: ['openFile'] + }); + if (canceled || !filePaths.length) return { canceled: true }; + const content = fs.readFileSync(filePaths[0], 'utf-8'); + // Parse log format: date|hoster|link||filename| + const entries = []; + for (const line of content.split('\n')) { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) continue; + const parts = trimmed.split('|'); + if (parts.length >= 5) { + const hoster = (parts[1] || '').trim(); + const fileName = (parts[4] || '').trim(); + if (hoster && fileName) entries.push({ hoster, fileName }); + } + } + return { entries, path: filePaths[0] }; +}); + ipcMain.handle('copy-to-clipboard', (_event, text) => { clipboard.writeText(text); return true; diff --git a/preload.js b/preload.js index 27f9318..705e0be 100644 --- a/preload.js +++ b/preload.js @@ -38,6 +38,9 @@ contextBridge.exposeInMainWorld('api', { finishAfterActive: () => ipcRenderer.invoke('finish-after-active'), runHealthCheck: (payload) => ipcRenderer.invoke('run-health-check', payload), + // Log import + importUploadLog: () => ipcRenderer.invoke('import-upload-log'), + // Clipboard copyToClipboard: (text) => ipcRenderer.invoke('copy-to-clipboard', text), diff --git a/renderer/app.js b/renderer/app.js index 52d0fd0..8a9978b 100644 --- a/renderer/app.js +++ b/renderer/app.js @@ -3098,6 +3098,7 @@ function setupListeners() { queueJobs.forEach(j => { if (j.status === 'error') selectedJobIds.add(j.id); }); retrySelectedJobs(); }); + document.getElementById('importLogBtn').addEventListener('click', importUploadLog); document.getElementById('confirmHosterModalBtn').addEventListener('click', applyHosterSelection); document.getElementById('cancelHosterModalBtn').addEventListener('click', cancelHosterModal); document.getElementById('closeHosterModalBtn').addEventListener('click', cancelHosterModal); @@ -3280,6 +3281,47 @@ function handleShutdownCountdown(data) { }, 1000); } +// --- Log import: remove already-uploaded file+hoster combos from queue --- +async function importUploadLog() { + const result = await window.api.importUploadLog(); + if (!result || result.canceled) return; + const entries = result.entries || []; + if (entries.length === 0) { + showCopyToast('Keine Einträge im Log gefunden'); + return; + } + + // Build lookup Set: "filename_lower|hoster" + const logKeys = new Set(); + for (const entry of entries) { + logKeys.add(`${entry.fileName.toLowerCase()}|${entry.hoster.toLowerCase()}`); + } + + // Find queue jobs that match (already uploaded) + let removed = 0; + queueJobs = queueJobs.filter(job => { + const key = `${job.fileName.toLowerCase()}|${job.hoster.toLowerCase()}`; + if (logKeys.has(key) && job.status !== 'done') { + removeJobFromIndex(job); + removed++; + return false; + } + return true; + }); + + if (removed > 0) { + selectedJobIds.clear(); + syncSelectedFilesFromQueue(); + rebuildJobIndex(); + renderQueueTable(); + updateUploadView(); + updateStatusBar(); + persistQueueStateSoon(true); + } + + showCopyToast(`${removed} bereits hochgeladene Jobs aus Queue entfernt (${entries.length} Log-Einträge gelesen)`); +} + // --- Link operations --- function copyAllLinks() { const links = queueJobs diff --git a/renderer/index.html b/renderer/index.html index eaff136..997f820 100644 --- a/renderer/index.html +++ b/renderer/index.html @@ -94,6 +94,7 @@