feat: download original asset (#25302)

Co-authored-by: bwees <brandonwees@gmail.com>
This commit is contained in:
Daniel Dietzler
2026-01-16 13:05:13 -06:00
committed by GitHub
parent a2b03f7650
commit 07675a2de4
29 changed files with 354 additions and 11 deletions

View File

@@ -112,8 +112,18 @@
const { Cast } = $derived(getGlobalActions($t));
const { Share, Download, SharedLinkDownload, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } =
$derived(getAssetActions($t, asset));
const {
Share,
Download,
DownloadOriginal,
SharedLinkDownload,
Offline,
Favorite,
Unfavorite,
PlayMotionPhoto,
StopMotionPhoto,
Info,
} = $derived(getAssetActions($t, asset));
const sharedLink = getSharedLink();
// TODO: Enable when edits are ready for release
@@ -195,6 +205,7 @@
{/if}
<ActionMenuItem action={Download} />
<ActionMenuItem action={DownloadOriginal} />
{#if !isLocked}
{#if asset.isTrashed}

View File

@@ -25,7 +25,7 @@
if (assets.length === 1) {
clearSelect();
let asset = await getAssetInfo({ ...authManager.params, id: assets[0].id });
await handleDownloadAsset(asset);
await handleDownloadAsset(asset, { edited: true });
return;
}

View File

@@ -22,6 +22,7 @@ import { modalManager, toastManager, type ActionItem } from '@immich/ui';
import {
mdiAlertOutline,
mdiDownload,
mdiDownloadBox,
mdiHeart,
mdiHeartOutline,
mdiInformationOutline,
@@ -51,7 +52,15 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
shortcuts: { key: 'd', shift: true },
type: $t('assets'),
$if: () => !!currentAuthUser,
onAction: () => handleDownloadAsset(asset),
onAction: () => handleDownloadAsset(asset, { edited: true }),
};
const DownloadOriginal: ActionItem = {
title: $t('download_original'),
icon: mdiDownloadBox,
type: $t('assets'),
$if: () => !!currentAuthUser && asset.isEdited,
onAction: () => handleDownloadAsset(asset, { edited: false }),
};
const SharedLinkDownload: ActionItem = {
@@ -115,10 +124,21 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
shortcuts: [{ key: 'i' }],
};
return { Share, Download, SharedLinkDownload, Offline, Info, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto };
return {
Share,
Download,
DownloadOriginal,
SharedLinkDownload,
Offline,
Info,
Favorite,
Unfavorite,
PlayMotionPhoto,
StopMotionPhoto,
};
};
export const handleDownloadAsset = async (asset: AssetResponseDto) => {
export const handleDownloadAsset = async (asset: AssetResponseDto, { edited }: { edited: boolean }) => {
const $t = await getFormatter();
const assets = [
@@ -154,7 +174,12 @@ export const handleDownloadAsset = async (asset: AssetResponseDto) => {
try {
toastManager.success($t('downloading_asset_filename', { values: { filename: asset.originalFileName } }));
downloadUrl(getBaseUrl() + `/assets/${id}/original` + (queryParams ? `?${queryParams}` : ''), filename);
downloadUrl(
getBaseUrl() +
`/assets/${id}/original` +
(queryParams ? `?${queryParams}&edited=${edited}` : `?edited=${edited}`),
filename,
);
} catch (error) {
handleError(error, $t('errors.error_downloading', { values: { filename } }));
}

View File

@@ -30,6 +30,7 @@ export const assetFactory = Sync.makeFactory<AssetResponseDto>({
visibility: AssetVisibility.Timeline,
width: faker.number.int({ min: 100, max: 1000 }),
height: faker.number.int({ min: 100, max: 1000 }),
isEdited: false,
});
export const timelineAssetFactory = Sync.makeFactory<TimelineAsset>({