Converting one track is a one-line command. Converting two hundred consistently is a different problem โ and the part that goes wrong is never the encoding.
If you have a catalogue of audio you want on YouTube, Reels, TikTok and Shorts, you need a video per track, usually in two shapes, all looking like they came from the same place. Doing that by hand is where people give up. Here is how to script it properly.
The naive version works and is worth starting from:
for f in audio/*.mp3; do
name=$(basename "$f" .mp3)
ffmpeg -loop 1 -i cover.jpg -i "$f" \
-c:v libx264 -tune stillimage -pix_fmt yuv420p \
-c:a aac -b:a 320k -shortest -movflags +faststart \
"out/${name}.mp4"
done
Run that overnight on a hundred tracks and you will have a hundred videos. You will also discover the five things below, which is why this guide exists.
Add ten new tracks and the loop redoes all hundred. Skip files that already have output:
[ -f "out/${name}.mp4" ] && continue
A corrupt MP3 at track 40 stops everything, and you find out in the morning. Let each track fail on its own and keep going, and log what failed:
if ! ffmpeg -v error -i "$f" ... "out/${name}.mp4"; then
echo "FAILED: $f" >> failures.log
continue
fi
Spaces, apostrophes, em-dashes and non-ASCII characters in track titles will each break something downstream โ an upload form, a CSV, a scheduler. Decide on a slug format early and stick to it:
slug=$(echo "$name" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^a-z0-9]+/-/g; s/^-|-$//g')
YouTube and Facebook want 16:9. Reels, TikTok, Shorts and Pinterest want 9:16. The same file cannot serve both โ a horizontal video on Reels gets letterboxed into a strip and performs badly. Render both from the same source in the same pass, into separate folders, so they stay in sync.
The worst failure, because it looks like success. A wrong -shortest interaction or a malformed input can produce a valid MP4 that stops after ten seconds. Verify every output before you trust it:
ffprobe -v error -show_entries format=duration \
-of csv=p=0 "out/${name}.mp4"
Compare that number to the source audio's duration. If it is short, the render failed regardless of what the exit code said.
Check every file before uploading. Distribution platforms reject undersized or truncated files, and by then you have already spent the time. A verification pass over the whole output folder costs seconds and saves a rejected batch.
Consistency is what makes a catalogue look professional rather than assembled. In practice that means, for every track:
loudnorm so one track is not jarringly louder than the next.-af loudnorm=I=-14:TP=-1.5:LRA=11
-14 LUFS is what YouTube, Spotify and most platforms normalise to anyway; matching it means they leave your audio alone.
| Approach | 100 tracks, both ratios |
|---|---|
| By hand in an editor | Days |
| A basic loop, then fixing the failures | An overnight run plus a day of cleanup |
| A verified pipeline with resume | One overnight run, walk away |
Social Video Factory takes a folder of audio and background clips and produces finished branded videos in both aspect ratios โ logo, QR code, titles from filenames, loudness matched, every output verified. A downloadable Claude skill, one purchase.
See how it works