mirror of
https://github.com/immich-app/immich
synced 2025-11-07 17:27:20 +00:00
feat(web/server) public album sharing (#1266)
This commit is contained in:
parent
fd15cdbf40
commit
10789503c1
101 changed files with 4879 additions and 347 deletions
|
|
@ -23,7 +23,7 @@
|
|||
export let showMotionPlayButton: boolean;
|
||||
export let isMotionPhotoPlaying = false;
|
||||
|
||||
const isOwner = asset.ownerId === $page.data.user.id;
|
||||
const isOwner = asset.ownerId === $page.data.user?.id;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
|
|
@ -94,12 +94,15 @@
|
|||
title="Favorite"
|
||||
/>
|
||||
{/if}
|
||||
<CircleIconButton logo={DeleteOutline} on:click={() => dispatch('delete')} title="Delete" />
|
||||
<CircleIconButton
|
||||
logo={DotsVertical}
|
||||
on:click={(event) => showOptionsMenu(event)}
|
||||
title="More"
|
||||
/>
|
||||
|
||||
{#if isOwner}
|
||||
<CircleIconButton logo={DeleteOutline} on:click={() => dispatch('delete')} title="Delete" />
|
||||
<CircleIconButton
|
||||
logo={DotsVertical}
|
||||
on:click={(event) => showOptionsMenu(event)}
|
||||
title="More"
|
||||
/>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -10,12 +10,7 @@
|
|||
import { downloadAssets } from '$lib/stores/download';
|
||||
import VideoViewer from './video-viewer.svelte';
|
||||
import AlbumSelectionModal from '../shared-components/album-selection-modal.svelte';
|
||||
import {
|
||||
api,
|
||||
AssetResponseDto,
|
||||
AssetTypeEnum,
|
||||
AlbumResponseDto
|
||||
} from '@api';
|
||||
import { api, AssetResponseDto, AssetTypeEnum, AlbumResponseDto } from '@api';
|
||||
import {
|
||||
notificationController,
|
||||
NotificationType
|
||||
|
|
@ -25,6 +20,9 @@
|
|||
import { addAssetsToAlbum } from '$lib/utils/asset-utils';
|
||||
|
||||
export let asset: AssetResponseDto;
|
||||
export let publicSharedKey = '';
|
||||
export let showNavigation = true;
|
||||
|
||||
$: {
|
||||
appearsInAlbums = [];
|
||||
|
||||
|
|
@ -91,12 +89,12 @@
|
|||
|
||||
const handleDownload = () => {
|
||||
if (asset.livePhotoVideoId) {
|
||||
downloadFile(asset.livePhotoVideoId, true);
|
||||
downloadFile(asset.id, false);
|
||||
downloadFile(asset.livePhotoVideoId, true, publicSharedKey);
|
||||
downloadFile(asset.id, false, publicSharedKey);
|
||||
return;
|
||||
}
|
||||
|
||||
downloadFile(asset.id, false);
|
||||
downloadFile(asset.id, false, publicSharedKey);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -111,7 +109,7 @@
|
|||
};
|
||||
};
|
||||
|
||||
const downloadFile = async (assetId: string, isLivePhoto: boolean) => {
|
||||
const downloadFile = async (assetId: string, isLivePhoto: boolean, key: string) => {
|
||||
try {
|
||||
const { filenameWithoutExtension } = getTemplateFilename();
|
||||
|
||||
|
|
@ -126,6 +124,9 @@
|
|||
$downloadAssets[imageFileName] = 0;
|
||||
|
||||
const { data, status } = await api.assetApi.downloadFile(assetId, false, false, {
|
||||
params: {
|
||||
key
|
||||
},
|
||||
responseType: 'blob',
|
||||
onDownloadProgress: (progressEvent) => {
|
||||
if (progressEvent.lengthComputable) {
|
||||
|
|
@ -251,69 +252,74 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class={`row-start-2 row-span-end col-start-1 col-span-2 flex place-items-center hover:cursor-pointer w-3/4 mb-[60px] ${
|
||||
asset.type === AssetTypeEnum.Video ? '' : 'z-[999]'
|
||||
}`}
|
||||
on:mouseenter={() => {
|
||||
halfLeftHover = true;
|
||||
halfRightHover = false;
|
||||
}}
|
||||
on:mouseleave={() => {
|
||||
halfLeftHover = false;
|
||||
}}
|
||||
on:click={navigateAssetBackward}
|
||||
on:keydown={navigateAssetBackward}
|
||||
>
|
||||
<button
|
||||
class="rounded-full p-3 hover:bg-gray-500 hover:text-gray-700 z-[1000] text-gray-500 mx-4"
|
||||
class:navigation-button-hover={halfLeftHover}
|
||||
{#if showNavigation}
|
||||
<div
|
||||
class={`row-start-2 row-span-end col-start-1 col-span-2 flex place-items-center hover:cursor-pointer w-3/4 mb-[60px] ${
|
||||
asset.type === AssetTypeEnum.Video ? '' : 'z-[999]'
|
||||
}`}
|
||||
on:mouseenter={() => {
|
||||
halfLeftHover = true;
|
||||
halfRightHover = false;
|
||||
}}
|
||||
on:mouseleave={() => {
|
||||
halfLeftHover = false;
|
||||
}}
|
||||
on:click={navigateAssetBackward}
|
||||
on:keydown={navigateAssetBackward}
|
||||
>
|
||||
<ChevronLeft size="36" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="rounded-full p-3 hover:bg-gray-500 hover:text-gray-700 z-[1000] text-gray-500 mx-4"
|
||||
class:navigation-button-hover={halfLeftHover}
|
||||
on:click={navigateAssetBackward}
|
||||
>
|
||||
<ChevronLeft size="36" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="row-start-1 row-span-full col-start-1 col-span-4">
|
||||
{#key asset.id}
|
||||
{#if asset.type === AssetTypeEnum.Image}
|
||||
{#if shouldPlayMotionPhoto && asset.livePhotoVideoId}
|
||||
<VideoViewer
|
||||
{publicSharedKey}
|
||||
assetId={asset.livePhotoVideoId}
|
||||
on:close={closeViewer}
|
||||
on:onVideoEnded={() => (shouldPlayMotionPhoto = false)}
|
||||
/>
|
||||
{:else}
|
||||
<PhotoViewer assetId={asset.id} on:close={closeViewer} />
|
||||
<PhotoViewer {publicSharedKey} assetId={asset.id} on:close={closeViewer} />
|
||||
{/if}
|
||||
{:else}
|
||||
<VideoViewer assetId={asset.id} on:close={closeViewer} />
|
||||
<VideoViewer {publicSharedKey} assetId={asset.id} on:close={closeViewer} />
|
||||
{/if}
|
||||
{/key}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class={`row-start-2 row-span-full col-start-3 col-span-2 flex justify-end place-items-center hover:cursor-pointer w-3/4 justify-self-end mb-[60px] ${
|
||||
asset.type === AssetTypeEnum.Video ? '' : 'z-[500]'
|
||||
}`}
|
||||
on:click={navigateAssetForward}
|
||||
on:keydown={navigateAssetForward}
|
||||
on:mouseenter={() => {
|
||||
halfLeftHover = false;
|
||||
halfRightHover = true;
|
||||
}}
|
||||
on:mouseleave={() => {
|
||||
halfRightHover = false;
|
||||
}}
|
||||
>
|
||||
<button
|
||||
class="rounded-full p-3 hover:bg-gray-500 hover:text-gray-700 text-gray-500 mx-4"
|
||||
class:navigation-button-hover={halfRightHover}
|
||||
{#if showNavigation}
|
||||
<div
|
||||
class={`row-start-2 row-span-full col-start-3 col-span-2 flex justify-end place-items-center hover:cursor-pointer w-3/4 justify-self-end mb-[60px] ${
|
||||
asset.type === AssetTypeEnum.Video ? '' : 'z-[500]'
|
||||
}`}
|
||||
on:click={navigateAssetForward}
|
||||
on:keydown={navigateAssetForward}
|
||||
on:mouseenter={() => {
|
||||
halfLeftHover = false;
|
||||
halfRightHover = true;
|
||||
}}
|
||||
on:mouseleave={() => {
|
||||
halfRightHover = false;
|
||||
}}
|
||||
>
|
||||
<ChevronRight size="36" />
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
class="rounded-full p-3 hover:bg-gray-500 hover:text-gray-700 text-gray-500 mx-4"
|
||||
class:navigation-button-hover={halfRightHover}
|
||||
on:click={navigateAssetForward}
|
||||
>
|
||||
<ChevronRight size="36" />
|
||||
</button>
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
{#if isShowDetail}
|
||||
<div
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
} from '../shared-components/notification/notification';
|
||||
|
||||
export let assetId: string;
|
||||
export let publicSharedKey = '';
|
||||
|
||||
let assetInfo: AssetResponseDto;
|
||||
let assetData: string;
|
||||
|
|
@ -18,7 +19,11 @@
|
|||
let copyImageToClipboard: (src: string) => Promise<Blob>;
|
||||
|
||||
onMount(async () => {
|
||||
const { data } = await api.assetApi.getAssetById(assetId);
|
||||
const { data } = await api.assetApi.getAssetById(assetId, {
|
||||
params: {
|
||||
key: publicSharedKey
|
||||
}
|
||||
});
|
||||
assetInfo = data;
|
||||
|
||||
//Import hack :( see https://github.com/vadimkorr/svelte-carousel/issues/27#issuecomment-851022295
|
||||
|
|
@ -29,6 +34,9 @@
|
|||
const loadAssetData = async () => {
|
||||
try {
|
||||
const { data } = await api.assetApi.serveFile(assetInfo.id, false, true, {
|
||||
params: {
|
||||
key: publicSharedKey
|
||||
},
|
||||
responseType: 'blob'
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
import { api, AssetResponseDto, getFileUrl } from '@api';
|
||||
|
||||
export let assetId: string;
|
||||
|
||||
export let publicSharedKey = '';
|
||||
let asset: AssetResponseDto;
|
||||
|
||||
let videoPlayerNode: HTMLVideoElement;
|
||||
|
|
@ -15,7 +15,11 @@
|
|||
const dispatch = createEventDispatcher();
|
||||
|
||||
onMount(async () => {
|
||||
const { data: assetInfo } = await api.assetApi.getAssetById(assetId);
|
||||
const { data: assetInfo } = await api.assetApi.getAssetById(assetId, {
|
||||
params: {
|
||||
key: publicSharedKey
|
||||
}
|
||||
});
|
||||
|
||||
await loadVideoData(assetInfo);
|
||||
|
||||
|
|
@ -25,7 +29,7 @@
|
|||
const loadVideoData = async (assetInfo: AssetResponseDto) => {
|
||||
isVideoLoading = true;
|
||||
|
||||
videoUrl = getFileUrl(assetInfo.id, false, true);
|
||||
videoUrl = getFileUrl(assetInfo.id, false, true, publicSharedKey);
|
||||
|
||||
return assetInfo;
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue