From 687e477ca5589501a23b690bacfc8fe041aea2cd Mon Sep 17 00:00:00 2001 From: Maurice Date: Mon, 9 Nov 2026 10:59:41 +0100 Subject: [PATCH] fix(synology): the asset lookup asks its two candidates without an await in a loop --- server/src/nest/memories/synology.service.ts | 53 ++++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/server/src/nest/memories/synology.service.ts b/server/src/nest/memories/synology.service.ts index 87a2d6107..1f06fb42d 100644 --- a/server/src/nest/memories/synology.service.ts +++ b/server/src/nest/memories/synology.service.ts @@ -740,29 +740,38 @@ export class SynologyService { // both are asked in turn, and only an item whose own thumbnail is this unit // counts: never a neighbour's capture time or GPS. const unit = Number(parsedId.id); - let lastFailure: ServiceResult = fail('Photo not found', 404); - for (const itemId of [unit, unit + 1]) { - const infoParams: ApiCallParams = { - api: 'SYNO.Foto.Browse.Item', - method: 'get', - version: 5, - id: `[${itemId}]`, - additional: ['thumbnail', 'resolution', 'exif', 'gps', 'address', 'orientation', 'description'], - }; - if (passphrase) infoParams.passphrase = passphrase; - const result = await this._requestSynologyApi<{ list: SynologyPhotoItem[] }>(targetUserId, infoParams); - if (!result.success) { - lastFailure = result as ServiceResult; - continue; - } - const metadata = result.data.list?.find((item) => this._isItemOfUnit(item, parsedId.id)); - if (!metadata) continue; + const own = await this._readItemOfUnit(targetUserId, unit, parsedId.id, passphrase); + const found = + own.success && own.data ? own : await this._readItemOfUnit(targetUserId, unit + 1, parsedId.id, passphrase); + if (!found.success) return found as ServiceResult; + if (!found.data) return fail('Photo not found', 404); - const normalized = this._normalizeSynologyPhotoInfo(metadata); - normalized.id = photoId; - return success(normalized); - } - return lastFailure; + const normalized = this._normalizeSynologyPhotoInfo(found.data); + normalized.id = photoId; + return success(normalized); + } + + /** + * One Browse.Item `get` by item id, answering the item only when its own + * thumbnail is the requested unit, and null when it belongs to another photo. + */ + private async _readItemOfUnit( + userId: number, + itemId: number, + unitId: string, + passphrase?: string, + ): Promise> { + const infoParams: ApiCallParams = { + api: 'SYNO.Foto.Browse.Item', + method: 'get', + version: 5, + id: `[${itemId}]`, + additional: ['thumbnail', 'resolution', 'exif', 'gps', 'address', 'orientation', 'description'], + }; + if (passphrase) infoParams.passphrase = passphrase; + const result = await this._requestSynologyApi<{ list: SynologyPhotoItem[] }>(userId, infoParams); + if (!result.success) return result as ServiceResult; + return success(result.data.list?.find((item) => this._isItemOfUnit(item, unitId)) ?? null); } /**