Files
jenna-tools/xmerge.ts
bipproduction 822b68c10f tambahannya
2025-12-07 09:00:54 +08:00

106 lines
3.2 KiB
TypeScript

import * as fs from "node:fs/promises";
import { constants as fsConstants } from "node:fs";
import { execFile } from "node:child_process";
import { promisify } from "node:util";
// --- Konfigurasi ---
const TEMP_DIR = "./temp-tts";
const LIST_FILE_NAME = "wav-list.txt";
const exec = promisify(execFile);
/**
* Menggabungkan daftar file WAV menggunakan ffmpeg concat demuxer.
* @param relativeFileNames Array NAMA file WAV yang berada di TEMP_DIR (misal: ['a.wav', 'b.wav']).
* @param output Path lengkap untuk menyimpan file WAV hasil gabungan.
*/
async function merge(relativeFileNames: string[], output: string): Promise<void> {
if (relativeFileNames.length === 0) {
console.warn("⚠️ Tidak ada file untuk digabungkan. Melewati proses.");
return;
}
console.log(`\n🔧 Menggabungkan ${relativeFileNames.length} file WAV menggunakan ffmpeg...`);
const listFilePath = `${TEMP_DIR}/${LIST_FILE_NAME}`;
// Perbaikan: Tulis nama file saja tanpa prefix TEMP_DIR agar path valid saat concat
const listContent = relativeFileNames
.map((f) => `file '${f.replace(/'/g, "'\\''")}'`)
.join("\n");
try {
await fs.writeFile(listFilePath, listContent, "utf-8");
} catch (err) {
console.error(`❌ Gagal menulis file list ${listFilePath}:`, err);
throw new Error(`Gagal menyiapkan file list untuk ffmpeg.`);
}
try {
await exec("ffmpeg", [
"-f", "concat",
"-safe", "0",
"-i", listFilePath,
"-c", "copy", // Menggabungkan tanpa re-encoding
output,
]);
console.log(`✅ File berhasil digabungkan dan disimpan di: ${output}\n`);
} catch (err) {
console.error("❌ Kesalahan saat menjalankan ffmpeg:", err);
if (err instanceof Error && 'stdout' in err) {
console.error('ffmpeg stderr output:', (err as any).stderr);
}
throw new Error(`Penggabungan ffmpeg gagal.`);
} finally {
try {
await fs.unlink(listFilePath);
} catch {
console.warn(`⚠️ Gagal menghapus file list ${listFilePath}.`);
}
}
}
// --- Fungsi Utama ---
export async function merge_wav() {
await fs.mkdir(`./output`, { recursive: true }).catch(() => {});
const output = `./output/merged.wav`;
try {
await fs.access(output, fsConstants.F_OK);
await fs.unlink(output);
} catch (error) {}
try {
// Cek apakah direktori TEMP_DIR ada
await fs.access(TEMP_DIR, fsConstants.F_OK);
} catch {
console.error(`❌ Direktori sementara ${TEMP_DIR} tidak ditemukan. Pastikan sudah membuat folder tersebut.`);
return;
}
// Baca daftar file WAV dalam TEMP_DIR
const allFiles = await fs.readdir(TEMP_DIR);
const wavFileNames = allFiles
.filter((f) => f.endsWith(".wav"))
.sort((a, b) => {
const aNum = parseInt(a?.split("_")[2] || "0");
const bNum = parseInt(b?.split("_")[2] || "0");
return aNum - bNum;
});
try {
await merge(wavFileNames, output);
} catch (err) {
console.error("⛔ Proses penggabungan utama gagal.");
process.exit(1);
}
}
if (import.meta.main) {
merge_wav();
}