agent-media-cli 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,263 +0,0 @@
1
- // Copyright 2026 agent-media contributors. Apache-2.0 license.
2
- /**
3
- * `agent-media text` command.
4
- *
5
- * Overlays text onto a local media file (video or image) using ffmpeg.
6
- * This is a LOCAL-ONLY command — it does NOT call the API, does NOT
7
- * require authentication, and does NOT cost credits. All processing
8
- * is performed on the local machine via ffmpeg.
9
- *
10
- * Supported input formats: .mp4, .webm, .mov, .jpg, .jpeg, .png, .webp
11
- *
12
- * Flow:
13
- * 1. Validate input file exists and has a supported extension.
14
- * 2. Check that ffmpeg is available on the system PATH.
15
- * 3. Build an ffmpeg drawtext filter command based on options.
16
- * 4. Execute ffmpeg with a progress spinner.
17
- * 5. Report the output file path and size.
18
- */
19
- import { existsSync, statSync } from 'node:fs';
20
- import { basename, dirname, extname, join, resolve } from 'node:path';
21
- import { execFile } from 'node:child_process';
22
- import { promisify } from 'node:util';
23
- import chalk from 'chalk';
24
- import { detectOutputMode, printJson, printQuiet, createSpinner, } from '../lib/output.js';
25
- import { CLIError, handleError } from '../lib/errors.js';
26
- const execFileAsync = promisify(execFile);
27
- /** Supported media file extensions. */
28
- const SUPPORTED_VIDEO_EXTS = new Set(['.mp4', '.webm', '.mov']);
29
- const SUPPORTED_IMAGE_EXTS = new Set(['.jpg', '.jpeg', '.png', '.webp']);
30
- const SUPPORTED_EXTS = new Set([...SUPPORTED_VIDEO_EXTS, ...SUPPORTED_IMAGE_EXTS]);
31
- /** Text position presets mapping to ffmpeg y-coordinate expressions. */
32
- const POSITION_Y_EXPR = {
33
- top: 'th+__PADDING__',
34
- center: '(h-th)/2',
35
- bottom: 'h-th-__PADDING__',
36
- };
37
- /**
38
- * Check whether ffmpeg is available on the system PATH.
39
- *
40
- * Runs `ffmpeg -version` and returns `true` if it exits successfully.
41
- */
42
- async function isFfmpegAvailable() {
43
- try {
44
- await execFileAsync('ffmpeg', ['-version']);
45
- return true;
46
- }
47
- catch {
48
- return false;
49
- }
50
- }
51
- /**
52
- * Determine whether the input file is a video or an image based on extension.
53
- */
54
- function isVideoFile(ext) {
55
- return SUPPORTED_VIDEO_EXTS.has(ext.toLowerCase());
56
- }
57
- /**
58
- * Build the default output file path by inserting `_text` before the extension.
59
- *
60
- * Example: `/path/to/video.mp4` -> `/path/to/video_text.mp4`
61
- */
62
- function buildDefaultOutputPath(inputPath) {
63
- const dir = dirname(inputPath);
64
- const ext = extname(inputPath);
65
- const base = basename(inputPath, ext);
66
- return join(dir, `${base}_text${ext}`);
67
- }
68
- /**
69
- * Parse a hex color string to an ffmpeg-compatible color value.
70
- *
71
- * Accepts `#RRGGBB` or `#RRGGBBAA` formats. Returns an ffmpeg color
72
- * string like `0xRRGGBBAA` or `0xRRGGBB`.
73
- */
74
- function hexToFfmpegColor(hex) {
75
- const cleaned = hex.replace(/^#/, '');
76
- return `0x${cleaned}`;
77
- }
78
- /**
79
- * Parse a hex color with alpha to separate color and opacity for boxcolor.
80
- *
81
- * Accepts `#RRGGBB` or `#RRGGBBAA`. Returns `color@opacity` for ffmpeg.
82
- */
83
- function hexToFfmpegBoxColor(hex) {
84
- const cleaned = hex.replace(/^#/, '');
85
- if (cleaned.length === 8) {
86
- const rgb = cleaned.slice(0, 6);
87
- const alpha = parseInt(cleaned.slice(6, 8), 16) / 255;
88
- return `0x${rgb}@${alpha.toFixed(2)}`;
89
- }
90
- return `0x${cleaned}`;
91
- }
92
- /**
93
- * Escape special characters in text for ffmpeg drawtext filter.
94
- *
95
- * ffmpeg drawtext requires escaping colons, backslashes, and single quotes.
96
- */
97
- function escapeDrawtext(text) {
98
- return text
99
- .replace(/\\/g, '\\\\\\\\')
100
- .replace(/'/g, "'\\\\\\'")
101
- .replace(/:/g, '\\\\:')
102
- .replace(/%/g, '%%');
103
- }
104
- /**
105
- * Format bytes to a human-readable string (e.g., "15.2 MB").
106
- */
107
- function formatBytes(bytes) {
108
- if (bytes < 1024)
109
- return `${bytes} B`;
110
- if (bytes < 1024 * 1024)
111
- return `${(bytes / 1024).toFixed(1)} KB`;
112
- if (bytes < 1024 * 1024 * 1024)
113
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
114
- return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
115
- }
116
- /**
117
- * Build the ffmpeg drawtext filter string.
118
- */
119
- function buildDrawtextFilter(opts) {
120
- const escapedText = escapeDrawtext(opts.text);
121
- const color = hexToFfmpegColor(opts.fontColor);
122
- const boxColor = hexToFfmpegBoxColor(opts.bgColor);
123
- const yExpr = (POSITION_Y_EXPR[opts.position] ?? POSITION_Y_EXPR['bottom'])
124
- .replace(/__PADDING__/g, String(opts.padding));
125
- const parts = [
126
- `text='${escapedText}'`,
127
- `fontsize=${opts.fontSize}`,
128
- `fontcolor=${color}`,
129
- `x=(w-text_w)/2`,
130
- `y=${yExpr}`,
131
- `box=1`,
132
- `boxcolor=${boxColor}`,
133
- `boxborderw=${opts.padding}`,
134
- ];
135
- return `drawtext=${parts.join(':')}`;
136
- }
137
- export function registerTextCommand(program) {
138
- program
139
- .command('text')
140
- .description('Overlay text on a local media file using ffmpeg (no API, no auth, no cost)')
141
- .requiredOption('-m, --media <file>', 'Input media file path')
142
- .requiredOption('-t, --text <text>', 'Text to overlay')
143
- .option('--position <pos>', 'Text position: top, center, bottom', 'bottom')
144
- .option('--font-size <n>', 'Font size in pixels (default: 48 for video, 36 for images)')
145
- .option('--color <hex>', 'Text color as hex (e.g., #FFFFFF)', '#FFFFFF')
146
- .option('--bg-color <hex>', 'Background color for text box (e.g., #000000AA)', '#000000AA')
147
- .option('--padding <n>', 'Padding around text in pixels', '20')
148
- .option('-o, --output <file>', 'Output file path (default: input with _text suffix)')
149
- .action(async (cmdOpts) => {
150
- const globalOpts = program.opts();
151
- const mode = detectOutputMode(globalOpts);
152
- try {
153
- const startTime = Date.now();
154
- // ── Step 1: Validate input file ───────────────────────────────
155
- const inputPath = resolve(cmdOpts.media);
156
- if (!existsSync(inputPath)) {
157
- throw new CLIError(`Input file not found: ${inputPath}`, {
158
- code: 'FILE_NOT_FOUND',
159
- suggestion: 'Check the file path and try again.',
160
- });
161
- }
162
- const ext = extname(inputPath).toLowerCase();
163
- if (!SUPPORTED_EXTS.has(ext)) {
164
- throw new CLIError(`Unsupported file format: ${ext}`, {
165
- code: 'UNSUPPORTED_FORMAT',
166
- suggestion: `Supported formats: ${[...SUPPORTED_EXTS].join(', ')}`,
167
- });
168
- }
169
- // ── Step 2: Check ffmpeg availability ─────────────────────────
170
- const ffmpegOk = await isFfmpegAvailable();
171
- if (!ffmpegOk) {
172
- throw new CLIError('ffmpeg is not installed.', {
173
- code: 'FFMPEG_NOT_FOUND',
174
- suggestion: 'Install with: brew install ffmpeg (macOS) or apt install ffmpeg (Linux)',
175
- });
176
- }
177
- // ── Step 3: Resolve options ───────────────────────────────────
178
- const isVideo = isVideoFile(ext);
179
- const defaultFontSize = isVideo ? 48 : 36;
180
- const fontSize = cmdOpts.fontSize
181
- ? parseInt(cmdOpts.fontSize, 10)
182
- : defaultFontSize;
183
- const padding = parseInt(cmdOpts.padding, 10);
184
- const position = cmdOpts.position.toLowerCase();
185
- if (!POSITION_Y_EXPR[position]) {
186
- throw new CLIError(`Invalid position: "${cmdOpts.position}"`, {
187
- code: 'INVALID_OPTION',
188
- suggestion: 'Valid positions: top, center, bottom',
189
- });
190
- }
191
- const outputPath = cmdOpts.output
192
- ? resolve(cmdOpts.output)
193
- : buildDefaultOutputPath(inputPath);
194
- // ── Step 4: Build and execute ffmpeg command ──────────────────
195
- const filter = buildDrawtextFilter({
196
- text: cmdOpts.text,
197
- fontSize,
198
- fontColor: cmdOpts.color,
199
- bgColor: cmdOpts.bgColor,
200
- padding,
201
- position,
202
- });
203
- const ffmpegArgs = [
204
- '-i', inputPath,
205
- '-vf', filter,
206
- ];
207
- if (isVideo) {
208
- // Copy audio stream without re-encoding
209
- ffmpegArgs.push('-codec:a', 'copy');
210
- }
211
- // Overwrite output file without prompting
212
- ffmpegArgs.push('-y', outputPath);
213
- const spinner = createSpinner(`Overlaying text on ${basename(inputPath)}...`);
214
- if (mode === 'human')
215
- spinner.start();
216
- try {
217
- await execFileAsync('ffmpeg', ffmpegArgs);
218
- }
219
- catch (error) {
220
- if (mode === 'human')
221
- spinner.fail('ffmpeg failed');
222
- const message = error instanceof Error ? error.message : 'Unknown ffmpeg error';
223
- throw new CLIError(`ffmpeg processing failed: ${message}`, {
224
- code: 'FFMPEG_ERROR',
225
- suggestion: 'Verify the input file is valid and ffmpeg supports the format.',
226
- });
227
- }
228
- // ── Step 5: Report results ────────────────────────────────────
229
- if (!existsSync(outputPath)) {
230
- if (mode === 'human')
231
- spinner.fail('Output file was not created');
232
- throw new CLIError('ffmpeg completed but output file was not created.', {
233
- code: 'OUTPUT_MISSING',
234
- suggestion: 'Check ffmpeg output for warnings or errors.',
235
- });
236
- }
237
- const outputStat = statSync(outputPath);
238
- const durationMs = Date.now() - startTime;
239
- switch (mode) {
240
- case 'json':
241
- printJson({
242
- input: inputPath,
243
- output: outputPath,
244
- text: cmdOpts.text,
245
- position,
246
- fileSize: outputStat.size,
247
- duration_ms: durationMs,
248
- });
249
- break;
250
- case 'quiet':
251
- printQuiet(outputPath);
252
- break;
253
- default:
254
- spinner.succeed(`Created: ${chalk.cyan(outputPath)} (${formatBytes(outputStat.size)})`);
255
- break;
256
- }
257
- }
258
- catch (error) {
259
- handleError(error);
260
- }
261
- });
262
- }
263
- //# sourceMappingURL=text.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/commands/text.ts"],"names":[],"mappings":"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"}