diff --git a/js/downloads.js b/js/downloads.js index ed548af..0c9703c 100644 --- a/js/downloads.js +++ b/js/downloads.js @@ -238,6 +238,10 @@ export function updateDownloadProgress(trackId, progress) { progressFill.style.background = '#3b82f6'; // Blue for encoding statusEl.textContent = `Converting: ${percent}%`; } else if (progress instanceof ProgressMessage || progress.message) { + if (progress instanceof FfmpegProgress && (progress.stage == 'parsing' || progress.stage == 'stdout')) { + return; + } + progressFill.style.width = '100%'; progressFill.style.background = '#3b82f6'; statusEl.textContent = progress.message; @@ -961,7 +965,7 @@ function updateBulkDownloadProgress(notifEl, current, total, currentItem, progre } if (progress instanceof FfmpegProgress) { - if (progress.stage == 'stdout') { + if (progress.stage == 'stdout' || progress.stage == 'parsing') { return; } diff --git a/js/ffmpeg.js b/js/ffmpeg.js index f5e5f40..80f1012 100644 --- a/js/ffmpeg.js +++ b/js/ffmpeg.js @@ -55,11 +55,13 @@ async function ffmpegWorker( const assets = loadFfmpeg(); return new Promise((resolve, reject) => { + let endCategory = null; const worker = new FfmpegWorker(); // Handle abort signal const abortHandler = () => { worker.terminate(); + endCategory?.(); reject(new FfmpegError('FFMPEG aborted')); }; @@ -72,20 +74,30 @@ async function ffmpegWorker( } worker.onmessage = (e) => { - const { type, blob, message, stage, progress } = e.data; + const { type, blob, message, stage, progress, command } = e.data; if (type === 'complete') { if (signal) signal.removeEventListener('abort', abortHandler); worker.terminate(); + endCategory?.(); resolve(blob); } else if (type === 'error') { if (signal) signal.removeEventListener('abort', abortHandler); worker.terminate(); + endCategory?.(); reject(new FfmpegError(message)); } else if (type === 'progress' && message) { onProgress?.(new FfmpegProgress(stage, progress || 0, message)); } else if (type === 'progress' && stage != 'loading' && progress !== null) { onProgress?.(new FfmpegProgress(stage, progress || 0, message)); + } else if (type === 'command') { + if (logConsole) { + const consoleCategory = `ffmpeg ${command?.join(' ')}`; + // eslint-disable-next-line no-console + console.groupCollapsed(consoleCategory); + // eslint-disable-next-line no-console + endCategory = () => console.groupEnd(); + } } else if (type === 'log') { onProgress?.(new FfmpegProgress('stdout', 0, message)); if (logConsole) { @@ -97,6 +109,7 @@ async function ffmpegWorker( worker.onerror = (error) => { if (signal) signal.removeEventListener('abort', abortHandler); worker.terminate(); + endCategory?.(); reject(new FfmpegError('Worker failed: ' + error.message)); }; diff --git a/js/ffmpeg.types.ts b/js/ffmpeg.types.ts index 2eb82dd..6e9d899 100644 --- a/js/ffmpeg.types.ts +++ b/js/ffmpeg.types.ts @@ -1,6 +1,6 @@ export class FfmpegProgress implements MonochromeProgress { constructor( - public readonly stage: 'loading' | 'encoding' | 'finalizing' | 'stdout', + public readonly stage: 'loading' | 'parsing' | 'encoding' | 'finalizing' | 'stdout', public readonly progress: number, public readonly message?: string ) {} diff --git a/js/ffmpeg.worker.js b/js/ffmpeg.worker.js index b34c4ce..8da739d 100644 --- a/js/ffmpeg.worker.js +++ b/js/ffmpeg.worker.js @@ -40,7 +40,7 @@ async function loadFFmpeg(loadOptions = {}) { ffmpeg = new FFmpeg(); ffmpeg.on('log', ({ message }) => { - self.postMessage({ type: 'log', message }); + self.postMessage({ type: 'log', stage: 'stdout', message }); // Try to extract total duration from input log if (totalDurationSeconds === null) { @@ -124,7 +124,7 @@ self.onmessage = async (e) => { } const ffmpegArgs = ['-i', 'input', ...args, ...(output.name ? [output.name] : [])]; - self.postMessage({ type: 'log', message: `FFmpeg command: ffmpeg ${ffmpegArgs.join(' ')}` }); + self.postMessage({ type: 'command', command: ffmpegArgs }); const exitCode = await ffmpeg.exec(ffmpegArgs);