Photo: save path, is-local, content bytes, metadata and EXIF getters (closes #141)
check / check (push) Successful in 1m24s
check / check (push) Successful in 1m24s
`Photo` gains:
- `savePath` and `isLocal`: synchronous, disk only. Where `lib.backup()` writes the original under the library's `downloadDirectory`, and whether all of it is there; a copy only in the cache does not count.
- `content()` and `exif()`: async, may download. `exif()` reads the common EXIF fields of a JPEG and returns `{}` for anything else.
- The getters `modifiedAt` and `hash`, also on `PhotoRecord`, and `year`.
For a live photo the backup has not stored yet, `savePath` carries the title's extension, and the image may be stored under a different one. The JPEG EXIF scan moved to `src/exif.ts`. The exported `PhotoContent` interface gains `savePath` and `isLocal`.
Judgement call: `iso` is read only when the file stores it as a single number.
Model: opus-5-5
This commit was merged in pull request #142.
This commit is contained in:
@@ -224,6 +224,7 @@ quak/
|
||||
backup.ts resilient full-account backup with dedup
|
||||
metadata-backup.ts
|
||||
backup-metadata: the metadata quak keeps, as JSON
|
||||
exif.ts EXIF read from a JPEG's bytes
|
||||
mldata-fetch.ts fetch + decrypt per-file ML data
|
||||
filename.ts safe file names from server metadata
|
||||
errors.ts error types shared across layers
|
||||
@@ -692,16 +693,42 @@ https://git.eeqj.de/sneak/quak/issues/75).
|
||||
|
||||
An `Album` exposes its record fields and `album.photos.list()` → `Photo[]`
|
||||
(newest first). A `Photo` exposes its record fields other than `thumbnailPath`
|
||||
and `originalPath`, `photo.record()` → `PhotoRecord`, and two content methods:
|
||||
and `originalPath`, and `photo.year`, the local-time year of `takenAt`, all as
|
||||
synchronous getters read from RAM; `photo.record()` → `PhotoRecord`. Two more
|
||||
synchronous getters look at the disk and never touch the network:
|
||||
|
||||
- `photo.savePath` → `string | undefined` — where `lib.backup()` writes the
|
||||
original, `originals/<fileID>.<ext>` under the `downloadDirectory` the library
|
||||
was opened with, whether or not it is there yet: for a live photo already
|
||||
stored, its image. For a live photo not yet stored, it carries the title's
|
||||
extension, and the backup may store the image under a different one, found
|
||||
inside the live photo. `undefined` when the library has no `downloadDirectory`
|
||||
or no content source.
|
||||
- `photo.isLocal` → `boolean` — whether the whole original is at `savePath`.
|
||||
|
||||
Four async methods may download:
|
||||
|
||||
- `await photo.original(opts?)` → `{ path, bytes, videoPath? }` — the
|
||||
full-resolution file. For a live photo, `path` and `bytes` are its image's and
|
||||
`videoPath` is its video.
|
||||
- `await photo.thumbnail(opts?)` → `{ path, bytes }`.
|
||||
- `await photo.content(opts?)` → `Uint8Array` — the original's bytes, read
|
||||
through `original()`; for a live photo, its image's.
|
||||
- `await photo.exif(opts?)` → `PhotoExif` — `make`, `model`, `lensModel`,
|
||||
`dateTimeOriginal`, `offsetTimeOriginal`, `exposureTime`, `fNumber`, `iso`,
|
||||
`focalLength`, `orientation`, `gpsLatitude`, `gpsLongitude` and `gpsAltitude`,
|
||||
each absent when the file lacks it. GPS values are signed decimal degrees and
|
||||
metres. `dateTimeOriginal` is the camera's clock reading held in the `Date`'s
|
||||
UTC fields; `offsetTimeOriginal`, when present, is that clock's offset from
|
||||
UTC. Only a JPEG's EXIF is read: any other original gives `{}`, and a video
|
||||
gives `{}` without being downloaded.
|
||||
|
||||
Both serve from the on-disk content cache when the bytes are present and
|
||||
otherwise fetch through the pools; `opts.onProgress` reports per-file progress.
|
||||
They throw when the library was opened without a content source.
|
||||
They serve from the on-disk content cache when the bytes are present and
|
||||
otherwise fetch through the pools; `original()`, `content()` and `exif()` also
|
||||
serve an original the backup has already stored. `opts.onProgress` reports
|
||||
per-file progress. They throw when the library was opened without a content
|
||||
source. An original that `content()` or `exif()` downloads lands in the cache,
|
||||
which does not make `isLocal` true; only `lib.backup()` does.
|
||||
|
||||
Lower-level accessors that return decrypted model objects (which hold key
|
||||
material) are also available: `listCollections()`, `getCollection(id)`,
|
||||
@@ -713,10 +740,12 @@ material) are also available: `listCollections()`, `getCollection(id)`,
|
||||
The GUI-facing records hold no key material and no binary, so they survive
|
||||
`structuredClone`/JSON across the Electron IPC boundary:
|
||||
|
||||
- `PhotoRecord`: `fileID`, `albumIDs`, `title`, `takenAt` (milliseconds),
|
||||
`fileType`, optional `caption` / `width` / `height` / `latitude` /
|
||||
`longitude`, `isArchived`, `isHidden`, and `thumbnailPath` / `originalPath`
|
||||
once the bytes are cached (for a live photo, `originalPath` is its image).
|
||||
- `PhotoRecord`: `fileID`, `albumIDs`, `title`, `takenAt` and `modifiedAt`
|
||||
(milliseconds), `fileType`, optional `caption` / `width` / `height` /
|
||||
`latitude` / `longitude`, optional `hash` (the content hash recorded at
|
||||
upload; very old files have none), `isArchived`, `isHidden`, and
|
||||
`thumbnailPath` / `originalPath` once the bytes are cached (for a live photo,
|
||||
`originalPath` is its image).
|
||||
- `AlbumRecord`: `collectionID`, `name`, `type`, `isShared`, `updationTime`, and
|
||||
`fileIDs` (newest first).
|
||||
- `LibrarySnapshot`: `{ albums, photos, takenAt }`.
|
||||
@@ -811,6 +840,7 @@ from a very old client, is stored unchecked.
|
||||
- `src/library/records.ts`: `PhotoRecord`, `AlbumRecord`, `LibrarySnapshot`,
|
||||
`LibraryChange`
|
||||
- `src/library/mlsearch.ts`: `MLDataAPI`, `SimilarResult`
|
||||
- `src/exif.ts`: `PhotoExif`
|
||||
- `src/library/pools.ts`: `RequestPools`, `RequestPoolsOptions`, `BoundedPool`
|
||||
- `src/backup.ts`: `BackupOptions`, `BackupResult`, `BackupError`
|
||||
- `src/client.ts`: `Client`, `LoginOptions`, `ClientSnapshot`
|
||||
|
||||
Reference in New Issue
Block a user