2026-07-02 00:53:17 +02:00
|
|
|
|
# photogallery
|
|
|
|
|
|
|
|
|
|
|
|
A minimal static photo gallery with an Atom feed and an upload API.
|
|
|
|
|
|
|
|
|
|
|
|
## How it works
|
|
|
|
|
|
|
|
|
|
|
|
1. Drop `photo.jpg` + `photo.toml` into the content directory (or upload via the web UI at `/upload`).
|
|
|
|
|
|
2. The binary watches the directory and rebuilds the static site on any change.
|
|
|
|
|
|
3. nginx serves `public/` and proxies `/upload` to the local API, secured with htpasswd.
|
|
|
|
|
|
|
2026-07-02 02:30:35 +02:00
|
|
|
|
For each photo the generator produces a 600×600 square thumbnail for the grid
|
|
|
|
|
|
and an aspect-preserved medium JPEG (longest side 1600) for the detail page.
|
|
|
|
|
|
The original file stays reachable from a download link on the detail page.
|
|
|
|
|
|
Regeneration is skipped when the destination is at least as new as the source,
|
|
|
|
|
|
so editing one sidecar doesn't reprocess every photo.
|
|
|
|
|
|
|
|
|
|
|
|
The upload page reads `DateTimeOriginal` from a JPEG's EXIF (or falls back to
|
|
|
|
|
|
the file's modification time) and prefills the date field, which stays
|
|
|
|
|
|
editable before submitting.
|
|
|
|
|
|
|
2026-07-02 00:53:17 +02:00
|
|
|
|
## Sidecar format
|
|
|
|
|
|
|
|
|
|
|
|
```toml
|
|
|
|
|
|
caption = "Tempelhof at sunrise"
|
|
|
|
|
|
date = "2026-06-14"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
If no `.toml` is present the filename is used as the caption and today's date as the date.
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Using as a NixOS flake module
|
|
|
|
|
|
|
|
|
|
|
|
### 1. Add to your flake inputs
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
inputs = {
|
|
|
|
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
|
|
|
|
photogallery.url = "github:youruser/photogallery";
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. Import the module
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
|
|
|
|
|
|
modules = [
|
|
|
|
|
|
inputs.photogallery.nixosModules.default
|
|
|
|
|
|
./configuration.nix
|
|
|
|
|
|
];
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. Configure
|
|
|
|
|
|
|
|
|
|
|
|
```nix
|
|
|
|
|
|
services.photogallery = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
baseURL = "https://photos.yourdomain.tld";
|
|
|
|
|
|
|
2026-07-02 02:30:35 +02:00
|
|
|
|
# Optional: identity shown on the header and copyright footer
|
|
|
|
|
|
author = "Ada Lovelace";
|
|
|
|
|
|
handle = "@ada@example.com";
|
|
|
|
|
|
bio = "Photos from the field.";
|
|
|
|
|
|
bioAlt = ""; # optional secondary line in the alt-script font
|
|
|
|
|
|
|
|
|
|
|
|
# Optional: swap fonts
|
|
|
|
|
|
fontsURL = "https://fonts.googleapis.com/css2?family=EB+Garamond:wght@400;600;700&family=Manjari:wght@400;700&display=swap";
|
|
|
|
|
|
serifFamily = "EB Garamond";
|
|
|
|
|
|
mlFamily = "Manjari";
|
|
|
|
|
|
|
2026-07-02 00:53:17 +02:00
|
|
|
|
# Optional: built-in nginx vhost
|
|
|
|
|
|
nginx = {
|
|
|
|
|
|
enable = true;
|
|
|
|
|
|
domain = "photos.yourdomain.tld";
|
|
|
|
|
|
htpasswdFile = "/etc/nginx/.htpasswd-gallery";
|
|
|
|
|
|
};
|
|
|
|
|
|
};
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Create the htpasswd file:
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
nix-shell -p apacheHttpd --run \
|
|
|
|
|
|
"htpasswd -c /etc/nginx/.htpasswd-gallery youruser"
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Available options
|
|
|
|
|
|
|
|
|
|
|
|
| Option | Default | Description |
|
|
|
|
|
|
|-----------------------------|------------------------------------|--------------------------------------|
|
|
|
|
|
|
| `enable` | `false` | Enable the service |
|
|
|
|
|
|
| `baseURL` | — | Public URL, no trailing slash |
|
|
|
|
|
|
| `contentDir` | `/var/lib/photogallery/content` | Images and .toml sidecars |
|
|
|
|
|
|
| `outputDir` | `/var/lib/photogallery/public` | Generated site output |
|
|
|
|
|
|
| `port` | `8080` | Upload API port (localhost only) |
|
2026-07-02 02:30:35 +02:00
|
|
|
|
| `author` | `Ashik Salahudeen` | Name shown on the header, photo pages and copyright footer |
|
|
|
|
|
|
| `handle` | `@puttaalu@inflo.ws` | Handle line under the author name |
|
|
|
|
|
|
| `bio` | `Personal photo journal.` | Primary bio line |
|
|
|
|
|
|
| `bioAlt` | Malayalam default | Secondary bio line in the alt-script font (`""` to omit) |
|
|
|
|
|
|
| `fontsURL` | Crimson Pro + Manjari | Stylesheet URL loading both web fonts |
|
|
|
|
|
|
| `serifFamily` | `Crimson Pro` | CSS font-family for the primary serif |
|
|
|
|
|
|
| `mlFamily` | `Manjari` | CSS font-family for the alt-script bio |
|
2026-07-02 00:53:17 +02:00
|
|
|
|
| `nginx.enable` | `false` | Configure an nginx vhost |
|
|
|
|
|
|
| `nginx.domain` | — | Domain for the vhost |
|
|
|
|
|
|
| `nginx.htpasswdFile` | — | htpasswd file for `/upload` |
|
|
|
|
|
|
| `nginx.enableACME` | `true` | Enable Let's Encrypt |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Bootstrap (first build)
|
|
|
|
|
|
|
|
|
|
|
|
`buildGoModule` needs a `go.sum` and the correct `vendorHash`.
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. Generate go.sum
|
|
|
|
|
|
go mod tidy
|
|
|
|
|
|
|
|
|
|
|
|
# 2. Commit go.sum
|
|
|
|
|
|
git add go.sum && git commit -m "add go.sum"
|
|
|
|
|
|
|
|
|
|
|
|
# 3. Get the vendorHash — this will fail and print the correct hash
|
|
|
|
|
|
nix build
|
|
|
|
|
|
# error: hash mismatch ... got: sha256-XXXXX...
|
|
|
|
|
|
|
|
|
|
|
|
# 4. Paste the hash into flake.nix, then build again
|
|
|
|
|
|
nix build
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Uploading via curl
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
curl -u user:password \
|
|
|
|
|
|
-F "image=@photo.jpg" \
|
|
|
|
|
|
-F "caption=Tempelhof at sunrise" \
|
|
|
|
|
|
-F "date=2026-06-14" \
|
|
|
|
|
|
https://photos.yourdomain.tld/upload
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Or open `https://photos.yourdomain.tld/upload` in a browser.
|