@mediaproc/audio 1.1.1 → 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.
@@ -3,20 +3,25 @@ import { stat, writeFile, unlink } from 'fs/promises';
3
3
  import { join, dirname } from 'path';
4
4
  import { runFFmpeg, getAudioMetadata, checkFFmpeg, formatFileSize, formatDuration } from '../utils/ffmpeg.js';
5
5
  import { styleFFmpegOutput, shouldDisplayLine } from '../utils/ffmpeg-output.js';
6
- import { AUDIO_EXTENSIONS, parseInputPaths, createStandardHelp, showPluginBranding } from '@mediaproc/core';
6
+ import { AUDIO_EXTENSIONS, validatePaths, createStandardHelp, resolveOutputPaths } from '@mediaproc/core';
7
7
  import ora from 'ora';
8
8
  export function mergeCommand(audioCmd) {
9
9
  audioCmd
10
10
  .command('merge [inputs...]')
11
11
  .description('Merge multiple audio files into one')
12
- .option('-o, --output <path>', 'Output file path', 'merged.mp3')
12
+ .option('-o, --output <path>', 'Output file path (must include extension)')
13
13
  .option('--format <format>', 'Output format: mp3, aac, wav, flac, ogg', 'mp3')
14
+ .option('--codec <codec>', 'Specify output audio codec (overrides default for format)')
14
15
  .option('--bitrate <bitrate>', 'Output bitrate (e.g., 192k, 320k)', '192k')
15
16
  .option('--crossfade <seconds>', 'Crossfade duration between files (seconds)', parseFloat)
16
17
  .option('--normalize', 'Normalize audio levels before merging')
18
+ .option('--fade-in <seconds>', 'Add fade-in effect (seconds)', parseFloat)
19
+ .option('--fade-out <seconds>', 'Add fade-out effect (seconds)', parseFloat)
20
+ .option('--remove-silence', 'Remove silence between tracks')
21
+ .option('--metadata <key=value>', 'Set custom metadata (repeatable)', (val, acc = []) => { acc.push(val); return acc; }, [])
17
22
  .option('--dry-run', 'Preview command without executing')
18
23
  .option('-v, --verbose', 'Show detailed FFmpeg output')
19
- .option('--explain', 'Explain the proper flow of this command in detail (Coming Soon...)')
24
+ .option('--explain [mode]', 'Show a detailed explanation of what this command will do, including technical and human-readable output. Modes: human, details, json. Adds context like timestamp, user, and platform.')
20
25
  .option('-h, --help', 'Display help for merge command')
21
26
  .action(async (inputs, options) => {
22
27
  if (options.help || !inputs || inputs.length === 0) {
@@ -36,7 +41,7 @@ export function mergeCommand(audioCmd) {
36
41
  { flag: '--crossfade <seconds>', description: 'Crossfade duration between files in seconds (0-10)' },
37
42
  { flag: '--normalize', description: 'Normalize audio levels before merging for consistent volume' },
38
43
  { flag: '--dry-run', description: 'Preview FFmpeg command without executing' },
39
- { flag: '--explain', description: 'Explain what is happening behind the scene in proper flow and in detail (Coming Soon...)' },
44
+ { flag: '--explain [mode]', description: 'Show a detailed explanation of what this command will do, including technical and human-readable output. Modes: human, details, json. Adds context like timestamp, user, and platform.' },
40
45
  { flag: '-v, --verbose', description: 'Show detailed FFmpeg output and progress' }
41
46
  ],
42
47
  examples: [
@@ -59,40 +64,61 @@ export function mergeCommand(audioCmd) {
59
64
  console.error(chalk.red('\nāœ— Error: At least 2 audio files required for merging'));
60
65
  process.exit(1);
61
66
  }
62
- console.log(chalk.blue(`\nšŸ”— Merging ${inputs.length} audio files...`));
63
- // Validate all input files
64
- const validatedInputs = [];
65
- for (const input of inputs) {
66
- try {
67
- const paths = parseInputPaths(input, AUDIO_EXTENSIONS);
68
- validatedInputs.push(...paths);
69
- }
70
- catch (err) {
71
- console.warn(chalk.yellow(`⚠ Skipping invalid input: ${input}`));
72
- }
67
+ // Provide default output file name if not provided
68
+ let outputPathArg = options.output;
69
+ if (!outputPathArg) {
70
+ outputPathArg = 'merged.mp3';
73
71
  }
74
- if (validatedInputs.length < 2) {
72
+ // Use pathValidator for all input/output validation
73
+ const { inputFiles, outputPath, errors } = validatePaths(inputs.join(','), outputPathArg, { allowedExtensions: AUDIO_EXTENSIONS });
74
+ if (errors.length > 0) {
75
+ errors.forEach(e => console.error(chalk.red(e)));
76
+ process.exit(1);
77
+ }
78
+ if (inputFiles.length < 2) {
75
79
  console.error(chalk.red('\nāœ— Error: Not enough valid audio files found'));
76
80
  process.exit(1);
77
81
  }
78
- // Show input files
82
+ // Always use resolveOutputPaths to generate output file(s)
83
+ const outputFormat = options.format || 'mp3';
84
+ const outputPathsMap = resolveOutputPaths(inputFiles, outputPath, {
85
+ suffix: '-merged',
86
+ newExtension: `.${outputFormat}`
87
+ });
88
+ const outputFiles = Array.from(outputPathsMap.values());
89
+ console.log(chalk.blue(`\nšŸ”— Merging ${inputFiles.length} audio files...`));
90
+ // Show input files and collect extensions
79
91
  let totalDuration = 0;
80
- for (const inputFile of validatedInputs) {
92
+ for (const inputFile of inputFiles) {
81
93
  const metadata = await getAudioMetadata(inputFile);
82
94
  console.log(chalk.dim(` ${inputFile} (${formatDuration(metadata.duration)})`));
83
95
  totalDuration += metadata.duration;
84
96
  }
85
97
  console.log(chalk.dim(`\nTotal duration: ${formatDuration(totalDuration)}`));
86
98
  // Create concat file list
87
- const concatFile = join(dirname(validatedInputs[0]), '.concat-list.txt');
88
- const concatContent = validatedInputs.map(f => `file '${f}'`).join('\n');
99
+ const concatFile = join(dirname(inputFiles[0]), '.concat-list.txt');
100
+ const concatContent = inputFiles.map(f => `file '${f}'`).join('\n');
89
101
  await writeFile(concatFile, concatContent);
90
102
  const args = ['-f', 'concat', '-safe', '0', '-i', concatFile, '-y'];
91
- // Add crossfade if specified
103
+ // Output codec selection
104
+ const codecMap = {
105
+ mp3: 'libmp3lame',
106
+ aac: 'aac',
107
+ flac: 'flac',
108
+ wav: 'pcm_s16le',
109
+ ogg: 'libvorbis',
110
+ };
111
+ let codec = options.codec || codecMap[outputFormat] || 'libmp3lame';
112
+ if (codec)
113
+ args.push('-c:a', codec);
114
+ if (options.bitrate)
115
+ args.push('-b:a', options.bitrate);
116
+ // Audio filter chain
117
+ let filterChain = '';
118
+ // Crossfade
92
119
  if (options.crossfade) {
93
- // Build complex filter for crossfade
94
120
  const filterParts = [];
95
- for (let i = 0; i < validatedInputs.length - 1; i++) {
121
+ for (let i = 0; i < inputFiles.length - 1; i++) {
96
122
  if (i === 0) {
97
123
  filterParts.push(`[0:a][1:a]acrossfade=d=${options.crossfade}[a01]`);
98
124
  }
@@ -101,44 +127,79 @@ export function mergeCommand(audioCmd) {
101
127
  }
102
128
  }
103
129
  args.push('-filter_complex', filterParts.join(';'));
104
- args.push('-map', `[a0${validatedInputs.length - 1}]`);
130
+ args.push('-map', `[a0${inputFiles.length - 1}]`);
105
131
  }
106
- // Normalization
132
+ // Normalization (if not crossfade)
107
133
  if (options.normalize && !options.crossfade) {
108
- args.push('-af', 'loudnorm=I=-16:TP=-1.5:LRA=11');
134
+ filterChain += (filterChain ? ',' : '') + 'loudnorm=I=-16:TP=-1.5:LRA=11';
135
+ }
136
+ // Fade in/out
137
+ if (options.fadeIn) {
138
+ filterChain += (filterChain ? ',' : '') + `afade=t=in:st=0:d=${options.fadeIn}`;
139
+ }
140
+ if (options.fadeOut && totalDuration) {
141
+ const fadeStart = totalDuration - options.fadeOut;
142
+ filterChain += (filterChain ? ',' : '') + `afade=t=out:st=${fadeStart}:d=${options.fadeOut}`;
143
+ }
144
+ // Silence removal
145
+ if (options.removeSilence) {
146
+ filterChain += (filterChain ? ',' : '') + 'silenceremove=start_periods=1:start_silence=0.1:start_threshold=-50dB';
147
+ }
148
+ if (filterChain && !options.crossfade) {
149
+ args.push('-af', filterChain);
150
+ }
151
+ // Metadata
152
+ if (options.metadata && Array.isArray(options.metadata)) {
153
+ for (const entry of options.metadata) {
154
+ const [key, value] = entry.split('=');
155
+ if (key && value)
156
+ args.push('-metadata', `${key}=${value}`);
157
+ }
158
+ }
159
+ // Output file (merge always produces a single output file)
160
+ if (outputFiles.length > 0) {
161
+ args.push(outputFiles[0]);
109
162
  }
110
- // Output bitrate
111
- args.push('-b:a', options.bitrate);
112
- args.push(options.output);
113
163
  if (options.dryRun) {
114
164
  console.log(chalk.yellow('\n[DRY RUN] Would execute:'));
115
165
  console.log(chalk.dim(`ffmpeg ${args.join(' ')}`));
116
166
  await unlink(concatFile);
117
- showPluginBranding('Audio', '../../package.json');
118
167
  return;
119
168
  }
120
- if (options.explain) {
121
- console.log(chalk.gray('Explain mode is not yet available.'));
122
- console.log(chalk.cyan('Planned for v0.8.x.'));
123
- }
124
169
  const spinner = ora('Merging audio files...').start();
125
170
  try {
126
171
  await runFFmpeg(args, options.verbose, (line) => {
127
- if (shouldDisplayLine(line, options.verbose)) {
172
+ if (shouldDisplayLine(line, options.verbose ?? false)) {
128
173
  console.log(styleFFmpegOutput(line));
129
174
  }
130
175
  });
131
- const outputStat = await stat(options.output);
176
+ let outputStat;
177
+ if (outputPath) {
178
+ outputStat = await stat(outputPath);
179
+ }
132
180
  // Clean up concat file
133
181
  await unlink(concatFile);
134
182
  spinner.succeed(chalk.green('Merge complete'));
135
- console.log(chalk.green(`āœ“ Output: ${options.output}`));
136
- console.log(chalk.dim(`Duration: ${formatDuration(totalDuration)} • Size: ${formatFileSize(outputStat.size)}`));
137
- showPluginBranding('Audio', '../../package.json');
183
+ if (outputPath) {
184
+ console.log(chalk.green(`āœ“ Output: ${outputPath}`));
185
+ if (outputStat) {
186
+ console.log(chalk.dim(`Duration: ${formatDuration(totalDuration)} • Size: ${formatFileSize(outputStat.size)}`));
187
+ }
188
+ }
138
189
  }
139
190
  catch (error) {
140
191
  await unlink(concatFile).catch(() => { });
141
192
  spinner.fail(chalk.red('Merge failed'));
193
+ // Enhanced error reporting for common ffmpeg concat/decoder issues
194
+ const errObj = error;
195
+ const errMsg = (errObj && errObj.message) ? errObj.message : String(error);
196
+ if (/Invalid data found when processing input|Error submitting packet to decoder/i.test(errMsg)) {
197
+ console.error(chalk.yellow('\nāš ļø One or more input files may be corrupted, incompatible, or not suitable for merging.'));
198
+ console.error(chalk.yellow('Please ensure all input files are valid, have the same codec/sample rate/channels, and are not damaged.'));
199
+ }
200
+ else if (/Unable to choose an output format|Invalid argument|Error opening output file/i.test(errMsg)) {
201
+ console.error(chalk.yellow('\nāš ļø Output path or format may be invalid. Make sure the output file has a valid extension and is not a directory.'));
202
+ }
142
203
  throw error;
143
204
  }
144
205
  }
@@ -1 +1 @@
1
- {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/commands/merge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/commands/merge.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/commands/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAwIxD"}
1
+ {"version":3,"file":"normalize.d.ts","sourceRoot":"","sources":["../../src/commands/normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CA4LxD"}
@@ -2,7 +2,7 @@ import chalk from 'chalk';
2
2
  import { stat } from 'fs/promises';
3
3
  import { runFFmpeg, getAudioMetadata, checkFFmpeg, formatFileSize, formatDuration } from '../utils/ffmpeg.js';
4
4
  import { styleFFmpegOutput, shouldDisplayLine } from '../utils/ffmpeg-output.js';
5
- import { AUDIO_EXTENSIONS, parseInputPaths, resolveOutputPaths, validatePaths, createStandardHelp, showPluginBranding } from '@mediaproc/core';
5
+ import { AUDIO_EXTENSIONS, validatePaths, resolveOutputPaths, createStandardHelp } from '@mediaproc/core';
6
6
  import ora from 'ora';
7
7
  export function normalizeCommand(audioCmd) {
8
8
  audioCmd
@@ -15,9 +15,9 @@ export function normalizeCommand(audioCmd) {
15
15
  .option('--format <format>', 'Output format (default: same as input)')
16
16
  .option('--dry-run', 'Preview command without executing')
17
17
  .option('-v, --verbose', 'Show detailed FFmpeg output')
18
- .option('--explain', 'Explain the proper flow of this command in detail (Coming Soon...)')
18
+ .option('--explain [mode]', 'Show a detailed explanation of what this command will do, including technical and human-readable output. Modes: human, details, json. Adds context like timestamp, user, and platform.')
19
19
  .option('-h, --help', 'Display help for normalize command')
20
- .action(async (input, options) => {
20
+ .action(async function (input, options) {
21
21
  if (options.help || !input) {
22
22
  createStandardHelp({
23
23
  commandName: 'normalize',
@@ -35,7 +35,7 @@ export function normalizeCommand(audioCmd) {
35
35
  { flag: '-m, --method <method>', description: 'Normalization method: loudnorm (EBU R128 standard), peak' },
36
36
  { flag: '--format <format>', description: 'Output format: mp3, aac, wav, flac (default: same as input)' },
37
37
  { flag: '--dry-run', description: 'Preview FFmpeg command without executing' },
38
- { flag: '--explain', description: 'Explain what is happening behind the scene in proper flow and in detail (Coming Soon...)' },
38
+ { flag: '--explain [mode]', description: 'Show a detailed explanation of what this command will do, including technical and human-readable output. Modes: human, details, json. Adds context like timestamp, user, and platform.' },
39
39
  { flag: '-v, --verbose', description: 'Show detailed FFmpeg output and progress' }
40
40
  ],
41
41
  examples: [
@@ -54,14 +54,31 @@ export function normalizeCommand(audioCmd) {
54
54
  console.error(chalk.red('\nāœ— FFmpeg not found. Please install FFmpeg first.'));
55
55
  process.exit(1);
56
56
  }
57
- const inputPaths = parseInputPaths(input, AUDIO_EXTENSIONS);
57
+ const { inputFiles, outputPath, errors } = validatePaths(input, options.output, { allowedExtensions: AUDIO_EXTENSIONS });
58
+ if (errors.length > 0) {
59
+ errors.forEach(e => console.error(chalk.red(e)));
60
+ process.exit(1);
61
+ }
58
62
  const suffix = options.format ? `-normalized.${options.format}` : '-normalized';
59
- const { outputPath } = validatePaths(input, options.output, { allowedExtensions: AUDIO_EXTENSIONS });
60
- const outputPathsMap = resolveOutputPaths(inputPaths, outputPath, { suffix });
63
+ const outputPathsMap = resolveOutputPaths(inputFiles, outputPath, { suffix });
61
64
  const outputPaths = Array.from(outputPathsMap.values());
62
- for (let i = 0; i < inputPaths.length; i++) {
63
- const inputFile = inputPaths[i];
65
+ for (let i = 0; i < inputFiles.length; i++) {
66
+ const inputFile = inputFiles[i];
64
67
  const outputFile = outputPaths[i];
68
+ // Warn if normalization is requested for a format known to be problematic
69
+ const unsupportedNormFormats = ['ogg'];
70
+ let outFormat = options.format;
71
+ if (!outFormat) {
72
+ const extMatch = outputFile.match(/\.([a-zA-Z0-9]+)$/);
73
+ outFormat = extMatch && [
74
+ 'mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a', 'wma', 'opus', 'ape', 'alac', 'mov', 'mkv'
75
+ ].includes(extMatch[1].toLowerCase())
76
+ ? extMatch[1].toLowerCase()
77
+ : undefined;
78
+ }
79
+ if (outFormat && unsupportedNormFormats.includes(outFormat) && (options.method === 'loudnorm' || options.method === 'peak')) {
80
+ console.warn(chalk.yellow(`āš ļø Warning: Normalization for format '${outFormat}' may not be supported or may fail. If you encounter errors, try using a different output format (e.g., wav, flac, mp3, aac).`));
81
+ }
65
82
  console.log(chalk.blue(`\nšŸ“Š Normalizing: ${inputFile}`));
66
83
  const metadata = await getAudioMetadata(inputFile);
67
84
  const inputStat = await stat(inputFile);
@@ -69,16 +86,50 @@ export function normalizeCommand(audioCmd) {
69
86
  `Sample Rate: ${metadata.sampleRate} Hz • ` +
70
87
  `Channels: ${metadata.channels}`));
71
88
  const args = ['-i', inputFile, '-y'];
89
+ let filterApplied = false;
72
90
  if (options.method === 'loudnorm') {
73
- // EBU R128 loudness normalization
74
91
  args.push('-af', `loudnorm=I=${options.target}:TP=${options.maxLevel}:LRA=11:print_format=summary`);
92
+ filterApplied = true;
75
93
  }
76
94
  else if (options.method === 'peak') {
77
- // Simple peak normalization
78
95
  args.push('-af', 'volume=0dB');
96
+ filterApplied = true;
79
97
  }
80
- // Preserve original codec if no format specified
81
- if (!options.format) {
98
+ // Determine output format and codec
99
+ if (!outFormat) {
100
+ const extMatch = outputFile.match(/\.([a-zA-Z0-9]+)$/);
101
+ outFormat = extMatch && [
102
+ 'mp3', 'wav', 'flac', 'aac', 'ogg', 'm4a', 'wma', 'opus', 'ape', 'alac', 'mov', 'mkv'
103
+ ].includes(extMatch[1].toLowerCase())
104
+ ? extMatch[1].toLowerCase()
105
+ : undefined;
106
+ }
107
+ // Prevent filter+streamcopy: show error if user tries to use filters with stream copy
108
+ if (filterApplied) {
109
+ if (outFormat === 'mp3') {
110
+ args.push('-c:a', 'libmp3lame');
111
+ }
112
+ else if (outFormat === 'aac' || outFormat === 'm4a') {
113
+ args.push('-c:a', 'aac');
114
+ }
115
+ else if (outFormat === 'flac') {
116
+ args.push('-c:a', 'flac');
117
+ }
118
+ else if (outFormat === 'wav') {
119
+ args.push('-c:a', 'pcm_s16le');
120
+ }
121
+ else {
122
+ args.push('-c:a', 'libmp3lame'); // Default to mp3 codec for safety
123
+ }
124
+ }
125
+ else {
126
+ // No filter: safe to streamcopy
127
+ // But if user tries to add a filter (e.g. via method=peak) and also requests stream copy, show error
128
+ if (options.method === 'peak' || options.method === 'loudnorm') {
129
+ // Defensive: should not happen, but catch any logic error
130
+ console.error(chalk.red('\nāœ— Error: Cannot use normalization filters with stream copy. Please remove normalization options or use a supported codec.'));
131
+ process.exit(1);
132
+ }
82
133
  args.push('-c:a', 'copy');
83
134
  }
84
135
  args.push(outputFile);
@@ -87,32 +138,39 @@ export function normalizeCommand(audioCmd) {
87
138
  console.log(chalk.dim(`ffmpeg ${args.join(' ')}`));
88
139
  continue;
89
140
  }
90
- if (options.explain) {
91
- console.log(chalk.gray('Explain mode is not yet available.'));
92
- console.log(chalk.cyan('Planned for v0.8.x.'));
93
- }
94
141
  const spinner = ora('Normalizing...').start();
95
- try {
96
- await runFFmpeg(args, options.verbose, (line) => {
97
- if (shouldDisplayLine(line, options.verbose)) {
98
- console.log(styleFFmpegOutput(line));
99
- }
100
- });
101
- const outputStat = await stat(outputFile);
102
- spinner.succeed(chalk.green('Normalization complete'));
103
- console.log(chalk.green(`āœ“ Output: ${outputFile}`));
104
- console.log(chalk.dim(`Target: ${options.target} LUFS • Peak limit: ${options.maxLevel} dB`));
105
- console.log(chalk.dim(`Size: ${formatFileSize(inputStat.size)} → ${formatFileSize(outputStat.size)}`));
142
+ // Capture FFmpeg output to parse measured LUFS
143
+ let measuredLufs = undefined;
144
+ await runFFmpeg(args, options.verbose ?? false, (line) => {
145
+ if (shouldDisplayLine(line, options.verbose ?? false)) {
146
+ console.log(styleFFmpegOutput(line));
147
+ }
148
+ // Parse measured_I from loudnorm summary
149
+ if (options.method === 'loudnorm') {
150
+ const match = line.match(/Measured_I:\s*(-?\d+\.?\d*)/);
151
+ if (match)
152
+ measuredLufs = match[1];
153
+ }
154
+ });
155
+ const outputStat = await stat(outputFile);
156
+ spinner.succeed(chalk.green('Normalization complete'));
157
+ console.log(chalk.green(`āœ“ Output: ${outputFile}`));
158
+ if (options.method === 'loudnorm') {
159
+ if (measuredLufs !== undefined) {
160
+ console.log(chalk.dim(`Measured: ${measuredLufs} LUFS • Target: ${options.target} LUFS • Peak limit: ${options.maxLevel} dB`));
161
+ }
162
+ else {
163
+ console.log(chalk.dim(`Target: ${options.target} LUFS • Peak limit: ${options.maxLevel} dB (LUFS not available)`));
164
+ }
106
165
  }
107
- catch (error) {
108
- spinner.fail(chalk.red('Normalization failed'));
109
- throw error;
166
+ else {
167
+ console.log(chalk.dim(`Peak limit: ${options.maxLevel} dB`));
110
168
  }
169
+ console.log(chalk.dim(`Size: ${formatFileSize(inputStat.size)} → ${formatFileSize(outputStat.size)}`));
111
170
  }
112
- if (inputPaths.length > 1) {
113
- console.log(chalk.green(`\nāœ“ Normalized ${inputPaths.length} files successfully`));
171
+ if (inputFiles.length > 1) {
172
+ console.log(chalk.green(`\nāœ“ Normalized ${inputFiles.length} files successfully`));
114
173
  }
115
- showPluginBranding('Audio', '../../package.json');
116
174
  }
117
175
  catch (error) {
118
176
  console.error(chalk.red(`\nāœ— Error: ${error.message}`));
@@ -1 +1 @@
1
- {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/commands/normalize.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"normalize.js","sourceRoot":"","sources":["../../src/commands/normalize.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"trim.d.ts","sourceRoot":"","sources":["../../src/commands/trim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAoLnD"}
1
+ {"version":3,"file":"trim.d.ts","sourceRoot":"","sources":["../../src/commands/trim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASzC,wBAAgB,WAAW,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAsLnD"}
@@ -2,7 +2,7 @@ import chalk from 'chalk';
2
2
  import { stat } from 'fs/promises';
3
3
  import { runFFmpeg, getAudioMetadata, checkFFmpeg, formatFileSize, formatDuration, parseTime } from '../utils/ffmpeg.js';
4
4
  import { styleFFmpegOutput, shouldDisplayLine } from '../utils/ffmpeg-output.js';
5
- import { AUDIO_EXTENSIONS, parseInputPaths, resolveOutputPaths, validatePaths, createStandardHelp, showPluginBranding } from '@mediaproc/core';
5
+ import { AUDIO_EXTENSIONS, validatePaths, resolveOutputPaths, createStandardHelp } from '@mediaproc/core';
6
6
  import ora from 'ora';
7
7
  export function trimCommand(audioCmd) {
8
8
  audioCmd
@@ -20,9 +20,9 @@ export function trimCommand(audioCmd) {
20
20
  .option('--metadata <key=value>', 'Set custom metadata (repeatable)', (val, acc = []) => { acc.push(val); return acc; }, [])
21
21
  .option('--dry-run', 'Preview command without executing')
22
22
  .option('-v, --verbose', 'Show detailed FFmpeg output')
23
- .option('--explain', 'Explain the proper flow of this command in detail (Coming Soon...)')
23
+ .option('--explain [mode]', 'Show a detailed explanation of what this command will do, including technical and human-readable output. Modes: human, details, json. Adds context like timestamp, user, and platform.')
24
24
  .option('-h, --help', 'Display help for trim command')
25
- .action(async (input, options) => {
25
+ .action(async function (input, options) {
26
26
  if (options.help || !input) {
27
27
  createStandardHelp({
28
28
  commandName: 'trim',
@@ -45,7 +45,7 @@ export function trimCommand(audioCmd) {
45
45
  { flag: '--force', description: 'Overwrite output files without prompt' },
46
46
  { flag: '--metadata <key=value>', description: 'Set custom metadata (repeatable)' },
47
47
  { flag: '--dry-run', description: 'Preview FFmpeg command without executing' },
48
- { flag: '--explain', description: 'Explain what is happening behind the scene in proper flow and in detail (Coming Soon...)' },
48
+ { flag: '--explain [mode]', description: 'Show a detailed explanation of what this command will do, including technical and human-readable output. Modes: human, details, json. Adds context like timestamp, user, and platform.' },
49
49
  { flag: '-v, --verbose', description: 'Show detailed FFmpeg output and progress' }
50
50
  ],
51
51
  examples: [
@@ -69,20 +69,33 @@ export function trimCommand(audioCmd) {
69
69
  console.error(chalk.red('\nāœ— Error: Either --end or --duration must be specified'));
70
70
  process.exit(1);
71
71
  }
72
- const inputPaths = parseInputPaths(input, AUDIO_EXTENSIONS);
72
+ const { inputFiles, outputPath, errors } = validatePaths(input, options.output, { allowedExtensions: AUDIO_EXTENSIONS });
73
+ if (errors.length > 0) {
74
+ errors.forEach(e => console.error(chalk.red(e)));
75
+ process.exit(1);
76
+ }
73
77
  const suffix = options.format ? `-trimmed.${options.format}` : '-trimmed';
74
- const { outputPath } = validatePaths(input, options.output, { allowedExtensions: AUDIO_EXTENSIONS });
75
- const outputPathsMap = resolveOutputPaths(inputPaths, outputPath, { suffix });
78
+ const outputPathsMap = resolveOutputPaths(inputFiles, outputPath, { suffix });
76
79
  const outputPaths = Array.from(outputPathsMap.values());
77
- for (let i = 0; i < inputPaths.length; i++) {
78
- const inputFile = inputPaths[i];
80
+ for (let i = 0; i < inputFiles.length; i++) {
81
+ const inputFile = inputFiles[i];
79
82
  const outputFile = outputPaths[i];
80
83
  console.log(chalk.blue(`\nāœ‚ļø Trimming: ${inputFile}`));
81
84
  const metadata = await getAudioMetadata(inputFile);
82
85
  const inputStat = await stat(inputFile);
86
+ if (!options.start)
87
+ throw new Error('Start time is required for trim');
83
88
  const startTime = parseTime(options.start);
84
- const endTime = options.end ? parseTime(options.end) : startTime + parseTime(options.duration);
85
- const duration = endTime - startTime;
89
+ let duration = 0;
90
+ let endTime = startTime;
91
+ if (options.end) {
92
+ endTime = parseTime(options.end);
93
+ duration = endTime - startTime;
94
+ }
95
+ else if (options.duration) {
96
+ duration = parseTime(options.duration);
97
+ endTime = startTime + duration;
98
+ }
86
99
  console.log(chalk.dim(`Duration: ${formatDuration(metadata.duration)} • ` +
87
100
  `Sample Rate: ${metadata.sampleRate} Hz`));
88
101
  console.log(chalk.dim(`Trim: ${formatDuration(startTime)} → ${formatDuration(endTime)} ` +
@@ -129,17 +142,12 @@ export function trimCommand(audioCmd) {
129
142
  if (options.dryRun) {
130
143
  console.log(chalk.yellow('\n[DRY RUN] Would execute:'));
131
144
  console.log(chalk.dim(`ffmpeg ${args.join(' ')}`));
132
- showPluginBranding('Audio', '../../package.json');
133
145
  continue;
134
146
  }
135
- if (options.explain) {
136
- console.log(chalk.gray('Explain mode is not yet available.'));
137
- console.log(chalk.cyan('Planned for v0.8.x.'));
138
- }
139
147
  const spinner = ora('Trimming...').start();
140
148
  try {
141
- await runFFmpeg(args, options.verbose, (line) => {
142
- if (shouldDisplayLine(line, options.verbose)) {
149
+ await runFFmpeg(args, options.verbose ?? false, (line) => {
150
+ if (shouldDisplayLine(line, options.verbose ?? false)) {
143
151
  console.log(styleFFmpegOutput(line));
144
152
  }
145
153
  });
@@ -153,10 +161,7 @@ export function trimCommand(audioCmd) {
153
161
  throw error;
154
162
  }
155
163
  }
156
- if (inputPaths.length > 1) {
157
- console.log(chalk.green(`\nāœ“ Trimmed ${inputPaths.length} files successfully`));
158
- }
159
- showPluginBranding('Audio', '../../package.json');
164
+ console.log(chalk.green(`\nāœ“ Trimmed ${inputFiles.length} files successfully`));
160
165
  }
161
166
  catch (error) {
162
167
  console.error(chalk.red(`\nāœ— Error: ${error.message}`));