✨ feat: auto-deduplicate queue against upload log on startup
When the app restarts with a restored queue, it now automatically reads all fileuploader.log files and removes jobs that were already successfully uploaded in a previous session. This prevents re-uploading files that completed before a crash/close. The dedup runs silently before the UI renders — no user action needed. Also adds 'read-own-upload-log' IPC that reads all log variants (base + daily logs) without file picker. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a7b24ec363
commit
bf7f35d06c
39
main.js
39
main.js
@ -845,6 +845,45 @@ ipcMain.handle('import-backup', async (_event, password) => {
|
|||||||
return { ok: true, config: configStore.load() };
|
return { ok: true, config: configStore.load() };
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ipcMain.handle('read-own-upload-log', () => {
|
||||||
|
// Read all log files (base + daily logs) and return parsed entries
|
||||||
|
const entries = [];
|
||||||
|
const basePath = getBaseLogFilePath();
|
||||||
|
const dir = path.dirname(basePath);
|
||||||
|
const ext = path.extname(basePath);
|
||||||
|
const name = path.basename(basePath, ext);
|
||||||
|
|
||||||
|
// Collect all matching log files (base + daily variants)
|
||||||
|
const logFiles = [];
|
||||||
|
try {
|
||||||
|
for (const file of fs.readdirSync(dir)) {
|
||||||
|
if (file.startsWith(name) && file.endsWith(ext)) {
|
||||||
|
logFiles.push(path.join(dir, file));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
if (logFiles.length === 0 && fs.existsSync(basePath)) {
|
||||||
|
logFiles.push(basePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const logPath of logFiles) {
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(logPath, 'utf-8');
|
||||||
|
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 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
return entries;
|
||||||
|
});
|
||||||
|
|
||||||
ipcMain.handle('import-upload-log', async () => {
|
ipcMain.handle('import-upload-log', async () => {
|
||||||
const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, {
|
const { canceled, filePaths } = await dialog.showOpenDialog(mainWindow, {
|
||||||
title: 'Upload-Log importieren',
|
title: 'Upload-Log importieren',
|
||||||
|
|||||||
@ -39,6 +39,7 @@ contextBridge.exposeInMainWorld('api', {
|
|||||||
runHealthCheck: (payload) => ipcRenderer.invoke('run-health-check', payload),
|
runHealthCheck: (payload) => ipcRenderer.invoke('run-health-check', payload),
|
||||||
|
|
||||||
// Log import
|
// Log import
|
||||||
|
readOwnUploadLog: () => ipcRenderer.invoke('read-own-upload-log'),
|
||||||
importUploadLog: () => ipcRenderer.invoke('import-upload-log'),
|
importUploadLog: () => ipcRenderer.invoke('import-upload-log'),
|
||||||
|
|
||||||
// Clipboard
|
// Clipboard
|
||||||
|
|||||||
@ -55,6 +55,7 @@ async function init() {
|
|||||||
ensureAccountStatusEntries();
|
ensureAccountStatusEntries();
|
||||||
syncSelectedUploadHosters();
|
syncSelectedUploadHosters();
|
||||||
restoreQueueStateFromConfig();
|
restoreQueueStateFromConfig();
|
||||||
|
await _autoDeduplicateFromLog();
|
||||||
renderHosterSummary();
|
renderHosterSummary();
|
||||||
renderHosterModal();
|
renderHosterModal();
|
||||||
renderSettings();
|
renderSettings();
|
||||||
@ -3281,6 +3282,34 @@ function handleShutdownCountdown(data) {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// --- Auto-deduplicate restored queue against own upload log on startup ---
|
||||||
|
async function _autoDeduplicateFromLog() {
|
||||||
|
if (queueJobs.length === 0) return;
|
||||||
|
try {
|
||||||
|
const entries = await window.api.readOwnUploadLog();
|
||||||
|
if (!entries || entries.length === 0) return;
|
||||||
|
const logKeys = new Set();
|
||||||
|
for (const entry of entries) {
|
||||||
|
logKeys.add(`${entry.fileName.toLowerCase()}|${entry.hoster.toLowerCase()}`);
|
||||||
|
}
|
||||||
|
let removed = 0;
|
||||||
|
queueJobs = queueJobs.filter(job => {
|
||||||
|
const key = `${job.fileName.toLowerCase()}|${job.hoster.toLowerCase()}`;
|
||||||
|
if (logKeys.has(key)) {
|
||||||
|
if (job.file && job.hoster) _completedUploadKeys.add(`${job.file}|${job.hoster}`);
|
||||||
|
removed++;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (removed > 0) {
|
||||||
|
rebuildJobIndex();
|
||||||
|
syncSelectedFilesFromQueue();
|
||||||
|
window.api.debugLog(`auto-dedup: removed ${removed} already-uploaded jobs from restored queue (${entries.length} log entries)`);
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
// --- Log import: remove already-uploaded file+hoster combos from queue ---
|
// --- Log import: remove already-uploaded file+hoster combos from queue ---
|
||||||
async function importUploadLog() {
|
async function importUploadLog() {
|
||||||
const result = await window.api.importUploadLog();
|
const result = await window.api.importUploadLog();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user