fix(library): sync React photos state after scan and support case-insensitive existing photo lookup

This commit is contained in:
2026-10-08 20:50:18 +07:00
parent c26a4c21a7
commit f834d10762
4 changed files with 26 additions and 11 deletions
+7 -6
View File
@@ -796,15 +796,12 @@ function Catalogue() {
// roll, and the rows outside the folder being re-read are rows the
// reader is looking at.
if (!from) setDirs(result.dirs);
// No read back here. The reading handed its frames over as it stored
// them, and the screen watching it reads the catalogue back once the
// reading is done — the same read, half a beat later, and not a second
// one of the whole catalogue for a strip that is already drawn.
await reload();
} catch {
setNote(t('lib.failed'));
}
},
[t]
[reload, t]
);
// The folder this screen is on is read back to the disk on the way in, and again
@@ -1003,6 +1000,7 @@ function Catalogue() {
// numbers drawn over the column would count a roll down to a branch of itself.
// The column falls back on the catalogue until the reading is through.
const read = live ? live.progress.counts : null;
const liveDirs = live ? live.progress.dirs : null;
// Memoize photo count map derived from photos and dirs array separately so that
// live scan progress ticks (every 200ms) do not re-scan tens of thousands of photos.
const baseTreeInfo = useMemo(() => {
@@ -1032,8 +1030,11 @@ function Catalogue() {
if (normDir) add(normF, normDir, true);
}
for (const dir of dirs) add(dir.folder, dir.rel, false);
if (liveDirs) {
for (const dir of liveDirs) add(dir.folder, dir.rel, false);
}
return { hits, foldersUnder };
}, [photos, dirs]);
}, [photos, dirs, liveDirs]);
const nodes = useMemo<Node[]>(() => {
const { hits, foldersUnder } = baseTreeInfo;
+18 -4
View File
@@ -724,7 +724,12 @@ export async function scanFolder(
jump?: () => string | null,
from = ''
): Promise<ScanProgress> {
const known = new Map((await listPhotos(folder.name)).map((p) => [p.id, p]));
const rawKnown = await listPhotos(folder.name);
const known = new Map<string, LibraryPhoto>();
for (const p of rawKnown) {
known.set(p.id, p);
known.set(p.id.toLowerCase(), p);
}
// A reading kept to one folder keeps no position of its own. The position file
// belongs to the reading that walks the whole roll, and a fraction of the tree
// written into it would hand the next visit a roll with the rest of itself
@@ -808,9 +813,17 @@ export async function scanFolder(
counts[key.toLowerCase()] = counts[key];
}
};
for (const id of known.keys()) count(id.startsWith(`${normRoot}/`) ? id.slice(normRoot.length + 1) : id);
const relOfId = (id: string) => {
const normId = normPath(id);
const prefix = `${normRoot}/`.toLowerCase();
if (normId.toLowerCase().startsWith(prefix)) {
return normId.slice(normRoot.length + 1);
}
return normId;
};
for (const id of known.keys()) count(relOfId(id));
const knownPaths = new Set(
[...known.keys()].map((id) => (id.startsWith(`${normRoot}/`) ? id.slice(normRoot.length + 1) : id))
[...known.keys()].map((id) => relOfId(id))
);
const countedDiscovered = new Set<string>();
const countDiscovered = (rel: string) => {
@@ -825,8 +838,9 @@ export async function scanFolder(
// been read once before is a reading of a hundred thousand frames even while
// the walk is still up in its first folders, and one kept to a subfolder is
// measured against the frames under that one alone.
const heldPrefix = `${folder.name}/${from}`.toLowerCase();
const held = bounded
? [...known.keys()].filter((id) => id.startsWith(`${folder.name}/${from}`)).length
? [...known.keys()].filter((id) => id.toLowerCase().startsWith(heldPrefix)).length
: known.size;
// What the screen is told, and how often. The column is redrawn out of the
// count and the count moves with every frame, so telling the screen a frame at