On-disk content and thumbnail cache with per-photo fetch and prefetch (closes #46)
check / check (push) Successful in 33s

Adds the on-disk content and thumbnail cache keyed by fileID: originals/ and thumbnails/ under cacheDirectory, present-means-complete (streaming atomic rename), orphan temp reaping on open. Photo.original/thumbnail return a cached path with no network when present, else fetch through the shared request pool; thumbnails.ensure drives the thumbnail pool with priority, dedup and AbortSignal. One shared RequestPools set serves both the ML fetch and the content cache. Content-hash integrity is deferred (#68); authenticated streaming decrypt guarantees integrity now.

Model: opus-4-8
This commit was merged in pull request #66.
This commit is contained in:
2026-09-22 18:38:22 +02:00
parent 61dfec8d38
commit 5db59a6e2b
9 changed files with 1179 additions and 19 deletions
+16
View File
@@ -166,11 +166,20 @@ const toAlbumRecord = (
};
};
// The cache paths known for a file, so the projection can expose them on the
// record without the read layer reaching into the content cache itself.
export type CachedPathLookup = (fileID: number) => {
originalPath?: string;
thumbnailPath?: string;
};
// Project the decrypted collections and file memberships into by-id records.
// `files` is every membership (a file appears once per collection it is in).
// `cachedPaths`, when given, fills each record's cache paths.
export const deriveRecords = (
collections: Collection[],
files: EnteFile[],
cachedPaths?: CachedPathLookup,
): DerivedRecords => {
const byFileID = new Map<number, EnteFile[]>();
for (const f of files) {
@@ -183,6 +192,13 @@ export const deriveRecords = (
const takenAtByFile = new Map<number, number>();
for (const [fileID, memberships] of byFileID) {
const record = toPhotoRecord(fileID, memberships);
if (cachedPaths) {
const paths = cachedPaths(fileID);
if (paths.originalPath !== undefined)
record.originalPath = paths.originalPath;
if (paths.thumbnailPath !== undefined)
record.thumbnailPath = paths.thumbnailPath;
}
photos.set(fileID, record);
takenAtByFile.set(fileID, record.takenAt);
}