diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-19 21:03:03 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-19 21:03:03 +0300 |
| commit | 2cdec0ccd3ec1fdcafdc4f12fb30c7d58c7632b8 (patch) | |
| tree | b273182a25d4cdb760d6eb6f31ebad012173178f /docs | |
| parent | 0213d6345866351b08b34a1991c2cc14a31f9349 (diff) | |
docs: split README into quick-start + reference pages under docs/
Trim README.md to a quick-start guide (install, init, generate, sync,
clean) with a main-flags table and feature-toggle summary, and move the
detailed reference material into focused pages under docs/:
installation, usage, configuration, generation, publishing, templates.
Correctness fixes carried over during the split:
- The 'Site generated ... with <URL>' source link lives in the page
header bar (header.tmpl), not the footer (footer.tmpl only renders
the tarball download). Fixed in docs and the SOURCE_URL code comment.
- --sync is a config-backed action and accepts --config PATH / reads
./shuriken.conf; the --config action list now includes it.
- --refresh-splash also re-copies the site favicon; documented.
- State the Bash 5.1 requirement (enforced by the script) in the docs.
- docs/stats-exif-audit.md: the EXIF cache moved to
metadata-cache.source.sh and the native-field parser extension was
implemented; add a status note and fix the stale module path.
bin/shuriken regenerated from the config.source.sh comment change.
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/configuration.md | 84 | ||||
| -rw-r--r-- | docs/generation.md | 115 | ||||
| -rw-r--r-- | docs/installation.md | 58 | ||||
| -rw-r--r-- | docs/publishing.md | 45 | ||||
| -rw-r--r-- | docs/stats-exif-audit.md | 14 | ||||
| -rw-r--r-- | docs/templates.md | 34 | ||||
| -rw-r--r-- | docs/usage.md | 105 |
7 files changed, 453 insertions, 2 deletions
diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000..07bc1e0 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,84 @@ +# Configuration + +The config file is a Bash file sourced by shuriken. `shuriken --init` creates +`./shuriken.conf` from the default config; edit it and override any of the +variables below. Command-line options (see [usage.md](usage.md)) override config +values for the current run. + +## Variables + +| Variable | Default | Description | +| --- | --- | --- | +| `TITLE` | `A simple Shuriken` | Album title. | +| `HEIGHT` | `1200` | Scaled photo height in pixels. Leave unset to keep original size. Optional positive integer. | +| `THUMBHEIGHT` | `300` | Thumbnail height in pixels. Positive integer. | +| `MAXPREVIEWS` | `40` | Maximum previews per page. Positive integer. | +| `IMAGE_JOBS` | `3` | Parallel jobs for image processing and HTML template rendering. Positive integer. | +| `IMAGEMAGICK_TIMEOUT` | `60` | Per-ImageMagick-command timeout in seconds. Positive integer. | +| `TAR_TIMEOUT` | `120` | Tarball creation timeout in seconds. Positive integer. | +| `SHUFFLE` | `no` | Randomly shuffle all previews. `yes`/`no`. | +| `SPLASH_PAGE` | `yes` | Generate a splash landing page at `index.html`. `yes`/`no`. | +| `STATS_PAGE` | `no` | Generate the EXIF stats site under `stats/`. `yes`/`no`. | +| `RANDOM_SEED` | _(unset)_ | Any non-empty value makes splash/background picks, animation classes, timestamps, and shuffle order repeatable. | +| `INCOMING_DIR` | `$(pwd)/incoming` | Directory containing source photos (full path). | +| `DIST_DIR` | `$(pwd)/dist` | Output directory (full path). | +| `TEMPLATE_DIR` | `/usr/share/shuriken/templates/default` | Template directory. Falls back to the source tree's `share/templates/default` when running from a checkout. | +| `FAVICON` | _(unset = bundled default)_ | Custom favicon, published as `favicon.ico`. Must be a readable file when set. | +| `SOURCE_URL` | `https://codeberg.org/snonux/shuriken.sh` | Project/source link shown in the page header bar. | +| `TARBALL_INCLUDE` | `yes` (in `--init` config) | Include a `.tar` of the incoming dir in the dist. `yes`/`no`. | +| `TARBALL_SUFFIX` | `.tar` | Suffix for the generated tarball. | +| `TAR_OPTS` | `(-c)` | Tar options as a Bash array (or whitespace-separated scalar). | +| `SYNC_DELETE` | `yes` | Pass `--delete` to rsync on `--sync`. `yes`/`no`. | +| `SYNC_DESTINATIONS` | `()` | Bash array of rsync destinations. See [publishing.md](publishing.md). | +| `ORIGINAL_BASEPATH` | _(unset)_ | Recorded in `shuriken.json` for debugging a published album. | + +> Note on `TARBALL_INCLUDE`: the bundled `shuriken.default.conf` sets it to +> `yes`, so a freshly `--init`'d config enables the tarball. The runtime default +> applied when a config file leaves it unset is `no`. + +## Supported source images + +Only regular files in `INCOMING_DIR` (top level, `maxdepth 1`) with supported +image extensions are processed as album images. Supported extensions are `jpg`, +`jpeg`, `png`, `webp`, and `gif`, matched case-insensitively. Other files, such +as `.txt` or `.md` notes, are ignored with a warning so generation can continue. + +## Validation + +`shuriken` validates the loaded config and command-line overrides before acting. +The checks (details in `src/lib/config.validate.source.sh`): + +* **Required values** are set: `TITLE`, `THUMBHEIGHT`, `MAXPREVIEWS`, + `IMAGE_JOBS`, `INCOMING_DIR`, `DIST_DIR`, `TEMPLATE_DIR`. +* **Positive integers**: `THUMBHEIGHT`, `MAXPREVIEWS`, `IMAGE_JOBS`, + `IMAGEMAGICK_TIMEOUT`, `TAR_TIMEOUT`; `HEIGHT` is an optional positive integer. +* **`yes`/`no` settings**: `SHUFFLE`, `SPLASH_PAGE`, `STATS_PAGE`, + `TARBALL_INCLUDE`, `SYNC_DELETE` (where applicable). +* **Readable input**: `INCOMING_DIR` must be a readable directory; `TEMPLATE_DIR` + must be a readable directory containing the required templates (plus `splash` + when `SPLASH_PAGE=yes`). +* **Writable output**: `DIST_DIR` (or its nearest existing parent) must be + writable. +* **ImageMagick** availability (`magick` or `convert`). +* **`FAVICON`**, when set, must be a readable file. +* **`--clean`** additionally refuses to delete dangerous paths (filesystem root, + `HOME`, the current directory, well-known system trees) after resolving + `DIST_DIR` canonically. +* **`--sync`** requires at least one destination and rsync. + +Generation stops before writing album output when validation fails. + +## `--print-config` output format + +`--print-config` writes stable shell-style assignments to stdout in this order: + +`CONFIG_SOURCE`, `INCOMING_DIR`, `DIST_DIR`, `TEMPLATE_DIR`, `FAVICON`, +`SOURCE_URL`, `TITLE`, `HEIGHT`, `THUMBHEIGHT`, `MAXPREVIEWS`, `IMAGE_JOBS`, +`IMAGEMAGICK_TIMEOUT`, `RANDOM_SEED`, `SHUFFLE`, `SPLASH_PAGE`, `STATS_PAGE`, +`TARBALL_INCLUDE`, `TARBALL_SUFFIX`, `TAR_TIMEOUT`, `TAR_OPTS`, `SYNC_DELETE`, +`SYNC_DESTINATIONS`, `ORIGINAL_BASEPATH`. + +Scalar values use Bash `%q` quoting; `TAR_OPTS` and `SYNC_DESTINATIONS` are +normalized to Bash array assignments, so the output can be parsed by shell +tooling. `--quiet` does not suppress this output, and `--verbose` does not add +human-readable diagnostics to it.
\ No newline at end of file diff --git a/docs/generation.md b/docs/generation.md new file mode 100644 index 0000000..b477b30 --- /dev/null +++ b/docs/generation.md @@ -0,0 +1,115 @@ +# Generation + +This page describes how `shuriken --generate` works and the features that +affect its output. + +## Artifact reuse and incremental generation + +Normal generation preserves reusable generated artifacts from the previous +`DIST_DIR` while still rerendering HTML, random splash/background choices, +animation classes, timestamps, and shuffled preview order. Existing scaled +photos, thumbnails, and blurs are reused from the previous output when the +source image is unchanged. + +## The EXIF cache + +The per-photo EXIF `identify` output is cached in a separate `cache/exif/` +directory created next to `DIST_DIR` (i.e. parallel to `dist/` in the working +directory — the path is `$(dirname "$DIST_DIR")/cache/exif`). Each cache entry +records a `<photo>:<size>:<mtime>` signature so it is reused only while the +source file is unchanged. + +This cache is volatile and safe to delete, is **not** part of the published +output (it is never written into `DIST_DIR`, so `--sync` does not deploy it), +and persists across runs even if `DIST_DIR` is removed or rebuilt. Because +reading EXIF from full-size originals is the slowest part of generation, keeping +this cache makes regenerating an album dramatically faster: an unchanged photo +skips `identify` entirely. + +* `--clean` removes `DIST_DIR` (and any leftover staging directories) but leaves + `cache/` in place; delete `cache/` by hand to force a full EXIF rebuild on the + next run. +* `--force` (with `--generate`) clears `cache/` once up front, then repopulates + it during the run, so there is still exactly one `identify` per photo even + under force. + +## Splash page + +By default the generated root `index.html` is a no-JavaScript splash page using +a randomly selected album photo. Set `SPLASH_PAGE=no` or pass `--no-splash` to +restore the top-level redirect to `page-1.html`. + +To quickly pick a new random splash photo for an already generated album, run +`shuriken --refresh-splash`. This rewrites `DIST_DIR/index.html` (and re-copies +the site favicon) using the existing `photos` and `blurs` output, so it avoids +reprocessing images and rerendering album pages. It requires `SPLASH_PAGE=yes`; +pass `--random-seed VALUE` when you need a repeatable pick. + +## Stats site + +`shuriken` can also generate a no-JavaScript stats site with EXIF-derived +insights (camera leaderboard, shooting dates, exposure, dimension, format, and +decoded-enum breakdowns), reachable from the `Stats` link in the page header +bar. This is off by default; set `STATS_PAGE=yes` or pass `--stats` to enable it. + +Every row on the stats overview is clickable: each bucket (each camera, ISO, +year, aperture, orientation, …) is its own filter "mini-album" — a gallery of +just the matching photos with view pages whose previous/next cycle within that +filter. + +To keep the album root uncluttered, all of this lives under a `stats/` +subdirectory: the overview is `stats/index.html` and each mini-album is its own +directory `stats/<filter>/` (gallery `index.html` plus numbered view pages). Only +the main album sits in `DIST_DIR` itself. The mini-album pages reuse the album's +shared `photos/`, `thumbs/`, and `blurs/` assets (only the HTML is per-filter) +and are rendered in parallel honouring `IMAGE_JOBS`. Set `STATS_PAGE=no` or pass +`--no-stats` (the default) to skip the whole `stats/` tree and hide the link. + +See [stats-exif-audit.md](stats-exif-audit.md) for the EXIF field coverage +analysis behind these categories. + +## Reproducibility + +By default, splash and background photos, animation classes, generated +timestamps, and `--shuffle` preview order remain non-deterministic. Set +`RANDOM_SEED` in the config, or pass `--random-seed VALUE`, to make those +choices repeatable for stable tests or reproducible album builds. Use the same +seed and inputs to produce the same HTML. + +## Parallelism and timeouts + +ImageMagick photo processing and per-photo HTML template rendering run in +parallel. The default is `IMAGE_JOBS=3`. Set `IMAGE_JOBS` in the config, or pass +`--image-jobs N`, to tune the number of concurrent image and template jobs. + +Each ImageMagick command is bounded by `IMAGEMAGICK_TIMEOUT=60` seconds, and +tarball creation is bounded by `TAR_TIMEOUT=120` seconds. Set either config +value to a positive integer to adjust the limit for large images or archives. + +## Generation metadata (`shuriken.json`) + +Successful generation writes `shuriken.json` into the output directory. This +metadata records: + +* the generator name and version, and a generation timestamp; +* the config source and template name/directory; +* the source `INCOMING_DIR` and source image count; +* generated photo, thumbnail, and HTML file counts; +* tarball status (included + file); +* effective settings (title, height, thumbheight, maxpreviews, image jobs, + random seed, shuffle, splash page, stats page, original basepath) useful for + debugging a published album. + +## Favicon + +Generation writes `favicon.ico` into the output directory and the default +templates link to it. By default this is the bundled shuriken favicon; set +`FAVICON` in the config or pass `--favicon PATH` to publish your own favicon +file instead (it is copied in as `favicon.ico`). + +## Source URL + +The page header bar links to the project source ("Site generated … with +<URL>"). This defaults to the shuriken.sh repository; set `SOURCE_URL` in +the config or pass `--source-url URL` to point it at your own album's repository +instead. The displayed link text is the URL with its scheme removed.
\ No newline at end of file diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..60c8859 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,58 @@ +# Installation + +## Requirements + +* **Bash 5.1 or newer.** shuriken uses features that require it and exits with + an error on older Bash. +* **ImageMagick.** The script prefers the modern `magick` command and falls back + to `convert` / `identify` when only the legacy tools are present. +* **rsync** (only needed for `shuriken --sync`). + +## Build and install from a source checkout + +```sh +just build +sudo just install +``` + +`just install` installs: + +* `shuriken` to `/usr/bin`, +* templates to `/usr/share/shuriken/templates/default` and static assets to + `/usr/share/shuriken/assets`, +* the default config to `/etc/default/shuriken`. + +## Packaging / staging overrides + +Override install paths with `DESTDIR`, `PREFIX`, `BINDIR`, `DATADIR`, or +`SYSCONFDIR` when packaging or staging an install: + +```sh +DESTDIR="$PWD/pkg" PREFIX=/usr just install +DESTDIR="$PWD/pkg" PREFIX=/usr just deinstall +``` + +`just uninstall` is an alias for `just deinstall`. + +Defaults: `PREFIX=/usr`, `BINDIR=$PREFIX/bin`, `DATADIR=$PREFIX/share`, +`SYSCONFDIR=/etc/default`. + +## The generated `bin/shuriken` artifact + +`bin/shuriken` is a committed generated artifact kept in sync with +`src/shuriken.sh` for compatibility with existing checkouts and packaging. Its +source of truth is `src/shuriken.sh` rendered through the `VERSION` and +`LIB_SOURCES` values in `Justfile`. + +* Run `just build` after changing `src/shuriken.sh` or any `src/lib/*.source.sh` + file, and keep `bin/shuriken` synchronized. +* Run `just check-generated` to verify that the tracked script has not drifted. + `just test` and `just install` run that drift check before rebuilding, so a + stale committed output is never silently hidden. + +## Running from a checkout (no install) + +You can run `./bin/shuriken` directly from a source checkout. The stock default +template directory resolves to the installed location when it exists, and +otherwise falls back to the source tree's `share/templates/default`. Likewise +the bundled favicon falls back to `assets/site/favicon.ico`.
\ No newline at end of file diff --git a/docs/publishing.md b/docs/publishing.md new file mode 100644 index 0000000..f31eaaf --- /dev/null +++ b/docs/publishing.md @@ -0,0 +1,45 @@ +# Publishing + +To publish generated output, configure destinations and run `shuriken --sync`. + +## `SYNC_DESTINATIONS` + +`SYNC_DESTINATIONS` must be a Bash array, even for a single destination: + +```sh +SYNC_DESTINATIONS=( + admin@fishfinger.buetow.org:/var/www/htdocs/example.org/ + admin@blowfish.buetow.org:/var/www/htdocs/example.org/ +) +``` + +A scalar string is rejected with an error, since word-splitting would break +destinations that contain spaces (for example +`SYNC_DESTINATIONS=( '/path/with spaces/' )` is the correct spelling). + +`--sync` validates that `SYNC_DESTINATIONS` contains at least one destination and +that rsync is installed. + +## Overriding destinations per run + +Pass `--sync-destination DEST` one or more times with `--sync` to override the +configured destinations for that run only: + +```sh +shuriken --sync --sync-destination user@host:/var/www/htdocs/example.org/ +``` + +## The rsync command + +`--sync` runs, for each destination: + +```sh +rsync -av --delete "$DIST_DIR/" "$destination" +``` + +The trailing slash on `DIST_DIR/` means the generated **contents** are copied +into the target directory. Set `SYNC_DELETE=no` or pass `--no-sync-delete` to +omit `--delete`. + +`--sync` reads `./shuriken.conf` by default; pass `--config PATH` to select a +different config file.
\ No newline at end of file diff --git a/docs/stats-exif-audit.md b/docs/stats-exif-audit.md index 1b1023b..2da9cae 100644 --- a/docs/stats-exif-audit.md +++ b/docs/stats-exif-audit.md @@ -1,5 +1,13 @@ # Stats Page EXIF Field Coverage Audit +> **Status note (added after implementation):** This is a historical design +> record from task `nm0`. The stats site it scopes has since been implemented +> (`src/lib/stats-aggregate.source.sh`, `src/lib/stats-render.source.sh`, +> `src/lib/stats-filter-album.source.sh`), including the "native-field parser +> extension" described below as required work — `Geometry`/`Format` lines are +> now read alongside the `exif:` lines. The verdicts and decode maps below +> remain accurate as a description of what the EXIF data can and cannot support. + Task `nm0` for the stats site feature (see `/home/paul/.pi/plans/shuriken-stats-site.md`). This document decides which of the planned stats categories are actually buildable from the EXIF/identify data @@ -13,8 +21,10 @@ library (there is none to point at): * `src/lib/imagemagick.source.sh` runs `magick identify -verbose <file>` (or `convert <file> -verbose info:` when only the legacy `convert` is present). -* `src/lib/album.source.sh` caches that raw output per photo under a volatile - `./cache/exif/<photo>.txt` (parallel to `./dist`) and parses it. +* The shared EXIF cache in `src/lib/metadata-cache.source.sh` (promoted out of + the album module after this audit was written) caches that raw output per + photo under a volatile `./cache/exif/<photo>.txt` (parallel to `./dist`); + `src/lib/album-metadata.source.sh` parses it. The parser detail that drives every decision below: shuriken only reads EXIF through this regex (`photo_exif_details_html`, `_photo_exif_values_to`): diff --git a/docs/templates.md b/docs/templates.md new file mode 100644 index 0000000..f34be9d --- /dev/null +++ b/docs/templates.md @@ -0,0 +1,34 @@ +# HTML templates + +Templates live under `share/templates/default` in the source tree and under the +installed template directory (`/usr/share/shuriken/templates/default`) after +installation. + +The stock default resolves to the installed template directory when it exists, +and otherwise falls back to the source tree's `share/templates/default` when +running from a checkout. Copy and edit templates, then point `TEMPLATE_DIR` or +`--template PATH` at the customized directory. + +## Required templates + +A template directory must contain these `.tmpl` files (validated before +generation): + +`details`, `footer`, `header`, `next`, `prev`, `preview`, `previewpage`, +`redirect`, `view`. + +When `SPLASH_PAGE=yes`, the `splash` template is also required. + +## Stats templates + +The stats site adds two more templates, `camera.tmpl` and `cameraview.tmpl` +(per-camera mini-album), plus `stats.tmpl` for the overview page. These are only +used when `STATS_PAGE=yes`. + +## Header bar and footer + +* The page **header bar** (`header.tmpl`) renders the "Site generated … with + <SOURCE_URL>" link and, when `STATS_PAGE=yes`, the `Stats` navigation + link. +* The page **footer** (`footer.tmpl`) renders the "Download all photos in + original size" tarball link, shown only when `TARBALL_INCLUDE=yes`.
\ No newline at end of file diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 0000000..b11514b --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,105 @@ +# CLI reference + +``` +shuriken --init +shuriken --generate [--config PATH] [OPTIONS] +shuriken --refresh-splash [--config PATH] [OPTIONS] +shuriken --sync [--config PATH] [OPTIONS] +shuriken --dry-run [--config PATH] [OPTIONS] +shuriken --print-config [--config PATH] [OPTIONS] +shuriken --clean [--config PATH] [OPTIONS] +shuriken --version +``` + +## Actions + +* `--init` creates `./shuriken.conf` in the current working directory from the + default config. It refuses to overwrite an existing file. `--init` is a + non-config action: it rejects `--config`, any config override, and `--force`. +* `--generate` builds the static album. +* `--force` (only valid with `--generate`) rebuilds from scratch instead of + reusing cached scaled photos, thumbnails, blurs, or EXIF data from the existing + output. Using `--force` with any other action is a usage error. +* `--refresh-splash` rewrites only the generated root splash page. Requires + `SPLASH_PAGE=yes`. +* `--sync` publishes the generated output directory to configured rsync + destinations. See [publishing.md](publishing.md). +* `--dry-run` loads the config and overrides, validates the planned generation, + and prints the effective paths, image count, tarball plan, and generated file + plan without writing output or running ImageMagick or tar. Its tarball filename + uses `<timestamp>` as a placeholder so the output is stable. +* `--print-config` loads the config and overrides, validates basic config values, + and prints the effective configuration without writing output, running + ImageMagick, running tar, cleaning, or initializing. See + [configuration.md](configuration.md) for the output format. +* `--clean` removes the configured output directory and any leftover + `.shuriken.*.staging`/`.backup` directories the generation pipeline created as + siblings of `DIST_DIR` (e.g. from an interrupted run). It accepts the same + override options as the other actions, but only `--dist` changes what it + removes. `--clean` leaves the EXIF `cache/` in place; delete `cache/` by hand + to force a full EXIF rebuild on the next run. +* `--version` prints the program version. + +## `--config PATH` + +`--config PATH` selects the config file for **any config-backed action**: +`--generate`, `--refresh-splash`, `--sync`, `--dry-run`, `--print-config`, and +`--clean`. (`--init` and `--version` never load a config and reject `--config`.) + +When `--config PATH` is not provided, those actions read `./shuriken.conf`. If +the file is missing, run `shuriken --init` first. + +`--dry-run`, `--print-config`, and `--refresh-splash` accept the same override +options as `--generate`. + +## Config-value override options + +These long options override config values for the current run. Each pairs with a +config variable documented in [configuration.md](configuration.md). + +| Option | Config value | +| --- | --- | +| `--incoming PATH` | `INCOMING_DIR` | +| `--dist PATH` | `DIST_DIR` | +| `--template PATH` | `TEMPLATE_DIR` | +| `--favicon PATH` | `FAVICON` | +| `--source-url URL` | `SOURCE_URL` | +| `--title TEXT` | `TITLE` | +| `--height VALUE` | `HEIGHT` | +| `--thumbheight VALUE` | `THUMBHEIGHT` | +| `--maxpreviews N` | `MAXPREVIEWS` | +| `--image-jobs N` | `IMAGE_JOBS` | +| `--random-seed VALUE` | `RANDOM_SEED` | +| `--shuffle` | `SHUFFLE=yes` | +| `--no-shuffle` | `SHUFFLE=no` | +| `--splash` | `SPLASH_PAGE=yes` | +| `--no-splash` | `SPLASH_PAGE=no` | +| `--stats` | `STATS_PAGE=yes` | +| `--no-stats` | `STATS_PAGE=no` | +| `--tarball` | `TARBALL_INCLUDE=yes` | +| `--no-tarball` | `TARBALL_INCLUDE=no` | +| `--sync-delete` | `SYNC_DELETE=yes` | +| `--no-sync-delete` | `SYNC_DELETE=no` | + +Pass `--sync-destination DEST` one or more times with `--sync` to override the +configured sync destinations for that run. + +## Output flags + +Output is human-readable by default and reports routine generation progress. + +* `--quiet` suppresses routine progress while still writing errors to stderr. +* `--verbose` adds extra diagnostics, including the selected config file, + effective paths, skipped existing files, staging output directory, and tarball + decisions. +* If `--quiet` and `--verbose` are repeated or combined, the last output flag + wins. `--quiet` does not suppress `--print-config` output, and `--verbose` + does not add human-readable diagnostics to it. + +## Validation before generation + +Before generating, shuriken validates the loaded config and command-line +overrides: required values, positive-integer settings, `yes`/`no` settings, +readable input and template directories, a writable output location, and +ImageMagick availability. Generation stops before writing album output when +validation fails. See [configuration.md](configuration.md) for the details.
\ No newline at end of file |
