mediatools is a single-binary Go CLI that wraps common ImageMagick and ffmpeg operations behind a consistent, discoverable command tree.
It is deliberately opinionated about output: images are always written as .jpg, videos as .mp4. There is no output-format flag, which is what lets every command share one set of flags and one quality scale.
- Go 1.26+
- ImageMagick 7+ (
magickbinary on$PATH) - ffmpeg (
ffmpegandffprobebinaries on$PATH)
Install dependencies on macOS:
brew install imagemagick ffmpegmake build| Command | Output |
|---|---|
mediatools convert image <file(s)> |
<name>.jpg |
mediatools convert video <file(s)> |
<name>.mp4 |
mediatools resize image <file(s)> <width> |
<name>_<width>x.jpg |
mediatools resize video <file(s)> <width> |
<name>_<width>x.mp4 |
mediatools inspect image <file(s)> |
metadata on stdout |
mediatools inspect video <file(s)> |
metadata on stdout |
mediatools convert image input.png
mediatools convert image *.webp --quality 90
mediatools convert video input.mov
mediatools convert video *.mkv --quality 90
mediatools inspect image input.jpg
mediatools inspect video input.mp4
mediatools resize image input.png 800
mediatools resize image *.png 800 --quality 90
mediatools resize video input.mkv 1280
mediatools resize video input.mp4 1280 --quality 90Multiple files come from your shell's globbing; mediatools does not expand patterns itself.
Resize caps the width and preserves the aspect ratio. It never upscales a file that is already narrower than the target.
One input always produces one output. A multi-frame image — an animated GIF, a multi-page PDF, a layered TIFF or PSD — is read as its first frame, and inspect describes that same frame, so what you see is what a conversion would write.
convert and resize share the same flags, accepted either before or after the subcommand:
-o, --out-dir <dir>: Output directory (default: same as input).-f, --force: Overwrite existing output files (default: skip).--md5: Use the MD5 hash of the input's contents as the output filename.-q, --quality <1-100>: Output quality, higher is better (default: 95).--dry-run: Print what would happen without writing anything.
inspect is read-only and takes no flags.
--quality means the same thing on both sides: for images it is the JPEG quality, for videos it is mapped onto x264's CRF scale (which runs in the opposite direction) so the same number means comparably good output either way.
mediatools plans every output path before running anything, and refuses the whole batch if the plan would destroy data — either because two inputs map to the same output, or because an output would land on one of the inputs:
$ mediatools convert image photo.png photo.jpg
Error: unsafe output paths detected, aborting before any files were processed:
photo.jpg <- photo.png, photo.jpgPaths are compared as the filesystem sees them, so on macOS and Windows Photo.JPG and photo.jpg are correctly treated as one file.
An input that is already in the target format is skipped rather than re-encoded:
$ mediatools convert image photo.jpg
⊘ skipped photo.jpg: output is the input file (already .jpg)Passing --force or an explicit --quality says you want that re-encode, and since it cannot be done without destroying the original, the batch refuses and tells you where to write instead. Use --out-dir or --md5:
$ mediatools convert image photo.jpg -q 70
Error: unsafe output paths detected, aborting before any files were processed:
photo.jpg would overwrite the input file (use --out-dir or --md5 to write elsewhere)
$ mediatools convert image photo.jpg -q 70 -o smaller/
✓ converted photo.jpg -> smaller/photo.jpg--force only permits overwriting outputs; it never authorises destroying an input.
Every encode is written to a temporary file next to its destination and renamed into place only once the tool has succeeded, so a run that fails part-way leaves the destination exactly as it was. That includes --force: the file you were replacing survives intact until there is a complete one to replace it with.
There is no time limit on an encode — a long video legitimately takes hours. Ctrl-C cancels the running tool, leaves no partial file behind, and reports the files it never got to.
make checkTests generate real image and video fixtures with magick and ffmpeg, and skip themselves when those binaries are missing.