// convert.js const fs = require("fs"); const path = require("path"); const { spawn, execSync } = require("child_process"); // Ensure output folder exists if (!fs.existsSync("output")) fs.mkdirSync("output"); // Step 1: Search for files const inputDir = "inputs"; const files = fs.readdirSync(inputDir); const audioFile = files.find(f => f.toLowerCase().endsWith(".wav")); const imageFile = files.find(f => f.toLowerCase().match(/\.(jpg|jpeg|svg|png)$/)); if (!audioFile || !imageFile) { console.error("❌ Missing .wav and/or .jpg/.svg file in inputs/"); process.exit(1); } const audioPath = path.join(inputDir, audioFile); const imagePath = path.join(inputDir, imageFile); const outputName = `output-${Date.now() + Math.random() * 1000}.mp4`; const outputPath = path.join("output", outputName); // Step 2: Get audio duration let durationSec = 0; try { const durationStr = execSync( `ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "${audioPath}"` ).toString().trim(); durationSec = parseFloat(durationStr); console.log(`🎧 Audio duration: ${durationSec.toFixed(2)} sec`); } catch (err) { console.error("❌ Could not determine audio duration"); process.exit(1); } // Step 3: Convert using ffmpeg const args = [ "-loop", "1", "-i", imagePath, "-i", audioPath, "-c:v", "libx264", "-preset", "ultrafast", "-tune", "stillimage", "-crf", "23", "-c:a", "aac", "-shortest", "-pix_fmt", "yuv420p", "-movflags", "+faststart", outputPath ]; console.log(`🚀 Starting conversion: ${path.basename(imageFile)} + ${path.basename(audioFile)} → ${outputName}`); const ffmpeg = spawn("ffmpeg", args); ffmpeg.stderr.on("data", (data) => { const line = data.toString().trim(); const timeMatch = line.match(/time=(\d+):(\d+):([\d.]+)/); if (timeMatch) { const [, h, m, s] = timeMatch; const timeSec = parseInt(h) * 3600 + parseInt(m) * 60 + parseFloat(s); const percent = Math.min(100, ((timeSec / durationSec) * 100).toFixed(1)); console.log(`${line} | 📊 ${percent}%`); } else { console.log(line); } }); ffmpeg.on("exit", (code) => { if (code !== 0) { console.error(`❌ FFmpeg exited with code ${code}`); return; } console.log(`✅ Conversion complete! Saved to: ${outputPath}`); });