mirror of
				https://github.com/immich-app/immich.git
				synced 2025-11-03 19:17:11 -05:00 
			
		
		
		
	feat(web): avoid duplicate call + small refactor (#1731)
This commit is contained in:
		
							parent
							
								
									6b3892987a
								
							
						
					
					
						commit
						53fb3a36f7
					
				
							
								
								
									
										14
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								web/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -17,7 +17,6 @@
 | 
				
			|||||||
				"lodash-es": "^4.17.21",
 | 
									"lodash-es": "^4.17.21",
 | 
				
			||||||
				"luxon": "^3.1.1",
 | 
									"luxon": "^3.1.1",
 | 
				
			||||||
				"socket.io-client": "^4.5.1",
 | 
									"socket.io-client": "^4.5.1",
 | 
				
			||||||
				"svelte-keydown": "^0.5.0",
 | 
					 | 
				
			||||||
				"svelte-material-icons": "^2.0.2"
 | 
									"svelte-material-icons": "^2.0.2"
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			"devDependencies": {
 | 
								"devDependencies": {
 | 
				
			||||||
@ -54,7 +53,6 @@
 | 
				
			|||||||
				"svelte": "^3.44.0",
 | 
									"svelte": "^3.44.0",
 | 
				
			||||||
				"svelte-check": "^2.7.1",
 | 
									"svelte-check": "^2.7.1",
 | 
				
			||||||
				"svelte-jester": "^2.3.2",
 | 
									"svelte-jester": "^2.3.2",
 | 
				
			||||||
				"svelte-keydown": "^0.5.0",
 | 
					 | 
				
			||||||
				"svelte-preprocess": "^4.10.7",
 | 
									"svelte-preprocess": "^4.10.7",
 | 
				
			||||||
				"tailwindcss": "^3.0.24",
 | 
									"tailwindcss": "^3.0.24",
 | 
				
			||||||
				"tslib": "^2.3.1",
 | 
									"tslib": "^2.3.1",
 | 
				
			||||||
@ -10592,12 +10590,6 @@
 | 
				
			|||||||
				"svelte": ">= 3"
 | 
									"svelte": ">= 3"
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"node_modules/svelte-keydown": {
 | 
					 | 
				
			||||||
			"version": "0.5.0",
 | 
					 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/svelte-keydown/-/svelte-keydown-0.5.0.tgz",
 | 
					 | 
				
			||||||
			"integrity": "sha512-DgY6AYlKbBocSvjC3kUeNPcStJQOTOCxAGG9ymVHzJdsQ1hRJuB8pcnB4UFH8uH3bAPdYyXXa3LwenLDL41eqQ==",
 | 
					 | 
				
			||||||
			"dev": true
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		"node_modules/svelte-material-icons": {
 | 
							"node_modules/svelte-material-icons": {
 | 
				
			||||||
			"version": "2.0.4",
 | 
								"version": "2.0.4",
 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-2.0.4.tgz",
 | 
								"resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-2.0.4.tgz",
 | 
				
			||||||
@ -19031,12 +19023,6 @@
 | 
				
			|||||||
			"dev": true,
 | 
								"dev": true,
 | 
				
			||||||
			"requires": {}
 | 
								"requires": {}
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		"svelte-keydown": {
 | 
					 | 
				
			||||||
			"version": "0.5.0",
 | 
					 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/svelte-keydown/-/svelte-keydown-0.5.0.tgz",
 | 
					 | 
				
			||||||
			"integrity": "sha512-DgY6AYlKbBocSvjC3kUeNPcStJQOTOCxAGG9ymVHzJdsQ1hRJuB8pcnB4UFH8uH3bAPdYyXXa3LwenLDL41eqQ==",
 | 
					 | 
				
			||||||
			"dev": true
 | 
					 | 
				
			||||||
		},
 | 
					 | 
				
			||||||
		"svelte-material-icons": {
 | 
							"svelte-material-icons": {
 | 
				
			||||||
			"version": "2.0.4",
 | 
								"version": "2.0.4",
 | 
				
			||||||
			"resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-2.0.4.tgz",
 | 
								"resolved": "https://registry.npmjs.org/svelte-material-icons/-/svelte-material-icons-2.0.4.tgz",
 | 
				
			||||||
 | 
				
			|||||||
@ -52,7 +52,6 @@
 | 
				
			|||||||
		"svelte": "^3.44.0",
 | 
							"svelte": "^3.44.0",
 | 
				
			||||||
		"svelte-check": "^2.7.1",
 | 
							"svelte-check": "^2.7.1",
 | 
				
			||||||
		"svelte-jester": "^2.3.2",
 | 
							"svelte-jester": "^2.3.2",
 | 
				
			||||||
		"svelte-keydown": "^0.5.0",
 | 
					 | 
				
			||||||
		"svelte-preprocess": "^4.10.7",
 | 
							"svelte-preprocess": "^4.10.7",
 | 
				
			||||||
		"tailwindcss": "^3.0.24",
 | 
							"tailwindcss": "^3.0.24",
 | 
				
			||||||
		"tslib": "^2.3.1",
 | 
							"tslib": "^2.3.1",
 | 
				
			||||||
@ -70,7 +69,6 @@
 | 
				
			|||||||
		"lodash-es": "^4.17.21",
 | 
							"lodash-es": "^4.17.21",
 | 
				
			||||||
		"luxon": "^3.1.1",
 | 
							"luxon": "^3.1.1",
 | 
				
			||||||
		"socket.io-client": "^4.5.1",
 | 
							"socket.io-client": "^4.5.1",
 | 
				
			||||||
		"svelte-keydown": "^0.5.0",
 | 
					 | 
				
			||||||
		"svelte-material-icons": "^2.0.2"
 | 
							"svelte-material-icons": "^2.0.2"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -304,7 +304,7 @@
 | 
				
			|||||||
						on:onVideoEnded={() => (shouldPlayMotionPhoto = false)}
 | 
											on:onVideoEnded={() => (shouldPlayMotionPhoto = false)}
 | 
				
			||||||
					/>
 | 
										/>
 | 
				
			||||||
				{:else}
 | 
									{:else}
 | 
				
			||||||
					<PhotoViewer {publicSharedKey} assetId={asset.id} on:close={closeViewer} />
 | 
										<PhotoViewer {publicSharedKey} {asset} on:close={closeViewer} />
 | 
				
			||||||
				{/if}
 | 
									{/if}
 | 
				
			||||||
			{:else}
 | 
								{:else}
 | 
				
			||||||
				<VideoViewer {publicSharedKey} assetId={asset.id} on:close={closeViewer} />
 | 
									<VideoViewer {publicSharedKey} assetId={asset.id} on:close={closeViewer} />
 | 
				
			||||||
 | 
				
			|||||||
@ -1,39 +1,21 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
	import { fade } from 'svelte/transition';
 | 
						import { fade } from 'svelte/transition';
 | 
				
			||||||
 | 
					 | 
				
			||||||
	import { onMount } from 'svelte';
 | 
					 | 
				
			||||||
	import LoadingSpinner from '../shared-components/loading-spinner.svelte';
 | 
						import LoadingSpinner from '../shared-components/loading-spinner.svelte';
 | 
				
			||||||
	import { api, AssetResponseDto } from '@api';
 | 
						import { api, AssetResponseDto } from '@api';
 | 
				
			||||||
	import Keydown from 'svelte-keydown';
 | 
						import { copyImageToClipboard } from 'copy-image-clipboard';
 | 
				
			||||||
	import {
 | 
						import {
 | 
				
			||||||
		notificationController,
 | 
							notificationController,
 | 
				
			||||||
		NotificationType
 | 
							NotificationType
 | 
				
			||||||
	} from '../shared-components/notification/notification';
 | 
						} from '../shared-components/notification/notification';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	export let assetId: string;
 | 
						export let asset: AssetResponseDto;
 | 
				
			||||||
	export let publicSharedKey = '';
 | 
						export let publicSharedKey = '';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let assetInfo: AssetResponseDto;
 | 
					 | 
				
			||||||
	let assetData: string;
 | 
						let assetData: string;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let copyImageToClipboard: (src: string) => Promise<Blob>;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	onMount(async () => {
 | 
					 | 
				
			||||||
		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
 | 
					 | 
				
			||||||
		const module = await import('copy-image-clipboard');
 | 
					 | 
				
			||||||
		copyImageToClipboard = module.copyImageToClipboard;
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const loadAssetData = async () => {
 | 
						const loadAssetData = async () => {
 | 
				
			||||||
		try {
 | 
							try {
 | 
				
			||||||
			const { data } = await api.assetApi.serveFile(assetInfo.id, false, true, {
 | 
								const { data } = await api.assetApi.serveFile(asset.id, false, true, {
 | 
				
			||||||
				params: {
 | 
									params: {
 | 
				
			||||||
					key: publicSharedKey
 | 
										key: publicSharedKey
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
@ -51,42 +33,51 @@
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const handleKeypress = async (keyEvent: CustomEvent<string>) => {
 | 
						const handleKeypress = async ({ metaKey, ctrlKey, key }: KeyboardEvent) => {
 | 
				
			||||||
		if (keyEvent.detail == 'Control-c' || keyEvent.detail == 'Meta-c') {
 | 
							if ((metaKey || ctrlKey) && key === 'c') {
 | 
				
			||||||
			await doCopy();
 | 
								await doCopy();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	export const doCopy = async () => {
 | 
						export const doCopy = async () => {
 | 
				
			||||||
		await copyImageToClipboard(assetData);
 | 
							try {
 | 
				
			||||||
		notificationController.show({
 | 
								await copyImageToClipboard(assetData);
 | 
				
			||||||
			type: NotificationType.Info,
 | 
								notificationController.show({
 | 
				
			||||||
			message: 'Copied image to clipboard.',
 | 
									type: NotificationType.Info,
 | 
				
			||||||
			timeout: 3000
 | 
									message: 'Copied image to clipboard.',
 | 
				
			||||||
		});
 | 
									timeout: 3000
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							} catch (err) {
 | 
				
			||||||
 | 
								console.error(err);
 | 
				
			||||||
 | 
								notificationController.show({
 | 
				
			||||||
 | 
									type: NotificationType.Error,
 | 
				
			||||||
 | 
									message: 'Copying image to clipboard failed. Click here to learn more.',
 | 
				
			||||||
 | 
									timeout: 5000,
 | 
				
			||||||
 | 
									action: {
 | 
				
			||||||
 | 
										type: 'link',
 | 
				
			||||||
 | 
										target:
 | 
				
			||||||
 | 
											'https://github.com/LuanEdCosta/copy-image-clipboard#enable-clipboard-api-features-in-firefox'
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
</script>
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<Keydown on:combo={handleKeypress} />
 | 
					<svelte:window on:keydown={handleKeypress} on:copyImage={doCopy} />
 | 
				
			||||||
 | 
					 | 
				
			||||||
<svelte:window on:copyImage={async () => await doCopy()} />
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
<div
 | 
					<div
 | 
				
			||||||
	transition:fade={{ duration: 150 }}
 | 
						transition:fade={{ duration: 150 }}
 | 
				
			||||||
	class="flex place-items-center place-content-center h-full select-none"
 | 
						class="flex place-items-center place-content-center h-full select-none"
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
	{#if assetInfo}
 | 
						{#await loadAssetData()}
 | 
				
			||||||
		{#await loadAssetData()}
 | 
							<LoadingSpinner />
 | 
				
			||||||
			<LoadingSpinner />
 | 
						{:then assetData}
 | 
				
			||||||
		{:then assetData}
 | 
							<img
 | 
				
			||||||
			<img
 | 
								transition:fade={{ duration: 150 }}
 | 
				
			||||||
				transition:fade={{ duration: 150 }}
 | 
								src={assetData}
 | 
				
			||||||
				src={assetData}
 | 
								alt={asset.id}
 | 
				
			||||||
				alt={assetId}
 | 
								class="object-contain h-full transition-all"
 | 
				
			||||||
				class="object-contain h-full transition-all"
 | 
								draggable="false"
 | 
				
			||||||
				loading="lazy"
 | 
							/>
 | 
				
			||||||
				draggable="false"
 | 
						{/await}
 | 
				
			||||||
			/>
 | 
					 | 
				
			||||||
		{/await}
 | 
					 | 
				
			||||||
	{/if}
 | 
					 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
				
			|||||||
@ -1,40 +1,17 @@
 | 
				
			|||||||
<script lang="ts">
 | 
					<script lang="ts">
 | 
				
			||||||
	import { fade } from 'svelte/transition';
 | 
						import { fade } from 'svelte/transition';
 | 
				
			||||||
 | 
						import { createEventDispatcher } from 'svelte';
 | 
				
			||||||
	import { createEventDispatcher, onMount } from 'svelte';
 | 
					 | 
				
			||||||
	import LoadingSpinner from '../shared-components/loading-spinner.svelte';
 | 
						import LoadingSpinner from '../shared-components/loading-spinner.svelte';
 | 
				
			||||||
	import { api, AssetResponseDto, getFileUrl } from '@api';
 | 
						import { getFileUrl } from '@api';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	export let assetId: string;
 | 
						export let assetId: string;
 | 
				
			||||||
	export let publicSharedKey = '';
 | 
						export let publicSharedKey = '';
 | 
				
			||||||
	let asset: AssetResponseDto;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	let isVideoLoading = true;
 | 
						let isVideoLoading = true;
 | 
				
			||||||
	let videoUrl: string;
 | 
					 | 
				
			||||||
	const dispatch = createEventDispatcher();
 | 
						const dispatch = createEventDispatcher();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	onMount(async () => {
 | 
						const handleCanPlay = (ev: Event & { currentTarget: HTMLVideoElement }) => {
 | 
				
			||||||
		const { data: assetInfo } = await api.assetApi.getAssetById(assetId, {
 | 
							const playerNode = ev.currentTarget;
 | 
				
			||||||
			params: {
 | 
					 | 
				
			||||||
				key: publicSharedKey
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		await loadVideoData(assetInfo);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		asset = assetInfo;
 | 
					 | 
				
			||||||
	});
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const loadVideoData = async (assetInfo: AssetResponseDto) => {
 | 
					 | 
				
			||||||
		isVideoLoading = true;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		videoUrl = getFileUrl(assetInfo.id, false, true, publicSharedKey);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return assetInfo;
 | 
					 | 
				
			||||||
	};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	const handleCanPlay = (ev: Event) => {
 | 
					 | 
				
			||||||
		const playerNode = ev.target as HTMLVideoElement;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		playerNode.muted = true;
 | 
							playerNode.muted = true;
 | 
				
			||||||
		playerNode.play();
 | 
							playerNode.play();
 | 
				
			||||||
@ -48,21 +25,19 @@
 | 
				
			|||||||
	transition:fade={{ duration: 150 }}
 | 
						transition:fade={{ duration: 150 }}
 | 
				
			||||||
	class="flex place-items-center place-content-center h-full select-none"
 | 
						class="flex place-items-center place-content-center h-full select-none"
 | 
				
			||||||
>
 | 
					>
 | 
				
			||||||
	{#if asset}
 | 
						<video
 | 
				
			||||||
		<video
 | 
							controls
 | 
				
			||||||
			controls
 | 
							class="h-full object-contain"
 | 
				
			||||||
			class="h-full object-contain"
 | 
							src={getFileUrl(assetId, false, true, publicSharedKey)}
 | 
				
			||||||
			on:canplay={handleCanPlay}
 | 
							on:canplay={handleCanPlay}
 | 
				
			||||||
			on:ended={() => dispatch('onVideoEnded')}
 | 
							on:ended={() => dispatch('onVideoEnded')}
 | 
				
			||||||
		>
 | 
						>
 | 
				
			||||||
			<source src={videoUrl} type="video/mp4" />
 | 
							<track kind="captions" />
 | 
				
			||||||
			<track kind="captions" />
 | 
						</video>
 | 
				
			||||||
		</video>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
		{#if isVideoLoading}
 | 
						{#if isVideoLoading}
 | 
				
			||||||
			<div class="absolute flex place-items-center place-content-center">
 | 
							<div class="absolute flex place-items-center place-content-center">
 | 
				
			||||||
				<LoadingSpinner />
 | 
								<LoadingSpinner />
 | 
				
			||||||
			</div>
 | 
							</div>
 | 
				
			||||||
		{/if}
 | 
					 | 
				
			||||||
	{/if}
 | 
						{/if}
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user