Multi-Hoster-Upload/lib/upload-manager.js

150 lines
3.9 KiB
JavaScript

const { EventEmitter } = require('events');
const path = require('path');
const fs = require('fs');
const crypto = require('crypto');
const { uploadFile } = require('./hosters');
const VidmolyUploader = require('./vidmoly-upload');
class UploadManager extends EventEmitter {
constructor() {
super();
this.abortController = new AbortController();
this.running = false;
}
async startBatch(tasks) {
this.running = true;
this.abortController = new AbortController();
const { signal } = this.abortController;
const batchId = `batch-${Date.now()}`;
const results = new Map(); // fileName -> { name, size, results: [] }
// Initialize result map per file
for (const task of tasks) {
const fileName = path.basename(task.file);
if (!results.has(task.file)) {
let size = 0;
try { size = fs.statSync(task.file).size; } catch {}
results.set(task.file, { name: fileName, size, results: [] });
}
}
// Build upload promises
const promises = tasks.map(async (task) => {
const uploadId = crypto.randomBytes(8).toString('hex');
const fileName = path.basename(task.file);
let fileSize = 0;
try { fileSize = fs.statSync(task.file).size; } catch {}
// Emit initial status
this.emit('progress', {
uploadId,
fileName,
hoster: task.hoster,
status: 'getting-server',
progress: 0,
bytesUploaded: 0,
bytesTotal: fileSize,
error: null,
result: null
});
try {
let result;
const progressCb = (bytesUploaded, bytesTotal) => {
this.emit('progress', {
uploadId,
fileName,
hoster: task.hoster,
status: 'uploading',
progress: bytesTotal > 0 ? bytesUploaded / bytesTotal : 0,
bytesUploaded,
bytesTotal,
error: null,
result: null
});
};
if (task.hoster === 'vidmoly.me' && task.username) {
// Vidmoly: login-based upload
const vidmoly = new VidmolyUploader();
await vidmoly.login(task.username, task.password);
result = await vidmoly.upload(task.file, progressCb, signal);
} else {
result = await uploadFile(task.hoster, task.file, task.apiKey, progressCb, signal);
}
this.emit('progress', {
uploadId,
fileName,
hoster: task.hoster,
status: 'done',
progress: 1,
bytesUploaded: fileSize,
bytesTotal: fileSize,
error: null,
result
});
results.get(task.file).results.push({
hoster: task.hoster,
status: 'done',
...result
});
} catch (err) {
const errorMsg = err.name === 'AbortError' ? 'Abgebrochen' : err.message;
this.emit('progress', {
uploadId,
fileName,
hoster: task.hoster,
status: 'error',
progress: 0,
bytesUploaded: 0,
bytesTotal: fileSize,
error: errorMsg,
result: null
});
results.get(task.file).results.push({
hoster: task.hoster,
status: 'error',
error: errorMsg,
download_url: null,
embed_url: null,
file_code: null
});
}
});
await Promise.allSettled(promises);
this.running = false;
const files = Array.from(results.values());
const total = tasks.length;
const succeeded = files.reduce((n, f) => n + f.results.filter(r => r.status === 'done').length, 0);
const summary = {
id: batchId,
timestamp: new Date().toISOString(),
total,
succeeded,
failed: total - succeeded,
files
};
this.emit('batch-done', summary);
}
cancel() {
if (this.running) {
this.abortController.abort();
this.running = false;
}
}
}
module.exports = UploadManager;