| Crates.io | icloudAlbum2hugo |
| lib.rs | icloudAlbum2hugo |
| version | 0.5.0 |
| created_at | 2025-05-04 04:02:02.70366+00 |
| updated_at | 2025-05-05 02:42:29.221255+00 |
| description | A command-line tool that syncs photos from iCloud Shared Albums to a Hugo site |
| homepage | |
| repository | https://github.com/harperreed/icloudAlbum2hugo |
| max_upload_size | |
| id | 1659366 |
| size | 300,892 |
A command-line tool that syncs photos from iCloud Shared Albums to a Hugo site.
This tool fetches photos from a shared iCloud album, extracts EXIF data, performs reverse geocoding (when location data is available), and organizes everything into Hugo page bundles under content/photostream/<photo_id>/.

# Clone the repository
git clone https://github.com/harperreed/icloudAlbum2hugo.git
cd icloudAlbum2hugo
# Build with cargo
cargo build --release
# Move the binary to a location in your PATH (optional)
cp target/release/icloud2hugo ~/.local/bin/
cargo install icloudAlbum2hugo
# 1. Initialize configuration
icloudAlbum2hugo init
# 2. Edit config.yaml and add your iCloud shared album URL
nano config.yaml
# 3. Sync photos from iCloud to your Hugo site
icloudAlbum2hugo sync
# 4. Check that everything is in sync
icloudAlbum2hugo status
Creates a default configuration file in the current directory.
# Create default config.yaml
icloudAlbum2hugo init
# Create config at a custom location
icloudAlbum2hugo init --config ~/my-hugo-site/custom-config.yaml
# Overwrite existing config file
icloudAlbum2hugo init --force
Synchronizes photos from your iCloud shared album to your Hugo site.
# Sync using default config
icloudAlbum2hugo sync
# Sync using a custom config file
icloudAlbum2hugo sync --config ~/my-hugo-site/custom-config.yaml
During synchronization, the following steps are performed:
Typical output looks like:
┌─────────────────────────────────────────────┐
│ icloudAlbum2hugo Photo Sync │
└─────────────────────────────────────────────┘
📋 Configuration:
• Album URL: https://www.icloud.com/sharedalbum/#B0aGWZmrRGZRiRW
• Output directory: content/photostream
• Data file: data/photos/index.yaml
📂 Loading photo index from data/photos/index.yaml...
• Photo index loaded with 42 photos
🔄 Fetching album data from iCloud...
• Album 'My Vacation Photos' fetched with 45 photos
📷 Syncing photos to local filesystem...
💾 Saving photo index to data/photos/index.yaml...
• Photo index saved successfully
✅ Sync completed successfully:
• Added: 3
• Updated: 0
• Unchanged: 42
• Deleted: 0
• Total photos in index: 45
Shows the current status of your local photos compared to the remote album.
# Check status using default config
icloudAlbum2hugo status
# Check status using custom config
icloudAlbum2hugo status --config ~/my-hugo-site/custom-config.yaml
The status command provides a detailed report including:
Typical output looks like:
┌─────────────────────────────────────────────┐
│ icloudAlbum2hugo Status │
└─────────────────────────────────────────────┘
📋 Configuration:
• Album URL: https://www.icloud.com/sharedalbum/#B0aGWZmrRGZRiRW
• Output directory: content/photostream
• Data file: data/photos/index.yaml
📂 Loading photo index from data/photos/index.yaml...
• Photo index loaded with 42 photos
• Last updated: 2023-07-15T10:24:35Z
• Photos with EXIF data: 38/42
• Photos with GPS coordinates: 32/42
• Photos with location info: 29/42
🔄 Fetching album data from iCloud...
• Album 'My Vacation Photos' fetched with 45 photos
📊 Status Summary:
• Local photos: 42
• Remote photos: 45
• Photos in sync: 42
• New photos to download: 3
• Photos to update: 0
• Photos to remove: 0
🆕 New photos to download:
1. Pmc7WgZhHjkSW9Ew - Beach sunset
2. QM732LSkhGkDfgT8 - Mountain view
3. RtvBc7HjnmL9sDf4 - Family dinner
📋 Suggested Actions:
• Run 'icloudAlbum2hugo sync' to update your local files
The configuration file (config.yaml) supports the following options:
# Required settings
album_url: "https://www.icloud.com/sharedalbum/#B0aGWZmrRGZRiRW" # Your iCloud shared album URL
out_dir: "content/photostream" # Output directory for Hugo page bundles
data_file: "data/photos/index.yaml" # Path to the photo index file
# Optional settings
fuzz_meters: 100.0 # Distance in meters to fuzz location (default: 100.0)
The URL should look like: https://www.icloud.com/sharedalbum/#B0aGWZmrRGZRiRW
The tool creates a clean Hugo site structure that works with most themes:
your-hugo-site/
├── config.yaml # Your Hugo config
├── content/
│ └── photostream/ # Photo content directory
│ ├── photo123456/ # Page bundle for one photo
│ │ ├── index.md # Frontmatter + caption
│ │ └── original.jpg
│ └── photo789012/ # Page bundle for another photo
│ ├── index.md
│ └── original.jpg
└── data/
└── photos/
└── index.yaml # Master index of all photos
Each index.md file contains comprehensive frontmatter:
---
title: "Photo taken on July 15, 2023" # Caption or auto-generated title
date: 2023-07-15T14:30:22+0000 # Photo creation date
guid: "photo123456" # Unique ID from iCloud
original_filename: "IMG_1234.jpg" # Original filename
width: 4032 # Image width in pixels
height: 3024 # Image height in pixels
# EXIF data (if available)
camera_make: "Apple" # Camera manufacturer
camera_model: "iPhone 12 Pro" # Camera model
exif_date: 2023-07-15T14:30:22+0000 # Date from EXIF data
# Location data (if available and with privacy fuzzing)
original_latitude: 41.878765 # Original GPS latitude
original_longitude: -87.635987 # Original GPS longitude
latitude: 41.878901 # Fuzzed latitude for privacy
longitude: -87.636123 # Fuzzed longitude for privacy
location: "Chicago, IL, USA" # Formatted location name
city: "Chicago" # City name
state: "Illinois" # State/province
country: "United States" # Country
# Camera settings (if available)
iso: 100 # ISO speed
exposure_time: 1/120 # Shutter speed
f_number: 1.8 # Aperture
focal_length: 4.2 # Focal length in mm
---
This is a beautiful sunset over Lake Michigan in Chicago.
Photo titles are generated following these rules:
To display your photos in Hugo, you can use any theme that supports page bundles. Here's an example of a simple list template (layouts/photostream/list.html):
{{ define "main" }}
<h1>{{ .Title }}</h1>
<div class="photo-grid">
{{ range .Pages.ByDate.Reverse }}
<div class="photo-item">
<a href="{{ .RelPermalink }}">
<img src="{{ .RelPermalink }}original.jpg" alt="{{ .Title }}" />
<h2>{{ .Title }}</h2>
</a>
</div>
{{ end }}
</div>
{{ end }}
And a single photo template (layouts/photostream/single.html):
{{ define "main" }}
<article class="photo-page">
<h1>{{ .Title }}</h1>
<div class="photo-container">
<img src="{{ .RelPermalink }}original.jpg" alt="{{ .Title }}" />
</div>
<div class="photo-metadata">
{{ with .Params.camera_make }}
<p><strong>Camera:</strong> {{ . }} {{ with $.Params.camera_model }}{{ . }}{{ end }}</p>
{{ end }}
{{ with .Params.exif_date }}
<p><strong>Taken:</strong> {{ dateFormat "January 2, 2006" . }}</p>
{{ end }}
{{ with .Params.location }}
<p><strong>Location:</strong> {{ . }}</p>
{{ end }}
{{ with .Params.iso }}
<p><strong>Settings:</strong> ISO {{ . }},
{{ with $.Params.exposure_time }}{{ . }}s, {{ end }}
{{ with $.Params.f_number }}f/{{ . }}, {{ end }}
{{ with $.Params.focal_length }}{{ . }}mm{{ end }}
</p>
{{ end }}
</div>
<div class="photo-content">
{{ .Content }}
</div>
</article>
{{ end }}
Problem: Cannot find your iCloud shared album URL
Solution: Make sure you're sharing the album publicly. In Photos, go to the album → Share → Share Link
Problem: No photos are downloaded
Solution: Check that your album URL is correct and the album is publicly shared
Problem: Missing EXIF data
Solution: Not all photos contain EXIF data. Photos that have been edited or sent through messaging apps often lose their EXIF information
Problem: Missing location data
Solution: Not all photos contain GPS information. Check that location services were enabled when the photos were taken
For more detailed debugging information, use the RUST_LOG environment variable:
# Informational logs
RUST_LOG=info icloudAlbum2hugo sync
# Debug level (more detailed)
RUST_LOG=debug icloudAlbum2hugo sync
# Trace level (very verbose)
RUST_LOG=trace icloudAlbum2hugo sync
To set up automatic syncing, add a cron job:
# Edit crontab
crontab -e
# Add line to run sync daily at 2 AM
0 2 * * * cd /path/to/your/hugo/site && /path/to/icloudAlbum2hugo sync >> sync.log 2>&1
If you want to use a different directory structure than content/photostream/<photo_id>, you can modify the out_dir setting in your config.yaml:
# Store photos in content/gallery instead
out_dir: "content/gallery"
Want to contribute? Great! Here's how to set up for development:
# Clone the repository
git clone https://github.com/harperreed/icloudAlbum2hugo.git
cd icloudAlbum2hugo
# Build and run with debug information
RUST_LOG=debug cargo run -- init
# Run tests
cargo test
# Run specific test
cargo test test_photo_title_formatting
# Run integration tests (requires iCloud token)
ICLOUD_TEST_TOKEN=YourToken cargo test --test icloud_integration_test -- --nocapture