Example script: download every album's photos and metadata (closes #144)
check / check (push) Successful in 1m20s

`examples/download-albums.ts` logs in from `QUAK_EMAIL` and `QUAK_PASSWORD`, then walks every album from `await lib.fresh()`. For each photo it runs `photo.download()` to the photo's save path and writes `{savePath}.json`, which holds the photo's record and EXIF. For each album it writes `{dir}/albums/{collectionID}.json` with the album's name and its photos' save paths. A file is written only when its content changes, so a second run downloads and rewrites nothing.

The script opens the library with prefetching off, as `quak backup` does. The build type-checks `examples/`. The README says how to run it.

Model: opus-5-5
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
This commit was merged in pull request #150.
This commit is contained in:
2026-10-02 00:33:00 +02:00
committed by clawbot
parent d40f339c0b
commit 10afa7a7f4
5 changed files with 491 additions and 5 deletions
+38 -4
View File
@@ -80,6 +80,36 @@ await lib.close();
The lower-level `Client` (login, session serialization, and the raw
enumeration/download calls) is exported too and documented under Design below.
## Examples
`examples/download-albums.ts` downloads every album's photos and their metadata
into a directory, `photos` in the working directory unless you name another. The
build compiles it; run it after `yarn install`:
```bash
yarn build
QUAK_EMAIL=… QUAK_PASSWORD=… node dist/examples/download-albums.js [dir]
```
It opens the library with `precacheThumbnails` and `precacheOriginals` off, as
`quak backup` does, so the only file content it fetches is the originals it
saves. It asks on the terminal for a two-factor or email code when the account
requires one, and writes:
- each photo's original at its save path under `dir`, as `photo.download()`
writes it: `YYYY/YYYY-MM/YYYY-MM-DD/YYYY-MM-DD.<fileID>.<ext>`, and for a live
photo its image, its video and the `.livephoto.json` file naming them
- beside each original, a JSON file named after it with `.json` added, for
example `2026-03-01.12345.jpg.json`: the photo's record (`photo.record()`)
without its cache paths, and its EXIF fields (`photo.exif()`) under `exif`
- `albums/<collectionID>.json` for each album: its `collectionID`, its `name`,
and under `savePaths` the save paths of its photos relative to `dir`, newest
first
A photo in several albums is downloaded once. A second run downloads nothing and
rewrites only the JSON files whose content changed. A failed download stops the
run; running it again carries on, since every photo already saved is skipped.
## Entrypoints
This repository adheres to the
@@ -239,6 +269,9 @@ quak/
index.ts public library exports
bin/
quak.ts CLI entrypoint (commander.js)
examples/
download-albums.ts
download every album's photos and metadata
test/ unit + integration tests (vitest)
Makefile
Dockerfile lint phase, test phase, compile
@@ -247,10 +280,11 @@ quak/
```
`make build` compiles that tree into `dist/`, preserving its shape: the library
lands in `dist/src/` and the CLI in `dist/bin/quak.js`, which is what
`package.json` points `main`, `types` and `bin` at. The compiler's `rootDir` is
the repository root rather than `src/`, because `bin/` is compiled too and
`rootDir` has to contain everything that is compiled.
lands in `dist/src/`, the examples in `dist/examples/`, and the CLI in
`dist/bin/quak.js`, which is what `package.json` points `main`, `types` and
`bin` at. The compiler's `rootDir` is the repository root rather than `src/`,
because `bin/` is compiled too and `rootDir` has to contain everything that is
compiled.
### Cryptography