quak collections reads the collection list alone (closes #210)
check / check (push) Canceled after 0s

On an empty cache the read commands opened their library with a refresh that fetched and decrypted the files of every collection in turn, printing nothing and storing nothing until it had them all, so `quak collections` seemed to hang on a large account. The new `lib.freshCollections()` is the fresh read of the collection list alone: one request, and nothing stored, so a later refresh still fetches every collection's files. The read commands open their library with the new `refreshOnOpen: false` and make only the refresh they ask for. A refresh sends a "progress" event after each collection whose files it fetched; the commands that wait on one print it on stderr, except with `--json`.

Model: opus-5-5
This commit was merged in pull request #214.
This commit is contained in:
2026-10-18 19:01:34 +02:00
parent 7ec71bf7ec
commit 982b878d69
9 changed files with 537 additions and 58 deletions
+16 -13
View File
@@ -2,12 +2,16 @@
//
// `collections`, `files --collection`, `get`, and `get-thumb` must answer for
// the account's state at the moment the command runs, not for whatever the
// local cache last happened to hold (owner amendment, issue #36). Each helper
// therefore forces a server round-trip through `Library.fresh()` and only then
// reads — so a collection, file, or metadata change made elsewhere is visible.
// local cache last happened to hold (owner amendment, issue #36). `files`,
// `get` and `get-thumb` therefore force a server round-trip through
// `Library.fresh()` and only then read — so a collection, file, or metadata
// change made elsewhere is visible. `collections` asks the library for the
// collection list alone through `Library.freshCollections()` (issue #210): a
// refresh would also fetch the files of every collection, which on a large
// account takes long and which `collections` does not print.
//
// `collections` and `files` also list in the library's own enumeration order —
// `listCollections()`/`listFiles()`, the order the pre-library CLI printed —
// `collections` lists in the server's order and `files` in the library's own
// enumeration order (`listFiles()`), the orders the pre-library CLI printed,
// rather than the `albums`/`photos` projection's newest-first order, which
// re-sorts the rows. The field values still come from each record's raw
// metadata via `cli-output.ts`.
@@ -17,23 +21,22 @@ import type { Photo, PhotosAPI } from "./library/index.js";
// The slice of `Library` these helpers read. `Library` satisfies it
// structurally; a test can drive them with a stand-in that records the
// `fresh()` call and serves records in a known enumeration order.
// `fresh()` and `freshCollections()` calls and serves records in a known
// enumeration order.
export interface FreshReadLibrary {
fresh(): Promise<unknown>;
listCollections(): Collection[];
freshCollections(): Promise<Collection[]>;
getCollection(id: number): Collection | undefined;
listFiles(collectionID: number): EnteFile[];
getFileByID(fileID: number): EnteFile | undefined;
photos: Pick<PhotosAPI, "byID">;
}
// Every live collection, current as of a forced refresh, in enumeration order.
export const freshCollections = async (
// Every live collection, current as of one collections request, in the
// server's order.
export const freshCollections = (
lib: FreshReadLibrary,
): Promise<Collection[]> => {
await lib.fresh();
return lib.listCollections();
};
): Promise<Collection[]> => lib.freshCollections();
// The files of one collection, current as of a forced refresh, in enumeration
// order. `undefined` (not an empty list) when the collection does not exist, so