mirror of
https://github.com/samsonjs/immich.git
synced 2026-04-27 15:07:45 +00:00
refactor: download action (#25124)
This commit is contained in:
parent
ef4aec7398
commit
4f803832ad
9 changed files with 109 additions and 103 deletions
|
|
@ -1,4 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { isEnabled } from '$lib/utils';
|
||||||
import { IconButton, type ActionItem } from '@immich/ui';
|
import { IconButton, type ActionItem } from '@immich/ui';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -9,6 +10,6 @@
|
||||||
const { title, icon, color = 'secondary', onAction } = $derived(action);
|
const { title, icon, color = 'secondary', onAction } = $derived(action);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if icon && (action.$if?.() ?? true)}
|
{#if icon && isEnabled(action)}
|
||||||
<IconButton variant="ghost" shape="round" {color} {icon} aria-label={title} onclick={() => onAction(action)} />
|
<IconButton variant="ghost" shape="round" {color} {icon} aria-label={title} onclick={() => onAction(action)} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
||||||
16
web/src/lib/components/ActionMenuItem.svelte
Normal file
16
web/src/lib/components/ActionMenuItem.svelte
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
||||||
|
import { isEnabled } from '$lib/utils';
|
||||||
|
import { type ActionItem } from '@immich/ui';
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
action: ActionItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
const { action }: Props = $props();
|
||||||
|
const { title, icon, onAction } = $derived(action);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if icon && isEnabled(action)}
|
||||||
|
<MenuOption {icon} text={title} onClick={() => onAction(action)} />
|
||||||
|
{/if}
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import { shortcut } from '$lib/actions/shortcut';
|
|
||||||
import MenuOption from '$lib/components/shared-components/context-menu/menu-option.svelte';
|
|
||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
|
||||||
import type { TimelineAsset } from '$lib/managers/timeline-manager/types';
|
|
||||||
import { downloadFile } from '$lib/utils/asset-utils';
|
|
||||||
import { getAssetInfo } from '@immich/sdk';
|
|
||||||
import { IconButton } from '@immich/ui';
|
|
||||||
import { mdiDownload } from '@mdi/js';
|
|
||||||
import { t } from 'svelte-i18n';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
asset: TimelineAsset;
|
|
||||||
menuItem?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
let { asset, menuItem = false }: Props = $props();
|
|
||||||
|
|
||||||
const onDownloadFile = async () => downloadFile(await getAssetInfo({ ...authManager.params, id: asset.id }));
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<svelte:document use:shortcut={{ shortcut: { key: 'd', shift: true }, onShortcut: onDownloadFile }} />
|
|
||||||
|
|
||||||
{#if !menuItem}
|
|
||||||
<IconButton
|
|
||||||
color="secondary"
|
|
||||||
shape="round"
|
|
||||||
variant="ghost"
|
|
||||||
icon={mdiDownload}
|
|
||||||
aria-label={$t('download')}
|
|
||||||
onclick={onDownloadFile}
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<MenuOption icon={mdiDownload} text={$t('download')} onClick={onDownloadFile} />
|
|
||||||
{/if}
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
import { goto } from '$app/navigation';
|
import { goto } from '$app/navigation';
|
||||||
import { resolve } from '$app/paths';
|
import { resolve } from '$app/paths';
|
||||||
import ActionButton from '$lib/components/ActionButton.svelte';
|
import ActionButton from '$lib/components/ActionButton.svelte';
|
||||||
|
import ActionMenuItem from '$lib/components/ActionMenuItem.svelte';
|
||||||
import type { OnAction, PreAction } from '$lib/components/asset-viewer/actions/action';
|
import type { OnAction, PreAction } from '$lib/components/asset-viewer/actions/action';
|
||||||
import AddToAlbumAction from '$lib/components/asset-viewer/actions/add-to-album-action.svelte';
|
import AddToAlbumAction from '$lib/components/asset-viewer/actions/add-to-album-action.svelte';
|
||||||
import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte';
|
import AddToStackAction from '$lib/components/asset-viewer/actions/add-to-stack-action.svelte';
|
||||||
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
|
import ArchiveAction from '$lib/components/asset-viewer/actions/archive-action.svelte';
|
||||||
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
|
import DeleteAction from '$lib/components/asset-viewer/actions/delete-action.svelte';
|
||||||
import DownloadAction from '$lib/components/asset-viewer/actions/download-action.svelte';
|
|
||||||
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
|
import KeepThisDeleteOthersAction from '$lib/components/asset-viewer/actions/keep-this-delete-others.svelte';
|
||||||
import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte';
|
import RatingAction from '$lib/components/asset-viewer/actions/rating-action.svelte';
|
||||||
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte';
|
import RemoveAssetFromStack from '$lib/components/asset-viewer/actions/remove-asset-from-stack.svelte';
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
|
import { photoViewerImgElement } from '$lib/stores/assets-store.svelte';
|
||||||
import { user } from '$lib/stores/user.store';
|
import { user } from '$lib/stores/user.store';
|
||||||
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
import { photoZoomState } from '$lib/stores/zoom-image.store';
|
||||||
import { getAssetJobName, getSharedLink, withoutIcons } from '$lib/utils';
|
import { getAssetJobName, withoutIcons } from '$lib/utils';
|
||||||
import type { OnUndoDelete } from '$lib/utils/actions';
|
import type { OnUndoDelete } from '$lib/utils/actions';
|
||||||
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
import { canCopyImageToClipboard } from '$lib/utils/asset-utils';
|
||||||
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
import { toTimelineAsset } from '$lib/utils/timeline-util';
|
||||||
|
|
@ -96,9 +96,7 @@
|
||||||
setPlayOriginalVideo,
|
setPlayOriginalVideo,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
const sharedLink = getSharedLink();
|
|
||||||
let isOwner = $derived($user && asset.ownerId === $user?.id);
|
let isOwner = $derived($user && asset.ownerId === $user?.id);
|
||||||
let showDownloadButton = $derived(sharedLink ? sharedLink.allowDownload : !asset.isOffline);
|
|
||||||
let isLocked = $derived(asset.visibility === AssetVisibility.Locked);
|
let isLocked = $derived(asset.visibility === AssetVisibility.Locked);
|
||||||
let smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch);
|
let smartSearchEnabled = $derived(featureFlagsManager.value.smartSearch);
|
||||||
|
|
||||||
|
|
@ -113,9 +111,8 @@
|
||||||
|
|
||||||
const { Cast } = $derived(getGlobalActions($t));
|
const { Cast } = $derived(getGlobalActions($t));
|
||||||
|
|
||||||
const { Share, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } = $derived(
|
const { Share, Download, SharedLinkDownload, Offline, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto, Info } =
|
||||||
getAssetActions($t, asset),
|
$derived(getAssetActions($t, asset));
|
||||||
);
|
|
||||||
|
|
||||||
// $: showEditorButton =
|
// $: showEditorButton =
|
||||||
// isOwner &&
|
// isOwner &&
|
||||||
|
|
@ -169,10 +166,7 @@
|
||||||
/>
|
/>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if !isOwner && showDownloadButton}
|
<ActionButton action={SharedLinkDownload} />
|
||||||
<DownloadAction asset={toTimelineAsset(asset)} />
|
|
||||||
{/if}
|
|
||||||
|
|
||||||
<ActionButton action={Info} />
|
<ActionButton action={Info} />
|
||||||
<ActionButton action={Favorite} />
|
<ActionButton action={Favorite} />
|
||||||
<ActionButton action={Unfavorite} />
|
<ActionButton action={Unfavorite} />
|
||||||
|
|
@ -188,9 +182,8 @@
|
||||||
{#if showSlideshow && !isLocked}
|
{#if showSlideshow && !isLocked}
|
||||||
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
<MenuOption icon={mdiPresentationPlay} text={$t('slideshow')} onClick={onPlaySlideshow} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if showDownloadButton}
|
|
||||||
<DownloadAction asset={toTimelineAsset(asset)} menuItem />
|
<ActionMenuItem action={Download} />
|
||||||
{/if}
|
|
||||||
|
|
||||||
{#if !isLocked}
|
{#if !isLocked}
|
||||||
{#if asset.isTrashed}
|
{#if asset.isTrashed}
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
import { shortcut as bindShortcut, shortcutLabel as computeShortcutLabel } from '$lib/actions/shortcut';
|
import { shortcut as bindShortcut, shortcutLabel as computeShortcutLabel } from '$lib/actions/shortcut';
|
||||||
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
|
import { optionClickCallbackStore, selectedIdStore } from '$lib/stores/context-menu.store';
|
||||||
import { generateId } from '$lib/utils/generate-id';
|
import { generateId } from '$lib/utils/generate-id';
|
||||||
import { Icon } from '@immich/ui';
|
import { Icon, type IconLike } from '@immich/ui';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
text: string;
|
text: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
icon?: string;
|
icon?: IconLike;
|
||||||
activeColor?: string;
|
activeColor?: string;
|
||||||
textColor?: string;
|
textColor?: string;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
let {
|
let {
|
||||||
text,
|
text,
|
||||||
subtitle = '',
|
subtitle = '',
|
||||||
icon = '',
|
icon,
|
||||||
activeColor = 'bg-slate-300',
|
activeColor = 'bg-slate-300',
|
||||||
textColor = 'text-immich-fg dark:text-immich-dark-bg',
|
textColor = 'text-immich-fg dark:text-immich-dark-bg',
|
||||||
onClick,
|
onClick,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,8 @@
|
||||||
|
|
||||||
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
import { getAssetControlContext } from '$lib/components/timeline/AssetSelectControlBar.svelte';
|
||||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { downloadArchive, downloadFile } from '$lib/utils/asset-utils';
|
import { handleDownloadAsset } from '$lib/services/asset.service';
|
||||||
|
import { downloadArchive } from '$lib/utils/asset-utils';
|
||||||
import { getAssetInfo } from '@immich/sdk';
|
import { getAssetInfo } from '@immich/sdk';
|
||||||
import { IconButton } from '@immich/ui';
|
import { IconButton } from '@immich/ui';
|
||||||
import { mdiDownload } from '@mdi/js';
|
import { mdiDownload } from '@mdi/js';
|
||||||
|
|
@ -24,7 +25,7 @@
|
||||||
if (assets.length === 1) {
|
if (assets.length === 1) {
|
||||||
clearSelect();
|
clearSelect();
|
||||||
let asset = await getAssetInfo({ ...authManager.params, id: assets[0].id });
|
let asset = await getAssetInfo({ ...authManager.params, id: assets[0].id });
|
||||||
await downloadFile(asset);
|
await handleDownloadAsset(asset);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,27 @@
|
||||||
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
|
import { assetViewerManager } from '$lib/managers/asset-viewer-manager.svelte';
|
||||||
|
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||||
import { eventManager } from '$lib/managers/event-manager.svelte';
|
import { eventManager } from '$lib/managers/event-manager.svelte';
|
||||||
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
import SharedLinkCreateModal from '$lib/modals/SharedLinkCreateModal.svelte';
|
||||||
import { user as authUser } from '$lib/stores/user.store';
|
import { user as authUser, preferences } from '$lib/stores/user.store';
|
||||||
|
import { getSharedLink, sleep } from '$lib/utils';
|
||||||
|
import { downloadUrl } from '$lib/utils/asset-utils';
|
||||||
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
import { openFileUploadDialog } from '$lib/utils/file-uploader';
|
||||||
import { handleError } from '$lib/utils/handle-error';
|
import { handleError } from '$lib/utils/handle-error';
|
||||||
import { getFormatter } from '$lib/utils/i18n';
|
import { getFormatter } from '$lib/utils/i18n';
|
||||||
import { AssetVisibility, copyAsset, deleteAssets, updateAsset, type AssetResponseDto } from '@immich/sdk';
|
import { asQueryString } from '$lib/utils/shared-links';
|
||||||
|
import {
|
||||||
|
AssetVisibility,
|
||||||
|
copyAsset,
|
||||||
|
deleteAssets,
|
||||||
|
getAssetInfo,
|
||||||
|
getBaseUrl,
|
||||||
|
updateAsset,
|
||||||
|
type AssetResponseDto,
|
||||||
|
} from '@immich/sdk';
|
||||||
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
import { modalManager, toastManager, type ActionItem } from '@immich/ui';
|
||||||
import {
|
import {
|
||||||
mdiAlertOutline,
|
mdiAlertOutline,
|
||||||
|
mdiDownload,
|
||||||
mdiHeart,
|
mdiHeart,
|
||||||
mdiHeartOutline,
|
mdiHeartOutline,
|
||||||
mdiInformationOutline,
|
mdiInformationOutline,
|
||||||
|
|
@ -20,6 +33,7 @@ import type { MessageFormatter } from 'svelte-i18n';
|
||||||
import { get } from 'svelte/store';
|
import { get } from 'svelte/store';
|
||||||
|
|
||||||
export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) => {
|
export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) => {
|
||||||
|
const sharedLink = getSharedLink();
|
||||||
const currentAuthUser = get(authUser);
|
const currentAuthUser = get(authUser);
|
||||||
const isOwner = !!(currentAuthUser && currentAuthUser.id === asset.ownerId);
|
const isOwner = !!(currentAuthUser && currentAuthUser.id === asset.ownerId);
|
||||||
|
|
||||||
|
|
@ -31,6 +45,20 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
|
||||||
onAction: () => modalManager.show(SharedLinkCreateModal, { assetIds: [asset.id] }),
|
onAction: () => modalManager.show(SharedLinkCreateModal, { assetIds: [asset.id] }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const Download: ActionItem = {
|
||||||
|
title: $t('download'),
|
||||||
|
icon: mdiDownload,
|
||||||
|
shortcuts: { key: 'd', shift: true },
|
||||||
|
type: $t('assets'),
|
||||||
|
$if: () => !!currentAuthUser,
|
||||||
|
onAction: () => handleDownloadAsset(asset),
|
||||||
|
};
|
||||||
|
|
||||||
|
const SharedLinkDownload: ActionItem = {
|
||||||
|
...Download,
|
||||||
|
$if: () => !currentAuthUser && sharedLink && sharedLink.allowDownload,
|
||||||
|
};
|
||||||
|
|
||||||
const PlayMotionPhoto: ActionItem = {
|
const PlayMotionPhoto: ActionItem = {
|
||||||
title: $t('play_motion_photo'),
|
title: $t('play_motion_photo'),
|
||||||
icon: mdiMotionPlayOutline,
|
icon: mdiMotionPlayOutline,
|
||||||
|
|
@ -87,7 +115,50 @@ export const getAssetActions = ($t: MessageFormatter, asset: AssetResponseDto) =
|
||||||
shortcuts: [{ key: 'i' }],
|
shortcuts: [{ key: 'i' }],
|
||||||
};
|
};
|
||||||
|
|
||||||
return { Share, Offline, Info, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto };
|
return { Share, Download, SharedLinkDownload, Offline, Info, Favorite, Unfavorite, PlayMotionPhoto, StopMotionPhoto };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const handleDownloadAsset = async (asset: AssetResponseDto) => {
|
||||||
|
const $t = await getFormatter();
|
||||||
|
|
||||||
|
const assets = [
|
||||||
|
{
|
||||||
|
filename: asset.originalFileName,
|
||||||
|
id: asset.id,
|
||||||
|
size: asset.exifInfo?.fileSizeInByte || 0,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const isAndroidMotionVideo = (asset: AssetResponseDto) => {
|
||||||
|
return asset.originalPath.includes('encoded-video');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (asset.livePhotoVideoId) {
|
||||||
|
const motionAsset = await getAssetInfo({ ...authManager.params, id: asset.livePhotoVideoId });
|
||||||
|
if (!isAndroidMotionVideo(motionAsset) || get(preferences)?.download.includeEmbeddedVideos) {
|
||||||
|
assets.push({
|
||||||
|
filename: motionAsset.originalFileName,
|
||||||
|
id: asset.livePhotoVideoId,
|
||||||
|
size: motionAsset.exifInfo?.fileSizeInByte || 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const queryParams = asQueryString(authManager.params);
|
||||||
|
|
||||||
|
for (const [i, { filename, id }] of assets.entries()) {
|
||||||
|
if (i !== 0) {
|
||||||
|
// play nice with Safari
|
||||||
|
await sleep(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
toastManager.success($t('downloading_asset_filename', { values: { filename: asset.originalFileName } }));
|
||||||
|
downloadUrl(getBaseUrl() + `/assets/${id}/original` + (queryParams ? `?${queryParams}` : ''), filename);
|
||||||
|
} catch (error) {
|
||||||
|
handleError(error, $t('errors.error_downloading', { values: { filename } }));
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleFavorite = async (asset: AssetResponseDto) => {
|
const handleFavorite = async (asset: AssetResponseDto) => {
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ import {
|
||||||
type SharedLinkResponseDto,
|
type SharedLinkResponseDto,
|
||||||
type UserResponseDto,
|
type UserResponseDto,
|
||||||
} from '@immich/sdk';
|
} from '@immich/sdk';
|
||||||
import { toastManager, type ActionItem } from '@immich/ui';
|
import { toastManager, type ActionItem, type IfLike } from '@immich/ui';
|
||||||
import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiHeadSyncOutline, mdiImageRefreshOutline } from '@mdi/js';
|
import { mdiCogRefreshOutline, mdiDatabaseRefreshOutline, mdiHeadSyncOutline, mdiImageRefreshOutline } from '@mdi/js';
|
||||||
import { init, register, t } from 'svelte-i18n';
|
import { init, register, t } from 'svelte-i18n';
|
||||||
import { derived, get } from 'svelte/store';
|
import { derived, get } from 'svelte/store';
|
||||||
|
|
@ -443,3 +443,5 @@ export const semverToName = ({ major, minor, patch }: ServerVersionResponseDto)
|
||||||
|
|
||||||
export const withoutIcons = (actions: ActionItem[]): ActionItem[] =>
|
export const withoutIcons = (actions: ActionItem[]): ActionItem[] =>
|
||||||
actions.map((action) => ({ ...action, icon: undefined }));
|
actions.map((action) => ({ ...action, icon: undefined }));
|
||||||
|
|
||||||
|
export const isEnabled = ({ $if }: IfLike) => $if?.() ?? true;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { assetsSnapshot } from '$lib/managers/timeline-manager/utils.svelte';
|
||||||
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
import type { AssetInteraction } from '$lib/stores/asset-interaction.svelte';
|
||||||
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
import { isSelectingAllAssets } from '$lib/stores/assets-store.svelte';
|
||||||
import { preferences } from '$lib/stores/user.store';
|
import { preferences } from '$lib/stores/user.store';
|
||||||
import { downloadRequest, sleep, withError } from '$lib/utils';
|
import { downloadRequest, withError } from '$lib/utils';
|
||||||
import { getByteUnitString } from '$lib/utils/byte-units';
|
import { getByteUnitString } from '$lib/utils/byte-units';
|
||||||
import { getFormatter } from '$lib/utils/i18n';
|
import { getFormatter } from '$lib/utils/i18n';
|
||||||
import { navigate } from '$lib/utils/navigation';
|
import { navigate } from '$lib/utils/navigation';
|
||||||
|
|
@ -23,7 +23,6 @@ import {
|
||||||
createStack,
|
createStack,
|
||||||
deleteAssets,
|
deleteAssets,
|
||||||
deleteStacks,
|
deleteStacks,
|
||||||
getAssetInfo,
|
|
||||||
getBaseUrl,
|
getBaseUrl,
|
||||||
getDownloadInfo,
|
getDownloadInfo,
|
||||||
getStack,
|
getStack,
|
||||||
|
|
@ -232,48 +231,6 @@ export const downloadArchive = async (fileName: string, options: Omit<DownloadIn
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const downloadFile = async (asset: AssetResponseDto) => {
|
|
||||||
const $t = get(t);
|
|
||||||
const assets = [
|
|
||||||
{
|
|
||||||
filename: asset.originalFileName,
|
|
||||||
id: asset.id,
|
|
||||||
size: asset.exifInfo?.fileSizeInByte || 0,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const isAndroidMotionVideo = (asset: AssetResponseDto) => {
|
|
||||||
return asset.originalPath.includes('encoded-video');
|
|
||||||
};
|
|
||||||
|
|
||||||
if (asset.livePhotoVideoId) {
|
|
||||||
const motionAsset = await getAssetInfo({ ...authManager.params, id: asset.livePhotoVideoId });
|
|
||||||
if (!isAndroidMotionVideo(motionAsset) || get(preferences)?.download.includeEmbeddedVideos) {
|
|
||||||
assets.push({
|
|
||||||
filename: motionAsset.originalFileName,
|
|
||||||
id: asset.livePhotoVideoId,
|
|
||||||
size: motionAsset.exifInfo?.fileSizeInByte || 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const queryParams = asQueryString(authManager.params);
|
|
||||||
|
|
||||||
for (const [i, { filename, id }] of assets.entries()) {
|
|
||||||
if (i !== 0) {
|
|
||||||
// play nice with Safari
|
|
||||||
await sleep(500);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
toastManager.success($t('downloading_asset_filename', { values: { filename: asset.originalFileName } }));
|
|
||||||
downloadUrl(getBaseUrl() + `/assets/${id}/original` + (queryParams ? `?${queryParams}` : ''), filename);
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error, $t('errors.error_downloading', { values: { filename } }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the lowercase filename extension without a dot (.) and
|
* Returns the lowercase filename extension without a dot (.) and
|
||||||
* an empty string when not found.
|
* an empty string when not found.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue