A static photo gallery generator

cbenning, updated 🕥 2023-03-29 03:15:29


License Badge Version Badge

Fussel is a static photo gallery generator. It can build a simple static photo gallery site with nothing but a directory full of photos.

Demo Site

Features and Properties: - No server-side code to worry about once generated - Builds special "Person" gallery for people found in XMP face tags. - Adds watermarks - Mobile friendly - Automatic dark-mode - Uses EXIF hints to rotate photos - Predictable slug-basted urls

Common Use-cases: - Image Portfolios - Family Photos - Sharing Photo Archives - etc


| Albums Screenshot | Album Screenshot |
|---|---| | People Screenshot | Person Screenshot |


Demo Gif



  • Python 3.7+
  • node v18.14.0 LTS
  • npm v9.3.1
  • yarn 1.22

Install dependencies

  • ./setup.sh

Setup Site


  • Copy sample_config.yml to config.yml
  • Edit config.yml to your needs (minimal change is to set INPUT_PATH)

Curate photos

The folder you point gallery.input_path at must have subfolders inside it with the folder names as the name of the albums you want in the gallery.


If you have your .env setup with: gallery: input_path: "/home/user/Photos/gallery"

Then that path should look like this: /home/user/Photos/gallery: - Album 1 - Album 2 - Sub Album 1 - Album 3 - Sub Album 2 - ...

Generate your site

Run the following script to generate your site into the path you set in gallery.output_path folder. - ./generate_site.sh

Host your site

Point your web server at gallery.output_path folder or copy/upload the gallery.output_path folder to your web host HTTP root.

Quick setup

After running generate_site.sh

  • python -m http.server --directory <output_path> (go to localhost:8000 in browser)

Development setup

  • cd fussel/web
  • yarn start


If you don't want to fuss with anything and would like to use docker instead to generate your site...


Required: * <input_dir> is the absolute path to top-level photo folder * <output_dir> is the absolute path to where you want the generated site written to

Note: * The two -e env variables PGID and PUID tells the container what to set the output folder permissions to once done. Otherwise it is set to root permissions * For the label-based config to work you must mount /var/run/docker.sock into the container, eg: -v /var/run/docker.sock:/var/run/docker.sock fussel

Optional: You can provide any value found in the config.yml file in a docker label variable using --label item=value

docker run \ -e PGID=$(id -g) \ -e PUID=$(id -u) \ -v /var/run/docker.sock:/var/run/docker.sock \ -v <input_path>:/input:ro \ -v <output_path>:/output \ --label gallery.input_path="/input" \ --label gallery.output_path="/output" \ --label gallery.overwrite=False \ --label gallery.parallel_tasks=4 \ --label gallery.albums.recursive=True \ --label gallery.albums.recursive_name_pattern="{parent_album} > {album}" \ --label gallery.people.enable=True \ --label gallery.watermark.enable=True \ --label gallery.watermark.path="web/src/images/fussel-watermark.png" \ --label gallery.watermark.size_ratio=0.3 \ --label site.http_root="/" \ --label site.title="Fussel Gallery" \ ghcr.io/cbenning/fussel:latest

Once complete you can upload the output folder to your webserver, or see what it looks like with python -m http.server --directory <output_path>


I get an error 'JavaScript heap out of memory'

Try increasing your Node memory allocation: NODE_OPTIONS="--max-old-space-size=2048" yarn build

Reference: https://github.com/cbenning/fussel/issues/25


"False" in labels does not become false in configuration

opened on 2023-03-04 12:03:33 by dan1elhughes

When running the following docker command, the "False" and "True" parameters appear to not be parsed correctly - I would guess because jq reads that as a truthy string.

For example, see people.enable and watermark.enable below.

bash docker run \ -e PGID=$(id -g) \ -e PUID=$(id -u) \ -v /home/dan/Backups/Exports:/input:ro \ -v $(pwd):/output \ --label gallery.input_path="/input" \ --label gallery.output_path="/output" \ --label gallery.overwrite=False \ --label albums.recursive=True \ --label albums.recursive_name_pattern="{parent_album} > {album}" \ --label people.enable=False \ # <---- 🚩 --label watermark.enable=False \ # <---- 🚩 --label watermark.path="web/src/images/fussel-watermark.png" \ --label watermark.size_ratio=0.3 \ --label site.http_root="/" \ --label site.title="Dan Hughes" \ -v /var/run/docker.sock:/var/run/docker.sock fussel

This create the following yaml config, where the booleans are strings:

yaml Generating yaml config... albums: recursive: "True" recursive_name_pattern: '{parent_album} > {album}' gallery: input_path: /input output_path: /output overwrite: "False" org: opencontainers: image: description: 'A static photo gallery generator ' licenses: MIT source: https://github.com/cbenning/fussel people: enable: "False" # <---- 🚩 site: http_root: / title: Dan Hughes watermark: enable: "False" # <---- 🚩 path: web/src/images/fussel-watermark.png size_ratio: "0.3"

Then, in the logs of the output, watermarks are generated:

Importing /input/2023-01-21 Katie's as 2023-01-21 Katie's (2023-01-21-katie-s) --> Processing /input/2023-01-21 Katie's/DSCF5615.jpeg... --> Processing /input/2023-01-21 Katie's/DSCF5603.jpeg... --> Processing /input/2023-01-21 Katie's/DSCF5572.jpeg... --> Processing /input/2023-01-21 Katie's/DSCF5641.jpeg... ----> Copying to /fussel/fussel/web/public/static/_gallery/albums/2023-01-21-katie-s/original_dsc f5603-jpeg.jpeg ----> Copying to /fussel/fussel/web/public/static/_gallery/albums/2023-01-21-katie-s/original_dsc f5572-jpeg.jpeg ----> Copying to /fussel/fussel/web/public/static/_gallery/albums/2023-01-21-katie-s/original_dsc f5615-jpeg.jpeg ----> Copying to /fussel/fussel/web/public/static/_gallery/albums/2023-01-21-katie-s/original_dsc f5641-jpeg.jpeg ------> Generating photo sizes: 500x400 800x640 1024x819 1600x1280 ------> Adding watermark # <---- 🚩 --> Processing /input/2023-01-21 Katie's/DSCF5581.jpeg... ------> Generating photo sizes: 500x625 800x1000 1024x1280 1600x2000 ------> Adding watermark # <---- 🚩 --> Processing /input/2023-01-21 Katie's/DSCF5613.jpeg... ----> Copying to

It appears that the boolean inputs are ignored and default values used instead.

Love the project! 🕊️

Invalid label tags in documentation

opened on 2023-02-20 02:31:32 by h4de5

documentation says "albums.recursive" https://github.com/cbenning/fussel/blob/20c853f03b2a9a0db3e78b29bd6ad93cbd6477f8/README.md?plain=1#L122

but config is read from "gallery.albums.recursive" https://github.com/cbenning/fussel/blob/20c853f03b2a9a0db3e78b29bd6ad93cbd6477f8/fussel/generator/config.py#L39

same with most other label parameters.

Fake ticket for usage of github user images

opened on 2023-02-17 23:18:34 by cbenning None

Update docker image

opened on 2023-02-13 14:50:44 by cbenning

V2 needs a new docker image.

Update README docs and Photos for v2

opened on 2023-02-13 14:50:03 by cbenning

Update README, everything is mostly still v1 specific

[Feature request] Year-Based view

opened on 2021-10-21 08:12:00 by juliangaal

Have you thought about adding a view that can be filtered by year? Cheers


v2.0.2 2023-03-06 04:19:19

What's Changed

  • Fix docker and update deps by @cbenning in https://github.com/cbenning/fussel/pull/107
  • Full Changelog: https://github.com/cbenning/fussel/compare/2.0.1...2.0.2

v2.0.1 2023-02-19 07:24:07

Update some dependencies with CVE's

v2.0.0 2023-02-18 05:08:35

What's Changed

  • Completely re-written components using different dependencies less likely to become abandonware
  • Completely re-written backend
  • Multi-threaded gallery processing
  • Yaml configuration
  • EXIF-based rotation of images
  • New label-based docker image
  • Lots of bug fixes

2.0.0-rc2 2023-02-13 05:07:15

What's Changed

  • Multiprocessing support @cbenning in https://github.com/cbenning/fussel/pull/97
  • Reproduced the issue and fussel now just ignored face detection if ap… by @cbenning in https://github.com/cbenning/fussel/pull/98

Full Changelog: https://github.com/cbenning/fussel/compare/2.0.0-rc1...2.0.0-rc2

v2.0.0-rc1 2023-01-23 04:16:59

Total re-write using much simpler routing mechanism and most of libs replaced (as previous ones became abandonware)

v1.0.10 2021-01-09 23:11:12

  • Updated dependencies
  • add favicon & robots.txt
  • add dark mode
  • use transparent logo
  • optimize docker build
  • Additional image verification
  • Make fussel adhere the order of photos by filename

Contributors to this release * @kcirtapw * @Radtoo * @chrisx8 * @cbenning

Chris Benninger


GitHub Repository Homepage

gallery photos docker static-site-generator