From dfb2f98b3320c46b2999e720919a136064965b86 Mon Sep 17 00:00:00 2001 From: Joao Carreira Date: Tue, 29 Sep 2026 00:31:33 +0100 Subject: [PATCH] feat: compression 20 --- src/helpers/compression.server.ts | 2 +- src/helpers/ffmpeg-log.server.ts | 3 ++- src/pages/api/assets/compression/results.ts | 1 + src/pages/api/assets/compression/transcode.ts | 16 +++++++++++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/helpers/compression.server.ts b/src/helpers/compression.server.ts index 8a930c3..a5f51f0 100644 --- a/src/helpers/compression.server.ts +++ b/src/helpers/compression.server.ts @@ -10,7 +10,7 @@ const COMPRESSION_ROOT = "/app/data/compression"; const ORIGINALS_ROOT = "/originals"; const COMPRESSION_JOB_FILE = "job.json"; -export type CompressionJobStatus = "compressed" | "replacing" | "replaced"; +export type CompressionJobStatus = "compressing" | "compressed" | "replacing" | "replaced"; export interface CompressionJob { version: 1; diff --git a/src/helpers/ffmpeg-log.server.ts b/src/helpers/ffmpeg-log.server.ts index f412dd3..986ffc9 100644 --- a/src/helpers/ffmpeg-log.server.ts +++ b/src/helpers/ffmpeg-log.server.ts @@ -23,7 +23,8 @@ export const runLoggedFfmpegCommand = async ( log.write(`Command: ${resolvedCommand}\n\n`); await new Promise((resolve, reject) => { - const child = spawn(resolvedCommand, { shell: true }); + // Replace the shell with FFmpeg so `close` signals the encoder's completion. + const child = spawn(`exec ${resolvedCommand}`, { shell: true }); let stderrTail = ""; let settled = false; diff --git a/src/pages/api/assets/compression/results.ts b/src/pages/api/assets/compression/results.ts index e163aa5..930cb17 100644 --- a/src/pages/api/assets/compression/results.ts +++ b/src/pages/api/assets/compression/results.ts @@ -40,6 +40,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) continue; } if (job.ownerId !== currentUser.id) continue; + if (job.status === "compressing") continue; try { const outputPath = path.join(getCompressionDirectory(job.sourceAssetId), job.outputFileName); diff --git a/src/pages/api/assets/compression/transcode.ts b/src/pages/api/assets/compression/transcode.ts index 6ed8cab..6efe083 100644 --- a/src/pages/api/assets/compression/transcode.ts +++ b/src/pages/api/assets/compression/transcode.ts @@ -38,18 +38,32 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse) const inputPath = getOriginalAssetPath(asset.originalPath); const outputPath = getCompressionOutputPath(asset.id, asset.originalFileName); + const outputFileName = outputPath.split("/").pop() || `${asset.id}-compressed.mp4`; try { await clearCompressionDirectory(asset.id); await ensureCompressionDirectory(asset.id); const originalStat = await stat(inputPath); + await writeCompressionJob({ + version: 1, + ownerId: currentUser.id, + sourceAssetId: asset.id, + originalFileName: asset.originalFileName, + originalPath: asset.originalPath, + localDateTime: asset.localDateTime.toISOString(), + originalSize: originalStat.size, + outputFileName, + compressedSize: 0, + compressedAt: new Date().toISOString(), + status: "compressing", + }); + const command = await getFfmpegCommand(currentUser.id); const runLoggedFfmpegCommand: typeof runFfmpegCommand = (await import("@/helpers/ffmpeg-log.server")).runLoggedFfmpegCommand; await runLoggedFfmpegCommand(command, inputPath, outputPath); const outputStat = await stat(outputPath); - const outputFileName = outputPath.split("/").pop() || `${asset.id}-compressed.mp4`; await writeCompressionJob({ version: 1,