Nothing reads a photo's EXIF, so every column upstream fills is empty #209

Closed
opened 2026-09-12 17:35:31 +02:00 by Claude · 1 comment
Collaborator

A photo is resolved and filed, but nothing reads the file itself, so every column Emby.Photos/PhotoProvider.cs fills is left empty. Split out of #194, which covered the resolvers.

grep -rn "exif\|Exif" crates/ephyra-app/src/scan/ crates/ephyra-images/src/ returns nothing.

What upstream fills

upstream/Emby.Photos/PhotoProvider.cs, ~175 lines, over TagLib:

dimensions Width, Height (:95-96) — from image.Properties, and the one pair that does not need an EXIF tag
camera CameraMake, CameraModel (:92-93), Aperture (:79), ShutterSpeed (:84), ExposureTime, FocalLength (:129-130)
place Latitude, Longitude, Altitude (:132…)
dates DateCreated, PremiereDate, ProductionYear, all off dateTaken (:111-113) — note DateCreated is .ToUniversalTime() and PremiereDate is not
text Name from ImageTag.Title when there is one (:105), Overview from Comment (:100), Genres, Tags from Keywords (:116-117), Software (:118)
other CommunityRating from ImageTag.Rating (:98), Orientation (:122-126, explicitly nulled for one value)

Width/Height are the ones with reach beyond the detail page: a client sizes a grid from them.

