102 lines
2.8 KiB
Markdown
102 lines
2.8 KiB
Markdown
|
|
# photogallery
|
|||
|
|
|
|||
|
|
Personal static photo gallery with Atom feed and upload API. Single-user.
|
|||
|
|
No database, no framework — just a Go binary that watches a directory and regenerates a static site.
|
|||
|
|
|
|||
|
|
## Architecture
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
content/ # images + .toml sidecars (source of truth)
|
|||
|
|
public/ # generated output (served by nginx / --serve flag)
|
|||
|
|
templates/ # embedded HTML templates
|
|||
|
|
static/ # embedded CSS
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The binary does three things at once:
|
|||
|
|
- Watches `content/` via fsnotify and rebuilds on any change
|
|||
|
|
- Serves a multipart upload API at `POST /upload`
|
|||
|
|
- In dev mode (`--serve`), also serves `public/` as static files
|
|||
|
|
|
|||
|
|
In production nginx sits in front: serves `public/` directly, proxies `/upload` to localhost, htpasswd on the upload endpoint.
|
|||
|
|
|
|||
|
|
## Stack
|
|||
|
|
|
|||
|
|
- **Go** — stdlib + `BurntSushi/toml`, `fsnotify/fsnotify`, `golang.org/x/image`
|
|||
|
|
- **Templates** — `html/template`, embedded via `embed.FS`
|
|||
|
|
- **Images** — centre-crop to square, Catmull-Rom resize to 600×600 JPEG thumbnails
|
|||
|
|
- **Feed** — Atom (`encoding/xml`)
|
|||
|
|
- **NixOS** — `flake.nix` + `module.nix`, exports `nixosModules.default`
|
|||
|
|
|
|||
|
|
## Sidecar format
|
|||
|
|
|
|||
|
|
```toml
|
|||
|
|
caption = "Tempelhof at sunrise"
|
|||
|
|
date = "2026-06-14"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Missing sidecar → filename as caption, today as date.
|
|||
|
|
|
|||
|
|
## Design
|
|||
|
|
|
|||
|
|
- Gruvbox dark hard colour scheme
|
|||
|
|
- Vollkorn (serif) for headings and captions
|
|||
|
|
- Manjari for Malayalam text (bio line)
|
|||
|
|
- 3-column square grid → 2-column on mobile
|
|||
|
|
- Single photo page with sidebar
|
|||
|
|
|
|||
|
|
## Running locally
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
nix develop
|
|||
|
|
go mod tidy
|
|||
|
|
go run . --serve
|
|||
|
|
# gallery: http://localhost:8080
|
|||
|
|
# upload: http://localhost:8080/upload
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## NixOS module usage
|
|||
|
|
|
|||
|
|
```nix
|
|||
|
|
inputs.photogallery.url = "github:youruser/photogallery";
|
|||
|
|
# in modules:
|
|||
|
|
inputs.photogallery.nixosModules.default
|
|||
|
|
# in configuration.nix:
|
|||
|
|
services.photogallery = {
|
|||
|
|
enable = true;
|
|||
|
|
baseURL = "https://photos.yourdomain.tld";
|
|||
|
|
nginx = {
|
|||
|
|
enable = true;
|
|||
|
|
domain = "photos.yourdomain.tld";
|
|||
|
|
htpasswdFile = "/etc/nginx/.htpasswd-gallery";
|
|||
|
|
};
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Bootstrap (first nix build)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
go mod tidy # generates go.sum — commit it
|
|||
|
|
nix build # fails, prints correct vendorHash
|
|||
|
|
# paste hash into flake.nix
|
|||
|
|
nix build # succeeds
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Key files
|
|||
|
|
|
|||
|
|
| File | Purpose |
|
|||
|
|
|---|---|
|
|||
|
|
| `main.go` | Flags, wires generator + watcher + server |
|
|||
|
|
| `generator.go` | Scans content dir, renders HTML + Atom feed, generates thumbs |
|
|||
|
|
| `server.go` | Upload API + optional static file serving |
|
|||
|
|
| `watcher.go` | fsnotify watcher with 500ms debounce |
|
|||
|
|
| `assets.go` | `//go:embed` for templates and static |
|
|||
|
|
| `module.nix` | NixOS module (systemd service, tmpfiles, nginx vhost) |
|
|||
|
|
| `flake.nix` | `buildGoModule` package + devShell + nixosModules |
|
|||
|
|
|
|||
|
|
## What's not done yet
|
|||
|
|
|
|||
|
|
- ActivityPub federation (planned later — start with RSS/Atom)
|
|||
|
|
- Multi-image upload
|
|||
|
|
- Delete/edit via UI
|
|||
|
|
- Any auth beyond nginx htpasswd
|