This repository has been archived by the owner on Mar 15, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
142 lines (129 loc) · 3.27 KB
/
index.js
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
#!/usr/bin/env node
const path = require('path');
const exec = require('child_process').exec;
const argv = require('minimist')(process.argv.slice(2));
const async = require('async');
const osTmpdir = require('os-tmpdir');
const tmp = osTmpdir();
const help = `
Usage: movtogif [videoFile] [outputFile]
CLI to convert mov to animated gif
Example:
$ movtogif ~/Desktop/video.mov ~/Desktop/video.gif
Options:
-v --version Display current software version
-h --help Display help and usage details
-r --resize Resize the gif. The default value is 75%
-d --delay Delay between the frames generated. The default is 8
`;
const missingDependencies = `
Make sure ffmpeg and imagemagick are installed.
$ brew update
$ brew install ffmpeg
$ brew install imagemagick
`;
const input = argv._[0];
const output = argv._[1];
const temp = `${tmp}/movtogif`;
const options = {
resize: argv.resize || argv.r,
delay: argv.delay || argv.d
};
if (!input || !output) {
console.log(help);
process.exit(0);
}
const which = (cmd, callback) => {
exec(`which ${cmd} 2>/dev/null && { echo >&1 ${cmd} found; exit 0; }`,
(error, stdout, stderr) => {
if (stdout.length === 0) {
console.error(missingDependencies);
}
callback();
}
);
};
const mkdirTemp = callback => {
exec(`mkdir -p ${temp}`, (error, stdout, stderr) => callback());
}
const cleanup = callback => {
exec(`rm -rf ${temp}`, (error, stdout, stderr) => callback());
}
const metadata = () => {
const cmd = [
'ffprobe',
'-v error',
'-of flat=s=_',
'-select_streams v:0',
'-show_entries',
'stream=height,width',
`${input}`
].join(' ');
return new Promise((resolve, reject) => {
exec(cmd, (error, stdout, stderr) => {
const width = /width=(\d+)/.exec(stdout);
const height = /height=(\d+)/.exec(stdout);
if (!!height && !!width) {
resolve({
width: width[1],
height: height[1]
});
} else {
reject();
}
});
});
};
const ffmpeg = callback => {
const r = 10;
console.log('Preparing recipe 📕');
metadata()
.then(dimensions => {
const cmd = [
'ffmpeg',
`-i ${input}`,
'-vf',
`scale=${dimensions.width}:-1`,
`-r ${r}`,
`${temp}/gif%3d.png`
].join(' ');
exec(cmd, null, () => callback());
}
);
};
const convert = callback => {
const resize = options.resize || '75%';
const delay = options.delay || 8;
const cmd = ['convert',
`-resize ${resize}`,
`-delay ${delay}`,
'-dither none',
'-coalesce',
'-layers optimize',
'-depth 8',
'-colors 128',
'-loop 0',
`${temp}/gif*.png ${output}`
].join(' ');
console.log('Cooking 🍳');
exec(cmd, (error, stdout, stderr) => {
console.log('Done 🍔');
console.log(`📺 ~> ${output}`);
callback();
});
}
async.series([
callback => which('ffmpeg', () => callback()),
callback => which('convert', () => callback()),
callback => mkdirTemp(() => callback()),
callback => ffmpeg(() => callback()),
callback => convert(() => callback()),
callback => cleanup(() => callback())
], (err, results) => {
if (err) {
console.log(err)
return;
}
//console.log(tmp);
//console.log(results);
});