Compare commits

..

No commits in common. "796aeb520dedda932b3c4740911561b431837f2e" and "9b5184f76fbc058c944083a3d795abb136697a5f" have entirely different histories.

5 changed files with 4 additions and 137 deletions

View File

@ -43,17 +43,7 @@ class UploadManager extends EventEmitter {
} }
switchAccount(hoster, fallbackAccount) { switchAccount(hoster, fallbackAccount) {
const prev = this._accountOverrides.get(hoster);
this._accountOverrides.set(hoster, fallbackAccount); this._accountOverrides.set(hoster, fallbackAccount);
this._rotLog('switchAccount', {
hoster,
prevOverrideId: prev ? prev.id : null,
toAccountId: fallbackAccount ? fallbackAccount.id : null
});
}
_rotLog(event, data) {
this.emit('rot-log', { ts: Date.now(), event, ...data });
} }
updateSettings(hosterSettings, globalSettings) { updateSettings(hosterSettings, globalSettings) {
@ -148,7 +138,6 @@ class UploadManager extends EventEmitter {
// straight to the fallback even after the original recovered. // straight to the fallback even after the original recovered.
this._failedAccounts.clear(); this._failedAccounts.clear();
this._accountOverrides.clear(); this._accountOverrides.clear();
this._rotLog('batch-start', { taskCount: tasks.length });
const { signal } = this.abortController; const { signal } = this.abortController;
const batchId = `batch-${Date.now()}`; const batchId = `batch-${Date.now()}`;
@ -273,19 +262,10 @@ class UploadManager extends EventEmitter {
if (task.accountId && this._failedAccounts.has(task.hoster + ':' + task.accountId)) { if (task.accountId && this._failedAccounts.has(task.hoster + ':' + task.accountId)) {
const override = this._accountOverrides.get(task.hoster); const override = this._accountOverrides.get(task.hoster);
if (override && !this._failedAccounts.has(task.hoster + ':' + override.id)) { if (override && !this._failedAccounts.has(task.hoster + ':' + override.id)) {
this._rotLog('pre-job-swap', {
hoster: task.hoster, fileName, fromAccountId: task.accountId, toAccountId: override.id
});
task.accountId = override.id; task.accountId = override.id;
task.username = override.username; task.username = override.username;
task.password = override.password; task.password = override.password;
task.apiKey = override.apiKey; task.apiKey = override.apiKey;
} else {
this._rotLog('pre-job-swap-blocked', {
hoster: task.hoster, fileName, accountId: task.accountId,
hasOverride: !!override,
overrideAlsoFailed: override ? this._failedAccounts.has(task.hoster + ':' + override.id) : false
});
} }
} }
@ -491,39 +471,14 @@ class UploadManager extends EventEmitter {
// resolve the next fallback, then retry. Loop so A → B → C → ... works // resolve the next fallback, then retry. Loop so A → B → C → ... works
// for hosters with 3+ accounts (the old code only did one level: A → B // for hosters with 3+ accounts (the old code only did one level: A → B
// and stopped, even if C would have worked). // and stopped, even if C would have worked).
this._rotLog('retries-exhausted', {
hoster: task.hoster, fileName, accountId: task.accountId,
lastError: lastError ? lastError.message : null
});
while (task.accountId && !this._failedAccounts.has(task.hoster + ':' + task.accountId)) { while (task.accountId && !this._failedAccounts.has(task.hoster + ':' + task.accountId)) {
if (signal.aborted || this.stopAfterActive) break; if (signal.aborted || this.stopAfterActive) break;
this._failedAccounts.set(task.hoster + ':' + task.accountId, true); this._failedAccounts.set(task.hoster + ':' + task.accountId, true);
this._rotLog('mark-failed', {
hoster: task.hoster, fileName, accountId: task.accountId,
lastError: lastError ? lastError.message : null
});
this.emit('account-failed', { hoster: task.hoster, accountId: task.accountId }); this.emit('account-failed', { hoster: task.hoster, accountId: task.accountId });
await this._sleep(800, signal); await this._sleep(800, signal);
const override = this._accountOverrides.get(task.hoster); const override = this._accountOverrides.get(task.hoster);
if (!override) { if (!override || this._failedAccounts.has(task.hoster + ':' + override.id)) break;
this._rotLog('rotation-end', {
hoster: task.hoster, fileName, reason: 'no-override-set',
lastFailedAccountId: task.accountId
});
break;
}
if (this._failedAccounts.has(task.hoster + ':' + override.id)) {
this._rotLog('rotation-end', {
hoster: task.hoster, fileName, reason: 'override-already-failed',
overrideId: override.id, lastFailedAccountId: task.accountId
});
break;
}
// Switch to fallback account and retry this file // Switch to fallback account and retry this file
this._rotLog('rotate', {
hoster: task.hoster, fileName,
fromAccountId: task.accountId, toAccountId: override.id
});
task.accountId = override.id; task.accountId = override.id;
task.username = override.username; task.username = override.username;
task.password = override.password; task.password = override.password;
@ -596,9 +551,6 @@ class UploadManager extends EventEmitter {
} }
const error = lastError && lastError.message ? lastError.message : 'Unbekannter Fehler'; const error = lastError && lastError.message ? lastError.message : 'Unbekannter Fehler';
this._rotLog('final-error', {
hoster: task.hoster, fileName, lastFailedAccountId: task.accountId, error
});
emitFinalStatus('error', { error }); emitFinalStatus('error', { error });
recordFinalResult('error', { error }); recordFinalResult('error', { error });
} catch (err) { } catch (err) {

73
main.js
View File

@ -68,58 +68,6 @@ function debugLog(msg) {
} catch {} } catch {}
} }
// Dedicated account-rotation log so users can trace fallback decisions
// without wading through general debug output. Writes to account-rotation.log
// in the same directory as fileuploader.log (honors user's configured path).
function getRotLogPath() {
const base = getLogFilePath();
const dir = path.dirname(base);
return path.join(dir, 'account-rotation.log');
}
const _rotLogBuffer = [];
let _rotLogFlushTimer = null;
let _rotLogWriting = false;
function _flushRotLog() {
if (_rotLogWriting || _rotLogBuffer.length === 0) return;
const chunk = _rotLogBuffer.join('');
_rotLogBuffer.length = 0;
_rotLogWriting = true;
const tryTargets = [
getRotLogPath(),
path.join(app.getPath('desktop') || app.getPath('userData'), 'account-rotation.log'),
path.join(app.getPath('userData'), 'account-rotation.log')
];
const write = (i) => {
if (i >= tryTargets.length) { _rotLogWriting = false; return; }
try {
fs.mkdirSync(path.dirname(tryTargets[i]), { recursive: true });
} catch {}
fs.appendFile(tryTargets[i], chunk, 'utf-8', (err) => {
if (err) return write(i + 1);
_rotLogWriting = false;
if (_rotLogBuffer.length) setImmediate(_flushRotLog);
});
};
write(0);
}
function rotLog(msg, ts) {
try {
const iso = new Date(ts || Date.now()).toISOString();
const line = `[${iso}] ${msg}\n`;
_rotLogBuffer.push(line);
// Mirror into the main debug log for single-file-grep convenience.
_debugLogBuffer.push(`[${iso}] [ROT] ${msg}\n`);
if (!_rotLogFlushTimer) {
_rotLogFlushTimer = setTimeout(() => { _rotLogFlushTimer = null; _flushRotLog(); }, 500);
}
if (!_debugLogFlushTimer) {
_debugLogFlushTimer = setTimeout(() => { _debugLogFlushTimer = null; _flushDebugLog(); }, 500);
}
} catch {}
}
// Catch unhandled rejections from fire-and-forget async calls // Catch unhandled rejections from fire-and-forget async calls
process.on('unhandledRejection', (reason) => { process.on('unhandledRejection', (reason) => {
debugLog(`UNHANDLED REJECTION: ${reason && reason.stack ? reason.stack : reason}`); debugLog(`UNHANDLED REJECTION: ${reason && reason.stack ? reason.stack : reason}`);
@ -854,12 +802,6 @@ app.on('before-quit', () => {
_uploadLogBuffer.length = 0; _uploadLogBuffer.length = 0;
} }
} catch {} } catch {}
try {
if (_rotLogBuffer.length) {
fs.appendFileSync(getRotLogPath(), _rotLogBuffer.join(''), 'utf-8');
_rotLogBuffer.length = 0;
}
} catch {}
}); });
// --- IPC Handlers --- // --- IPC Handlers ---
@ -1077,24 +1019,13 @@ ipcMain.handle('start-upload', (_event, payload) => {
const cfg = configStore.load(); const cfg = configStore.load();
const fallback = getNextFallbackAccount(cfg, hoster, accountId); const fallback = getNextFallbackAccount(cfg, hoster, accountId);
if (fallback) { if (fallback) {
rotLog(`main: account-failed ${hoster} ${accountId}resolved fallback ${fallback.id}`); debugLog(`account-failed: ${hoster} ${accountId}fallback to ${fallback.id}`);
uploadManager.switchAccount(hoster, fallback); uploadManager.switchAccount(hoster, fallback);
if (mainWindow && !mainWindow.isDestroyed()) { if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('account-switched', { hoster, fromAccountId: accountId, toAccountId: fallback.id }); mainWindow.webContents.send('account-switched', { hoster, fromAccountId: accountId, toAccountId: fallback.id });
} }
} else { } else {
rotLog(`main: account-failed ${hoster} ${accountId} → NO fallback available (end of chain)`); debugLog(`account-failed: ${hoster} ${accountId} → no fallback available`);
}
});
uploadManager.on('rot-log', (entry) => {
const { ts, event, ...rest } = entry;
const pairs = Object.entries(rest)
.map(([k, v]) => `${k}=${typeof v === 'string' ? v : JSON.stringify(v)}`)
.join(' ');
rotLog(`[${event}] ${pairs}`, ts);
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('account-rotation-log', entry);
} }
}); });

