Batch transcode a folder of videos with Handbrake's CLI

I've used Handbrake for years, to transcode practically any video file—including ripped DVDs and Blu-Rays—so I can watch the videos on practically any device. It's especially helpful for .mkv files, which can have a hodgepodge of video formats inside, and are notoriously difficult to play back, especially on older or more locked down playback devices.

But Handbrake's achilles heel, as a GUI-first application, is in a lack of easy batch operation. You can queue videos up one at a time, which is nice, but more recently, as I've ripped more TV seasons onto my NAS, I've wanted to transcode 5, 10, or 20 files at a time.

Enter HandBrakeCLI. Assuming you're on a Mac and installed Handbrake already (e.g. with brew install --cask handbrake), download HandBrakeCLI, mount the downloaded disk image, and copy the executable into a system path:

sudo cp /Volumes/HandBrakeCLI-1.5.1/HandBrakeCLI /usr/local/bin/

Then you can use it to loop over an entire directory—even recursively—and transcode all the video files within.

Here's a very tiny bash script I use to do just that, converting any file that ends in .mkv to an MP4 using the General/HQ 1080p30 Surround preset:

Let that run for a while, and you can transcode an entire TV series in one go.

Comments

I use Handbrake, but I've never used the CLI. I'll need to try it.
I routinely transcode multiple files through the GUI, though. I put all the files in a single directory (typically where they'd be anyway for a single season of a show). Then drag the directory and drop it on the Handbrake GUI. It will "load" all of the files.
Then, click on the "Down Arrow" on the right side of "Add to Queue" and select "Add All". The next button changes to "Start Queue". Clicking that will start the transcode process for all of the files.
It won't go into subdirectories, but you can drag those in and add them to the queue just like the first directory.

Thanks for the script for this, I'd honestly not come across handbrake at all until now. My gut instinct would always be to use ffmpeg for something like this, especially if you want to script it. Is there any reason you chose handbrake instead of ffmpeg here?

Handbrake has a much easier method of setting up presets, though directly scripting ffmpeg would be a perfectly valid choice, especially if you're more familiar with the CLI flags. In this case (for movie transcoding, I'm more familiar with Handbrake's GUI and like the confirmation it gives me when I'm setting up or tweaking a new preset.

Fossil here. What if you wanted to similarly rip/save a bunch of music CDs to a quality electronic format ?

Big fan of the videos. Not that I'd tell you to stop using your NAS and install UNRAID, but they seem to have made transcoding easy for noobs like me, or people who can fiddle, but don't want to. Tdarr and Unmanic are both available as docker images.

Again, big fan. Started running FreshRSS on my NAS, and came across your blog. Keep it up, you are doing God's work.

For this sort of scripting I highly recommend checking out FFMPEG. Its what Handbrake uses under the hood and has an excellent Command line interface. I imagine the presets will even match up.

Thank you for this script, it's been incredible. For anyone who may be interested, I made some tweaks because I wanted the transcoded .mp4 files to go to a different directory, then to remove the original .mkv. Keep in mind I have hard coded directories, so you would want to edit that or use the same directory structure.

#!/bin/bash
#
# This script requires HandBrakeCLI. On macOS, at least, you need to download
# and install it separately from Handbrake.
#
# See: https://handbrake.fr/downloads2.php

MKVDIR="$HOME/Movies/ripped/mkv"

    # Change the preset if you like (see options: "HandBrakeCLI --preset-list")
    # If you want to transcode ALL movie files, remove the -name option.
    find "$MKVDIR"/* -type f -name "*.mkv" -exec bash -c '
        MP4DIR="$HOME/Movies/ripped/mp4"
        MKVFILENAME="${1##*/}";
        MP4FILENAME="${MKVFILENAME%.mkv}.mp4";
        HandBrakeCLI -i "$1" -o "$MP4DIR/$MP4FILENAME" --preset="General/HQ 2160p60 4K HEVC Surround";
        rm "$1";
    ' __ {} \;

If all you're trying to do is batch-convert piles of MKVs into MP4 (i.e., so your Apple devices won't turn up their noses), then Handbrake is the wrong tool -- since you don't need to re-render the video itself. You just need to "stream-copy" it into an MP4 "container". A job that takes hours now becomes one that takes minutes or seconds.