1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2025-01-01 08:31:59 +00:00

feat(server): deterministic download order (#7658)

This commit is contained in:
Jason Rasmussen 2024-03-05 16:04:43 -05:00 committed by GitHub
parent 8df63b7c94
commit 972d5a3411
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 3 deletions

View file

@ -90,7 +90,10 @@ describe(DownloadService.name, () => {
};
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noWebpPath]);
assetMock.getByIds.mockResolvedValue([
{ ...assetStub.noResizePath, id: 'asset-1' },
{ ...assetStub.noWebpPath, id: 'asset-2' },
]);
storageMock.createZipStream.mockReturnValue(archiveMock);
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
@ -110,7 +113,33 @@ describe(DownloadService.name, () => {
};
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
assetMock.getByIds.mockResolvedValue([assetStub.noResizePath, assetStub.noResizePath]);
assetMock.getByIds.mockResolvedValue([
{ ...assetStub.noResizePath, id: 'asset-1' },
{ ...assetStub.noResizePath, id: 'asset-2' },
]);
storageMock.createZipStream.mockReturnValue(archiveMock);
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({
stream: archiveMock.stream,
});
expect(archiveMock.addFile).toHaveBeenCalledTimes(2);
expect(archiveMock.addFile).toHaveBeenNthCalledWith(1, 'upload/library/IMG_123.jpg', 'IMG_123.jpg');
expect(archiveMock.addFile).toHaveBeenNthCalledWith(2, 'upload/library/IMG_123.jpg', 'IMG_123+1.jpg');
});
it('should be deterministic', async () => {
const archiveMock = {
addFile: jest.fn(),
finalize: jest.fn(),
stream: new Readable(),
};
accessMock.asset.checkOwnerAccess.mockResolvedValue(new Set(['asset-1', 'asset-2']));
assetMock.getByIds.mockResolvedValue([
{ ...assetStub.noResizePath, id: 'asset-2' },
{ ...assetStub.noResizePath, id: 'asset-1' },
]);
storageMock.createZipStream.mockReturnValue(archiveMock);
await expect(sut.downloadArchive(authStub.admin, { assetIds: ['asset-1', 'asset-2'] })).resolves.toEqual({

View file

@ -81,9 +81,16 @@ export class DownloadService {
const zip = this.storageRepository.createZipStream();
const assets = await this.assetRepository.getByIds(dto.assetIds);
const assetMap = new Map(assets.map((asset) => [asset.id, asset]));
const paths: Record<string, number> = {};
for (const { originalPath, originalFileName } of assets) {
for (const assetId of dto.assetIds) {
const asset = assetMap.get(assetId);
if (!asset) {
continue;
}
const { originalPath, originalFileName } = asset;
const extension = extname(originalPath);
let filename = `${originalFileName}${extension}`;
const count = paths[filename] || 0;