(params: FfmpegArgs, context?: ServerToolContext)
| 64 | name: Ffmpeg.id, |
| 65 | |
| 66 | async execute(params: FfmpegArgs, context?: ServerToolContext): Promise<FfmpegResult> { |
| 67 | if (!context?.userId) { |
| 68 | throw new Error('Authentication required') |
| 69 | } |
| 70 | const workspaceId = context.workspaceId |
| 71 | if (!workspaceId) { |
| 72 | return { success: false, message: 'Workspace ID is required' } |
| 73 | } |
| 74 | if (!VALID_OPERATIONS.includes(params.operation)) { |
| 75 | return { success: false, message: `Invalid operation "${params.operation}".` } |
| 76 | } |
| 77 | |
| 78 | const inputPaths = params.inputs?.files?.map((f) => f.path) ?? [] |
| 79 | if (inputPaths.length === 0) { |
| 80 | return { success: false, message: 'At least one input file is required in inputs.files' } |
| 81 | } |
| 82 | |
| 83 | try { |
| 84 | const mediaFiles: MediaFile[] = [] |
| 85 | for (const filePath of inputPaths) { |
| 86 | const fileRecord = await resolveWorkspaceFileReference(workspaceId, filePath) |
| 87 | if (!fileRecord) { |
| 88 | return { success: false, message: `Input file not found: ${filePath}` } |
| 89 | } |
| 90 | const buffer = await fetchWorkspaceFileBuffer(fileRecord) |
| 91 | mediaFiles.push({ |
| 92 | buffer, |
| 93 | mimeType: fileRecord.type || 'application/octet-stream', |
| 94 | name: fileRecord.name, |
| 95 | }) |
| 96 | } |
| 97 | |
| 98 | assertServerToolNotAborted(context) |
| 99 | const result = await runFfmpegOperation(params.operation, mediaFiles, { |
| 100 | text: params.text, |
| 101 | position: params.position, |
| 102 | start: params.start, |
| 103 | end: params.end, |
| 104 | width: params.width, |
| 105 | height: params.height, |
| 106 | aspectRatio: params.aspectRatio, |
| 107 | volume: params.volume, |
| 108 | musicVolume: params.musicVolume, |
| 109 | loopToVideo: params.loopToVideo, |
| 110 | format: params.format, |
| 111 | }) |
| 112 | |
| 113 | // probe reports metadata only — no file written. |
| 114 | if (params.operation === 'probe') { |
| 115 | return { |
| 116 | success: true, |
| 117 | message: `Probed ${mediaFiles[0]?.name ?? inputPaths[0]}: ${JSON.stringify(result.probe)}`, |
| 118 | probe: result.probe, |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | if (!result.buffer || !result.ext) { |
| 123 | return { success: false, message: `ffmpeg ${params.operation} produced no output` } |
nothing calls this directly
no test coverage detected