-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcli.js
More file actions
144 lines (121 loc) · 5.44 KB
/
Copy pathcli.js
File metadata and controls
144 lines (121 loc) · 5.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#!/usr/bin/env node
const { Command } = require('commander');
const VideoToFramesConverter = require('./VideoToFramesConverter');
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const program = new Command();
program
.name('video-to-frames')
.description('Convert videos to exactly 300 evenly spaced PNG frames in full HD quality')
.version('1.0.0');
program
.command('convert')
.description('Convert a video to 300 PNG frames')
.argument('<video>', 'Path to the video file')
.option('-o, --output <dir>', 'Output directory for frames', 'frames')
.option('-q, --quality <number>', 'PNG quality (1-31, lower is better)', '1')
.action(async (videoPath, options) => {
const converter = new VideoToFramesConverter();
try {
// Validate video file
if (!fs.existsSync(videoPath)) {
console.error(chalk.red(`❌ Video file not found: ${videoPath}`));
process.exit(1);
}
// Set quality if provided
if (options.quality) {
const quality = parseInt(options.quality);
if (quality < 1 || quality > 31) {
console.error(chalk.red('❌ Quality must be between 1 and 31'));
process.exit(1);
}
converter.outputQuality = quality;
}
// Convert video
await converter.convertVideo(videoPath, options.output);
} catch (error) {
console.error(chalk.red(`❌ Error: ${error.message}`));
process.exit(1);
}
});
program
.command('batch')
.description('Convert multiple videos to frames')
.argument('<pattern>', 'Glob pattern or directory containing videos')
.option('-o, --output <dir>', 'Base output directory', 'frames')
.option('-e, --extensions <ext...>', 'Video file extensions to process', ['mp4', 'avi', 'mov', 'mkv', 'wmv'])
.action(async (pattern, options) => {
const converter = new VideoToFramesConverter();
try {
let videoPaths = [];
// If pattern is a directory, find all video files
if (fs.existsSync(pattern) && fs.statSync(pattern).isDirectory()) {
const files = fs.readdirSync(pattern);
videoPaths = files
.filter(file => options.extensions.some(ext =>
file.toLowerCase().endsWith(`.${ext.toLowerCase()}`)))
.map(file => path.join(pattern, file));
} else {
// Assume it's a single file
if (fs.existsSync(pattern)) {
videoPaths = [pattern];
} else {
console.error(chalk.red(`❌ Path not found: ${pattern}`));
process.exit(1);
}
}
if (videoPaths.length === 0) {
console.error(chalk.red('❌ No video files found'));
process.exit(1);
}
console.log(chalk.blue(`Found ${videoPaths.length} video(s) to process:`));
videoPaths.forEach((path, i) => {
console.log(chalk.gray(` ${i + 1}. ${path}`));
});
await converter.batchConvert(videoPaths, options.output);
} catch (error) {
console.error(chalk.red(`❌ Error: ${error.message}`));
process.exit(1);
}
});
program
.command('info')
.description('Get information about a video file')
.argument('<video>', 'Path to the video file')
.action(async (videoPath) => {
const converter = new VideoToFramesConverter();
try {
if (!fs.existsSync(videoPath)) {
console.error(chalk.red(`❌ Video file not found: ${videoPath}`));
process.exit(1);
}
console.log(chalk.blue('📊 Analyzing video...'));
const metadata = await converter.getVideoMetadata(videoPath);
console.log(chalk.cyan('\nVideo Information:'));
console.log(chalk.gray(` File: ${videoPath}`));
console.log(chalk.gray(` Duration: ${metadata.duration.toFixed(2)} seconds`));
console.log(chalk.gray(` Frame Rate: ${metadata.frameRate.toFixed(2)} fps`));
console.log(chalk.gray(` Total Frames: ${metadata.totalFrames}`));
console.log(chalk.gray(` Resolution: ${metadata.width}x${metadata.height}`));
console.log(chalk.gray(` Codec: ${metadata.codec}`));
const timestamps = converter.calculateFrameTimestamps(metadata.totalFrames, metadata.duration);
console.log(chalk.yellow(`\n🎯 Would extract ${timestamps.length} frames at:`));
console.log(chalk.gray(` Frame interval: every ${(metadata.totalFrames / 300).toFixed(1)} frames`));
console.log(chalk.gray(` Time interval: every ${(metadata.duration / 300).toFixed(2)} seconds`));
} catch (error) {
console.error(chalk.red(`❌ Error: ${error.message}`));
process.exit(1);
}
});
// Handle unknown commands
program.on('command:*', () => {
console.error(chalk.red('❌ Invalid command. Use --help for available commands.'));
process.exit(1);
});
// Parse command line arguments
if (process.argv.length === 2) {
program.help();
} else {
program.parse();
}