fix: paginate Immich photo search — no longer limited to 200 — closes #137

The Immich metadata search was hardcoded to size: 200. Now paginates
through all results (1000 per page, up to 20k photos max).
This commit is contained in:
Maurice
2026-03-30 13:36:04 +02:00
parent 1166a09835
commit 7201380504
+26 -14
View File
@@ -77,20 +77,32 @@ router.post('/search', authenticate, async (req: Request, res: Response) => {
if (!user?.immich_url || !user?.immich_api_key) return res.status(400).json({ error: 'Immich not configured' }); if (!user?.immich_url || !user?.immich_api_key) return res.status(400).json({ error: 'Immich not configured' });
try { try {
const resp = await fetch(`${user.immich_url}/api/search/metadata`, { // Paginate through all results (Immich limits per-page to 1000)
method: 'POST', const allAssets: any[] = [];
headers: { 'x-api-key': user.immich_api_key, 'Content-Type': 'application/json' }, let page = 1;
body: JSON.stringify({ const pageSize = 1000;
takenAfter: from ? `${from}T00:00:00.000Z` : undefined, while (true) {
takenBefore: to ? `${to}T23:59:59.999Z` : undefined, const resp = await fetch(`${user.immich_url}/api/search/metadata`, {
type: 'IMAGE', method: 'POST',
size: 200, headers: { 'x-api-key': user.immich_api_key, 'Content-Type': 'application/json' },
}), body: JSON.stringify({
signal: AbortSignal.timeout(15000), takenAfter: from ? `${from}T00:00:00.000Z` : undefined,
}); takenBefore: to ? `${to}T23:59:59.999Z` : undefined,
if (!resp.ok) return res.status(resp.status).json({ error: 'Search failed' }); type: 'IMAGE',
const data = await resp.json() as { assets?: { items?: any[] } }; size: pageSize,
const assets = (data.assets?.items || []).map((a: any) => ({ page,
}),
signal: AbortSignal.timeout(15000),
});
if (!resp.ok) return res.status(resp.status).json({ error: 'Search failed' });
const data = await resp.json() as { assets?: { items?: any[] } };
const items = data.assets?.items || [];
allAssets.push(...items);
if (items.length < pageSize) break; // Last page
page++;
if (page > 20) break; // Safety limit (20k photos max)
}
const assets = allAssets.map((a: any) => ({
id: a.id, id: a.id,
takenAt: a.fileCreatedAt || a.createdAt, takenAt: a.fileCreatedAt || a.createdAt,
city: a.exifInfo?.city || null, city: a.exifInfo?.city || null,