fix(synology): use Thumbnail API with size xl for originals to avoid HEIC

Replace SYNO.Foto.Download with SYNO.Foto.Thumbnail (size=xl) for the
original kind, mirroring the Immich approach. Synology's download endpoint
returns the raw file (HEIC for iPhone photos), while the Thumbnail API
always serves a browser-compatible JPEG render.
This commit is contained in:
jubnl
2026-04-17 15:35:42 +02:00
parent 5046e1a2e0
commit 1963573db4
2 changed files with 14 additions and 31 deletions
+14 -21
View File
@@ -637,27 +637,20 @@ export async function streamSynologyAsset(
//size: 'sm' 240px| 'm' 320px| 'xl' 1280px| 'preview' ? //size: 'sm' 240px| 'm' 320px| 'xl' 1280px| 'preview' ?
const resolvedSize = size || 'sm'; // Use Thumbnail API for both thumbnail and original — avoids serving raw HEIC files
const params = kind === 'thumbnail' // (original uses xl size to get a full-resolution JPEG-compatible render)
? new URLSearchParams({ const resolvedSize = kind === 'original' ? 'xl' : (size || 'sm');
api: 'SYNO.Foto.Thumbnail', const params = new URLSearchParams({
method: 'get', api: 'SYNO.Foto.Thumbnail',
version: '2', method: 'get',
mode: 'download', version: '2',
id: parsedId.id, mode: 'download',
type: 'unit', id: parsedId.id,
size: resolvedSize, type: 'unit',
cache_key: parsedId.cacheKey, size: resolvedSize,
_sid: sid.data, cache_key: parsedId.cacheKey,
}) _sid: sid.data,
: new URLSearchParams({ });
api: 'SYNO.Foto.Download',
method: 'download',
version: '2',
cache_key: parsedId.cacheKey,
unit_id: `[${parsedId.id}]`,
_sid: sid.data,
});
if (passphrase) params.append('passphrase', passphrase); if (passphrase) params.append('passphrase', passphrase);
const url = _buildSynologyEndpoint(synology_credentials.data.synology_url, params.toString()); const url = _buildSynologyEndpoint(synology_credentials.data.synology_url, params.toString());
@@ -166,16 +166,6 @@ vi.mock('../../src/utils/ssrfGuard', async () => {
}); });
} }
// Original download
if (apiName === 'SYNO.Foto.Download') {
const imageBytes = Buffer.from('fake-synology-original');
return Promise.resolve({
ok: true, status: 200,
headers: { get: (h: string) => h === 'content-type' ? 'image/jpeg' : null },
body: new ReadableStream({ start(c) { c.enqueue(imageBytes); c.close(); } }),
});
}
return Promise.reject(new Error(`Unexpected safeFetch call to Synology: ${u}, api=${apiName}`)); return Promise.reject(new Error(`Unexpected safeFetch call to Synology: ${u}, api=${apiName}`));
} }