108 lines
3.2 KiB
JavaScript
108 lines
3.2 KiB
JavaScript
import fs from "fs";
|
|
import path from "path";
|
|
import color from "picocolors";
|
|
import { convert } from "./converters.js";
|
|
import { runInteractive, showSummary } from "./ui.js";
|
|
import { stopKeypress, waitForKey } from "../../keyboard.js";
|
|
import { record } from "../../stats.js";
|
|
|
|
const FORMAT_EXT = {
|
|
collada: ".dae",stp: ".stp", obj: ".obj", objnomtl: ".obj",
|
|
stl: ".stl", stlb: ".stl", ply: ".ply", plyb: ".ply", "3ds": ".3ds",
|
|
gltf2: ".gltf", glb2: ".glb",
|
|
assbin: ".assbin", assxml: ".assxml", x3d: ".x3d",
|
|
fbx: ".fbx", fbxa: ".fbx", "3mf": ".3mf", pbrt: ".pbrt", assjson: ".json"
|
|
};
|
|
|
|
function getOutputExt(format) {
|
|
return FORMAT_EXT[format] || "." + format;
|
|
}
|
|
|
|
async function processFile(file, config) {
|
|
const cwd = process.cwd();
|
|
const { dir, name } = path.parse(file);
|
|
const outputExt = getOutputExt(config.outputFormat);
|
|
const outputFile = path.join(dir || "", `${name}${outputExt}`);
|
|
const absolutePath = path.join(cwd, file);
|
|
|
|
if (!fs.existsSync(absolutePath)) {
|
|
return { ok: false, file, reason: "文件不存在" };
|
|
}
|
|
|
|
await convert(file, outputFile, config.outputFormat, cwd);
|
|
return { ok: true, file, output: outputFile };
|
|
}
|
|
|
|
async function waitForEsc() {
|
|
return waitForKey(color.dim("按 Esc 返回"), key => key?.name === "escape" || (key?.ctrl && key?.name === "c"));
|
|
}
|
|
|
|
async function run() {
|
|
const result = await runInteractive();
|
|
if (!result) return "back";
|
|
|
|
const { results } = result;
|
|
const config = {
|
|
files: results[0] || [],
|
|
outputFormat: results[1] || "glb2"
|
|
};
|
|
|
|
stopKeypress();
|
|
showSummary([
|
|
"源文件: " + (config.files.length ? config.files.join(", ") : "未选择"),
|
|
"目标格式: " + config.outputFormat.toUpperCase()
|
|
]);
|
|
|
|
if (!config.files.length) {
|
|
console.log(color.yellow("未选择任何模型文件"));
|
|
await waitForEsc();
|
|
return "back";
|
|
}
|
|
|
|
const total = config.files.length;
|
|
let success = 0;
|
|
const failed = [];
|
|
|
|
console.log(color.cyan(`开始转换 ${total} 个文件...\n`));
|
|
|
|
for (let i = 0; i < config.files.length; i++) {
|
|
const file = config.files[i];
|
|
const progress = `[${i + 1}/${total}]`;
|
|
console.log(color.dim(`${progress} 处理中: ${file}`));
|
|
|
|
try {
|
|
const result = await processFile(file, config);
|
|
if (result.ok) {
|
|
success++;
|
|
record("convert_format", config.outputFormat);
|
|
console.log(color.green(`${progress} ✓ ${file} → ${path.basename(result.output)}`));
|
|
} else {
|
|
failed.push({ file, reason: result.reason });
|
|
console.log(color.yellow(`${progress} ⊘ 跳过: ${file} (${result.reason})`));
|
|
}
|
|
} catch (err) {
|
|
failed.push({ file, reason: err?.message || String(err) });
|
|
console.log(color.red(`${progress} ✖ 失败: ${file}`));
|
|
console.log(color.dim(" " + String(err?.message || err)));
|
|
}
|
|
}
|
|
|
|
console.log("\n" + color.bgGreen(color.black(" 转换完成 ")));
|
|
if (success) {
|
|
console.log(color.green(`成功: ${success} 个`));
|
|
}
|
|
if (failed.length) {
|
|
console.log(color.yellow(`失败: ${failed.length} 个`));
|
|
}
|
|
|
|
await waitForEsc();
|
|
return "back";
|
|
}
|
|
|
|
export default {
|
|
id: "convert",
|
|
name: "格式转换",
|
|
desc: "支持多种模型格式转换",
|
|
run,
|
|
};
|