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
| const fs = require("fs"); const path = require("path"); const { spawn } = require("child_process"); const trash = require("trash");
const inputDir = process.argv[2];
if (!inputDir || !fs.existsSync(inputDir)) { console.error("❌ 请传入有效的目录路径"); process.exit(1); }
const VIDEO_EXTS = [".mp4", ".mov", ".mkv", ".avi", ".webm", ".m4v"];
const distDir = path.join(inputDir, "dist"); if (!fs.existsSync(distDir)) { fs.mkdirSync(distDir); }
async function encodeVideo(filePath, indexStr) { const fileName = path.basename(filePath); const baseName = path.parse(fileName).name; const outputPath = path.join(distDir, `${baseName}.mkv`);
return new Promise((resolve, reject) => { console.log( `🎬 正在编码 ${indexStr} :${fileName} → ${path.relative(inputDir, outputPath)}` );
const ffmpeg = spawn( "ffmpeg", [ "-i", filePath, "-vf", "colorspace=iall=bt709:all=bt709:fast=1", "-c:v", "libsvtav1", "-crf", "30", "-preset", "8", "-c:a", "copy", outputPath, ], { stdio: "inherit" } );
ffmpeg.on("close", async (code) => { if (code === 0) { console.log(`✅ ${indexStr} 编码完成:${fileName}`); try { await trash([filePath]); console.log(`🗑️ 已将原始文件移至废纸篓:${fileName}`); } catch (err) { console.error(`⚠️ 移动到废纸篓失败:${err.message}`); } resolve(); } else { console.error(`❌ 编码失败:${fileName}`); reject(new Error(`FFmpeg 退出码 ${code}`)); } }); }); }
(async () => { const files = fs .readdirSync(inputDir) .filter((file) => VIDEO_EXTS.includes(path.extname(file).toLowerCase())) .map((file) => path.join(inputDir, file));
if (files.length === 0) { console.log("📭 没有找到视频文件"); return; }
for (const [index, file] of files.entries()) { try { const indexStr = `${index}/${files.length}` await encodeVideo(file, indexStr); } catch (err) { console.error(`❌ 出错:${err.message}`); } }
console.log("🏁 所有文件处理完毕"); })();
|