View File

@ -1,6 +1,6 @@
{ {
"name": "multi-hoster-uploader", "name": "multi-hoster-uploader",
"version": "3.0.3", "version": "3.0.2",
"description": "Upload files to doodstream, voe, vidmoly, byse simultaneously", "description": "Upload files to doodstream, voe, vidmoly, byse simultaneously",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {

View File

@ -104,9 +104,6 @@ contextBridge.exposeInMainWorld('api', {
onUploadLogFallback: (callback) => { onUploadLogFallback: (callback) => {
ipcRenderer.on('upload-log-fallback', (_event, data) => callback(data)); ipcRenderer.on('upload-log-fallback', (_event, data) => callback(data));
}, },
onAccountRotationLog: (callback) => {
ipcRenderer.on('account-rotation-log', (_event, data) => callback(data));
},
// Remote Control // Remote Control
remoteGetSettings: () => ipcRenderer.invoke('remote:get-settings'), remoteGetSettings: () => ipcRenderer.invoke('remote:get-settings'),
remoteSaveSettings: (settings) => ipcRenderer.invoke('remote:save-settings', settings), remoteSaveSettings: (settings) => ipcRenderer.invoke('remote:save-settings', settings),

View File

@ -120,19 +120,6 @@ async function init() {
window.api.onUploadLogFallback((data) => { window.api.onUploadLogFallback((data) => {
alert('Der konfigurierte Log-Pfad konnte nicht beschrieben werden.\n\nNeue Einträge werden zwischenzeitlich hier gespeichert:\n' + (data && data.fallbackPath ? data.fallbackPath : '(Fallback)') + '\n\nBitte in den Einstellungen einen gültigen Pfad setzen.'); alert('Der konfigurierte Log-Pfad konnte nicht beschrieben werden.\n\nNeue Einträge werden zwischenzeitlich hier gespeichert:\n' + (data && data.fallbackPath ? data.fallbackPath : '(Fallback)') + '\n\nBitte in den Einstellungen einen gültigen Pfad setzen.');
}); });
window.api.onAccountRotationLog((entry) => {
// Surface only the user-visible rotation events as toasts; full detail
// goes to account-rotation.log. Keep it quiet otherwise.
if (!entry || !entry.event) return;
const hosterLabel = entry.hoster ? getHosterLabel(entry.hoster) : '';
if (entry.event === 'rotate') {
showCopyToast(`${hosterLabel}: Account-Wechsel → Fallback`);
} else if (entry.event === 'rotation-end') {
showCopyToast(`${hosterLabel}: Keine weiteren Fallback-Accounts verfügbar`);
} else if (entry.event === 'final-error') {
showCopyToast(`${hosterLabel}: Alle Accounts ausgeschöpft`);
}
});
// Folder monitor: auto-queue new files // Folder monitor: auto-queue new files
window.api.onFolderMonitorNewFiles((files) => { window.api.onFolderMonitorNewFiles((files) => {