dev-toolkit-cli 1.0.4 → 1.0.6
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/lib/bash.js +125 -27
- package/bin/lib/bash.js.map +1 -1
- package/package.json +1 -1
- package/src/lib/bash.ts +151 -30
package/bin/lib/bash.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { exec } from "child_process";
|
|
2
|
-
import { resolutionMapping } from "./constants.js";
|
|
3
2
|
import { CommanderError } from "commander";
|
|
3
|
+
import * as os from "os";
|
|
4
4
|
export const execAsync = (command) => new Promise((resolve, reject) => {
|
|
5
5
|
exec(command, (error, stdout, stderr) => {
|
|
6
6
|
if (error)
|
|
@@ -25,40 +25,138 @@ export async function check_dependencies(dependencies = globalDependencies) {
|
|
|
25
25
|
throw new CommanderError(1, "missing_dependencies", missing_dependencies.map((dep) => `'${dep}'`).join(", "));
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
|
|
28
|
+
// Cache para não termos que detectar a GPU toda vez que formos comprimir um vídeo
|
|
29
|
+
let cachedGpuType = null;
|
|
30
|
+
/**
|
|
31
|
+
* Detecta a GPU instalada na máquina rodando comandos nativos do SO.
|
|
32
|
+
*/
|
|
33
|
+
async function detectGPU() {
|
|
34
|
+
if (cachedGpuType)
|
|
35
|
+
return cachedGpuType; // Retorna do cache se já sabemos
|
|
36
|
+
const platform = os.platform();
|
|
29
37
|
try {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
//
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
// Se for Mac, assume VideoToolbox (Aceleração nativa da Apple)
|
|
39
|
+
if (platform === "darwin") {
|
|
40
|
+
cachedGpuType = "mac";
|
|
41
|
+
return cachedGpuType;
|
|
42
|
+
}
|
|
43
|
+
let output = "";
|
|
44
|
+
// Se for Windows, usa o WMIC para listar as placas de vídeo
|
|
45
|
+
if (platform === "win32") {
|
|
46
|
+
const stdout = await execAsync("wmic path win32_VideoController get name");
|
|
47
|
+
output = stdout.toLowerCase();
|
|
48
|
+
}
|
|
49
|
+
// Se for Linux, usa o lspci para listar os hardwares PCI
|
|
50
|
+
else if (platform === "linux") {
|
|
51
|
+
const stdout = await execAsync("lspci");
|
|
52
|
+
output = stdout.toLowerCase();
|
|
53
|
+
}
|
|
54
|
+
// Analisa a saída dos comandos para descobrir a marca
|
|
55
|
+
if (output.includes("nvidia")) {
|
|
56
|
+
cachedGpuType = "nvidia";
|
|
57
|
+
}
|
|
58
|
+
else if (output.includes("amd") || output.includes("radeon")) {
|
|
59
|
+
cachedGpuType = "amd";
|
|
60
|
+
}
|
|
61
|
+
else if (output.includes("intel")) {
|
|
62
|
+
cachedGpuType = "intel";
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
cachedGpuType = "cpu"; // Fallback se não identificar nada
|
|
66
|
+
}
|
|
44
67
|
}
|
|
45
|
-
catch {
|
|
46
|
-
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (error instanceof Error)
|
|
70
|
+
console.warn("⚠️ Aviso: Falha ao detectar GPU. Usando CPU por segurança.", error.message);
|
|
71
|
+
cachedGpuType = "cpu";
|
|
47
72
|
}
|
|
73
|
+
return cachedGpuType;
|
|
48
74
|
}
|
|
49
75
|
export async function ffmpeg_video_compress(input, output, resolution = "480p", forceResolution) {
|
|
76
|
+
// Exemplo de mapeamento (ajuste para bater com o seu código original)
|
|
77
|
+
const resolutionMapping = {
|
|
78
|
+
"4320p": { w: 7680, h: 4320 }, // 8K
|
|
79
|
+
"2160p": { w: 3840, h: 2160 }, // 4K
|
|
80
|
+
"1440p": { w: 2560, h: 1440 }, // Quad HD
|
|
81
|
+
"1080p": { w: 1920, h: 1080 }, // Full HD
|
|
82
|
+
"720p": { w: 1280, h: 720 }, // HD
|
|
83
|
+
"480p": { w: 854, h: 480 }, // SD (WVGA)
|
|
84
|
+
"360p": { w: 640, h: 360 }, // nHD
|
|
85
|
+
"240p": { w: 426, h: 240 }, // WQVGA
|
|
86
|
+
};
|
|
50
87
|
const { w, h } = resolutionMapping[resolution];
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
88
|
+
// 1. Detecta a GPU automaticamente
|
|
89
|
+
const gpu = await detectGPU();
|
|
90
|
+
// 2. Verifica se é Linux para usar a estratégia correta
|
|
91
|
+
const isLinux = os.platform() === "linux";
|
|
92
|
+
// Mapeia os Encoders. Nota: AMD e Intel no Linux usam VA-API
|
|
93
|
+
const encoders = {
|
|
94
|
+
nvidia: "-c:v h264_nvenc -preset p4",
|
|
95
|
+
amd: isLinux ? "-c:v h264_vaapi" : "-c:v h264_amf",
|
|
96
|
+
intel: isLinux ? "-c:v h264_vaapi" : "-c:v h264_qsv",
|
|
97
|
+
mac: "-c:v h264_videotoolbox",
|
|
98
|
+
cpu: "-c:v libx264 -preset fast",
|
|
99
|
+
};
|
|
100
|
+
const vcodec = encoders[gpu] || encoders.cpu;
|
|
101
|
+
// 3. Configura a aceleração e os filtros
|
|
102
|
+
let hwaccel = gpu === "cpu" ? "" : "-hwaccel auto";
|
|
103
|
+
let videoFilter = "";
|
|
104
|
+
// Lógica específica para o VA-API (AMD/Intel no Linux)
|
|
105
|
+
if (isLinux && (gpu === "amd" || gpu === "intel")) {
|
|
106
|
+
// Aponta diretamente para a placa de vídeo no Linux
|
|
107
|
+
hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
108
|
+
// O VA-API precisa que o formato seja nv12 e faça o upload para a GPU
|
|
109
|
+
videoFilter = forceResolution
|
|
110
|
+
? `-vf "scale=${w}:${h},format=nv12,hwupload"`
|
|
111
|
+
: `-vf "scale=-1:${h},format=nv12,hwupload"`;
|
|
57
112
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
113
|
+
else {
|
|
114
|
+
// Lógica padrão para Windows, Mac e NVIDIA
|
|
115
|
+
videoFilter = forceResolution ? `-s ${w}x${h}` : `-filter:v scale=-1:${h}`;
|
|
116
|
+
}
|
|
117
|
+
// 4. Monta e executa o comando FFmpeg
|
|
118
|
+
const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} -acodec copy -y "${output}"`;
|
|
119
|
+
console.log("Converting using: ", vcodec);
|
|
120
|
+
return execAsync(command);
|
|
61
121
|
}
|
|
122
|
+
// async function getBestEncoder(): Promise<string> {
|
|
123
|
+
// try {
|
|
124
|
+
// const { stdout } = (await execAsync("ffmpeg -encoders")) as {
|
|
125
|
+
// stdout: string;
|
|
126
|
+
// };
|
|
127
|
+
// // Prioridade para AMD (Windows: amf | Linux: vaapi)
|
|
128
|
+
// if (stdout.includes("h264_amf")) return "h264_amf";
|
|
129
|
+
// if (stdout.includes("h264_vaapi")) return "h264_vaapi";
|
|
130
|
+
// // Outros hardwares
|
|
131
|
+
// if (stdout.includes("h264_nvenc")) return "h264_nvenc";
|
|
132
|
+
// if (stdout.includes("h264_qsv")) return "h264_qsv";
|
|
133
|
+
// if (stdout.includes("h264_videotoolbox")) return "h264_videotoolbox";
|
|
134
|
+
// return "libx264"; // Fallback
|
|
135
|
+
// } catch {
|
|
136
|
+
// return "libx264";
|
|
137
|
+
// }
|
|
138
|
+
// }
|
|
139
|
+
// export async function ffmpeg_video_compress(
|
|
140
|
+
// input: string,
|
|
141
|
+
// output: string,
|
|
142
|
+
// resolution: Resolution = "480p",
|
|
143
|
+
// forceResolution?: boolean,
|
|
144
|
+
// ) {
|
|
145
|
+
// const { w, h } = resolutionMapping[resolution];
|
|
146
|
+
// const encoder = await getBestEncoder();
|
|
147
|
+
// // No VA-API (Linux), o redimensionamento deve ser feito via hardware para máxima performance
|
|
148
|
+
// let filter = forceResolution ? `scale=${w}:${h}` : `scale=-1:${h}`;
|
|
149
|
+
// if (encoder === "h264_vaapi") {
|
|
150
|
+
// // Adiciona upload para hardware se usar vaapi
|
|
151
|
+
// filter = `format=nv12,hwupload,scale_vaapi=w=${forceResolution ? w : -1}:h=${h}`;
|
|
152
|
+
// }
|
|
153
|
+
// const vaapiOpts =
|
|
154
|
+
// encoder === "h264_vaapi" ? "-vaapi_device /dev/dri/renderD128" : "";
|
|
155
|
+
// console.log("Compressing video using: ", encoder);
|
|
156
|
+
// return execAsync(
|
|
157
|
+
// `ffmpeg ${vaapiOpts} -i "${input}" -vf "${filter}" -c:v ${encoder} -pix_fmt yuv420p -acodec copy -y "${output}"`,
|
|
158
|
+
// );
|
|
159
|
+
// }
|
|
62
160
|
// export async function ffmpeg_video_compress(
|
|
63
161
|
// input: string,
|
|
64
162
|
// output: string,
|
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
package/src/lib/bash.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { exec } from "child_process";
|
|
2
2
|
import { Resolution, resolutionMapping } from "./constants.js";
|
|
3
3
|
import { CommanderError } from "commander";
|
|
4
|
+
import { promisify } from "util";
|
|
5
|
+
import * as os from "os";
|
|
4
6
|
|
|
5
|
-
export const execAsync = (command: string) =>
|
|
7
|
+
export const execAsync = (command: string): Promise<string> =>
|
|
6
8
|
new Promise((resolve, reject) => {
|
|
7
9
|
exec(command, (error, stdout, stderr) => {
|
|
8
10
|
if (error) reject(new Error(stderr));
|
|
@@ -33,26 +35,61 @@ export async function check_dependencies(dependencies = globalDependencies) {
|
|
|
33
35
|
);
|
|
34
36
|
}
|
|
35
37
|
}
|
|
38
|
+
type GpuType = "nvidia" | "amd" | "intel" | "mac" | "cpu";
|
|
39
|
+
|
|
40
|
+
// Cache para não termos que detectar a GPU toda vez que formos comprimir um vídeo
|
|
41
|
+
let cachedGpuType: GpuType | null = null;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Detecta a GPU instalada na máquina rodando comandos nativos do SO.
|
|
45
|
+
*/
|
|
46
|
+
async function detectGPU(): Promise<GpuType> {
|
|
47
|
+
if (cachedGpuType) return cachedGpuType; // Retorna do cache se já sabemos
|
|
48
|
+
|
|
49
|
+
const platform = os.platform();
|
|
36
50
|
|
|
37
|
-
async function getBestEncoder(): Promise<string> {
|
|
38
51
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
// Se for Mac, assume VideoToolbox (Aceleração nativa da Apple)
|
|
53
|
+
if (platform === "darwin") {
|
|
54
|
+
cachedGpuType = "mac";
|
|
55
|
+
return cachedGpuType;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
let output = "";
|
|
59
|
+
|
|
60
|
+
// Se for Windows, usa o WMIC para listar as placas de vídeo
|
|
61
|
+
if (platform === "win32") {
|
|
62
|
+
const stdout = await execAsync(
|
|
63
|
+
"wmic path win32_VideoController get name",
|
|
64
|
+
);
|
|
65
|
+
output = stdout.toLowerCase();
|
|
66
|
+
}
|
|
67
|
+
// Se for Linux, usa o lspci para listar os hardwares PCI
|
|
68
|
+
else if (platform === "linux") {
|
|
69
|
+
const stdout = await execAsync("lspci");
|
|
70
|
+
output = stdout.toLowerCase();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Analisa a saída dos comandos para descobrir a marca
|
|
74
|
+
if (output.includes("nvidia")) {
|
|
75
|
+
cachedGpuType = "nvidia";
|
|
76
|
+
} else if (output.includes("amd") || output.includes("radeon")) {
|
|
77
|
+
cachedGpuType = "amd";
|
|
78
|
+
} else if (output.includes("intel")) {
|
|
79
|
+
cachedGpuType = "intel";
|
|
80
|
+
} else {
|
|
81
|
+
cachedGpuType = "cpu"; // Fallback se não identificar nada
|
|
82
|
+
}
|
|
83
|
+
} catch (error) {
|
|
84
|
+
if (error instanceof Error)
|
|
85
|
+
console.warn(
|
|
86
|
+
"⚠️ Aviso: Falha ao detectar GPU. Usando CPU por segurança.",
|
|
87
|
+
error.message,
|
|
88
|
+
);
|
|
89
|
+
cachedGpuType = "cpu";
|
|
55
90
|
}
|
|
91
|
+
|
|
92
|
+
return cachedGpuType;
|
|
56
93
|
}
|
|
57
94
|
|
|
58
95
|
export async function ffmpeg_video_compress(
|
|
@@ -61,25 +98,109 @@ export async function ffmpeg_video_compress(
|
|
|
61
98
|
resolution: Resolution = "480p",
|
|
62
99
|
forceResolution?: boolean,
|
|
63
100
|
) {
|
|
101
|
+
// Exemplo de mapeamento (ajuste para bater com o seu código original)
|
|
102
|
+
const resolutionMapping: { [key in Resolution]: { w: number; h: number } } = {
|
|
103
|
+
"4320p": { w: 7680, h: 4320 }, // 8K
|
|
104
|
+
"2160p": { w: 3840, h: 2160 }, // 4K
|
|
105
|
+
"1440p": { w: 2560, h: 1440 }, // Quad HD
|
|
106
|
+
"1080p": { w: 1920, h: 1080 }, // Full HD
|
|
107
|
+
"720p": { w: 1280, h: 720 }, // HD
|
|
108
|
+
"480p": { w: 854, h: 480 }, // SD (WVGA)
|
|
109
|
+
"360p": { w: 640, h: 360 }, // nHD
|
|
110
|
+
"240p": { w: 426, h: 240 }, // WQVGA
|
|
111
|
+
};
|
|
112
|
+
|
|
64
113
|
const { w, h } = resolutionMapping[resolution];
|
|
65
|
-
const encoder = await getBestEncoder();
|
|
66
114
|
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
115
|
+
// 1. Detecta a GPU automaticamente
|
|
116
|
+
const gpu = await detectGPU();
|
|
117
|
+
|
|
118
|
+
// 2. Verifica se é Linux para usar a estratégia correta
|
|
119
|
+
const isLinux = os.platform() === "linux";
|
|
120
|
+
|
|
121
|
+
// Mapeia os Encoders. Nota: AMD e Intel no Linux usam VA-API
|
|
122
|
+
const encoders = {
|
|
123
|
+
nvidia: "-c:v h264_nvenc -preset p4",
|
|
124
|
+
amd: isLinux ? "-c:v h264_vaapi" : "-c:v h264_amf",
|
|
125
|
+
intel: isLinux ? "-c:v h264_vaapi" : "-c:v h264_qsv",
|
|
126
|
+
mac: "-c:v h264_videotoolbox",
|
|
127
|
+
cpu: "-c:v libx264 -preset fast",
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const vcodec = encoders[gpu] || encoders.cpu;
|
|
131
|
+
|
|
132
|
+
// 3. Configura a aceleração e os filtros
|
|
133
|
+
let hwaccel = gpu === "cpu" ? "" : "-hwaccel auto";
|
|
134
|
+
let videoFilter = "";
|
|
135
|
+
|
|
136
|
+
// Lógica específica para o VA-API (AMD/Intel no Linux)
|
|
137
|
+
if (isLinux && (gpu === "amd" || gpu === "intel")) {
|
|
138
|
+
// Aponta diretamente para a placa de vídeo no Linux
|
|
139
|
+
hwaccel = "-vaapi_device /dev/dri/renderD128";
|
|
140
|
+
|
|
141
|
+
// O VA-API precisa que o formato seja nv12 e faça o upload para a GPU
|
|
142
|
+
videoFilter = forceResolution
|
|
143
|
+
? `-vf "scale=${w}:${h},format=nv12,hwupload"`
|
|
144
|
+
: `-vf "scale=-1:${h},format=nv12,hwupload"`;
|
|
145
|
+
} else {
|
|
146
|
+
// Lógica padrão para Windows, Mac e NVIDIA
|
|
147
|
+
videoFilter = forceResolution ? `-s ${w}x${h}` : `-filter:v scale=-1:${h}`;
|
|
72
148
|
}
|
|
73
149
|
|
|
74
|
-
|
|
75
|
-
|
|
150
|
+
// 4. Monta e executa o comando FFmpeg
|
|
151
|
+
const command = `ffmpeg ${hwaccel} -i "${input}" ${videoFilter} ${vcodec} -acodec copy -y "${output}"`;
|
|
76
152
|
|
|
77
|
-
console.log("
|
|
153
|
+
console.log("Converting using: ", vcodec);
|
|
78
154
|
|
|
79
|
-
return execAsync(
|
|
80
|
-
`ffmpeg ${vaapiOpts} -i "${input}" -vf "${filter}" -c:v ${encoder} -pix_fmt yuv420p -acodec copy -y "${output}"`,
|
|
81
|
-
);
|
|
155
|
+
return execAsync(command);
|
|
82
156
|
}
|
|
157
|
+
|
|
158
|
+
// async function getBestEncoder(): Promise<string> {
|
|
159
|
+
// try {
|
|
160
|
+
// const { stdout } = (await execAsync("ffmpeg -encoders")) as {
|
|
161
|
+
// stdout: string;
|
|
162
|
+
// };
|
|
163
|
+
|
|
164
|
+
// // Prioridade para AMD (Windows: amf | Linux: vaapi)
|
|
165
|
+
// if (stdout.includes("h264_amf")) return "h264_amf";
|
|
166
|
+
// if (stdout.includes("h264_vaapi")) return "h264_vaapi";
|
|
167
|
+
|
|
168
|
+
// // Outros hardwares
|
|
169
|
+
// if (stdout.includes("h264_nvenc")) return "h264_nvenc";
|
|
170
|
+
// if (stdout.includes("h264_qsv")) return "h264_qsv";
|
|
171
|
+
// if (stdout.includes("h264_videotoolbox")) return "h264_videotoolbox";
|
|
172
|
+
|
|
173
|
+
// return "libx264"; // Fallback
|
|
174
|
+
// } catch {
|
|
175
|
+
// return "libx264";
|
|
176
|
+
// }
|
|
177
|
+
// }
|
|
178
|
+
|
|
179
|
+
// export async function ffmpeg_video_compress(
|
|
180
|
+
// input: string,
|
|
181
|
+
// output: string,
|
|
182
|
+
// resolution: Resolution = "480p",
|
|
183
|
+
// forceResolution?: boolean,
|
|
184
|
+
// ) {
|
|
185
|
+
// const { w, h } = resolutionMapping[resolution];
|
|
186
|
+
// const encoder = await getBestEncoder();
|
|
187
|
+
|
|
188
|
+
// // No VA-API (Linux), o redimensionamento deve ser feito via hardware para máxima performance
|
|
189
|
+
// let filter = forceResolution ? `scale=${w}:${h}` : `scale=-1:${h}`;
|
|
190
|
+
// if (encoder === "h264_vaapi") {
|
|
191
|
+
// // Adiciona upload para hardware se usar vaapi
|
|
192
|
+
// filter = `format=nv12,hwupload,scale_vaapi=w=${forceResolution ? w : -1}:h=${h}`;
|
|
193
|
+
// }
|
|
194
|
+
|
|
195
|
+
// const vaapiOpts =
|
|
196
|
+
// encoder === "h264_vaapi" ? "-vaapi_device /dev/dri/renderD128" : "";
|
|
197
|
+
|
|
198
|
+
// console.log("Compressing video using: ", encoder);
|
|
199
|
+
|
|
200
|
+
// return execAsync(
|
|
201
|
+
// `ffmpeg ${vaapiOpts} -i "${input}" -vf "${filter}" -c:v ${encoder} -pix_fmt yuv420p -acodec copy -y "${output}"`,
|
|
202
|
+
// );
|
|
203
|
+
// }
|
|
83
204
|
// export async function ffmpeg_video_compress(
|
|
84
205
|
// input: string,
|
|
85
206
|
// output: string,
|