From 3353253cefea794372ef8339954158ed28c7332a Mon Sep 17 00:00:00 2001 From: treamz Date: Sun, 22 Mar 2026 00:22:48 +0300 Subject: [PATCH] Fix video progress: parse each chunk, -progress pipe:2, out_time support - Parse time= from each stderr chunk (not accumulated buffer) - Add -progress pipe:2 flag for frequent progress output - Support both time= and out_time= formats - Progress only increases (no jumps back) --- routes/video.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/routes/video.js b/routes/video.js index 23c93f5..1012ca7 100644 --- a/routes/video.js +++ b/routes/video.js @@ -33,24 +33,26 @@ const jobs = new Map(); function runFFmpeg(args, jobId) { return new Promise((resolve, reject) => { const proc = spawn('ffmpeg', args, { timeout: 600000 }); // 10 min timeout - let stderr = ''; + let stderrBuf = ''; proc.stderr.on('data', (d) => { - stderr += d.toString(); - // Parse progress - const timeMatch = stderr.match(/time=(\d{2}):(\d{2}):(\d{2})/); + const chunk = d.toString(); + stderrBuf += chunk; + // Parse progress — look for time= or out_time= in chunk + const timeMatch = chunk.match(/(?:out_time|time)=\s*(\d{2}):(\d{2}):(\d{2})[\.\d]*/); if (timeMatch && jobs.has(jobId)) { const secs = parseInt(timeMatch[1]) * 3600 + parseInt(timeMatch[2]) * 60 + parseInt(timeMatch[3]); const job = jobs.get(jobId); if (job.duration > 0) { - job.progress = Math.min(99, Math.round((secs / job.duration) * 100)); + const pct = Math.min(99, Math.round((secs / job.duration) * 100)); + if (pct > job.progress) job.progress = pct; // only increase } } }); proc.on('close', (code) => { if (code === 0) resolve(); - else reject(new Error(`ffmpeg exited with code ${code}: ${stderr.slice(-500)}`)); + else reject(new Error(`ffmpeg exited with code ${code}: ${stderrBuf.slice(-500)}`)); }); proc.on('error', reject); @@ -144,7 +146,7 @@ router.post('/convert', express.json(), async (req, res) => { job.outputPath = outFile; try { - let args = ['-y', '-i', job.inputPath]; + let args = ['-y', '-progress', 'pipe:2', '-i', job.inputPath]; // Time range (for GIF or trim) if (startTime !== undefined && startTime > 0) args.push('-ss', String(startTime));