150 lines
3.9 KiB
JavaScript
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;
|