googlephotos: map EXIF/IPTC/XMP description to Google Photos description field by davispw · Pull Request #9499 · rclone/rclone · GitHub
Skip to content

googlephotos: map EXIF/IPTC/XMP description to Google Photos description field#9499

Draft
davispw wants to merge 3 commits into
rclone:masterfrom
davispw:gphotos-exif-description
Draft

googlephotos: map EXIF/IPTC/XMP description to Google Photos description field#9499
davispw wants to merge 3 commits into
rclone:masterfrom
davispw:gphotos-exif-description

Conversation

@davispw

@davispw davispw commented Jun 6, 2026

Copy link
Copy Markdown

Summary

This PR adds a new feature to the google photos rclone backend: automatic mapping of EXIF/IPTC/XMP image metadata to the Google Photos description field on upload.


How It Works

Two new configuration options are introduced:

Flag Type Default Description
--gphotos-upload-exif-description bool false Enable EXIF/IPTC/XMP description extraction on upload
--gphotos-exif-description-fields string list XMP-dc:Description,IPTC:Caption-Abstract,EXIF:ImageDescription,XMP-dc:Title,IPTC:ObjectName,XMP-photoshop:Headline,IPTC:Headline Priority-ordered list of metadata tags to search

On each upload, if --gphotos-upload-exif-description is set, rclone reads the source file's metadata and searches the configured tag list in order. The first non-empty value found is sent as the description in the mediaItems:batchCreate API call.

Namespace Prefixes and Custom XMP Parser

To distinguish between tags of the same name across different metadata blocks, fields can be prefixed with their namespace (e.g., EXIF:, IPTC:, XMP-dc:, XMP-photoshop:).

While the github.com/bep/imagemeta library is used to extract raw EXIF, IPTC, and XMP segments, it only parses simple key-value attributes and does not decode nested XML/RDF structures (such as Dublin Core metadata elements). To support these structures (e.g., nested <dc:title> tags generated by Adobe Lightroom Classic), this PR implements a custom XML pull-parser inside extractEXIFDescription.

Values are trimmed.

Tag Priority (default order)

The default field list reflects common conventions across modern and legacy metadata editors:

  1. XMP-dc:Description — Modern Dublin Core description (Lightroom / capture software)
  2. IPTC:Caption-Abstract — Legacy IPTC caption abstract (journalism standard)
  3. EXIF:ImageDescription — Baseline EXIF hardware/camera description
  4. XMP-dc:Title — Dublin Core title panel
  5. IPTC:ObjectName — Legacy IPTC object name / title
  6. XMP-photoshop:Headline — Modern Photoshop headline tag
  7. IPTC:Headline — Legacy IPTC headline tag

Configuration Example

[myphotos]
type = google photos
upload_exif_description = true
exif_description_fields = XMP-dc:Description,IPTC:Caption-Abstract,EXIF:ImageDescription

Or on the command line:

rclone copy ~/Photos/ gphotos:album/MyAlbum \
  --gphotos-upload-exif-description \
  --gphotos-exif-description-fields "XMP-dc:Description,IPTC:Caption-Abstract,EXIF:ImageDescription"

Manual Test Results

Important

