Munin is one of a pair of ravens that fly all over the world, Midgard, and bring information to the god Odin.
Munin is a static "api" image gallery generator. Munin will take a folder structure and turn it into a linked json api with responsive images. The idea is that the input folder structure will act as the "state" or "source of truth" and will be compared to the currently generated gallery and a diff will be generated. The first run will create a new gallery and the consecutive runs will only encode thumbnails and json files for new images/folders.
Munin does not come with a frontend, and encourages you to "build your own" or pair it with Hugin.
Munin uses libvips (via swift-vips), libexif and libiptcdata to read, resize, write images and their metadata. Munin runs on both macOS and Linux.
- Organise your album as folders
- Generate albums fast!
- Generate only changed albums/images
- Encode with all available cores via Swift structured concurrency (
TaskGroup+AsyncSemaphore) - Reuse original images by symlinking
- Generate multiple sizes for responsive usage
- Structure EXIF and other metadata as JSON
- Structure image by keywords
- Structure image by people
- Extract location data from images
- Statistics
Help:
$ munin --help
Usage:
$ munin
Options:
--config [default: munin.json] - JSON based configuration file for munin
--dry [default: false] - Dry-run, do not write gallery
--json [default: false] - Write only JSON files, no images, useful for updating data with new munin features
Munin is configured with a simple JSON file:
{
"name": "root",
"resolutions": [1600, 1200, 992, 768, 576, 340, 220, 180],
"jpegCompression": 0.75,
"sourceFolder": "album",
"targetFolder": "content",
"fileExtensions": ["jpg", "jpeg", "JPG", "JPEG"],
"logLevel": "info",
"diff": true,
"people": ["Kristoffer Andreas Dalby"]
}Every field has a sensible default (see MuninConfiguration in
Sources/MuninKit/Configuration.swift); the only fields you likely need to
set are sourceFolder and targetFolder.
Configuration values can also be overridden with MUNIN_* environment
variables (e.g. MUNIN_SOURCE_FOLDER, MUNIN_CONCURRENCY) or with
--key value command-line arguments.
-
Swift 6.3.1 (matches CI) — install via swiftly or the Swift.org tarball.
nixpkgs' Swift lags upstream and is not used by this project; seeflake.nixfor the dev shell that provides just the C library deps. -
Ubuntu 24.04 (primary CI target) or macOS 14+
-
System C libraries:
Ubuntu / Debian:
sudo apt install libvips-dev libexif-dev libiptcdata0-dev libgd-dev pkg-config
macOS (Homebrew):
brew install vips libexif libiptcdata pkg-config
Nix (via the bundled flake):
nix develop
The devShell provides every C dependency and the developer tools (
swift-format,sourcekit-lsp). It does not provide Swift — install that separately via swiftly or the Swift.org tarball.
git clone https://github.com/kradalby/munin
cd munin
make install # builds release, copies binary to ~/bin/muninOr, for a static-stdlib build (~73MB, no Swift runtime dependencies):
make build-staticAssuming Swift and the system libraries from the Requirements section above are in place:
make build # debug build
make test # run test suite (requires libvips on your system)
make run # build + run the binary
make lint # swiftlint
make fmt # swiftlint --fix + swift-formatFollow SwiftLint and
swift-format defaults. Both
tools are available in the nix devShell; make fmt runs both.
Sources/MuninKit— library: gallery model, read/write pipelines, config. The code lives across small, focused files split by concern (Album+Read.swift,Album+Write.swift,Photo+EXIFinlined inPhoto+Read.swift, etc.).Sources/Munin—AsyncParsableCommandCLI entrypoint.Tests/MuninKitTests— XCTest-based; each test uses a unique temp directory and shares a single VIPS initialisation viaVIPSBootstrap.startForTesting().
Concurrency is based on async/await + TaskGroup; there are no
DispatchQueues or DispatchGroups in the source. AsyncSemaphore
bounds concurrent VIPS/EXIF reads and image writes per-gallery based on
the concurrency config value.