Ro-Photo
Go console application that generates a static photo gallery by scanning source directories, extracting EXIF metadata, and organizing photos into a date-based directory structure.
Overview
Ro-Photo reads from one or more source directories containing photos, parses EXIF data from each image, and produces a structured static gallery. The output is organized into a hierarchical directory layout based on the date each photo was taken:
output/
thumbnails/
2024/03/15/IMG_1234.jpg
2024/
03/
15/
IMG_1234.JPG
IMG_1235.JPG
22/
DSC_0001.CR2
07/
01/
P1000042.JPG
Unsorted/
IMG_0001.HEIC
cameras/
about.html
index.html
Features
- YAML configuration — all settings defined in a single config file
- Multiple source locations — scan several directories in one run
- EXIF-based organization — photos are sorted by date taken (
DateTimeOriginal), not filesystem timestamps - Date-structured output — files are placed into
/YYYY/MM/DD/FILENAME.EXTdirectories automatically - Unsorted handling — photos without EXIF data are placed in an
Unsorted/directory - Thumbnail generation — JPEG thumbnails created for all formats (including RAW) with proper EXIF orientation
- SQLite metadata database — all photo metadata is aggregated into a local SQLite database for fast querying, filtering, and search
- Static gallery generation — responsive Tailwind CSS gallery with dark theme, lightbox, and pagination
- Gallery-only mode — regenerate HTML pages from existing database without re-scanning
SQLite Database
During scanning, all photo metadata is stored in a SQLite database (photos.db by default). This provides:
- Fast lookups and filtering by date, camera model, lens, GPS coordinates, etc.
- Incremental updates — only new or modified files are re-scanned
- A queryable record of the entire photo library independent of the generated gallery
Schema overview:
| Column | Description |
|---|---|
file_path |
Original source path |
file_name |
Base filename |
file_size |
Size in bytes |
date_taken |
DateTimeOriginal from EXIF |
camera_make |
Camera manufacturer |
camera_model |
Camera model |
lens_model |
Lens identifier |
focal_length |
Focal length in mm |
aperture |
F-number |
shutter_speed |
Exposure time |
iso |
ISO sensitivity |
gps_lat |
GPS latitude |
gps_lon |
GPS longitude |
width |
Image width in pixels |
height |
Image height in pixels |
output_path |
Path in the generated gallery |
thumbnail_path |
Path to the generated thumbnail |
Supported Formats
Standard Image Formats
| Format | Extensions |
|---|---|
| JPEG | .jpg, .jpeg |
| TIFF | .tif, .tiff |
| HEIF | .heic, .heif |
RAW Formats
| Brand | Extensions |
|---|---|
| Canon | .cr2, .cr3 |
| Nikon | .nef, .nrw |
| Sony | .arw, .srf, .sr2 |
| Fujifilm | .raf |
| Olympus | .orf |
| Panasonic | .rw2 |
| Pentax | .pef |
| Samsung | .srw |
| Sigma | .x3f |
| Leica | .rwl |
| Hasselblad | .3fr, .fff |
| Phase One | .iiq |
| Kodak | .kdc, .dcr |
| Epson | .erf |
| Mamiya | .mef |
| Minolta | .mrw |
| Leaf | .mos |
| Adobe / Generic | .dng |
Gallery
The static gallery is built with Tailwind CSS, producing a responsive, modern interface that works on desktop and mobile. The generated HTML files reference a bundled Tailwind CSS build, so the gallery can be served from any static file host or opened directly from disk.
Generated pages include:
- Index — overview with year and camera cards
- Year / Month / Day — hierarchical date-based browsing with pagination (50 photos per page)
- Photo detail — full-size image with EXIF metadata (camera, lens, exposure, GPS) and prev/next navigation
- Camera — photos grouped by camera model with pagination
- Unsorted — photos without detectable EXIF data
- About — project info, usage manual, author, and gallery stats
Configuration
The application is configured via a YAML file:
title: My Photo Gallery # gallery title shown in header, footer, and about page
author: John Doe # author name shown on the about page
sources: # one or more directories to scan for photos
- /path/to/photos/camera
- /path/to/photos/phone
- /mnt/external/photos
output: /path/to/gallery # directory where the gallery and organized photos are written
database: /path/to/photos.db # SQLite database path (default: "photos.db")
templates: /path/to/templates # path to HTML templates directory (default: "./templates")
| Setting | Required | Default | Description |
|---|---|---|---|
title |
No | Photo Gallery |
Gallery name displayed in header, footer, and page titles |
author |
No | — | Author name shown on the about page |
sources |
Yes | — | List of directories to scan for photos |
output |
Yes | — | Output directory for organized photos and gallery |
database |
No | photos.db |
Path to the SQLite metadata database |
templates |
No | ./templates |
Path to the HTML template files |
Usage
ro-photo --config config.yaml
Command-line Flags
| Flag | Default | Description |
|---|---|---|
--config |
config.yaml |
Path to the YAML configuration file |
--gallery-only |
false |
Skip scanning/copying, only regenerate gallery from the existing database |
Examples
Full run — scan sources, extract EXIF, copy files, generate thumbnails, build gallery:
ro-photo --config config.yaml
Regenerate gallery only (useful after editing templates):
ro-photo --config config.yaml --gallery-only
Building
go build -o ro-photo .
Requirements
- Go 1.21+
- No CGO required — uses pure Go SQLite driver