const express = require("express"); const multer = require("multer"); const { spawn } = require("child_process"); const fs = require("fs"); const app = express(); const upload = multer({ dest: "uploads/" }); app.post("/convert", upload.fields([{ name: "audio" }, { name: "image" }]), (req, res) => { if (!req.files || !req.files.audio || !req.files.image) { console.error("❌ Missing file(s) in request"); return res.status(400).send("Missing audio or image file."); } const audioPath = req.files.audio[0].path; const imagePath = req.files.image[0].path; const output = `output-${Date.now()}.mp4`; const args = [ "-loop", "1", "-i", imagePath, "-i", audioPath, "-c:v", "libx264", "-preset", "fast", "-tune", "stillimage", "-crf", "18", "-c:a", "aac", "-shortest", "-pix_fmt", "yuv420p", output ]; console.log(`🚀 Starting FFmpeg conversion: ${output}`); const ffmpeg = spawn("ffmpeg", args); let lastLog = Date.now(); ffmpeg.stderr.on("data", (data) => { const now = Date.now(); const text = data.toString(); // Log a progress update every 3 seconds max if (text.includes("frame=") && now - lastLog > 3000) { console.log(`[FFmpeg Progress] ${text.trim()}`); lastLog = now; } // If you want verbose output uncomment this: // console.log(`[FFmpeg Raw] ${text.trim()}`); }); ffmpeg.on("exit", (code) => { if (code !== 0) { console.error(`❌ FFmpeg failed with code ${code}`); res.status(500).send("Conversion failed"); } else { console.log("✅ FFmpeg finished successfully. Sending file..."); res.download(output, () => { fs.unlinkSync(audioPath); fs.unlinkSync(imagePath); fs.unlinkSync(output); }); } }); }); app.get("/", (req, res) => { res.send("🎧 FileConvert API is up."); }); app.listen(3000, () => console.log("✅ FileConvert API running on http://0.0.0.0:3000"));