Video: async conversion with live progress polling
- /convert now returns immediately, ffmpeg runs in background - Client polls /progress every second for live progress % - Progress endpoint returns downloadUrl/outputSize when done - UI shows real-time percentage during conversion
This commit is contained in:
parent
7f2a6f208f
commit
6aca7e9e47
@ -939,15 +939,8 @@
|
||||
throw new Error(err.error || 'Ошибка запуска');
|
||||
}
|
||||
|
||||
const data = await res.json();
|
||||
|
||||
// Server may return immediately (sync) or poll (async)
|
||||
if (data.status === 'done' || data.downloadUrl) {
|
||||
setProgressUI(100, 'Готово!');
|
||||
onConversionDone(data);
|
||||
} else {
|
||||
// Server starts processing in background, poll for progress
|
||||
startPolling();
|
||||
}
|
||||
} catch (err) {
|
||||
showConversionError(err.message || 'Ошибка конвертации');
|
||||
}
|
||||
|
||||
@ -184,20 +184,21 @@ router.post('/convert', express.json(), async (req, res) => {
|
||||
|
||||
args.push(outFile);
|
||||
|
||||
await runFFmpeg(args, jobId);
|
||||
// Start ffmpeg in background — respond immediately
|
||||
res.json({ status: 'processing' });
|
||||
|
||||
runFFmpeg(args, jobId).then(() => {
|
||||
job.status = 'done';
|
||||
job.progress = 100;
|
||||
|
||||
const outStat = fs.statSync(outFile);
|
||||
const savings = job.size > 0 ? Math.round((1 - outStat.size / job.size) * 100) : 0;
|
||||
|
||||
log.info(`Video ${mode}: ${job.originalName} → ${format} (${(outStat.size / 1024 / 1024).toFixed(1)}MB, ${savings}% saved)`);
|
||||
|
||||
res.json({
|
||||
status: 'done',
|
||||
downloadUrl: `/video/download/${jobId}${outExt}`,
|
||||
outputSize: outStat.size,
|
||||
savings,
|
||||
job.outputSize = outStat.size;
|
||||
job.savings = job.size > 0 ? Math.round((1 - outStat.size / job.size) * 100) : 0;
|
||||
job.downloadUrl = `/video/download/${jobId}${outExt}`;
|
||||
log.info(`Video ${mode}: ${job.originalName} → ${format} (${(outStat.size / 1024 / 1024).toFixed(1)}MB, ${job.savings}% saved)`);
|
||||
}).catch(err => {
|
||||
job.status = 'error';
|
||||
job.error = err.message.slice(0, 200);
|
||||
log.error('Video convert error', { error: err.message });
|
||||
});
|
||||
} catch (err) {
|
||||
job.status = 'error';
|
||||
@ -206,11 +207,20 @@ router.post('/convert', express.json(), async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Progress
|
||||
// Progress (returns downloadUrl when done)
|
||||
router.get('/progress/:jobId', (req, res) => {
|
||||
const job = jobs.get(req.params.jobId);
|
||||
if (!job) return res.status(404).json({ error: 'Not found' });
|
||||
res.json({ status: job.status, progress: job.progress });
|
||||
const result = { status: job.status, progress: job.progress };
|
||||
if (job.status === 'done') {
|
||||
result.downloadUrl = job.downloadUrl;
|
||||
result.outputSize = job.outputSize;
|
||||
result.savings = job.savings;
|
||||
}
|
||||
if (job.status === 'error') {
|
||||
result.error = job.error || 'Ошибка обработки';
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
|
||||
// Download result
|
||||
|
||||
Loading…
Reference in New Issue
Block a user