Also named in #194 and not done

  • A PhotoAlbum takes no folder image. The artwork name list is right (crates/ephyra-app/src/scan/images.rs now matches LocalImageProvider.cs:260's item is MusicAlbum || MusicArtist || PhotoAlbum), but nothing walks a photo album for one.
  • LibraryOptions.EnablePhotos exists in the DTO (crates/ephyra-dto/src/generated/models.rs:4208) and is consulted nowhere. Upstream uses it to decide whether photos in a non-photo library are resolved at all.

Where it goes

crates/ephyra-images already decodes; this is metadata rather than pixels, so the question worth settling first is whether the EXIF read belongs there or beside the other providers in crates/ephyra-app/src/metadata/.

Verifying

cargo xtask reference gen-library-kinds (xtask/src/reference/kinds.rs) lays a tree down, stands up its own container, scans, and writes upstream's rows into crates/ephyra-app/corpus/library-kinds.json; crates/ephyra-app/tests/library_kinds.rs replays our walk against it. It already registers a homevideos library — but the tree's images are placeholders, so the fixture needs photos carrying real EXIF before any of this can be diffed. A generated JPEG with known tags is enough and is reproducible, which a downloaded one is not.

A photo is resolved and filed, but nothing reads the file itself, so every column `Emby.Photos/PhotoProvider.cs` fills is left empty. Split out of #194, which covered the resolvers. `grep -rn "exif\|Exif" crates/ephyra-app/src/scan/ crates/ephyra-images/src/` returns nothing. ## What upstream fills `upstream/Emby.Photos/PhotoProvider.cs`, ~175 lines, over `TagLib`: | | | |---|---| | dimensions | `Width`, `Height` (`:95-96`) — from `image.Properties`, and the one pair that does **not** need an EXIF tag | | camera | `CameraMake`, `CameraModel` (`:92-93`), `Aperture` (`:79`), `ShutterSpeed` (`:84`), `ExposureTime`, `FocalLength` (`:129-130`) | | place | `Latitude`, `Longitude`, `Altitude` (`:132`…) | | dates | `DateCreated`, `PremiereDate`, `ProductionYear`, all off `dateTaken` (`:111-113`) — note `DateCreated` is `.ToUniversalTime()` and `PremiereDate` is not | | text | `Name` from `ImageTag.Title` when there is one (`:105`), `Overview` from `Comment` (`:100`), `Genres`, `Tags` from `Keywords` (`:116-117`), `Software` (`:118`) | | other | `CommunityRating` from `ImageTag.Rating` (`:98`), `Orientation` (`:122-126`, explicitly nulled for one value) | `Width`/`Height` are the ones with reach beyond the detail page: a client sizes a grid from them. ## Also named in #194 and not done - **A `PhotoAlbum` takes no folder image.** The artwork name list is right (`crates/ephyra-app/src/scan/images.rs` now matches `LocalImageProvider.cs:260`'s `item is MusicAlbum || MusicArtist || PhotoAlbum`), but nothing walks a photo album for one. - **`LibraryOptions.EnablePhotos`** exists in the DTO (`crates/ephyra-dto/src/generated/models.rs:4208`) and is consulted nowhere. Upstream uses it to decide whether photos in a non-photo library are resolved at all. ## Where it goes `crates/ephyra-images` already decodes; this is metadata rather than pixels, so the question worth settling first is whether the EXIF read belongs there or beside the other providers in `crates/ephyra-app/src/metadata/`. ## Verifying `cargo xtask reference gen-library-kinds` (`xtask/src/reference/kinds.rs`) lays a tree down, stands up its own container, scans, and writes upstream's rows into `crates/ephyra-app/corpus/library-kinds.json`; `crates/ephyra-app/tests/library_kinds.rs` replays our walk against it. It already registers a `homevideos` library — but the tree's images are placeholders, so **the fixture needs photos carrying real EXIF** before any of this can be diffed. A generated JPEG with known tags is enough and is reproducible, which a downloaded one is not.
Author
Collaborator

Fixed, and landed on main at 7bbf49e0.

What is read

  • The EXIF, TIFF, PNG (eXIf/iTXt), WebP and XMP tags are read in crates/ephyra-images/src/exif.rs, behind ImageStore::tags. Write::photographed applies them the way PhotoProvider.cs does:
    • camera, exposure and location go into the item's data;
    • width and height come from the picture;
    • the date taken becomes DateCreated, PremiereDate and ProductionYear;
    • the name comes from the title unless the name is locked;
    • the comment fills Overview, with "" when there is none;
    • keywords, rating and orientation are also taken.
  • For title, comment, rating and keywords, XMP answers before EXIF, as measured against upstream.
  • A file whose container is not recognised (a damaged picture, .avif) is left untouched, as upstream's TagLib failure leaves it.
  • Only the first 16 MiB of a picture is read for its tags.
  • LibraryOptions.EnablePhotos gates pictures, photo albums, and the album beside a rip, the same three resolvers upstream gates.

Verified
The library-kinds tree carries a generated JPEG with known EXIF and XMP. cargo xtask reference gen-library-kinds records what upstream read under a read block. A comparison test in xtask/src/reference/kinds.rs holds all twelve stored photo fields, plus width, height, name, year and date, to our reader.

Filed separately

  • #222: XMP first for the remaining properties.
  • #224: the name of a fully locked photo.
  • #225: the photo fields are not served on BaseItemDto.
  • #226: an omitted EnablePhotos reads as false.
Fixed, and landed on `main` at `7bbf49e0`. **What is read** - The EXIF, TIFF, PNG (`eXIf`/`iTXt`), WebP and XMP tags are read in `crates/ephyra-images/src/exif.rs`, behind `ImageStore::tags`. `Write::photographed` applies them the way `PhotoProvider.cs` does: - camera, exposure and location go into the item's data; - width and height come from the picture; - the date taken becomes `DateCreated`, `PremiereDate` and `ProductionYear`; - the name comes from the title unless the name is locked; - the comment fills `Overview`, with `""` when there is none; - keywords, rating and orientation are also taken. - For title, comment, rating and keywords, XMP answers before EXIF, as measured against upstream. - A file whose container is not recognised (a damaged picture, `.avif`) is left untouched, as upstream's TagLib failure leaves it. - Only the first 16 MiB of a picture is read for its tags. - `LibraryOptions.EnablePhotos` gates pictures, photo albums, and the album beside a rip, the same three resolvers upstream gates. **Verified** The library-kinds tree carries a generated JPEG with known EXIF and XMP. `cargo xtask reference gen-library-kinds` records what upstream read under a `read` block. A comparison test in `xtask/src/reference/kinds.rs` holds all twelve stored photo fields, plus width, height, name, year and date, to our reader. **Filed separately** - #222: XMP first for the remaining properties. - #224: the name of a fully locked photo. - #225: the photo fields are not served on `BaseItemDto`. - #226: an omitted `EnablePhotos` reads as `false`.
Sign in to join this conversation.
No description provided.