Step 2 (Hasher Integration) relies on the changes in fix-equal-hash-modtime-unsupported (PR #9500). The hasher overlay features (in-flight caching on Update and local size fingerprinting) are implemented in PR #9500; testing the metadata-only update without it will result in infinite upload loops under async batch mode or cache misses due to missing remote sizes.

Prerequisites

# Build rclone
go build .

# Create test photo with EXIF description
mkdir test_photos_exif
curl -L -o test_photos_exif/image.jpg https://picsum.photos/400/300
exiftool -ImageDescription="Scenic Sunset Over Mountains" test_photos_exif/image.jpg

Step 1: Upload and Verify Description Mapping

./rclone copy test_photos_exif/image.jpg gphotos:album/rclone_Metadata_Test/ \
  --gphotos-upload-exif-description -vv

Expected: file is uploaded successfully. Verify in the Google Photos web UI (https://photos.google.com):

  1. Open the rclone_Metadata_Test album and click image.jpg.
  2. Select the ⓘ (Info) icon.
  3. Confirm the description field shows "Scenic Sunset Over Mountains"

Step 2: Hasher Integration — Detecting Metadata-Only Changes

Using the hasher backend overlay, the local BoltDB cache tracks MD5 checksums. Because changing EXIF metadata modifies the file's binary content, hasher correctly detects the change and triggers a re-upload.

# Configure hasher overlay (if not already done)
rclone config create gphotos_cache hasher remote=gphotos: hashes=md5 max_age=24h

# Initial upload — hash computed in-flight and cached
./rclone copy test_photos_exif/image.jpg gphotos_cache:album/rclone_Metadata_Test/ \
  --gphotos-upload-exif-description --gphotos-batch-mode=sync \
  --ignore-size --ignore-checksum -vv
# → 2026/.../INFO : image.jpg: Copied (new)

# Second run — hash found in cache, skipped
./rclone copy test_photos_exif/image.jpg gphotos_cache:album/rclone_Metadata_Test/ \
  --gphotos-upload-exif-description --gphotos-batch-mode=sync \
  --ignore-size --ignore-checksum -vv
# → There was nothing to transfer

# Modify EXIF description locally
exiftool -ImageDescription="Spectacular Mountain Range" test_photos_exif/image.jpg

# Third run — MD5 changed, triggers re-upload with new description
./rclone copy test_photos_exif/image.jpg gphotos_cache:album/rclone_Metadata_Test/ \
  --gphotos-upload-exif-description --gphotos-batch-mode=sync \
  --ignore-size --ignore-checksum -vv
# → 2026/.../INFO : image.jpg: Copied (replaced existing)

Verify in the Google Photos web UI that the description for image.jpg in rclone_Metadata_Test now shows "Spectacular Mountain Range"


Automated Tests

Self-contained unit tests are added to verify the metadata extraction:

  • TestEXIFDescriptionMapping: Mocks the batch upload flow using an in-memory TIFF file with an EXIF ImageDescription tag.
  • TestExtractEXIFDescriptionXMP: Mocks the Dublin Core nested XMP tag parsing flow using an in-memory TIFF with a synthesized XMP block.
$ go test -v ./backend/googlephotos/...
=== RUN   TestEXIFDescriptionMapping
--- PASS: TestEXIFDescriptionMapping (0.00s)
=== RUN   TestExtractEXIFDescriptionXMP
--- PASS: TestExtractEXIFDescriptionXMP (0.00s)
...all other existing tests PASS...
ok  	github.com/rclone/rclone/backend/googlephotos	1.339s

Notes

  • No EXIF extraction happens when --gphotos-upload-exif-description is not set (zero performance impact by default).
  • If no matching tag is found, the description is left empty (no error).
  • The tag list is user-configurable to accommodate different metadata workflows (Lightroom, Darktable, camera-native EXIF, etc.).

Dependencies (gh-stack)

This PR is independent and has no dependencies.

Was the change discussed in an issue or in the forum before?

As far as I know, this was not discussed previously. This is a new feature to map EXIF/IPTC/XMP description metadata to Google Photos descriptions on upload.


Checklist

  • I have read the contribution guidelines.
  • I have added tests for all changes in this PR if appropriate.
  • I have added documentation for the changes if appropriate.
  • All commit messages are in house style.
  • I'm done, this Pull Request is ready for review :-)

@davispw davispw force-pushed the gphotos-exif-description branch 3 times, most recently from aa6bbc9 to b2eb08b Compare June 7, 2026 17:37
@davispw davispw force-pushed the gphotos-exif-description branch from b2eb08b to 2731cb1 Compare June 7, 2026 18:54
@davispw davispw force-pushed the gphotos-exif-description branch 4 times, most recently from bea07b0 to 449a3ce Compare June 13, 2026 18:25
davispw added 3 commits June 13, 2026 11:36
When uploading media, rclone can now read description metadata from
EXIF/IPTC/XMP tags and pass it to the Google Photos API as the media
item description, visible in the Google Photos UI.

This is controlled by two new options:
- read_exif_description: enable the feature (default: false)
- exif_description_fields: ordered list of tag names to try
  (default: Description,Caption-Abstract,ImageDescription,Title,ObjectName)

The first non-empty matching tag value is used. The feature uses the
github.com/bep/imagemeta library and reads only the first 512 KiB of
the upload stream to extract metadata before uploading.

Add unit test TestEXIFDescriptionMapping.
…ption fields

This adds a custom HandleXMP parser to extract Dublin Core nested title and
description tags (dc:title and dc:description) which are skipped by the default
imagemeta parser or are otherwise ignored since they are nested tags and not attributes.

This ensures that Lightroom-exported titles and descriptions successfully map
to the Google Photos description on upload.
@davispw davispw force-pushed the gphotos-exif-description branch from 449a3ce to e83cf5d Compare June 13, 2026 18:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant