dev-toolkit-cli 1.1.2 → 1.1.3
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.
- package/bin/actions/action-compress.js +7 -6
- package/bin/actions/action-compress.js.map +1 -1
- package/bin/lib/bash.js +42 -36
- package/bin/lib/bash.js.map +1 -1
- package/package.json +1 -1
- package/src/actions/action-compress.ts +15 -6
- package/src/lib/bash.ts +45 -36
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "fs/promises";
|
|
2
2
|
import mime from "mime";
|
|
3
|
-
import { getFolderFiles, replaceFilenameExtension, } from "../lib/utils/index.js";
|
|
4
|
-
import { check_dependencies, ffmpeg_image_to_webp,
|
|
3
|
+
import { addFilenameSuffix, getFolderFiles, replaceFilenameExtension, } from "../lib/utils/index.js";
|
|
4
|
+
import { check_dependencies, ffmpeg_image_to_webp, ffmpeg_compress_mp4_gpu, } from "../lib/bash.js";
|
|
5
5
|
export const FileType = ["image", "video"];
|
|
6
6
|
const unsupportedFormats = {
|
|
7
7
|
image: ["image/webp", "image/gif", "image/svg+xml"],
|
|
@@ -21,7 +21,8 @@ export async function file(pathname, { verbose, type, resolution, force, horizon
|
|
|
21
21
|
continue;
|
|
22
22
|
const fileType = mimetype.split("/")[0];
|
|
23
23
|
if (!(type ? [type] : FileType).includes(fileType) ||
|
|
24
|
-
(unsupportedFormats[fileType] || []).includes(mimetype)
|
|
24
|
+
(unsupportedFormats[fileType] || []).includes(mimetype) ||
|
|
25
|
+
filePath.includes(".compressed"))
|
|
25
26
|
continue;
|
|
26
27
|
const title = filePath
|
|
27
28
|
.substring(pathname.length)
|
|
@@ -35,7 +36,7 @@ export async function file(pathname, { verbose, type, resolution, force, horizon
|
|
|
35
36
|
if (fileType === "image")
|
|
36
37
|
await compressImage(filePath);
|
|
37
38
|
else if (fileType === "video")
|
|
38
|
-
await compressVideo(filePath);
|
|
39
|
+
await compressVideo(filePath, resolution, horizontal);
|
|
39
40
|
}
|
|
40
41
|
catch (err) {
|
|
41
42
|
if (verbose > 10)
|
|
@@ -50,8 +51,8 @@ async function compressImage(filePath) {
|
|
|
50
51
|
await ffmpeg_image_to_webp(filePath, replaceFilenameExtension(filePath, "webp"));
|
|
51
52
|
await fs.rm(filePath);
|
|
52
53
|
}
|
|
53
|
-
async function compressVideo(filePath) {
|
|
54
|
-
await
|
|
54
|
+
async function compressVideo(filePath, resolution, force) {
|
|
55
|
+
await ffmpeg_compress_mp4_gpu(filePath, addFilenameSuffix(filePath, ".compressed"), resolution, force);
|
|
55
56
|
await fs.rm(filePath);
|
|
56
57
|
}
|
|
57
58
|
//# sourceMappingURL=action-compress.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"action-compress.js","sourceRoot":"","sources":["../../src/actions/action-compress.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,aAAa,CAAC;AAC7B,OAAO,IAAI,MAAM,MAAM,CAAC;AAIxB,OAAO,
|
|
1
|
+
{"version":3,"file":"action-compress.js","sourceRoot":"","sources":["../../src/actions/action-compress.ts"],"names":[],"mappings":"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"}
|
package/bin/lib/bash.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { exec } from "child_process";
|
|
2
|
+
import { resolutionMapping } from "./constants.js";
|
|
2
3
|
import { CommanderError } from "commander";
|
|
3
4
|
import * as os from "os";
|
|
4
5
|
export const execAsync = (command) => new Promise((resolve, reject) => {
|
|
@@ -157,42 +158,47 @@ export async function ffmpeg_video_to_webm(input, output) {
|
|
|
157
158
|
// const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} ${acodec} -f webm -y "${output}"`;
|
|
158
159
|
// return execAsync(command);
|
|
159
160
|
// }
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
//
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
//
|
|
183
|
-
|
|
184
|
-
//
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
//
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
//
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
//
|
|
195
|
-
|
|
161
|
+
/**
|
|
162
|
+
* Comprime vídeo para MP4 (H.264) utilizando a GPU disponível com taxa de compressão otimizada.
|
|
163
|
+
*/
|
|
164
|
+
export async function ffmpeg_compress_mp4_gpu(input, output, // O arquivo deve terminar em .mp4
|
|
165
|
+
resolution = "480p", forceResolution) {
|
|
166
|
+
const { w, h } = resolutionMapping[resolution];
|
|
167
|
+
const gpu = await detectGPU();
|
|
168
|
+
const isLinux = os.platform() === "linux";
|
|
169
|
+
// 1. Mapeia os Encoders H.264 com equivalência de compressão (Qualidade vs Tamanho)
|
|
170
|
+
// O valor 28 é o "sweet spot". Menor = mais qualidade/mais pesado. Maior = menos qualidade/mais leve.
|
|
171
|
+
const encoders = {
|
|
172
|
+
nvidia: "-c:v h264_nvenc -preset p4 -cq 28",
|
|
173
|
+
amd: isLinux ? "-c:v h264_vaapi -qp 28" : "-c:v h264_amf -qp_i 28 -qp_p 28",
|
|
174
|
+
intel: isLinux
|
|
175
|
+
? "-c:v h264_vaapi -qp 28"
|
|
176
|
+
: "-c:v h264_qsv -global_quality 28",
|
|
177
|
+
mac: "-c:v h264_videotoolbox -q:v 60", // No Mac a escala é diferente, 60 é um bom balanço
|
|
178
|
+
cpu: "-c:v libx264 -preset fast -crf 28",
|
|
179
|
+
};
|
|
180
|
+
const vcodec = encoders[gpu] || encoders.cpu;
|
|
181
|
+
let hwaccel = gpu === "cpu" ? "" : "-hwaccel auto";
|
|
182
|
+
let videoFilter = "";
|
|
183
|
+
// 2. Define a string base do redimensionamento (Scale)
|
|
184
|
+
const scaleStr = forceResolution ? `scale=${w}:${h}` : `scale=-1:${h}`;
|
|
185
|
+
// 3. Aplica o filtro correto baseado na necessidade de VA-API no Linux
|
|
186
|
+
if (isLinux && (gpu === "amd" || gpu === "intel")) {
|
|
187
|
+
hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
188
|
+
// Integra a resolução e o upload para a GPU no mesmo filtro
|
|
189
|
+
videoFilter = `-vf "${scaleStr},format=nv12,hwupload"`;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
// Para NVIDIA, Mac e Windows, o scale simples via software antes de subir pra GPU funciona melhor
|
|
193
|
+
videoFilter = `-vf "${scaleStr}"`;
|
|
194
|
+
}
|
|
195
|
+
// 4. Áudio AAC universal e forçamento do container MP4
|
|
196
|
+
const acodec = "-c:a aac -b:a 128k";
|
|
197
|
+
const format = "-f mp4";
|
|
198
|
+
// 5. Monta e executa o comando final
|
|
199
|
+
const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} ${acodec} ${format} -y "${output}"`;
|
|
200
|
+
return execAsync(command);
|
|
201
|
+
}
|
|
196
202
|
export async function ffmpeg_image_to_webp(input, output) {
|
|
197
203
|
console.log(`Compressing image:`, input);
|
|
198
204
|
return execAsync(`ffmpeg -i "${input}" -c:v libwebp "${output}"`);
|
package/bin/lib/bash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/lib/bash.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/lib/bash.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -6,6 +6,7 @@ import path from "path";
|
|
|
6
6
|
import { Resolution } from "../lib/constants.js";
|
|
7
7
|
import {
|
|
8
8
|
addFilenamePrefix,
|
|
9
|
+
addFilenameSuffix,
|
|
9
10
|
getAvailablePathname,
|
|
10
11
|
getDirectory,
|
|
11
12
|
getFilename,
|
|
@@ -17,7 +18,7 @@ import {
|
|
|
17
18
|
import {
|
|
18
19
|
check_dependencies,
|
|
19
20
|
ffmpeg_image_to_webp,
|
|
20
|
-
|
|
21
|
+
ffmpeg_compress_mp4_gpu,
|
|
21
22
|
} from "../lib/bash.js";
|
|
22
23
|
|
|
23
24
|
export const FileType = ["image", "video"] as const;
|
|
@@ -58,7 +59,8 @@ export async function file(
|
|
|
58
59
|
const fileType = mimetype.split("/")[0] as FileType;
|
|
59
60
|
if (
|
|
60
61
|
!(type ? [type] : FileType).includes(fileType as FileType) ||
|
|
61
|
-
(unsupportedFormats[fileType] || []).includes(mimetype)
|
|
62
|
+
(unsupportedFormats[fileType] || []).includes(mimetype) ||
|
|
63
|
+
filePath.includes(".compressed")
|
|
62
64
|
)
|
|
63
65
|
continue;
|
|
64
66
|
|
|
@@ -75,7 +77,8 @@ export async function file(
|
|
|
75
77
|
|
|
76
78
|
try {
|
|
77
79
|
if (fileType === "image") await compressImage(filePath);
|
|
78
|
-
else if (fileType === "video")
|
|
80
|
+
else if (fileType === "video")
|
|
81
|
+
await compressVideo(filePath, resolution, horizontal);
|
|
79
82
|
} catch (err) {
|
|
80
83
|
if (verbose > 10) console.error(" Error compressing", err);
|
|
81
84
|
else console.error(" Error compressing", `"${filePath}"`);
|
|
@@ -93,10 +96,16 @@ async function compressImage(filePath: string) {
|
|
|
93
96
|
await fs.rm(filePath);
|
|
94
97
|
}
|
|
95
98
|
|
|
96
|
-
async function compressVideo(
|
|
97
|
-
|
|
99
|
+
async function compressVideo(
|
|
100
|
+
filePath: string,
|
|
101
|
+
resolution: Resolution,
|
|
102
|
+
force?: boolean,
|
|
103
|
+
) {
|
|
104
|
+
await ffmpeg_compress_mp4_gpu(
|
|
98
105
|
filePath,
|
|
99
|
-
|
|
106
|
+
addFilenameSuffix(filePath, ".compressed"),
|
|
107
|
+
resolution,
|
|
108
|
+
force,
|
|
100
109
|
);
|
|
101
110
|
await fs.rm(filePath);
|
|
102
111
|
}
|
package/src/lib/bash.ts
CHANGED
|
@@ -193,49 +193,58 @@ export async function ffmpeg_video_to_webm(
|
|
|
193
193
|
// return execAsync(command);
|
|
194
194
|
// }
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
//
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
196
|
+
/**
|
|
197
|
+
* Comprime vídeo para MP4 (H.264) utilizando a GPU disponível com taxa de compressão otimizada.
|
|
198
|
+
*/
|
|
199
|
+
export async function ffmpeg_compress_mp4_gpu(
|
|
200
|
+
input: string,
|
|
201
|
+
output: string, // O arquivo deve terminar em .mp4
|
|
202
|
+
resolution: Resolution = "480p",
|
|
203
|
+
forceResolution?: boolean,
|
|
204
|
+
) {
|
|
205
|
+
const { w, h } = resolutionMapping[resolution];
|
|
206
|
+
const gpu = await detectGPU();
|
|
207
|
+
const isLinux = os.platform() === "linux";
|
|
205
208
|
|
|
206
|
-
//
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
209
|
+
// 1. Mapeia os Encoders H.264 com equivalência de compressão (Qualidade vs Tamanho)
|
|
210
|
+
// O valor 28 é o "sweet spot". Menor = mais qualidade/mais pesado. Maior = menos qualidade/mais leve.
|
|
211
|
+
const encoders = {
|
|
212
|
+
nvidia: "-c:v h264_nvenc -preset p4 -cq 28",
|
|
213
|
+
amd: isLinux ? "-c:v h264_vaapi -qp 28" : "-c:v h264_amf -qp_i 28 -qp_p 28",
|
|
214
|
+
intel: isLinux
|
|
215
|
+
? "-c:v h264_vaapi -qp 28"
|
|
216
|
+
: "-c:v h264_qsv -global_quality 28",
|
|
217
|
+
mac: "-c:v h264_videotoolbox -q:v 60", // No Mac a escala é diferente, 60 é um bom balanço
|
|
218
|
+
cpu: "-c:v libx264 -preset fast -crf 28",
|
|
219
|
+
};
|
|
214
220
|
|
|
215
|
-
|
|
221
|
+
const vcodec = encoders[gpu] || encoders.cpu;
|
|
216
222
|
|
|
217
|
-
|
|
218
|
-
|
|
223
|
+
let hwaccel = gpu === "cpu" ? "" : "-hwaccel auto";
|
|
224
|
+
let videoFilter = "";
|
|
219
225
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
// hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
223
|
-
// // O VA-API precisa que os frames subam para a GPU no formato NV12
|
|
224
|
-
// videoFilter = forceResolution
|
|
225
|
-
// ? `-vf "scale=${w}:${h},format=nv12,hwupload"`
|
|
226
|
-
// : `-vf "scale=-1:${h},format=nv12,hwupload"`;
|
|
227
|
-
// } else {
|
|
228
|
-
// videoFilter = forceResolution ? `-s ${w}x${h}` : `-filter:v scale=-1:${h}`;
|
|
229
|
-
// }
|
|
226
|
+
// 2. Define a string base do redimensionamento (Scale)
|
|
227
|
+
const scaleStr = forceResolution ? `scale=${w}:${h}` : `scale=-1:${h}`;
|
|
230
228
|
|
|
231
|
-
//
|
|
232
|
-
|
|
229
|
+
// 3. Aplica o filtro correto baseado na necessidade de VA-API no Linux
|
|
230
|
+
if (isLinux && (gpu === "amd" || gpu === "intel")) {
|
|
231
|
+
hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
232
|
+
// Integra a resolução e o upload para a GPU no mesmo filtro
|
|
233
|
+
videoFilter = `-vf "${scaleStr},format=nv12,hwupload"`;
|
|
234
|
+
} else {
|
|
235
|
+
// Para NVIDIA, Mac e Windows, o scale simples via software antes de subir pra GPU funciona melhor
|
|
236
|
+
videoFilter = `-vf "${scaleStr}"`;
|
|
237
|
+
}
|
|
233
238
|
|
|
234
|
-
//
|
|
235
|
-
|
|
239
|
+
// 4. Áudio AAC universal e forçamento do container MP4
|
|
240
|
+
const acodec = "-c:a aac -b:a 128k";
|
|
241
|
+
const format = "-f mp4";
|
|
236
242
|
|
|
237
|
-
//
|
|
238
|
-
|
|
243
|
+
// 5. Monta e executa o comando final
|
|
244
|
+
const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} ${acodec} ${format} -y "${output}"`;
|
|
245
|
+
|
|
246
|
+
return execAsync(command);
|
|
247
|
+
}
|
|
239
248
|
|
|
240
249
|
export async function ffmpeg_image_to_webp(input: string, output: string) {
|
|
241
250
|
console.log(`Compressing image:`, input);
|