From f14d91d24a3316b92b03db44298c91a7064b525a Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 3 Oct 2026 13:51:44 +0000 Subject: [PATCH] refactor(media): trim unused ffmpeg wrapper options Binary paths, the ffmpeg version, the probe's container name and a configurable stall timeout had no caller; detection is cached per process, so every helper looks the binaries up itself. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01MRtGG9ARfqqhma3t85Ro2u --- packages/adapters/src/media/ffmpeg.test.ts | 1 - packages/adapters/src/media/ffmpeg.ts | 19 ++++++------------- .../src/media/video-edit-plan.test.ts | 1 - 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/packages/adapters/src/media/ffmpeg.test.ts b/packages/adapters/src/media/ffmpeg.test.ts index ab846da..e431827 100644 --- a/packages/adapters/src/media/ffmpeg.test.ts +++ b/packages/adapters/src/media/ffmpeg.test.ts @@ -60,7 +60,6 @@ describe("probe parsing", () => { ); expect(probe).toEqual({ durationMs: 12_345, - formatName: "mov,mp4,m4a,3gp,3g2,mj2", video: { codec: "h264", width: 1080, diff --git a/packages/adapters/src/media/ffmpeg.ts b/packages/adapters/src/media/ffmpeg.ts index e2ebc77..72eefc1 100644 --- a/packages/adapters/src/media/ffmpeg.ts +++ b/packages/adapters/src/media/ffmpeg.ts @@ -13,12 +13,10 @@ import { delimiter, join } from "node:path"; export interface FfmpegInfo { ffmpegPath: string; ffprobePath: string; - version: string; } export interface MediaProbe { durationMs: number; - formatName: string; /** Width and height as displayed: swapped when the stream is rotated by 90 or 270 degrees. */ video?: { codec: string; @@ -50,8 +48,6 @@ export interface RunFfmpegOptions { maxOutputBytes?: number; /** Files removed when the run fails or is aborted. */ outputs?: readonly string[]; - /** Kills ffmpeg when it reports no progress for this long. */ - stallTimeoutMs?: number; } export class FfmpegError extends Error { @@ -65,7 +61,8 @@ export class FfmpegError extends Error { } } -const DEFAULT_STALL_TIMEOUT_MS = 2 * 60_000; +/** ffmpeg reports progress twice a second while it works; silence this long means a hang. */ +const STALL_TIMEOUT_MS = 2 * 60_000; const PROBE_TIMEOUT_MS = 60_000; const STDERR_TAIL_BYTES = 8 * 1024; const KILL_GRACE_MS = 5_000; @@ -101,9 +98,7 @@ async function locateFfmpeg(): Promise { capture(ffmpegPath, ["-hide_banner", "-version"], { timeoutMs: 10_000 }), capture(ffprobePath, ["-hide_banner", "-version"], { timeoutMs: 10_000 }), ]); - if (ffmpeg.code !== 0 || ffprobe.code !== 0) return null; - const version = /version (\S+)/.exec(ffmpeg.stdout)?.[1] ?? "unknown"; - return { ffmpegPath, ffprobePath, version }; + return ffmpeg.code === 0 && ffprobe.code === 0 ? { ffmpegPath, ffprobePath } : null; } catch { return null; } @@ -129,7 +124,7 @@ async function findExecutable(name: string): Promise { return null; } -export async function requireFfmpeg(): Promise { +async function requireFfmpeg(): Promise { const info = await detectFfmpeg(); if (!info) throw new Error("ffmpeg and ffprobe are not installed on this server."); return info; @@ -223,7 +218,7 @@ interface ProbeStream { /** Parses `ffprobe -print_format json -show_format -show_streams` output. */ export function parseProbeOutput(json: string): MediaProbe { const data = JSON.parse(json) as { - format?: { duration?: string; format_name?: string }; + format?: { duration?: string }; streams?: ProbeStream[]; }; const streams = data.streams ?? []; @@ -237,7 +232,6 @@ export function parseProbeOutput(json: string): MediaProbe { Math.max(0, ...streams.map((stream) => positive(Number(stream.duration)) ?? 0)); return { durationMs: Math.round(seconds * 1000), - formatName: data.format?.format_name ?? "", ...(video?.width && video.height ? { video: probeVideo(video, video.width, video.height) } : {}), @@ -385,12 +379,11 @@ function spawnFfmpeg( setTimeout(() => finish(error), KILL_GRACE_MS).unref?.(); }; const abort = () => kill(signal?.reason ?? new Error("aborted")); - const stallTimeoutMs = options.stallTimeoutMs ?? DEFAULT_STALL_TIMEOUT_MS; const armStallTimer = () => { clearTimeout(stallTimer); stallTimer = setTimeout( () => kill(new FfmpegError("ffmpeg stopped making progress.", null, tail(stderr))), - stallTimeoutMs, + STALL_TIMEOUT_MS, ); stallTimer.unref?.(); }; diff --git a/packages/adapters/src/media/video-edit-plan.test.ts b/packages/adapters/src/media/video-edit-plan.test.ts index ea37cd6..4927f9e 100644 --- a/packages/adapters/src/media/video-edit-plan.test.ts +++ b/packages/adapters/src/media/video-edit-plan.test.ts @@ -13,7 +13,6 @@ function probe( const { durationMs = 10_000, hasAudio = true, ...video } = overrides; return { durationMs, - formatName: "mov,mp4,m4a,3gp,3g2,mj2", video: { codec: "h264", width: 1920,