From 6f75bbee7b0cfa9e63186c90c0666a32a4fdd225 Mon Sep 17 00:00:00 2001 From: diced Date: Thu, 19 Sep 2024 00:36:19 -0700 Subject: [PATCH] fix: thumbnail generation for audio in video container --- src/worker/thumbnail.ts | 47 +++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/src/worker/thumbnail.ts b/src/worker/thumbnail.ts index 3d714e540..2e309e546 100644 --- a/src/worker/thumbnail.ts +++ b/src/worker/thumbnail.ts @@ -28,23 +28,42 @@ if (isMainThread) { async function loadThumbnail(path) { const args = ['-i', path, '-frames:v', '1', '-f', 'mjpeg', 'pipe:1']; - const child = spawn(ffmpeg, args, { stdio: ['ignore', 'pipe', 'ignore'] }); + const child = spawn(ffmpeg, args, { stdio: ['ignore', 'pipe', 'pipe'] }); const data: Buffer = await new Promise((resolve, reject) => { const buffers = []; + const errorBuffers = []; + + child.stderr.on('data', (chunk) => { + errorBuffers.push(chunk); + }); child.stdout.on('data', (chunk) => { buffers.push(chunk); }); - child.once('error', reject); + child.once('error', (...a) => { + console.log(a); + + reject(); + }); child.once('close', (code) => { if (code !== 0) { - const msg = buffers.join('').trim(); - logger.debug(`cmd: ${ffmpeg} ${args.join(' ')}`); - logger.error(`while ${path} child exited with code ${code}: ${msg}`); + const msg = errorBuffers.join('').trim().split('\n'); + + logger.debug(`cmd: ${ffmpeg} ${args.join(' ')}\n${msg.join('\n')}`); + logger.error(`child exited with code ${code}: ${msg[msg.length - 1]}`); + + if (msg[msg.length - 1].includes('does not contain any stream')) { + // mismatched mimetype, for example a video/ogg (.ogg) file with no video stream since + // for this specific case just set the mimetype to audio/ogg + // the method will return an empty buffer since there is no video stream + + logger.error(`file ${path} does not contain any video stream, it is probably an audio file`); + resolve(Buffer.alloc(0)); + } - reject(new Error(`child exited with code ${code}`)); + reject(new Error(`child exited with code ${code} ffmpeg output:\n${msg.join('\n')}`)); } else { const buffer = Buffer.allocUnsafe(buffers.reduce((acc, val) => acc + val.length, 0)); @@ -99,6 +118,22 @@ async function start() { const thumbnail = await loadThumbnail(tmpFile); logger.debug(`loaded thumbnail: ${thumbnail.length} bytes mjpeg`); + if (thumbnail.length === 0 && file.mimetype === 'video/ogg') { + logger.info('file might be an audio file, setting mimetype to audio/ogg to avoid future errors'); + await prisma.file.update({ + where: { + id: file.id, + }, + data: { + mimetype: 'audio/ogg', + }, + }); + + await rm(tmpFile); + await prisma.$disconnect(); + process.exit(0); + } + const { thumbnail: thumb } = await prisma.file.update({ where: { id: file.id,