mirror of
https://github.com/immich-app/immich.git
synced 2025-06-05 14:44:41 -04:00
feat: use browser download manager for single file downloads (#17507)
* Fix download panel reactivity * Directly download individual files without buffering in memory * Fix shared link e2e download tests
This commit is contained in:
parent
43e3075f93
commit
9e49783e49
@ -48,7 +48,7 @@ test.describe('Shared Links', () => {
|
|||||||
await page.waitForSelector('[data-group] svg');
|
await page.waitForSelector('[data-group] svg');
|
||||||
await page.getByRole('checkbox').click();
|
await page.getByRole('checkbox').click();
|
||||||
await page.getByRole('button', { name: 'Download' }).click();
|
await page.getByRole('button', { name: 'Download' }).click();
|
||||||
await page.getByText('DOWNLOADING', { exact: true }).waitFor();
|
await page.waitForEvent('download');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('download all from shared link', async ({ page }) => {
|
test('download all from shared link', async ({ page }) => {
|
||||||
@ -56,6 +56,7 @@ test.describe('Shared Links', () => {
|
|||||||
await page.getByRole('heading', { name: 'Test Album' }).waitFor();
|
await page.getByRole('heading', { name: 'Test Album' }).waitFor();
|
||||||
await page.getByRole('button', { name: 'Download' }).click();
|
await page.getByRole('button', { name: 'Download' }).click();
|
||||||
await page.getByText('DOWNLOADING', { exact: true }).waitFor();
|
await page.getByText('DOWNLOADING', { exact: true }).waitFor();
|
||||||
|
await page.waitForEvent('download');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('enter password for a shared link', async ({ page }) => {
|
test('enter password for a shared link', async ({ page }) => {
|
||||||
|
@ -29,6 +29,7 @@ const update = (key: string, value: Partial<DownloadProgress> | null) => {
|
|||||||
const item = newState[key];
|
const item = newState[key];
|
||||||
Object.assign(item, value);
|
Object.assign(item, value);
|
||||||
item.percentage = Math.min(Math.floor((item.progress / item.total) * 100), 100);
|
item.percentage = Math.min(Math.floor((item.progress / item.total) * 100), 100);
|
||||||
|
newState[key] = { ...item };
|
||||||
|
|
||||||
return newState;
|
return newState;
|
||||||
});
|
});
|
||||||
|
@ -162,6 +162,18 @@ export const downloadBlob = (data: Blob, filename: string) => {
|
|||||||
URL.revokeObjectURL(url);
|
URL.revokeObjectURL(url);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const downloadUrl = (url: string, filename: string) => {
|
||||||
|
const anchor = document.createElement('a');
|
||||||
|
anchor.href = url;
|
||||||
|
anchor.download = filename;
|
||||||
|
|
||||||
|
document.body.append(anchor);
|
||||||
|
anchor.click();
|
||||||
|
anchor.remove();
|
||||||
|
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
};
|
||||||
|
|
||||||
export const downloadArchive = async (fileName: string, options: Omit<DownloadInfoDto, 'archiveSize'>) => {
|
export const downloadArchive = async (fileName: string, options: Omit<DownloadInfoDto, 'archiveSize'>) => {
|
||||||
const $preferences = get<UserPreferencesResponseDto | undefined>(preferences);
|
const $preferences = get<UserPreferencesResponseDto | undefined>(preferences);
|
||||||
const dto = { ...options, archiveSize: $preferences?.download.archiveSize };
|
const dto = { ...options, archiveSize: $preferences?.download.archiveSize };
|
||||||
@ -238,12 +250,8 @@ export const downloadFile = async (asset: AssetResponseDto) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const { filename, id, size } of assets) {
|
for (const { filename, id } of assets) {
|
||||||
const downloadKey = filename;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const abort = new AbortController();
|
|
||||||
downloadManager.add(downloadKey, size, abort);
|
|
||||||
const key = getKey();
|
const key = getKey();
|
||||||
|
|
||||||
notificationController.show({
|
notificationController.show({
|
||||||
@ -251,20 +259,9 @@ export const downloadFile = async (asset: AssetResponseDto) => {
|
|||||||
message: $t('downloading_asset_filename', { values: { filename: asset.originalFileName } }),
|
message: $t('downloading_asset_filename', { values: { filename: asset.originalFileName } }),
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO use sdk once it supports progress events
|
downloadUrl(getBaseUrl() + `/assets/${id}/original` + (key ? `?key=${key}` : ''), filename);
|
||||||
const { data } = await downloadRequest({
|
|
||||||
method: 'GET',
|
|
||||||
url: getBaseUrl() + `/assets/${id}/original` + (key ? `?key=${key}` : ''),
|
|
||||||
signal: abort.signal,
|
|
||||||
onDownloadProgress: (event) => downloadManager.update(downloadKey, event.loaded, event.total),
|
|
||||||
});
|
|
||||||
|
|
||||||
downloadBlob(data, filename);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleError(error, $t('errors.error_downloading', { values: { filename } }));
|
handleError(error, $t('errors.error_downloading', { values: { filename } }));
|
||||||
downloadManager.clear(downloadKey);
|
|
||||||
} finally {
|
|
||||||
setTimeout(() => downloadManager.clear(downloadKey), 5000);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user